Merge "Update InputConsumer_test.cpp to use getFdStateDebug" into main
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index d233902..bf9acb3 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -160,8 +160,7 @@
* Available since API level 29.
*/
typedef void (*ASurfaceTransaction_OnComplete)(void* _Null_unspecified context,
- ASurfaceTransactionStats* _Nonnull stats)
- __INTRODUCED_IN(29);
+ ASurfaceTransactionStats* _Nonnull stats);
/**
* The ASurfaceTransaction_OnCommit callback is invoked when transaction is applied and the updates
@@ -189,8 +188,7 @@
* Available since API level 31.
*/
typedef void (*ASurfaceTransaction_OnCommit)(void* _Null_unspecified context,
- ASurfaceTransactionStats* _Nonnull stats)
- __INTRODUCED_IN(31);
+ ASurfaceTransactionStats* _Nonnull stats);
/**
* The ASurfaceTransaction_OnBufferRelease callback is invoked when a buffer that was passed in
@@ -219,7 +217,7 @@
* Available since API level 36.
*/
typedef void (*ASurfaceTransaction_OnBufferRelease)(void* _Null_unspecified context,
- int release_fence_fd) __INTRODUCED_IN(36);
+ int release_fence_fd);
/**
* Returns the timestamp of when the frame was latched by the framework. Once a frame is
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 1d26d85..6698d0c 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -232,6 +232,15 @@
return cmd;
}
+static void printReturnCommandParcel(std::ostream& out, const Parcel& parcel) {
+ const void* cmds = parcel.data();
+ out << "\t" << HexDump(cmds, parcel.dataSize()) << "\n";
+ IF_LOG_COMMANDS() {
+ const void* end = parcel.data() + parcel.dataSize();
+ while (cmds < end) cmds = printReturnCommand(out, cmds);
+ }
+}
+
static const void* printCommand(std::ostream& out, const void* _cmd) {
static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
const int32_t* cmd = (const int32_t*)_cmd;
@@ -1235,13 +1244,15 @@
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
- if (bwr.write_consumed < mOut.dataSize())
+ if (bwr.write_consumed < mOut.dataSize()) {
+ std::ostringstream logStream;
+ printReturnCommandParcel(logStream, mIn);
LOG_ALWAYS_FATAL("Driver did not consume write buffer. "
- "err: %s consumed: %zu of %zu",
- statusToString(err).c_str(),
- (size_t)bwr.write_consumed,
- mOut.dataSize());
- else {
+ "err: %s consumed: %zu of %zu.\n"
+ "Return command: %s",
+ statusToString(err).c_str(), (size_t)bwr.write_consumed,
+ mOut.dataSize(), logStream.str().c_str());
+ } else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
@@ -1252,14 +1263,8 @@
}
IF_LOG_COMMANDS() {
std::ostringstream logStream;
- logStream << "Remaining data size: " << mOut.dataSize() << "\n";
- logStream << "Received commands from driver: ";
- const void* cmds = mIn.data();
- const void* end = mIn.data() + mIn.dataSize();
- logStream << "\t" << HexDump(cmds, mIn.dataSize()) << "\n";
- while (cmds < end) cmds = printReturnCommand(logStream, cmds);
- std::string message = logStream.str();
- ALOGI("%s", message.c_str());
+ printReturnCommandParcel(logStream, mIn);
+ ALOGI("%s", logStream.str().c_str());
}
return NO_ERROR;
}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index a1e53c5..0ef200b 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -499,11 +499,11 @@
EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs);
- // Potential flake, but make sure calls are handled in parallel. Due
- // to past flakes, this only checks that the amount of time taken has
- // some parallelism. Other tests such as ThreadPoolGreaterThanEqualRequested
- // check this more exactly.
- EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs);
+ // b/272429574, b/365294257
+ // This flakes too much to test. Parallelization is tested
+ // in ThreadPoolGreaterThanEqualRequested and other tests.
+ // Test to make sure calls are handled in parallel.
+ // EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs);
}
TEST_P(BinderRpc, ThreadPoolOverSaturated) {
@@ -515,8 +515,7 @@
constexpr size_t kNumCalls = kNumThreads + 3;
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
- // b/272429574 - below 500ms, the test fails
- testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/);
+ testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/);
}
TEST_P(BinderRpc, ThreadPoolLimitOutgoing) {
@@ -530,8 +529,7 @@
auto proc = createRpcTestSocketServerProcess(
{.numThreads = kNumThreads, .numOutgoingConnections = kNumOutgoingConnections});
- // b/272429574 - below 500ms, the test fails
- testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/);
+ testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/);
}
TEST_P(BinderRpc, ThreadingStressTest) {
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index a4d105d..da74e9c 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -45,7 +45,10 @@
#include <system/window.h>
+#include <com_android_graphics_libgui_flags.h>
+
namespace android {
+using namespace com::android::graphics::libgui;
// Macros for include BufferQueueCore information in log messages
#define BQ_LOGV(x, ...) \
@@ -924,6 +927,7 @@
uint64_t currentFrameNumber = 0;
BufferItem item;
int connectedApi;
+ bool enableEglCpuThrottling = true;
sp<Fence> lastQueuedFence;
{ // Autolock scope
@@ -1097,6 +1101,9 @@
VALIDATE_CONSISTENCY();
connectedApi = mCore->mConnectedApi;
+ if (flags::bq_producer_throttles_only_async_mode()) {
+ enableEglCpuThrottling = mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock;
+ }
lastQueuedFence = std::move(mLastQueueBufferFence);
mLastQueueBufferFence = std::move(acquireFence);
@@ -1142,7 +1149,7 @@
}
// Wait without lock held
- if (connectedApi == NATIVE_WINDOW_API_EGL) {
+ if (connectedApi == NATIVE_WINDOW_API_EGL && enableEglCpuThrottling) {
// Waiting here allows for two full buffers to be queued but not a
// third. In the event that frames take varying time, this makes a
// small trade-off in favor of latency rather than throughput.
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index c5f9c38..f126c0b 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -139,9 +139,9 @@
uint32_t ignore;
auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow |
ISurfaceComposerClient::eOpaque);
- mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat,
+ mBbqChild = mClient->createSurface(String8::format("[BBQ] %s", mName.c_str()), 0, 0, mFormat,
flags, mHandle, {}, &ignore);
- mBbq = sp<BLASTBufferQueue>::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat);
+ mBbq = sp<BLASTBufferQueue>::make("[BBQ]" + mName, mBbqChild, mWidth, mHeight, mFormat);
// This surface is always consumed by SurfaceFlinger, so the
// producerControlledByApp value doesn't matter; using false.
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
index df9b73b..d3f2899 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -106,4 +106,12 @@
description: "Remove usage of IGBPs in the libcameraservice."
bug: "342197849"
is_fixed_read_only: true
-} # wb_libcameraservice
\ No newline at end of file
+} # wb_libcameraservice
+
+flag {
+ name: "bq_producer_throttles_only_async_mode"
+ namespace: "core_graphics"
+ description: "BufferQueueProducer only CPU throttle on queueBuffer() in async mode."
+ bug: "359252619"
+ is_fixed_read_only: true
+} # bq_producer_throttles_only_async_mode
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index f1c4aed..60fb00e 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -192,3 +192,18 @@
description: "Prevents touchpad gesture changing window focus."
bug: "364460018"
}
+
+flag {
+ name: "enable_input_policy_profile"
+ namespace: "input"
+ description: "Apply input policy profile for input threads."
+ bug: "347122505"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "keyboard_repeat_keys"
+ namespace: "input"
+ description: "Allow user to enable key repeats or configure timeout before key repeat and key repeat delay rates."
+ bug: "336585002"
+}
diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp
index e3be3bc..d0ca78e 100644
--- a/libs/nativedisplay/ADisplay.cpp
+++ b/libs/nativedisplay/ADisplay.cpp
@@ -129,7 +129,7 @@
std::vector<DisplayConfigImpl> modesPerDisplay[size];
ui::DisplayConnectionType displayConnectionTypes[size];
int numModes = 0;
- for (int i = 0; i < size; ++i) {
+ for (size_t i = 0; i < size; ++i) {
ui::StaticDisplayInfo staticInfo;
if (const status_t status =
SurfaceComposerClient::getStaticDisplayInfo(ids[i].value, &staticInfo);
@@ -151,7 +151,7 @@
numModes += modes.size();
modesPerDisplay[i].reserve(modes.size());
- for (int j = 0; j < modes.size(); ++j) {
+ for (size_t j = 0; j < modes.size(); ++j) {
const ui::DisplayMode& mode = modes[j];
modesPerDisplay[i].emplace_back(
DisplayConfigImpl{static_cast<size_t>(mode.id), mode.resolution.getWidth(),
@@ -224,7 +224,7 @@
CHECK_NOT_NULL(display);
DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
float maxFps = 0.0;
- for (int i = 0; i < impl->numConfigs; ++i) {
+ for (size_t i = 0; i < impl->numConfigs; ++i) {
maxFps = std::max(maxFps, impl->configs[i].fps);
}
return maxFps;
@@ -261,7 +261,7 @@
for (size_t i = 0; i < impl->numConfigs; i++) {
auto* config = impl->configs + i;
- if (config->id == info.activeDisplayModeId) {
+ if (info.activeDisplayModeId >= 0 && config->id == (size_t)info.activeDisplayModeId) {
*outConfig = reinterpret_cast<ADisplayConfig*>(config);
return OK;
}
diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs
index a3a9dc6..c41ab8d 100644
--- a/libs/nativewindow/rust/src/handle.rs
+++ b/libs/nativewindow/rust/src/handle.rs
@@ -12,7 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use std::{mem::forget, ptr::NonNull};
+use std::{
+ ffi::c_int,
+ mem::forget,
+ os::fd::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
+ ptr::NonNull,
+};
/// Rust wrapper around `native_handle_t`.
///
@@ -22,6 +27,108 @@
pub struct NativeHandle(NonNull<ffi::native_handle_t>);
impl NativeHandle {
+ /// Creates a new `NativeHandle` with the given file descriptors and integer values.
+ ///
+ /// The `NativeHandle` will take ownership of the file descriptors and close them when it is
+ /// dropped.
+ pub fn new(fds: Vec<OwnedFd>, ints: &[c_int]) -> Option<Self> {
+ let fd_count = fds.len();
+ // SAFETY: native_handle_create doesn't have any safety requirements.
+ let handle = unsafe {
+ ffi::native_handle_create(fd_count.try_into().unwrap(), ints.len().try_into().unwrap())
+ };
+ let handle = NonNull::new(handle)?;
+ for (i, fd) in fds.into_iter().enumerate() {
+ // SAFETY: `handle` must be valid because it was just created, and the array offset is
+ // within the bounds of what we allocated above.
+ unsafe {
+ *(*handle.as_ptr()).data.as_mut_ptr().add(i) = fd.into_raw_fd();
+ }
+ }
+ for (i, value) in ints.iter().enumerate() {
+ // SAFETY: `handle` must be valid because it was just created, and the array offset is
+ // within the bounds of what we allocated above. Note that `data` is uninitialized
+ // until after this so we can't use `slice::from_raw_parts_mut` or similar to create a
+ // reference to it so we use raw pointers arithmetic instead.
+ unsafe {
+ *(*handle.as_ptr()).data.as_mut_ptr().add(fd_count + i) = *value;
+ }
+ }
+ // SAFETY: `handle` must be valid because it was just created.
+ unsafe {
+ ffi::native_handle_set_fdsan_tag(handle.as_ptr());
+ }
+ Some(Self(handle))
+ }
+
+ /// Returns a borrowed view of all the file descriptors in this native handle.
+ pub fn fds(&self) -> Vec<BorrowedFd> {
+ self.data()[..self.fd_count()]
+ .iter()
+ .map(|fd| {
+ // SAFETY: The `native_handle_t` maintains ownership of the file descriptor so it
+ // won't be closed until this `NativeHandle` is destroyed. The `BorrowedFd` will
+ // have a lifetime constrained to that of `&self`, so it can't outlive it.
+ unsafe { BorrowedFd::borrow_raw(*fd) }
+ })
+ .collect()
+ }
+
+ /// Returns the integer values in this native handle.
+ pub fn ints(&self) -> &[c_int] {
+ &self.data()[self.fd_count()..]
+ }
+
+ /// Destroys the `NativeHandle`, taking ownership of the file descriptors it contained.
+ pub fn into_fds(self) -> Vec<OwnedFd> {
+ let fds = self.data()[..self.fd_count()]
+ .iter()
+ .map(|fd| {
+ // SAFETY: The `native_handle_t` has ownership of the file descriptor, and
+ // after this we destroy it without closing the file descriptor so we can take over
+ // ownership of it.
+ unsafe { OwnedFd::from_raw_fd(*fd) }
+ })
+ .collect();
+
+ // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed
+ // after this because we own it and forget it.
+ unsafe {
+ assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0);
+ }
+ // Don't drop self, as that would cause `native_handle_close` to be called and close the
+ // file descriptors.
+ forget(self);
+ fds
+ }
+
+ /// Returns a reference to the underlying `native_handle_t`.
+ fn as_ref(&self) -> &ffi::native_handle_t {
+ // SAFETY: All the ways of creating a `NativeHandle` ensure that the `native_handle_t` is
+ // valid and initialised, and lives as long as the `NativeHandle`. We enforce Rust's
+ // aliasing rules by giving the reference a lifetime matching that of `&self`.
+ unsafe { self.0.as_ref() }
+ }
+
+ /// Returns the number of file descriptors included in the native handle.
+ fn fd_count(&self) -> usize {
+ self.as_ref().numFds.try_into().unwrap()
+ }
+
+ /// Returns the number of integer values included in the native handle.
+ fn int_count(&self) -> usize {
+ self.as_ref().numInts.try_into().unwrap()
+ }
+
+ /// Returns a slice reference for all the used `data` field of the native handle, including both
+ /// file descriptors and integers.
+ fn data(&self) -> &[c_int] {
+ let total_count = self.fd_count() + self.int_count();
+ // SAFETY: The data must have been initialised with this number of elements when the
+ // `NativeHandle` was created.
+ unsafe { self.as_ref().data.as_slice(total_count) }
+ }
+
/// Wraps a raw `native_handle_t` pointer, taking ownership of it.
///
/// # Safety
@@ -90,3 +197,47 @@
// SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just
// integers and file descriptors.
unsafe impl Sync for NativeHandle {}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::fs::File;
+
+ #[test]
+ fn create_empty() {
+ let handle = NativeHandle::new(vec![], &[]).unwrap();
+ assert_eq!(handle.fds().len(), 0);
+ assert_eq!(handle.ints(), &[]);
+ }
+
+ #[test]
+ fn create_with_ints() {
+ let handle = NativeHandle::new(vec![], &[1, 2, 42]).unwrap();
+ assert_eq!(handle.fds().len(), 0);
+ assert_eq!(handle.ints(), &[1, 2, 42]);
+ }
+
+ #[test]
+ fn create_with_fd() {
+ let file = File::open("/dev/null").unwrap();
+ let handle = NativeHandle::new(vec![file.into()], &[]).unwrap();
+ assert_eq!(handle.fds().len(), 1);
+ assert_eq!(handle.ints(), &[]);
+ }
+
+ #[test]
+ fn clone() {
+ let file = File::open("/dev/null").unwrap();
+ let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
+ assert_eq!(original.ints(), &[42]);
+ assert_eq!(original.fds().len(), 1);
+
+ let cloned = original.clone();
+ drop(original);
+
+ assert_eq!(cloned.ints(), &[42]);
+ assert_eq!(cloned.fds().len(), 1);
+
+ drop(cloned);
+ }
+}
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 1954fc5..0fd982e 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -97,6 +97,7 @@
bool cacheImageDimmedLayers = true;
bool cacheClippedLayers = true;
bool cacheShadowLayers = true;
+ bool cacheEdgeExtension = true;
bool cachePIPImageLayers = true;
bool cacheTransparentImageDimmedLayers = true;
bool cacheClippedDimmedImageLayers = true;
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 59b0656..57041ee 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -27,6 +27,8 @@
#include "ui/Rect.h"
#include "utils/Timers.h"
+#include <com_android_graphics_libgui_flags.h>
+
namespace android::renderengine::skia {
namespace {
@@ -619,6 +621,32 @@
}
}
+static void drawEdgeExtensionLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
+ const std::shared_ptr<ExternalTexture>& dstTexture,
+ const std::shared_ptr<ExternalTexture>& srcTexture) {
+ const Rect& displayRect = display.physicalDisplay;
+ // Make the layer
+ LayerSettings layer{
+ // Make the layer bigger than the texture
+ .geometry = Geometry{.boundaries = FloatRect(0, 0, displayRect.width(),
+ displayRect.height())},
+ .source = PixelSource{.buffer =
+ Buffer{
+ .buffer = srcTexture,
+ .isOpaque = 1,
+ }},
+ // The type of effect does not affect the shader's uniforms, but the layer must have a
+ // valid EdgeExtensionEffect to apply the shader
+ .edgeExtensionEffect =
+ EdgeExtensionEffect(true /* left */, false, false, true /* bottom */),
+ };
+ for (float alpha : {0.5, 0.0, 1.0}) {
+ layer.alpha = alpha;
+ auto layers = std::vector<LayerSettings>{layer};
+ renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
+ }
+}
+
//
// The collection of shaders cached here were found by using perfetto to record shader compiles
// during actions that involve RenderEngine, logging the layer settings, and the shader code
@@ -761,6 +789,12 @@
// Draw layers for b/185569240.
drawClippedLayers(renderengine, display, dstTexture, texture);
}
+
+ if (com::android::graphics::libgui::flags::edge_extension_shader() &&
+ config.cacheEdgeExtension) {
+ drawEdgeExtensionLayers(renderengine, display, dstTexture, texture);
+ drawEdgeExtensionLayers(renderengine, p3Display, dstTexture, texture);
+ }
}
if (config.cachePIPImageLayers) {
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index cb220ab..ca92ab5 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -217,6 +217,7 @@
"libcutils",
"libinput",
"liblog",
+ "libprocessgroup",
"libstatslog",
"libutils",
],
diff --git a/services/inputflinger/InputThread.cpp b/services/inputflinger/InputThread.cpp
index e74f258..449eb45 100644
--- a/services/inputflinger/InputThread.cpp
+++ b/services/inputflinger/InputThread.cpp
@@ -16,8 +16,14 @@
#include "InputThread.h"
+#include <android-base/logging.h>
+#include <com_android_input_flags.h>
+#include <processgroup/processgroup.h>
+
namespace android {
+namespace input_flags = com::android::input::flags;
+
namespace {
// Implementation of Thread from libutils.
@@ -43,6 +49,11 @@
: mName(name), mThreadWake(wake) {
mThread = sp<InputThreadImpl>::make(loop);
mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
+ if (input_flags::enable_input_policy_profile()) {
+ if (!applyInputEventProfile()) {
+ LOG(ERROR) << "Couldn't apply input policy profile for " << name;
+ }
+ }
}
InputThread::~InputThread() {
@@ -63,4 +74,14 @@
#endif
}
+bool InputThread::applyInputEventProfile() {
+#if defined(__ANDROID__)
+ return SetTaskProfiles(mThread->getTid(), {"InputPolicy"});
+#else
+ // Since thread information is not available and there's no benefit of
+ // applying the task profile on host, return directly.
+ return true;
+#endif
+}
+
} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 250e72c..75b494b 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -4491,6 +4491,10 @@
{ // acquire lock
mLock.lock();
+ if (input_flags::keyboard_repeat_keys() && !mConfig.keyRepeatEnabled) {
+ policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
+ }
+
if (shouldSendKeyToInputFilterLocked(args)) {
mLock.unlock();
@@ -7209,11 +7213,13 @@
}
void InputDispatcher::setKeyRepeatConfiguration(std::chrono::nanoseconds timeout,
- std::chrono::nanoseconds delay) {
+ std::chrono::nanoseconds delay,
+ bool keyRepeatEnabled) {
std::scoped_lock _l(mLock);
mConfig.keyRepeatTimeout = timeout.count();
mConfig.keyRepeatDelay = delay.count();
+ mConfig.keyRepeatEnabled = keyRepeatEnabled;
}
bool InputDispatcher::isPointerInWindow(const sp<android::IBinder>& token,
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 87dfd1d..1904058 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -153,8 +153,8 @@
// Public to allow tests to verify that a Monitor can get ANR.
void setMonitorDispatchingTimeoutForTest(std::chrono::nanoseconds timeout);
- void setKeyRepeatConfiguration(std::chrono::nanoseconds timeout,
- std::chrono::nanoseconds delay) override;
+ void setKeyRepeatConfiguration(std::chrono::nanoseconds timeout, std::chrono::nanoseconds delay,
+ bool keyRepeatEnabled) override;
bool isPointerInWindow(const sp<IBinder>& token, ui::LogicalDisplayId displayId,
DeviceId deviceId, int32_t pointerId) override;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h b/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h
index 5eb3a32..ba197d4 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h
@@ -34,8 +34,13 @@
// The key repeat inter-key delay.
nsecs_t keyRepeatDelay;
+ // Whether key repeat is enabled.
+ bool keyRepeatEnabled;
+
InputDispatcherConfiguration()
- : keyRepeatTimeout(500 * 1000000LL), keyRepeatDelay(50 * 1000000LL) {}
+ : keyRepeatTimeout(500 * 1000000LL),
+ keyRepeatDelay(50 * 1000000LL),
+ keyRepeatEnabled(true) {}
};
} // namespace android
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 653f595..463a952 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -227,10 +227,11 @@
virtual void cancelCurrentTouch() = 0;
/*
- * Updates key repeat configuration timeout and delay.
+ * Updates whether key repeat is enabled and key repeat configuration timeout and delay.
*/
virtual void setKeyRepeatConfiguration(std::chrono::nanoseconds timeout,
- std::chrono::nanoseconds delay) = 0;
+ std::chrono::nanoseconds delay,
+ bool keyRepeatEnabled) = 0;
/*
* Determine if a pointer from a device is being dispatched to the given window.
diff --git a/services/inputflinger/include/InputThread.h b/services/inputflinger/include/InputThread.h
index 5e75027..fcd913d 100644
--- a/services/inputflinger/include/InputThread.h
+++ b/services/inputflinger/include/InputThread.h
@@ -38,6 +38,7 @@
std::string mName;
std::function<void()> mThreadWake;
sp<Thread> mThread;
+ bool applyInputEventProfile();
};
} // namespace android
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c2f174f..f066b03 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -9091,6 +9091,7 @@
protected:
static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms;
+ static constexpr bool KEY_REPEAT_ENABLED = true;
std::shared_ptr<FakeApplicationHandle> mApp;
sp<FakeWindowHandle> mWindow;
@@ -9098,7 +9099,8 @@
virtual void SetUp() override {
InputDispatcherTest::SetUp();
- mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
+ mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY,
+ KEY_REPEAT_ENABLED);
setUpWindow();
}
@@ -9247,6 +9249,24 @@
expectKeyRepeatOnce(3);
}
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_NoRepeatWhenKeyRepeatDisabled) {
+ SCOPED_FLAG_OVERRIDE(keyboard_repeat_keys, true);
+ static constexpr std::chrono::milliseconds KEY_NO_REPEAT_ASSERTION_TIMEOUT = 100ms;
+
+ mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY,
+ /*repeatKeyEnabled=*/false);
+ sendAndConsumeKeyDown(/*deviceId=*/1);
+
+ ASSERT_GT(KEY_NO_REPEAT_ASSERTION_TIMEOUT, KEY_REPEAT_TIMEOUT)
+ << "Ensure the check for no key repeats extends beyond the repeat timeout duration.";
+ ASSERT_GT(KEY_NO_REPEAT_ASSERTION_TIMEOUT, KEY_REPEAT_DELAY)
+ << "Ensure the check for no key repeats extends beyond the repeat delay duration.";
+
+ // No events should be returned if key repeat is turned off.
+ // Wait for KEY_NO_REPEAT_ASSERTION_TIMEOUT to return no events to ensure key repeat disabled.
+ mWindow->assertNoEvents(KEY_NO_REPEAT_ASSERTION_TIMEOUT);
+}
+
/* Test InputDispatcher for MultiDisplay */
class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
public:
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index f4b0265..7b2596a 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -52,6 +52,7 @@
"-Wall",
"-Werror",
"-Wextra",
+ "-Wthread-safety",
"-fvisibility=hidden",
],
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index f56642b..0d00642 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -711,14 +711,17 @@
if (err == OK && isSensorCapped) {
if ((requestedSamplingPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) ||
!isRateCappedBasedOnPermission()) {
+ Mutex::Autolock _l(mConnectionLock);
mMicSamplingPeriodBackup[handle] = requestedSamplingPeriodNs;
} else {
+ Mutex::Autolock _l(mConnectionLock);
mMicSamplingPeriodBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
}
}
} else {
err = mService->disable(this, handle);
+ Mutex::Autolock _l(mConnectionLock);
mMicSamplingPeriodBackup.erase(handle);
}
return err;
@@ -750,8 +753,10 @@
if (ret == OK && isSensorCapped) {
if ((requestedSamplingPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) ||
!isRateCappedBasedOnPermission()) {
+ Mutex::Autolock _l(mConnectionLock);
mMicSamplingPeriodBackup[handle] = requestedSamplingPeriodNs;
} else {
+ Mutex::Autolock _l(mConnectionLock);
mMicSamplingPeriodBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
}
}
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 6a98a40..bb8733d 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -199,7 +199,8 @@
// valid mapping for sensors that require a permission in order to reduce the lookup time.
std::unordered_map<int32_t, int32_t> mHandleToAppOp;
// Mapping of sensor handles to its rate before being capped by the mic toggle.
- std::unordered_map<int, nsecs_t> mMicSamplingPeriodBackup;
+ std::unordered_map<int, nsecs_t> mMicSamplingPeriodBackup
+ GUARDED_BY(mConnectionLock);
userid_t mUserId;
std::optional<bool> mIsRateCappedBasedOnPermission;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index ac15b92..ee605b7 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -279,24 +279,6 @@
snapshot.getDebugString().c_str());
}
-bool needsInputInfo(const LayerSnapshot& snapshot, const RequestedLayerState& requested) {
- if (requested.potentialCursor) {
- return false;
- }
-
- if (snapshot.inputInfo.token != nullptr) {
- return true;
- }
-
- if (snapshot.hasBufferOrSidebandStream()) {
- return true;
- }
-
- return requested.windowInfoHandle &&
- requested.windowInfoHandle->getInfo()->inputConfig.test(
- gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
-}
-
void updateMetadata(LayerSnapshot& snapshot, const RequestedLayerState& requested,
const LayerSnapshotBuilder::Args& args) {
snapshot.metadata.clear();
@@ -1162,7 +1144,7 @@
}
updateVisibility(snapshot, snapshot.isVisible);
- if (!needsInputInfo(snapshot, requested)) {
+ if (!requested.needsInputInfo()) {
return;
}
@@ -1172,7 +1154,7 @@
bool noValidDisplay = !displayInfoOpt.has_value();
auto displayInfo = displayInfoOpt.value_or(sDefaultInfo);
- if (!requested.windowInfoHandle) {
+ if (!requested.hasInputInfo()) {
snapshot.inputInfo.inputConfig = InputConfig::NO_INPUT_CHANNEL;
}
fillInputFrameInfo(snapshot.inputInfo, displayInfo.transform, snapshot);
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 17d2610..5734ccf 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -62,6 +62,8 @@
metadata.merge(args.metadata);
changes |= RequestedLayerState::Changes::Metadata;
handleAlive = true;
+ // TODO: b/305254099 remove once we don't pass invisible windows to input
+ windowInfoHandle = nullptr;
if (parentId != UNASSIGNED_LAYER_ID) {
canBeRoot = false;
}
@@ -553,6 +555,24 @@
windowInfo->inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
}
+bool RequestedLayerState::needsInputInfo() const {
+ if (potentialCursor) {
+ return false;
+ }
+
+ if ((sidebandStream != nullptr) || (externalTexture != nullptr)) {
+ return true;
+ }
+
+ if (!windowInfoHandle) {
+ return false;
+ }
+
+ const auto windowInfo = windowInfoHandle->getInfo();
+ return windowInfo->token != nullptr ||
+ windowInfo->inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
+}
+
bool RequestedLayerState::hasBlur() const {
return backgroundBlurRadius > 0 || blurRegions.size() > 0;
}
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
index 48b9640..1d96dff 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
@@ -87,6 +87,7 @@
aidl::android::hardware::graphics::composer3::Composition getCompositionType() const;
bool hasValidRelativeParent() const;
bool hasInputInfo() const;
+ bool needsInputInfo() const;
bool hasBlur() const;
bool hasFrameUpdate() const;
bool hasReadyFrame() const;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c794a7b..65a0ed3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1003,6 +1003,8 @@
// which we maintain for backwards compatibility.
config.cacheUltraHDR =
base::GetBoolProperty("ro.surface_flinger.prime_shader_cache.ultrahdr"s, false);
+ config.cacheEdgeExtension =
+ base::GetBoolProperty("debug.sf.edge_extension_shader"s, true);
return getRenderEngine().primeCache(config);
});
diff --git a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
index b4efe0f..c7cc21c 100644
--- a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
@@ -619,4 +619,14 @@
}
}
+TEST_F(LayerLifecycleManagerTest, testInputInfoOfRequestedLayerState) {
+ // By default the layer has no buffer, so it doesn't need an input info
+ EXPECT_FALSE(getRequestedLayerState(mLifecycleManager, 111)->needsInputInfo());
+
+ setBuffer(111);
+ mLifecycleManager.commitChanges();
+
+ EXPECT_TRUE(getRequestedLayerState(mLifecycleManager, 111)->needsInputInfo());
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 9020723..75d2fa3 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1762,6 +1762,7 @@
UPDATE_AND_VERIFY(mSnapshotBuilder, {2});
EXPECT_TRUE(getSnapshot(1)->isHiddenByPolicy());
}
+
TEST_F(LayerSnapshotTest, edgeExtensionPropagatesInHierarchy) {
if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
@@ -1920,4 +1921,18 @@
EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.top, 0);
}
+TEST_F(LayerSnapshotTest, shouldUpdateInputWhenNoInputInfo) {
+ // By default the layer has no buffer, so we don't expect it to have an input info
+ EXPECT_FALSE(getSnapshot(111)->hasInputInfo());
+
+ setBuffer(111);
+
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_TRUE(getSnapshot(111)->hasInputInfo());
+ EXPECT_TRUE(getSnapshot(111)->inputInfo.inputConfig.test(
+ gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL));
+ EXPECT_FALSE(getSnapshot(2)->hasInputInfo());
+}
+
} // namespace android::surfaceflinger::frontend