Merge "Set better defaults for layer stack and oriented display space" into tm-dev
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 8ccab4c..fc4cfc9 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -32,7 +32,12 @@
"name": "CtsCompilationTestCases"
},
{
- "name": "SdkSandboxStorageHostTest"
+ "name": "SdkSandboxStorageHostTest",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ }
+ ]
}
]
}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 5003151..bdd5172 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -227,6 +227,12 @@
}
prebuilt_etc {
+ name: "android.software.opengles.deqp.level-2022-03-01.prebuilt.xml",
+ src: "android.software.opengles.deqp.level-2022-03-01.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.software.sip.voip.prebuilt.xml",
src: "android.software.sip.voip.xml",
defaults: ["frameworks_native_data_etc_defaults"],
@@ -245,6 +251,12 @@
}
prebuilt_etc {
+ name: "android.software.vulkan.deqp.level-2022-03-01.prebuilt.xml",
+ src: "android.software.vulkan.deqp.level-2022-03-01.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "aosp_excluded_hardware.prebuilt.xml",
src: "aosp_excluded_hardware.xml",
defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index b3bc7f4..c8e78fc 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -324,4 +324,42 @@
} // namespace ndk
+// Once minSdkVersion is 30, we are guaranteed to be building with the
+// Android 11 AIDL compiler which supports the SharedRefBase::make API.
+#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30 || defined(__ANDROID_APEX__)
+namespace ndk::internal {
+template <typename T, typename = void>
+struct is_complete_type : std::false_type {};
+
+template <typename T>
+struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
+} // namespace ndk::internal
+
+namespace std {
+
+// Define `SharedRefBase` specific versions of `std::make_shared` and
+// `std::make_unique` to block people from using them. Using them to allocate
+// `ndk::SharedRefBase` objects results in double ownership. Use
+// `ndk::SharedRefBase::make<T>(...)` instead.
+//
+// Note: We exclude incomplete types because `std::is_base_of` is undefined in
+// that case.
+
+template <typename T, typename... Args,
+ std::enable_if_t<ndk::internal::is_complete_type<T>::value, bool> = true,
+ std::enable_if_t<std::is_base_of<ndk::SharedRefBase, T>::value, bool> = true>
+shared_ptr<T> make_shared(Args...) { // SEE COMMENT ABOVE.
+ static_assert(!std::is_base_of<ndk::SharedRefBase, T>::value);
+}
+
+template <typename T, typename... Args,
+ std::enable_if_t<ndk::internal::is_complete_type<T>::value, bool> = true,
+ std::enable_if_t<std::is_base_of<ndk::SharedRefBase, T>::value, bool> = true>
+unique_ptr<T> make_unique(Args...) { // SEE COMMENT ABOVE.
+ static_assert(!std::is_base_of<ndk::SharedRefBase, T>::value);
+}
+
+} // namespace std
+#endif
+
/** @} */
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 357b454..1b136dc 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -231,8 +231,7 @@
}
TEST(NdkBinder, DetectNoSharedRefBaseCreated) {
- EXPECT_DEATH(std::make_shared<MyBinderNdkUnitTest>(),
- "SharedRefBase: no ref created during lifetime");
+ EXPECT_DEATH(MyBinderNdkUnitTest(), "SharedRefBase: no ref created during lifetime");
}
TEST(NdkBinder, GetServiceThatDoesntExist) {
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 57d496d..e5d32da 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -29,7 +29,6 @@
"libcutils",
"libhidlbase",
"liblog",
- "libutils",
],
target: {
@@ -37,12 +36,14 @@
shared_libs: [
"libbinder_ndk",
"libbinder",
+ "libutils",
],
},
host: {
static_libs: [
"libbinder_ndk",
"libbinder",
+ "libutils",
],
},
darwin: {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index f7cd5c4..502031c 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -16,8 +16,8 @@
#define LOG_TAG "LayerState"
-#include <apex/window.h>
-#include <inttypes.h>
+#include <cinttypes>
+#include <cmath>
#include <android/native_window.h>
#include <binder/Parcel.h>
@@ -25,10 +25,9 @@
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
#include <private/gui/ParcelUtils.h>
+#include <system/window.h>
#include <utils/Errors.h>
-#include <cmath>
-
namespace android {
using gui::FocusRequest;
@@ -679,7 +678,9 @@
if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE &&
- (!privileged || compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT)) {
+ (!privileged ||
+ (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT &&
+ compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) {
ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName,
compatibility, privileged ? "yes" : "no");
return false;
diff --git a/libs/input/android/os/InputEventInjectionResult.aidl b/libs/input/android/os/InputEventInjectionResult.aidl
index 3bc7068..34f10ec 100644
--- a/libs/input/android/os/InputEventInjectionResult.aidl
+++ b/libs/input/android/os/InputEventInjectionResult.aidl
@@ -29,8 +29,9 @@
/* Injection succeeded. */
SUCCEEDED = 0,
- /* Injection failed because the injected event did not target the appropriate window. */
- TARGET_MISMATCH = 1,
+ /* Injection failed because the injector did not have permission to inject
+ * into the application with input focus. */
+ PERMISSION_DENIED = 1,
/* Injection failed because there were no available input targets. */
FAILED = 2,
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 0923438..2d1354c 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -39,19 +39,6 @@
// clang-format on
};
-/*
- * Internal extension of compatibility value for ANativeWindow_setFrameRate. */
-enum ANativeWindow_FrameRateCompatibilityInternal {
- /**
- * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
- * to operate at the exact frame rate.
- *
- * This is used internally by the platform and should not be used by apps.
- * @hide
- */
- ANATIVEWINDOW_FRAME_RATE_EXACT = 100,
-};
-
/**
* Prototype of the function that an ANativeWindow implementation would call
* when ANativeWindow_cancelBuffer is called.
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index a319769..a54af1f 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1018,6 +1018,24 @@
return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation);
}
+/*
+ * Internal extension of ANativeWindow_FrameRateCompatibility.
+ */
+enum {
+ /**
+ * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
+ * to operate at the exact frame rate.
+ *
+ * Keep in sync with Surface.java constant.
+ */
+ ANATIVEWINDOW_FRAME_RATE_EXACT = 100,
+
+ /**
+ * This surface is ignored while choosing the refresh rate.
+ */
+ ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+};
+
static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate,
int8_t compatibility, int8_t changeFrameRateStrategy) {
return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate,
diff --git a/libs/renderengine/skia/ColorSpaces.cpp b/libs/renderengine/skia/ColorSpaces.cpp
index f367a84..37ff5df 100644
--- a/libs/renderengine/skia/ColorSpaces.cpp
+++ b/libs/renderengine/skia/ColorSpaces.cpp
@@ -65,7 +65,15 @@
case HAL_DATASPACE_TRANSFER_SMPTE_170M:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
case HAL_DATASPACE_TRANSFER_HLG:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut);
+ // return HLG transfer but scale by 1/12
+ skcms_TransferFunction hlgFn;
+ if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 1.f / 12.f, 2.f, 2.f,
+ 1.f / 0.17883277f, 0.28466892f,
+ 0.55991073f)) {
+ return SkColorSpace::MakeRGB(hlgFn, gamut);
+ } else {
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
+ }
case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
default:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 1fce31d..4f950b8 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -1193,10 +1193,6 @@
Gralloc4Allocator::Gralloc4Allocator(const Gralloc4Mapper& mapper) : mMapper(mapper) {
mAllocator = IAllocator::getService();
- if (mAllocator == nullptr) {
- ALOGW("allocator 4.x is not supported");
- return;
- }
if (__builtin_available(android 31, *)) {
if (hasIAllocatorAidl()) {
mAidlAllocator = AidlIAllocator::fromBinder(ndk::SpAIBinder(
@@ -1204,10 +1200,14 @@
ALOGE_IF(!mAidlAllocator, "AIDL IAllocator declared but failed to get service");
}
}
+ if (mAllocator == nullptr && mAidlAllocator == nullptr) {
+ ALOGW("allocator 4.x is not supported");
+ return;
+ }
}
bool Gralloc4Allocator::isLoaded() const {
- return mAllocator != nullptr;
+ return mAllocator != nullptr || mAidlAllocator != nullptr;
}
std::string Gralloc4Allocator::dumpDebugInfo(bool less) const {
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 22fbf45..831b64d 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -114,7 +114,6 @@
],
shared_libs: [
"libbinder",
- "libgui",
"liblog",
"libui",
"libutils",
diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
index 126a945..4c9d574 100644
--- a/libs/ui/tests/GraphicBufferOverBinder_test.cpp
+++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
@@ -20,9 +20,6 @@
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
-#include <gui/BufferQueue.h>
-#include <gui/IGraphicBufferConsumer.h>
-#include <gui/IGraphicBufferProducer.h>
#include <ui/GraphicBuffer.h>
#include <utils/Log.h>
diff --git a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
index c8e79a2..95cfae7 100644
--- a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
+++ b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
@@ -71,11 +71,14 @@
//
// The |total_active_duration_ns| must be set to the approximate total amount of
// time the GPU spent running work for |uid| within the period, without
-// "double-counting" parallel GPU work on the same GPU for the same |uid|. "GPU
-// work" should correspond to the "GPU slices" shown in the AGI (Android GPU
+// "double-counting" parallel GPU work on the same GPU for the same |uid|. Note
+// that even if the parallel GPU work was submitted from several different
+// processes (i.e. different PIDs) with the same UID, this overlapping work must
+// not be double-counted, as it still came from a single |uid|. "GPU work"
+// should correspond to the "GPU slices" shown in the AGI (Android GPU
// Inspector) tool, and so should include work such as fragment and non-fragment
// work/shaders running on the shader cores of the GPU. For example, given the
-// following:
+// following for a single |uid|:
// - A period has:
// - |start_time_ns|: 100,000,000 ns
// - |end_time_ns|: 800,000,000 ns
@@ -99,16 +102,20 @@
// - from 600,000,000 ns to 700,000,000 ns, giving a duration of 100,000,000 ns
// (GPU work D)
//
-// Thus, the |total_active_duration_ns| is the sum of the (non-overlapping)
-// durations. Drivers may not have efficient access to the exact start and end
-// times of all GPU work, as shown above, but drivers should try to
-// approximate/aggregate the value of |total_active_duration_ns| as accurately
-// as possible within the limitations of the hardware, without double-counting
-// parallel GPU work for the same |uid|. The |total_active_duration_ns| value
-// must be less than or equal to the period duration (|end_time_ns| -
-// |start_time_ns|); if the aggregation approach might violate this requirement
-// then the driver must clamp |total_active_duration_ns| to be at most the
-// period duration.
+// Thus, the |total_active_duration_ns| is the sum of these two
+// (non-overlapping) durations. Drivers may not have efficient access to the
+// exact start and end times of all GPU work, as shown above, but drivers should
+// try to approximate/aggregate the value of |total_active_duration_ns| as
+// accurately as possible within the limitations of the hardware, without
+// double-counting parallel GPU work for the same |uid|. The
+// |total_active_duration_ns| value must be less than or equal to the period
+// duration (|end_time_ns| - |start_time_ns|); if the aggregation approach might
+// violate this requirement then the driver must clamp
+// |total_active_duration_ns| to be at most the period duration.
+//
+// Protected mode: protected GPU work must not be reported. Periods must be
+// emitted, and the |total_active_duration_ns| value set, as if the protected
+// GPU work did not occur.
//
// Note that the above description allows for a certain amount of flexibility in
// how the driver tracks periods and emits the events. We list a few examples of
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index a2e60c4..32eec29 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -31,11 +31,11 @@
namespace android::inputdispatcher {
// An arbitrary device id.
-constexpr int32_t DEVICE_ID = 1;
+static const int32_t DEVICE_ID = 1;
-// The default pid and uid for windows created by the test.
-constexpr int32_t WINDOW_PID = 999;
-constexpr int32_t WINDOW_UID = 1001;
+// An arbitrary injector pid / uid pair that has permission to inject events.
+static const int32_t INJECTOR_PID = 999;
+static const int32_t INJECTOR_UID = 1001;
static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s;
static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms;
@@ -108,6 +108,8 @@
void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
+ bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override { return false; }
+
void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}
void setPointerCapture(const PointerCaptureRequest&) override {}
@@ -194,8 +196,8 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(mFrame);
- mInfo.ownerPid = WINDOW_PID;
- mInfo.ownerUid = WINDOW_UID;
+ mInfo.ownerPid = INJECTOR_PID;
+ mInfo.ownerUid = INJECTOR_UID;
mInfo.displayId = ADISPLAY_ID_DEFAULT;
}
@@ -308,14 +310,14 @@
for (auto _ : state) {
MotionEvent event = generateMotionEvent();
// Send ACTION_DOWN
- dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- INJECT_EVENT_TIMEOUT,
+ dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
// Send ACTION_UP
event.setAction(AMOTION_EVENT_ACTION_UP);
- dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- INJECT_EVENT_TIMEOUT,
+ dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
window->consumeEvent();
diff --git a/services/inputflinger/dispatcher/InjectionState.cpp b/services/inputflinger/dispatcher/InjectionState.cpp
index c2d3ad6..c8024a6 100644
--- a/services/inputflinger/dispatcher/InjectionState.cpp
+++ b/services/inputflinger/dispatcher/InjectionState.cpp
@@ -20,9 +20,10 @@
namespace android::inputdispatcher {
-InjectionState::InjectionState(const std::optional<int32_t>& targetUid)
+InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid)
: refCount(1),
- targetUid(targetUid),
+ injectorPid(injectorPid),
+ injectorUid(injectorUid),
injectionResult(android::os::InputEventInjectionResult::PENDING),
injectionIsAsync(false),
pendingForegroundDispatches(0) {}
diff --git a/services/inputflinger/dispatcher/InjectionState.h b/services/inputflinger/dispatcher/InjectionState.h
index 90cf150..0bfafb1 100644
--- a/services/inputflinger/dispatcher/InjectionState.h
+++ b/services/inputflinger/dispatcher/InjectionState.h
@@ -27,12 +27,13 @@
struct InjectionState {
mutable int32_t refCount;
- std::optional<int32_t> targetUid;
+ int32_t injectorPid;
+ int32_t injectorUid;
android::os::InputEventInjectionResult injectionResult; // initially PENDING
bool injectionIsAsync; // set to true if injection is not waiting for the result
int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
- explicit InjectionState(const std::optional<int32_t>& targetUid);
+ InjectionState(int32_t injectorPid, int32_t injectorUid);
void release();
private:
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f3d0b65..1cc4589 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -578,27 +578,6 @@
return false;
}
-// Checks targeted injection using the window's owner's uid.
-// Returns an empty string if an entry can be sent to the given window, or an error message if the
-// entry is a targeted injection whose uid target doesn't match the window owner.
-std::optional<std::string> verifyTargetedInjection(const sp<WindowInfoHandle>& window,
- const EventEntry& entry) {
- if (entry.injectionState == nullptr || !entry.injectionState->targetUid) {
- // The event was not injected, or the injected event does not target a window.
- return {};
- }
- const int32_t uid = *entry.injectionState->targetUid;
- if (window == nullptr) {
- return StringPrintf("No valid window target for injection into uid %d.", uid);
- }
- if (entry.injectionState->targetUid != window->getInfo()->ownerUid) {
- return StringPrintf("Injected event targeted at uid %d would be dispatched to window '%s' "
- "owned by uid %d.",
- uid, window->getName().c_str(), window->getInfo()->ownerUid);
- }
- return {};
-}
-
} // namespace
// --- InputDispatcher ---
@@ -1057,8 +1036,6 @@
switch (entry.type) {
case EventEntry::Type::KEY: {
- LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
- "Unexpected untrusted event.");
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
@@ -1096,8 +1073,6 @@
}
case EventEntry::Type::MOTION: {
- LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
- "Unexpected untrusted event.");
if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(entry))) {
mNextUnblockedEvent = mInboundQueue.back();
needWake = true;
@@ -1743,7 +1718,8 @@
}
setInjectionResult(*entry, injectionResult);
- if (injectionResult == InputEventInjectionResult::TARGET_MISMATCH) {
+ if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) {
+ ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
return true;
}
if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
@@ -2000,10 +1976,9 @@
// we have a valid, non-null focused window
resetNoFocusedWindowTimeoutLocked();
- // Verify targeted injection.
- if (const auto err = verifyTargetedInjection(focusedWindowHandle, entry); err) {
- ALOGW("Dropping injected event: %s", (*err).c_str());
- return InputEventInjectionResult::TARGET_MISMATCH;
+ // Check permissions.
+ if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {
+ return InputEventInjectionResult::PERMISSION_DENIED;
}
if (focusedWindowHandle->getInfo()->inputConfig.test(
@@ -2069,6 +2044,11 @@
nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
ATRACE_CALL();
+ enum InjectionPermission {
+ INJECTION_PERMISSION_UNKNOWN,
+ INJECTION_PERMISSION_GRANTED,
+ INJECTION_PERMISSION_DENIED
+ };
// For security reasons, we defer updating the touch state until we are sure that
// event injection will be allowed.
@@ -2078,6 +2058,7 @@
// Update the touch state as needed based on the properties of the touch event.
InputEventInjectionResult injectionResult = InputEventInjectionResult::PENDING;
+ InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
sp<WindowInfoHandle> newHoverWindowHandle(mLastHoverWindowHandle);
sp<WindowInfoHandle> newTouchedWindowHandle;
@@ -2126,7 +2107,7 @@
"in display %" PRId32,
displayId);
// TODO: test multiple simultaneous input streams.
- injectionResult = InputEventInjectionResult::FAILED;
+ injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
switchedDevice = false;
wrongDevice = true;
goto Failed;
@@ -2159,14 +2140,6 @@
newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();
}
- // Verify targeted injection.
- if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
- ALOGW("Dropping injected touch event: %s", (*err).c_str());
- injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
- newTouchedWindowHandle = nullptr;
- goto Failed;
- }
-
// Figure out whether splitting will be allowed for this window.
if (newTouchedWindowHandle != nullptr) {
if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
@@ -2210,11 +2183,6 @@
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
const WindowInfo& info = *windowHandle->getInfo();
- // Skip spy window targets that are not valid for targeted injection.
- if (const auto err = verifyTargetedInjection(windowHandle, entry); err) {
- continue;
- }
-
if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
ALOGI("Not sending touch event to %s because it is paused",
windowHandle->getName().c_str());
@@ -2308,14 +2276,6 @@
newTouchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus);
- // Verify targeted injection.
- if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
- ALOGW("Dropping injected event: %s", (*err).c_str());
- injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
- newTouchedWindowHandle = nullptr;
- goto Failed;
- }
-
// Drop touch events if requested by input feature
if (newTouchedWindowHandle != nullptr &&
shouldDropInput(entry, newTouchedWindowHandle)) {
@@ -2407,26 +2367,19 @@
goto Failed;
}
- // Ensure that all touched windows are valid for injection.
- if (entry.injectionState != nullptr) {
- std::string errs;
- for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
- if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
- // Allow ACTION_OUTSIDE events generated by targeted injection to be
- // dispatched to any uid, since the coords will be zeroed out later.
- continue;
- }
- const auto err = verifyTargetedInjection(touchedWindow.windowHandle, entry);
- if (err) errs += "\n - " + *err;
- }
- if (!errs.empty()) {
- ALOGW("Dropping targeted injection: At least one touched window is not owned by uid "
- "%d:%s",
- *entry.injectionState->targetUid, errs.c_str());
- injectionResult = InputEventInjectionResult::TARGET_MISMATCH;
- goto Failed;
- }
+ // Check permission to inject into all touched foreground windows.
+ if (std::any_of(tempTouchState.windows.begin(), tempTouchState.windows.end(),
+ [this, &entry](const TouchedWindow& touchedWindow) {
+ return (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0 &&
+ !checkInjectionPermission(touchedWindow.windowHandle,
+ entry.injectionState);
+ })) {
+ injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
+ injectionPermission = INJECTION_PERMISSION_DENIED;
+ goto Failed;
}
+ // Permission granted to inject into all touched foreground windows.
+ injectionPermission = INJECTION_PERMISSION_GRANTED;
// Check whether windows listening for outside touches are owned by the same UID. If it is
// set the policy flag that we will not reveal coordinate information to this window.
@@ -2492,6 +2445,19 @@
tempTouchState.filterNonAsIsTouchWindows();
Failed:
+ // Check injection permission once and for all.
+ if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
+ if (checkInjectionPermission(nullptr, entry.injectionState)) {
+ injectionPermission = INJECTION_PERMISSION_GRANTED;
+ } else {
+ injectionPermission = INJECTION_PERMISSION_DENIED;
+ }
+ }
+
+ if (injectionPermission != INJECTION_PERMISSION_GRANTED) {
+ return injectionResult;
+ }
+
// Update final pieces of touch state if the injector had permission.
if (!wrongDevice) {
if (switchedDevice) {
@@ -2689,6 +2655,26 @@
}
}
+bool InputDispatcher::checkInjectionPermission(const sp<WindowInfoHandle>& windowHandle,
+ const InjectionState* injectionState) {
+ if (injectionState &&
+ (windowHandle == nullptr ||
+ windowHandle->getInfo()->ownerUid != injectionState->injectorUid) &&
+ !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
+ if (windowHandle != nullptr) {
+ ALOGW("Permission denied: injecting event from pid %d uid %d to window %s "
+ "owned by uid %d",
+ injectionState->injectorPid, injectionState->injectorUid,
+ windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid);
+ } else {
+ ALOGW("Permission denied: injecting event from pid %d uid %d",
+ injectionState->injectorPid, injectionState->injectorUid);
+ }
+ return false;
+ }
+ return true;
+}
+
/**
* Indicate whether one window handle should be considered as obscuring
* another window handle. We only check a few preconditions. Actually
@@ -4207,20 +4193,20 @@
}
}
-InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* event,
- std::optional<int32_t> targetUid,
- InputEventInjectionSync syncMode,
- std::chrono::milliseconds timeout,
- uint32_t policyFlags) {
+InputEventInjectionResult InputDispatcher::injectInputEvent(
+ const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
+ InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) {
if (DEBUG_INBOUND_EVENT_DETAILS) {
- ALOGD("injectInputEvent - eventType=%d, targetUid=%s, syncMode=%d, timeout=%lld, "
- "policyFlags=0x%08x",
- event->getType(), targetUid ? std::to_string(*targetUid).c_str() : "none", syncMode,
- timeout.count(), policyFlags);
+ ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
+ "syncMode=%d, timeout=%lld, policyFlags=0x%08x",
+ event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags);
}
nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count();
- policyFlags |= POLICY_FLAG_INJECTED | POLICY_FLAG_TRUSTED;
+ policyFlags |= POLICY_FLAG_INJECTED;
+ if (hasInjectionPermission(injectorPid, injectorUid)) {
+ policyFlags |= POLICY_FLAG_TRUSTED;
+ }
// For all injected events, set device id = VIRTUAL_KEYBOARD_ID. The only exception is events
// that have gone through the InputFilter. If the event passed through the InputFilter, assign
@@ -4361,7 +4347,7 @@
return InputEventInjectionResult::FAILED;
}
- InjectionState* injectionState = new InjectionState(targetUid);
+ InjectionState* injectionState = new InjectionState(injectorPid, injectorUid);
if (syncMode == InputEventInjectionSync::NONE) {
injectionState->injectionIsAsync = true;
}
@@ -4433,7 +4419,8 @@
} // release lock
if (DEBUG_INJECTION) {
- ALOGD("injectInputEvent - Finished with result %d.", injectionResult);
+ ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d",
+ injectionResult, injectorPid, injectorUid);
}
return injectionResult;
@@ -4472,12 +4459,19 @@
return result;
}
+bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
+ return injectorUid == 0 ||
+ mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
+}
+
void InputDispatcher::setInjectionResult(EventEntry& entry,
InputEventInjectionResult injectionResult) {
InjectionState* injectionState = entry.injectionState;
if (injectionState) {
if (DEBUG_INJECTION) {
- ALOGD("Setting input event injection result to %d.", injectionResult);
+ ALOGD("Setting input event injection result to %d. "
+ "injectorPid=%d, injectorUid=%d",
+ injectionResult, injectionState->injectorPid, injectionState->injectorUid);
}
if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) {
@@ -4486,12 +4480,12 @@
case InputEventInjectionResult::SUCCEEDED:
ALOGV("Asynchronous input event injection succeeded.");
break;
- case InputEventInjectionResult::TARGET_MISMATCH:
- ALOGV("Asynchronous input event injection target mismatch.");
- break;
case InputEventInjectionResult::FAILED:
ALOGW("Asynchronous input event injection failed.");
break;
+ case InputEventInjectionResult::PERMISSION_DENIED:
+ ALOGW("Asynchronous input event injection permission denied.");
+ break;
case InputEventInjectionResult::TIMED_OUT:
ALOGW("Asynchronous input event injection timed out.");
break;
@@ -5146,28 +5140,54 @@
return true;
}
+/**
+ * Get the touched foreground window on the given display.
+ * Return null if there are no windows touched on that display, or if more than one foreground
+ * window is being touched.
+ */
+sp<WindowInfoHandle> InputDispatcher::findTouchedForegroundWindowLocked(int32_t displayId) const {
+ auto stateIt = mTouchStatesByDisplay.find(displayId);
+ if (stateIt == mTouchStatesByDisplay.end()) {
+ ALOGI("No touch state on display %" PRId32, displayId);
+ return nullptr;
+ }
+
+ const TouchState& state = stateIt->second;
+ sp<WindowInfoHandle> touchedForegroundWindow;
+ // If multiple foreground windows are touched, return nullptr
+ for (const TouchedWindow& window : state.windows) {
+ if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
+ if (touchedForegroundWindow != nullptr) {
+ ALOGI("Two or more foreground windows: %s and %s",
+ touchedForegroundWindow->getName().c_str(),
+ window.windowHandle->getName().c_str());
+ return nullptr;
+ }
+ touchedForegroundWindow = window.windowHandle;
+ }
+ }
+ return touchedForegroundWindow;
+}
+
// Binder call
-bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken) {
+bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken, int32_t displayId) {
sp<IBinder> fromToken;
{ // acquire lock
std::scoped_lock _l(mLock);
-
- auto it = std::find_if(mTouchStatesByDisplay.begin(), mTouchStatesByDisplay.end(),
- [](const auto& pair) { return pair.second.windows.size() == 1; });
- if (it == mTouchStatesByDisplay.end()) {
- ALOGW("Cannot transfer touch state because there is no exact window being touched");
- return false;
- }
- const int32_t displayId = it->first;
sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(destChannelToken, displayId);
if (toWindowHandle == nullptr) {
- ALOGW("Could not find window associated with token=%p", destChannelToken.get());
+ ALOGW("Could not find window associated with token=%p on display %" PRId32,
+ destChannelToken.get(), displayId);
return false;
}
- TouchState& state = it->second;
- const TouchedWindow& touchedWindow = state.windows[0];
- fromToken = touchedWindow.windowHandle->getToken();
+ sp<WindowInfoHandle> from = findTouchedForegroundWindowLocked(displayId);
+ if (from == nullptr) {
+ ALOGE("Could not find a source window in %s for %p", __func__, destChannelToken.get());
+ return false;
+ }
+
+ fromToken = from->getToken();
} // release lock
return transferTouchFocus(fromToken, destChannelToken);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index a9fb5c6..f3dac19 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -104,7 +104,7 @@
void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
android::os::InputEventInjectionResult injectInputEvent(
- const InputEvent* event, std::optional<int32_t> targetUid,
+ const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
uint32_t policyFlags) override;
@@ -125,7 +125,7 @@
bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
bool isDragDrop = false) override;
- bool transferTouch(const sp<IBinder>& destChannelToken) override;
+ bool transferTouch(const sp<IBinder>& destChannelToken, int32_t displayId) override;
base::Result<std::unique_ptr<InputChannel>> createInputChannel(
const std::string& name) override;
@@ -245,6 +245,9 @@
std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAtLocked(
int32_t displayId, int32_t x, int32_t y, bool isStylus) const REQUIRES(mLock);
+ sp<android::gui::WindowInfoHandle> findTouchedForegroundWindowLocked(int32_t displayId) const
+ REQUIRES(mLock);
+
sp<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const
REQUIRES(mLock);
@@ -275,6 +278,7 @@
// Event injection and synchronization.
std::condition_variable mInjectionResultAvailable;
+ bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
void setInjectionResult(EventEntry& entry,
android::os::InputEventInjectionResult injectionResult);
void transformMotionEntryForInjectionLocked(MotionEntry&,
@@ -550,6 +554,8 @@
void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId)
REQUIRES(mLock);
void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock);
+ bool checkInjectionPermission(const sp<android::gui::WindowInfoHandle>& windowHandle,
+ const InjectionState* injectionState);
// Enqueue a drag event if needed, and update the touch state.
// Uses findTouchedWindowTargetsLocked to make the decision
void addDragEventLocked(const MotionEntry& entry) REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 100bd18..d7bc5fb 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -68,16 +68,10 @@
* input injection to proceed.
* Returns one of the INPUT_EVENT_INJECTION_XXX constants.
*
- * If a targetUid is provided, InputDispatcher will only consider injecting the input event into
- * windows owned by the provided uid. If the input event is targeted at a window that is not
- * owned by the provided uid, input injection will fail. If no targetUid is provided, the input
- * event will be dispatched as-is.
- *
- * This method may be called on any thread (usually by the input manager). The caller must
- * perform all necessary permission checks prior to injecting events.
+ * This method may be called on any thread (usually by the input manager).
*/
virtual android::os::InputEventInjectionResult injectInputEvent(
- const InputEvent* event, std::optional<int32_t> targetUid,
+ const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
uint32_t policyFlags) = 0;
@@ -161,7 +155,7 @@
*
* Return true on success, false if there was no on-going touch.
*/
- virtual bool transferTouch(const sp<IBinder>& destChannelToken) = 0;
+ virtual bool transferTouch(const sp<IBinder>& destChannelToken, int32_t displayId) = 0;
/**
* Sets focus on the specified window.
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 575b3d7..de0b6da 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -125,6 +125,15 @@
/* Poke user activity for an event dispatched to a window. */
virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) = 0;
+ /* Checks whether a given application pid/uid has permission to inject input events
+ * into other applications.
+ *
+ * This method is special in that its implementation promises to be non-reentrant and
+ * is safe to call while holding other locks. (Most other methods make no such guarantees!)
+ */
+ virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
+ int32_t injectorUid) = 0;
+
/* Notifies the policy that a pointer down event has occurred outside the current focused
* window.
*
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index dc5fcec..a9a4c71 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -27,6 +27,9 @@
namespace android {
+// The default velocity control parameters that has no effect.
+static const VelocityControlParameters FLAT_VELOCITY_CONTROL_PARAMS{};
+
// --- CursorMotionAccumulator ---
CursorMotionAccumulator::CursorMotionAccumulator() {
@@ -154,8 +157,9 @@
mHWheelScale = 1.0f;
}
- if ((!changes && config->pointerCaptureRequest.enable) ||
- (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)) {
+ const bool configurePointerCapture = (!changes && config->pointerCaptureRequest.enable) ||
+ (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ if (configurePointerCapture) {
if (config->pointerCaptureRequest.enable) {
if (mParameters.mode == Parameters::MODE_POINTER) {
mParameters.mode = Parameters::MODE_POINTER_RELATIVE;
@@ -180,10 +184,18 @@
}
}
- if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
- mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
- mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
- mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
+ if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED) ||
+ configurePointerCapture) {
+ if (config->pointerCaptureRequest.enable) {
+ // Disable any acceleration or scaling when Pointer Capture is enabled.
+ mPointerVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
+ mWheelXVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
+ mWheelYVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
+ } else {
+ mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
+ mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
+ mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
+ }
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 1d63c0e..2ac8178 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -428,6 +428,8 @@
}
void KeyboardInputMapper::updateLedState(bool reset) {
+ // Clear the local led state then union the global led state.
+ mMetaState &= ~(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON);
mMetaState |= getContext()->getLedMetaState();
constexpr int32_t META_NUM = 3;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index f15ed9e..a167271 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -45,10 +45,10 @@
using namespace ftl::flag_operators;
// An arbitrary time value.
-static constexpr nsecs_t ARBITRARY_TIME = 1234;
+static const nsecs_t ARBITRARY_TIME = 1234;
// An arbitrary device id.
-static constexpr int32_t DEVICE_ID = 1;
+static const int32_t DEVICE_ID = 1;
// An arbitrary display id.
static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
@@ -61,12 +61,9 @@
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
-// The default pid and uid for windows created by the test.
-static constexpr int32_t WINDOW_PID = 999;
-static constexpr int32_t WINDOW_UID = 1001;
-
-// The default policy flags to use for event injection by tests.
-static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
+// An arbitrary injector pid / uid pair that has permission to inject events.
+static const int32_t INJECTOR_PID = 999;
+static const int32_t INJECTOR_UID = 1001;
// An arbitrary pid of the gesture monitor window
static constexpr int32_t MONITOR_PID = 2001;
@@ -475,6 +472,10 @@
void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
+ bool checkInjectEventsPermissionNonReentrant(int32_t pid, int32_t uid) override {
+ return pid == INJECTOR_PID && uid == INJECTOR_UID;
+ }
+
void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
std::scoped_lock lock(mLock);
mOnPointerDownToken = newToken;
@@ -559,8 +560,8 @@
/*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
ARBITRARY_TIME);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject key events with undefined action.";
// Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
@@ -568,8 +569,8 @@
INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
ARBITRARY_TIME, ARBITRARY_TIME);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject key events with ACTION_MULTIPLE.";
}
@@ -598,8 +599,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject motion events with undefined action.";
// Rejects pointer down with invalid index.
@@ -610,8 +611,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject motion events with pointer down index too large.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -622,8 +623,8 @@
identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject motion events with pointer down index too small.";
// Rejects pointer up with invalid index.
@@ -634,8 +635,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject motion events with pointer up index too large.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -646,8 +647,8 @@
identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject motion events with pointer up index too small.";
// Rejects motion events with invalid number of pointers.
@@ -658,8 +659,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 0, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject motion events with 0 pointers.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -669,8 +670,8 @@
ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject motion events with more than MAX_POINTERS pointers.";
// Rejects motion events with invalid pointer ids.
@@ -682,8 +683,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject motion events with pointer ids less than 0.";
pointerProperties[0].id = MAX_POINTER_ID + 1;
@@ -694,8 +695,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
// Rejects motion events with duplicate pointer ids.
@@ -708,8 +709,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 2, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
- 0ms, 0))
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, 0ms, 0))
<< "Should reject motion events with duplicate pointer ids.";
}
@@ -1012,8 +1013,8 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
- mInfo.ownerPid = WINDOW_PID;
- mInfo.ownerUid = WINDOW_UID;
+ mInfo.ownerPid = INJECTOR_PID;
+ mInfo.ownerUid = INJECTOR_UID;
mInfo.displayId = displayId;
mInfo.inputConfig = WindowInfo::InputConfig::DEFAULT;
}
@@ -1295,8 +1296,7 @@
int32_t displayId = ADISPLAY_ID_NONE,
InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
- bool allowKeyRepeat = true, std::optional<int32_t> targetUid = {},
- uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
+ bool allowKeyRepeat = true) {
KeyEvent event;
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -1305,11 +1305,13 @@
INVALID_HMAC, action, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE,
repeatCount, currentTime, currentTime);
+ int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
if (!allowKeyRepeat) {
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
}
// Inject event until dispatch out.
- return dispatcher->injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
+ return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, syncMode,
+ injectionTimeout, policyFlags);
}
static InputEventInjectionResult injectKeyDown(const std::unique_ptr<InputDispatcher>& dispatcher,
@@ -1452,10 +1454,10 @@
static InputEventInjectionResult injectMotionEvent(
const std::unique_ptr<InputDispatcher>& dispatcher, const MotionEvent& event,
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
- std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
- return dispatcher->injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
- policyFlags);
+ InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT) {
+ return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, injectionMode,
+ injectionTimeout,
+ POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
}
static InputEventInjectionResult injectMotionEvent(
@@ -1465,8 +1467,7 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION},
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
- nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
- std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
+ nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC)) {
MotionEvent event = MotionEventBuilder(action, source)
.displayId(displayId)
.eventTime(eventTime)
@@ -1478,8 +1479,7 @@
.build();
// Inject event until dispatch out.
- return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode, targetUid,
- policyFlags);
+ return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode);
}
static InputEventInjectionResult injectMotionDown(
@@ -2476,6 +2476,63 @@
secondWindow->consumeMotionUp();
}
+/**
+ * When 'transferTouch' API is invoked, dispatcher needs to find the "best" window to take touch
+ * from. When we have spy windows, there are several windows to choose from: either spy, or the
+ * 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
+ * natural to the user.
+ * In this test, we are sending a pointer to both spy window and first window. We then try to
+ * transfer touch to the second window. The dispatcher should identify the first window as the
+ * one that should lose the gesture, and therefore the action should be to move the gesture from
+ * the first window to the second.
+ * The main goal here is to test the behaviour of 'transferTouch' API, but it's still valid to test
+ * the other API, as well.
+ */
+TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ // Create a couple of windows + a spy window
+ sp<FakeWindowHandle> spyWindow =
+ new FakeWindowHandle(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+ spyWindow->setTrustedOverlay(true);
+ spyWindow->setSpy(true);
+ sp<FakeWindowHandle> firstWindow =
+ new FakeWindowHandle(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> secondWindow =
+ new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+
+ // Add the windows to the dispatcher
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, firstWindow, secondWindow}}});
+
+ // Send down to the first window
+ NotifyMotionArgs downMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&downMotionArgs);
+ // Only the first window and spy should get the down event
+ spyWindow->consumeMotionDown();
+ firstWindow->consumeMotionDown();
+
+ // Transfer touch to the second window. Non-spy window should be preferred over the spy window
+ // if f === 'transferTouch'.
+ TransferFunction f = GetParam();
+ const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
+ ASSERT_TRUE(success);
+ // The first window gets cancel and the second gets down
+ firstWindow->consumeMotionCancel();
+ secondWindow->consumeMotionDown();
+
+ // Send up event to the second window
+ NotifyMotionArgs upMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&upMotionArgs);
+ // The first window gets no events and the second+spy get up
+ firstWindow->assertNoEvents();
+ spyWindow->consumeMotionUp();
+ secondWindow->consumeMotionUp();
+}
+
TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
@@ -2545,7 +2602,8 @@
::testing::Values(
[&](const std::unique_ptr<InputDispatcher>& dispatcher,
sp<IBinder> /*ignored*/, sp<IBinder> destChannelToken) {
- return dispatcher->transferTouch(destChannelToken);
+ return dispatcher->transferTouch(destChannelToken,
+ ADISPLAY_ID_DEFAULT);
},
[&](const std::unique_ptr<InputDispatcher>& dispatcher,
sp<IBinder> from, sp<IBinder> to) {
@@ -2653,7 +2711,8 @@
secondWindow->consumeMotionDown();
// Transfer touch focus to the second window
- const bool transferred = mDispatcher->transferTouch(secondWindow->getToken());
+ const bool transferred =
+ mDispatcher->transferTouch(secondWindow->getToken(), ADISPLAY_ID_DEFAULT);
// The 'transferTouch' call should not succeed, because there are 2 touched windows
ASSERT_FALSE(transferred);
firstWindow->assertNoEvents();
@@ -2777,7 +2836,7 @@
firstWindowInPrimary->consumeMotionDown(SECOND_DISPLAY_ID);
// Transfer touch focus
- ASSERT_TRUE(mDispatcher->transferTouch(secondWindowInSecondary->getToken()));
+ ASSERT_TRUE(mDispatcher->transferTouch(secondWindowInSecondary->getToken(), SECOND_DISPLAY_ID));
// The first window gets cancel.
firstWindowInPrimary->consumeMotionCancel(SECOND_DISPLAY_ID);
@@ -3515,8 +3574,8 @@
* FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
*/
TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
- constexpr int32_t SLIPPERY_PID = WINDOW_PID + 1;
- constexpr int32_t SLIPPERY_UID = WINDOW_UID + 1;
+ constexpr int32_t SLIPPERY_PID = INJECTOR_PID + 1;
+ constexpr int32_t SLIPPERY_UID = INJECTOR_UID + 1;
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -4043,7 +4102,7 @@
const int32_t additionalPolicyFlags =
POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
policyFlags | additionalPolicyFlags));
@@ -4078,7 +4137,7 @@
const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
policyFlags | additionalPolicyFlags));
@@ -4585,7 +4644,7 @@
const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
InputEventInjectionResult result =
- mDispatcher->injectInputEvent(&event, {} /* targetUid */,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
InputEventInjectionSync::WAIT_FOR_RESULT,
INJECT_EVENT_TIMEOUT, policyFlags);
ASSERT_EQ(InputEventInjectionResult::FAILED, result)
@@ -6385,8 +6444,8 @@
mWindow->consumeFocusEvent(true);
// Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
- if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
- WINDOW_UID, /* hasPermission */ true)) {
+ if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
+ INJECTOR_UID, /* hasPermission */ true)) {
mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
}
@@ -7017,149 +7076,4 @@
window->assertNoEvents();
}
-struct User {
- int32_t mPid;
- int32_t mUid;
- uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
- std::unique_ptr<InputDispatcher>& mDispatcher;
-
- User(std::unique_ptr<InputDispatcher>& dispatcher, int32_t pid, int32_t uid)
- : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
-
- InputEventInjectionResult injectTargetedMotion(int32_t action) const {
- return injectMotionEvent(mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
- ADISPLAY_ID_DEFAULT, {100, 200},
- {AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION},
- INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
- systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
- }
-
- InputEventInjectionResult injectTargetedKey(int32_t action) const {
- return inputdispatcher::injectKey(mDispatcher, action, 0 /* repeatCount*/, ADISPLAY_ID_NONE,
- InputEventInjectionSync::WAIT_FOR_RESULT,
- INJECT_EVENT_TIMEOUT, false /*allowKeyRepeat*/, {mUid},
- mPolicyFlags);
- }
-
- sp<FakeWindowHandle> createWindow() const {
- std::shared_ptr<FakeApplicationHandle> overlayApplication =
- std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window = new FakeWindowHandle(overlayApplication, mDispatcher,
- "Owned Window", ADISPLAY_ID_DEFAULT);
- window->setOwnerInfo(mPid, mUid);
- return window;
- }
-};
-
-using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
-
-TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
- auto owner = User(mDispatcher, 10, 11);
- auto window = owner.createWindow();
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
-
- EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
- owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
- window->consumeMotionDown();
-
- setFocusedWindow(window);
- window->consumeFocusEvent(true);
-
- EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
- owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
- window->consumeKeyDown(ADISPLAY_ID_NONE);
-}
-
-TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
- auto owner = User(mDispatcher, 10, 11);
- auto window = owner.createWindow();
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
-
- auto rando = User(mDispatcher, 20, 21);
- EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
- rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
-
- setFocusedWindow(window);
- window->consumeFocusEvent(true);
-
- EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
- rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
- window->assertNoEvents();
-}
-
-TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
- auto owner = User(mDispatcher, 10, 11);
- auto window = owner.createWindow();
- auto spy = owner.createWindow();
- spy->setSpy(true);
- spy->setTrustedOverlay(true);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
-
- EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
- owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
- spy->consumeMotionDown();
- window->consumeMotionDown();
-}
-
-TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
- auto owner = User(mDispatcher, 10, 11);
- auto window = owner.createWindow();
-
- auto rando = User(mDispatcher, 20, 21);
- auto randosSpy = rando.createWindow();
- randosSpy->setSpy(true);
- randosSpy->setTrustedOverlay(true);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
-
- // The event is targeted at owner's window, so injection should succeed, but the spy should
- // not receive the event.
- EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
- owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
- randosSpy->assertNoEvents();
- window->consumeMotionDown();
-}
-
-TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
- auto owner = User(mDispatcher, 10, 11);
- auto window = owner.createWindow();
-
- auto rando = User(mDispatcher, 20, 21);
- auto randosSpy = rando.createWindow();
- randosSpy->setSpy(true);
- randosSpy->setTrustedOverlay(true);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
-
- // A user that has injection permission can inject into any window.
- EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
- ADISPLAY_ID_DEFAULT));
- randosSpy->consumeMotionDown();
- window->consumeMotionDown();
-
- setFocusedWindow(randosSpy);
- randosSpy->consumeFocusEvent(true);
-
- EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher));
- randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
- window->assertNoEvents();
-}
-
-TEST_F(InputDispatcherTargetedInjectionTest, CanGenerateActionOutsideToOtherUids) {
- auto owner = User(mDispatcher, 10, 11);
- auto window = owner.createWindow();
-
- auto rando = User(mDispatcher, 20, 21);
- auto randosWindow = rando.createWindow();
- randosWindow->setFrame(Rect{-10, -10, -5, -5});
- randosWindow->setWatchOutsideTouch(true);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosWindow, window}}});
-
- // We allow generation of ACTION_OUTSIDE events into windows owned by different uids.
- EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
- owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
- window->consumeMotionDown();
- randosWindow->consumeMotionOutside();
-}
-
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 8ba501c..b29a0a2 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -375,6 +375,11 @@
float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; }
+ void setVelocityControlParams(const VelocityControlParameters& params) {
+ mConfig.pointerVelocityControlParameters = params;
+ mConfig.wheelVelocityControlParameters = params;
+ }
+
private:
uint32_t mNextPointerCaptureSequenceNumber = 0;
@@ -2949,7 +2954,10 @@
}
void configureDevice(uint32_t changes) {
- if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+ if (!changes ||
+ (changes &
+ (InputReaderConfiguration::CHANGE_DISPLAY_INFO |
+ InputReaderConfiguration::CHANGE_POINTER_CAPTURE))) {
mReader->requestRefreshConfiguration(changes);
mReader->loopOnce();
}
@@ -3999,6 +4007,78 @@
ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
}
+TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleInMultiDevices) {
+ // keyboard 1.
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_NUML, false /*initially off*/);
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
+
+ KeyboardInputMapper& mapper1 =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+
+ // keyboard 2.
+ const std::string USB2 = "USB2";
+ const std::string DEVICE_NAME2 = "KEYBOARD2";
+ constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
+ constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
+ std::shared_ptr<InputDevice> device2 =
+ newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
+ ftl::Flags<InputDeviceClass>(0));
+ mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+ mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_NUML, false /*initially off*/);
+ mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
+
+ KeyboardInputMapper& mapper2 =
+ device2->addMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
+ device2->reset(ARBITRARY_TIME);
+
+ // Initial metastate is AMETA_NUM_LOCK_ON, turn it off.
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper2.getMetaState());
+
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+
+ // Toggle caps lock on and off.
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper2.getMetaState());
+
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+
+ // Toggle scroll lock on and off.
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper2.getMetaState());
+
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+}
+
// --- KeyboardInputMapperTest_ExternalDevice ---
class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest {
@@ -4842,6 +4922,54 @@
ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
}
+/**
+ * When Pointer Capture is enabled, we expect to report unprocessed relative movements, so any
+ * pointer acceleration or speed processing should not be applied.
+ */
+TEST_F(CursorInputMapperTest, PointerCaptureDisablesVelocityProcessing) {
+ addConfigurationProperty("cursor.mode", "pointer");
+ const VelocityControlParameters testParams(5.f /*scale*/, 0.f /*low threshold*/,
+ 100.f /*high threshold*/, 10.f /*acceleration*/);
+ mFakePolicy->setVelocityControlParams(testParams);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+ NotifyDeviceResetArgs resetArgs;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+ ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+ ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
+
+ NotifyMotionArgs args;
+
+ // Move and verify scale is applied.
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
+ const float relX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
+ const float relY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
+ ASSERT_GT(relX, 10);
+ ASSERT_GT(relY, 20);
+
+ // Enable Pointer Capture
+ mFakePolicy->setPointerCapture(true);
+ configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ NotifyPointerCaptureChangedArgs captureArgs;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyCaptureWasCalled(&captureArgs));
+ ASSERT_TRUE(captureArgs.request.enable);
+
+ // Move and verify scale is not applied.
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+ ASSERT_EQ(10, args.pointerCoords[0].getX());
+ ASSERT_EQ(20, args.pointerCoords[0].getY());
+}
+
TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
diff --git a/services/sensorservice/HidlSensorHalWrapper.cpp b/services/sensorservice/HidlSensorHalWrapper.cpp
index 4c64e59..c55c9b4 100644
--- a/services/sensorservice/HidlSensorHalWrapper.cpp
+++ b/services/sensorservice/HidlSensorHalWrapper.cpp
@@ -281,7 +281,7 @@
}
status_t HidlSensorHalWrapper::registerDirectChannel(const sensors_direct_mem_t* memory,
- int32_t* /*channelHandle*/) {
+ int32_t* outChannelHandle) {
if (mSensors == nullptr) return NO_INIT;
SharedMemType type;
@@ -309,14 +309,16 @@
.memoryHandle = memory->handle,
};
- status_t ret;
- checkReturn(mSensors->registerDirectChannel(mem, [&ret](auto result, auto channelHandle) {
- if (result == Result::OK) {
- ret = channelHandle;
- } else {
- ret = statusFromResult(result);
- }
- }));
+ status_t ret = OK;
+ checkReturn(mSensors->registerDirectChannel(mem,
+ [&ret, &outChannelHandle](auto result,
+ auto channelHandle) {
+ if (result == Result::OK) {
+ *outChannelHandle = channelHandle;
+ } else {
+ ret = statusFromResult(result);
+ }
+ }));
return ret;
}
diff --git a/services/sensorservice/HidlSensorHalWrapper.h b/services/sensorservice/HidlSensorHalWrapper.h
index 71c3512..d6ed178 100644
--- a/services/sensorservice/HidlSensorHalWrapper.h
+++ b/services/sensorservice/HidlSensorHalWrapper.h
@@ -112,7 +112,7 @@
virtual status_t injectSensorData(const sensors_event_t* event) override;
virtual status_t registerDirectChannel(const sensors_direct_mem_t* memory,
- int32_t* channelHandle) override;
+ int32_t* outChannelHandle) override;
virtual status_t unregisterDirectChannel(int32_t channelHandle) override;
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index a0e30ac..53a3025 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -766,7 +766,13 @@
if (mHalWrapper == nullptr) return NO_INIT;
Mutex::Autolock _l(mLock);
- return mHalWrapper->registerDirectChannel(memory, nullptr);
+ int32_t channelHandle;
+ status_t status = mHalWrapper->registerDirectChannel(memory, &channelHandle);
+ if (status != OK) {
+ channelHandle = -1;
+ }
+
+ return channelHandle;
}
void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 79e4c75..670233a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -376,6 +376,11 @@
}
ATRACE_CALL();
+ if (displayData.powerMode == hal::PowerMode::DOZE && enabled == hal::Vsync::ENABLE) {
+ ALOGV("%s will not enable vsync for display %s due to power mode %s", __FUNCTION__,
+ to_string(displayId).c_str(), to_string(displayData.powerMode).c_str());
+ return;
+ }
auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
RETURN_IF_HWC_ERROR(error, displayId);
@@ -552,6 +557,7 @@
setVsyncEnabled(displayId, hal::Vsync::DISABLE);
}
+ mDisplayData[displayId].powerMode = mode;
const auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
switch (mode) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 7dc10ea..8d67589 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -462,6 +462,8 @@
std::mutex vsyncEnabledLock;
hal::Vsync vsyncEnabled GUARDED_BY(vsyncEnabledLock) = hal::Vsync::DISABLE;
+ hal::PowerMode powerMode = hal::PowerMode::ON;
+
nsecs_t lastHwVsync = 0;
};
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 05f488b..cbafdd3 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -463,29 +463,41 @@
ALOGV("Failed to send actual work duration, skipping");
return;
}
-
- WorkDuration duration;
- duration.durationNanos = actualDurationNanos;
- mActualDuration = actualDurationNanos;
+ nsecs_t reportedDuration = actualDurationNanos;
// normalize the sent values to a pre-set target
if (sNormalizeTarget) {
- duration.durationNanos += mLastTargetDurationSent - mTargetDuration;
+ reportedDuration += mLastTargetDurationSent - mTargetDuration;
+ } else {
+ // when target duration change is within deviation and not updated, adjust the actual
+ // duration proportionally based on the difference, e.g. if new target is 5ms longer than
+ // last reported but actual duration is the same as last target, we want to report a smaller
+ // actual work duration now to indicate that we are overshooting
+ if (mLastTargetDurationSent != kDefaultTarget.count() && mTargetDuration != 0) {
+ reportedDuration =
+ static_cast<int64_t>(static_cast<long double>(mLastTargetDurationSent) /
+ mTargetDuration * actualDurationNanos);
+ mActualDuration = reportedDuration;
+ }
}
+ mActualDuration = reportedDuration;
+ WorkDuration duration;
+ duration.durationNanos = reportedDuration;
duration.timeStampNanos = timeStampNanos;
mPowerHintQueue.push_back(duration);
- nsecs_t targetNsec = mTargetDuration;
- nsecs_t durationNsec = actualDurationNanos;
-
if (sTraceHintSessionData) {
- ATRACE_INT64("Measured duration", durationNsec);
- ATRACE_INT64("Target error term", targetNsec - durationNsec);
+ ATRACE_INT64("Measured duration", actualDurationNanos);
+ ATRACE_INT64("Target error term", mTargetDuration - actualDurationNanos);
+
+ ATRACE_INT64("Reported duration", reportedDuration);
+ ATRACE_INT64("Reported target", mLastTargetDurationSent);
+ ATRACE_INT64("Reported target error term", mLastTargetDurationSent - reportedDuration);
}
- ALOGV("Sending actual work duration of: %" PRId64 " on target: %" PRId64
+ ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
" with error: %" PRId64,
- durationNsec, targetNsec, targetNsec - durationNsec);
+ reportedDuration, mLastTargetDurationSent, mLastTargetDurationSent - reportedDuration);
// This rate limiter queues similar duration reports to the powerhal into
// batches to avoid excessive binder calls. The criteria to send a given batch
@@ -501,7 +513,7 @@
}
mPowerHintQueue.clear();
// we save the non-normalized value here to detect % changes
- mLastActualDurationSent = actualDurationNanos;
+ mLastActualDurationSent = reportedDuration;
}
}
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 3f47ffd..61bb32b 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -173,8 +173,8 @@
// Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
static constexpr double kAllowedActualDeviationPercent = 0.1;
- // Max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
- static constexpr double kAllowedTargetDeviationPercent = 0.05;
+ // Max percent the target duration can vary without causing a report (eg: 0.1 = 10%)
+ static constexpr double kAllowedTargetDeviationPercent = 0.1;
// Target used for init and normalization, the actual value does not really matter
static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
// Amount of time after the last message was sent before the session goes stale
diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
index cc85352..e8c590e 100644
--- a/services/surfaceflinger/EffectLayer.cpp
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -114,7 +114,13 @@
}
sp<compositionengine::LayerFE> EffectLayer::getCompositionEngineLayerFE() const {
- return asLayerFE();
+ // There's no need to get a CE Layer if the EffectLayer isn't going to draw anything. In that
+ // case, it acts more like a ContainerLayer so returning a null CE Layer makes more sense
+ if (hasSomethingToDraw()) {
+ return asLayerFE();
+ } else {
+ return nullptr;
+ }
}
compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 997b1a1..d8a5601 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2185,7 +2185,7 @@
layerInfo->set_owner_uid(mOwnerUid);
- if (traceFlags & LayerTracing::TRACE_INPUT) {
+ if ((traceFlags & LayerTracing::TRACE_INPUT) && needsInputInfo()) {
WindowInfo info;
if (useDrawing) {
info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true);
@@ -2596,6 +2596,8 @@
return FrameRateCompatibility::ExactOrMultiple;
case ANATIVEWINDOW_FRAME_RATE_EXACT:
return FrameRateCompatibility::Exact;
+ case ANATIVEWINDOW_FRAME_RATE_NO_VOTE:
+ return FrameRateCompatibility::NoVote;
default:
LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility);
return FrameRateCompatibility::Default;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 80aa072..d4435c2 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -45,6 +45,15 @@
constexpr int kBufferWidth = 4 * kDigitWidth + 3 * kDigitSpace;
constexpr int kBufferHeight = kDigitHeight;
+SurfaceComposerClient::Transaction createTransaction(const sp<SurfaceControl>& surface) {
+ constexpr float kFrameRate = 0.f;
+ constexpr int8_t kCompatibility = ANATIVEWINDOW_FRAME_RATE_NO_VOTE;
+ constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
+
+ return SurfaceComposerClient::Transaction().setFrameRate(surface, kFrameRate, kCompatibility,
+ kSeamlessness);
+}
+
} // namespace
void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color,
@@ -213,12 +222,7 @@
return;
}
- constexpr float kFrameRate = 0.f;
- constexpr int8_t kCompatibility = static_cast<int8_t>(Layer::FrameRateCompatibility::NoVote);
- constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
-
- SurfaceComposerClient::Transaction()
- .setFrameRate(mSurfaceControl, kFrameRate, kCompatibility, kSeamlessness)
+ createTransaction(mSurfaceControl)
.setLayer(mSurfaceControl, INT32_MAX - 2)
.setTrustedOverlay(mSurfaceControl, true)
.apply();
@@ -243,9 +247,7 @@
}
}();
- SurfaceComposerClient::Transaction t;
- t.setTransform(mSurfaceControl, transform);
- t.apply();
+ createTransaction(mSurfaceControl).setTransform(mSurfaceControl, transform).apply();
BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint});
if (it == mBufferCache.end()) {
@@ -287,25 +289,21 @@
Rect frame((3 * width) >> 4, height >> 5);
frame.offsetBy(width >> 5, height >> 4);
- SurfaceComposerClient::Transaction t;
- t.setMatrix(mSurfaceControl, frame.getWidth() / static_cast<float>(kBufferWidth), 0, 0,
- frame.getHeight() / static_cast<float>(kBufferHeight));
- t.setPosition(mSurfaceControl, frame.left, frame.top);
- t.apply();
+ createTransaction(mSurfaceControl)
+ .setMatrix(mSurfaceControl, frame.getWidth() / static_cast<float>(kBufferWidth), 0, 0,
+ frame.getHeight() / static_cast<float>(kBufferHeight))
+ .setPosition(mSurfaceControl, frame.left, frame.top)
+ .apply();
}
void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
- SurfaceComposerClient::Transaction t;
- t.setLayerStack(mSurfaceControl, stack);
- t.apply();
+ createTransaction(mSurfaceControl).setLayerStack(mSurfaceControl, stack).apply();
}
void RefreshRateOverlay::changeRefreshRate(Fps fps) {
mCurrentFps = fps;
const auto buffer = getOrCreateBuffers(fps)[mFrame];
- SurfaceComposerClient::Transaction t;
- t.setBuffer(mSurfaceControl, buffer);
- t.apply();
+ createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
}
void RefreshRateOverlay::animate() {
@@ -314,9 +312,7 @@
const auto& buffers = getOrCreateBuffers(*mCurrentFps);
mFrame = (mFrame + 1) % buffers.size();
const auto buffer = buffers[mFrame];
- SurfaceComposerClient::Transaction t;
- t.setBuffer(mSurfaceControl, buffer);
- t.apply();
+ createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
}
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 115dc64..3bfc2cc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -95,6 +95,7 @@
#include <cmath>
#include <cstdint>
#include <functional>
+#include <memory>
#include <mutex>
#include <optional>
#include <type_traits>
@@ -113,6 +114,7 @@
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/Hal.h"
+#include "DisplayHardware/PowerAdvisor.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "DisplayRenderArea.h"
#include "EffectLayer.h"
@@ -327,7 +329,7 @@
mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
- mPowerAdvisor(*this),
+ mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)),
mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make(*this)) {
ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
}
@@ -413,7 +415,7 @@
property_get("debug.sf.disable_client_composition_cache", value, "0");
mDisableClientCompositionCache = atoi(value);
- property_get("debug.sf.predict_hwc_composition_strategy", value, "0");
+ property_get("debug.sf.predict_hwc_composition_strategy", value, "1");
mPredictCompositionStrategy = atoi(value);
// We should be reading 'persist.sys.sf.color_saturation' here
@@ -677,16 +679,16 @@
}
readPersistentProperties();
- mPowerAdvisor.onBootFinished();
- mPowerAdvisor.enablePowerHint(mFlagManager.use_adpf_cpu_hint());
- if (mPowerAdvisor.usePowerHintSession()) {
+ mPowerAdvisor->onBootFinished();
+ mPowerAdvisor->enablePowerHint(mFlagManager.use_adpf_cpu_hint());
+ if (mPowerAdvisor->usePowerHintSession()) {
std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
std::vector<int32_t> tidList;
tidList.emplace_back(gettid());
if (renderEngineTid.has_value()) {
tidList.emplace_back(*renderEngineTid);
}
- if (!mPowerAdvisor.startPowerHintSession(tidList)) {
+ if (!mPowerAdvisor->startPowerHintSession(tidList)) {
ALOGW("Cannot start power hint session");
}
}
@@ -812,7 +814,7 @@
// set initial conditions (e.g. unblank default device)
initializeDisplays();
- mPowerAdvisor.init();
+ mPowerAdvisor->init();
char primeShaderCache[PROPERTY_VALUE_MAX];
property_get("service.sf.prime_shader_cache", primeShaderCache, "1");
@@ -1284,10 +1286,10 @@
const char* const whence = __func__;
auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
ATRACE_NAME(whence);
- if (mPowerAdvisor.isUsingExpensiveRendering()) {
+ if (mPowerAdvisor->isUsingExpensiveRendering()) {
for (const auto& [_, display] : mDisplays) {
constexpr bool kDisable = false;
- mPowerAdvisor.setExpensiveRenderingExpected(display->getId(), kDisable);
+ mPowerAdvisor->setExpensiveRenderingExpected(display->getId(), kDisable);
}
}
});
@@ -1810,7 +1812,7 @@
if (hint == FrameHint::kActive) {
mScheduler->resetIdleTimer();
}
- mPowerAdvisor.notifyDisplayUpdateImminent();
+ mPowerAdvisor->notifyDisplayUpdateImminent();
mScheduler->scheduleFrame();
}
@@ -1980,7 +1982,7 @@
bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
FTL_FAKE_GUARD(kMainThreadContext) {
// we set this once at the beginning of commit to ensure consistency throughout the whole frame
- mPowerHintSessionData.sessionEnabled = mPowerAdvisor.usePowerHintSession();
+ mPowerHintSessionData.sessionEnabled = mPowerAdvisor->usePowerHintSession();
if (mPowerHintSessionData.sessionEnabled) {
mPowerHintSessionData.commitStart = systemTime();
}
@@ -1999,8 +2001,8 @@
mScheduledPresentTime = expectedVsyncTime;
if (mPowerHintSessionData.sessionEnabled) {
- mPowerAdvisor.setTargetWorkDuration(mExpectedPresentTime -
- mPowerHintSessionData.commitStart);
+ mPowerAdvisor->setTargetWorkDuration(mExpectedPresentTime -
+ mPowerHintSessionData.commitStart);
}
const auto vsyncIn = [&] {
if (!ATRACE_ENABLED()) return 0.f;
@@ -2264,7 +2266,7 @@
if (mPowerHintSessionData.sessionEnabled) {
const nsecs_t flingerDuration =
(mPowerHintSessionData.presentEnd - mPowerHintSessionData.commitStart);
- mPowerAdvisor.sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
+ mPowerAdvisor->sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
}
}
@@ -2728,12 +2730,12 @@
}
const auto displayId = info->id;
- const auto it = mPhysicalDisplayTokens.find(displayId);
+ const auto token = mPhysicalDisplayTokens.get(displayId);
if (event.connection == hal::Connection::CONNECTED) {
auto [supportedModes, activeMode] = loadDisplayModes(displayId);
- if (it == mPhysicalDisplayTokens.end()) {
+ if (!token) {
ALOGV("Creating display %s", to_string(displayId).c_str());
DisplayDeviceState state;
@@ -2748,14 +2750,13 @@
sp<IBinder> token = new BBinder();
mCurrentState.displays.add(token, state);
- mPhysicalDisplayTokens.emplace(displayId, std::move(token));
+ mPhysicalDisplayTokens.try_emplace(displayId, std::move(token));
mInterceptor->saveDisplayCreation(state);
} else {
ALOGV("Recreating display %s", to_string(displayId).c_str());
- const auto token = it->second;
- auto& state = mCurrentState.displays.editValueFor(token);
- state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId
+ auto& state = mCurrentState.displays.editValueFor(token->get());
+ state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId.
state.physical->supportedModes = std::move(supportedModes);
state.physical->activeMode = std::move(activeMode);
if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) {
@@ -2765,13 +2766,13 @@
} else {
ALOGV("Removing display %s", to_string(displayId).c_str());
- const ssize_t index = mCurrentState.displays.indexOfKey(it->second);
- if (index >= 0) {
+ if (const ssize_t index = mCurrentState.displays.indexOfKey(token->get()); index >= 0) {
const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
mInterceptor->saveDisplayDeletion(state.sequenceId);
mCurrentState.displays.removeItemsAt(index);
}
- mPhysicalDisplayTokens.erase(it);
+
+ mPhysicalDisplayTokens.erase(displayId);
}
processDisplayChangesLocked();
@@ -2919,7 +2920,7 @@
builder.setPixels(resolution);
builder.setIsSecure(state.isSecure);
- builder.setPowerAdvisor(&mPowerAdvisor);
+ builder.setPowerAdvisor(mPowerAdvisor.get());
builder.setName(state.displayName);
auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled);
@@ -2952,15 +2953,16 @@
}
LOG_FATAL_IF(!displaySurface);
- const auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay),
- state, displaySurface, producer);
- mDisplays.emplace(displayToken, display);
+ auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay), state,
+ displaySurface, producer);
if (display->isPrimary()) {
initScheduler(display);
}
if (!state.isVirtual()) {
dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
}
+
+ mDisplays.try_emplace(displayToken, std::move(display));
}
void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
@@ -3601,6 +3603,23 @@
if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
ISurfaceComposer::MAX_LAYERS);
+ static_cast<void>(mScheduler->schedule([=] {
+ ALOGE("Dumping random sampling of on-screen layers: ");
+ mDrawingState.traverse([&](Layer *layer) {
+ // Aim to dump about 200 layers to avoid totally trashing
+ // logcat. On the other hand, if there really are 4096 layers
+ // something has gone totally wrong its probably the most
+ // useful information in logcat.
+ if (rand() % 20 == 13) {
+ ALOGE("Layer: %s", layer->getName().c_str());
+ }
+ });
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ if (rand() % 20 == 13) {
+ ALOGE("Offscreen-layer: %s", offscreenLayer->getName().c_str());
+ }
+ }
+ }));
return NO_MEMORY;
}
@@ -3631,11 +3650,11 @@
}
void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
- const sp<IBinder>& applyToken) {
+ const sp<IBinder>& applyToken, FrameHint frameHint) {
modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken);
if (const bool scheduled = mTransactionFlags.fetch_or(mask) & mask; !scheduled) {
- scheduleCommit(FrameHint::kActive);
+ scheduleCommit(frameHint);
}
}
@@ -4007,7 +4026,7 @@
}
void SurfaceFlinger::queueTransaction(TransactionState& state) {
- Mutex::Autolock _l(mQueueLock);
+ Mutex::Autolock lock(mQueueLock);
// Generate a CountDownLatch pending state if this is a synchronous transaction.
if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) {
@@ -4026,7 +4045,9 @@
return TransactionSchedule::Late;
}(state.flags);
- setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken);
+ const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone;
+
+ setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint);
}
void SurfaceFlinger::waitForSynchronousTransaction(
@@ -7164,15 +7185,6 @@
return calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
}
-void TransactionState::traverseStatesWithBuffers(
- std::function<void(const layer_state_t&)> visitor) {
- for (const auto& state : states) {
- if (state.state.hasBufferChanges() && state.state.hasValidBuffer() && state.state.surface) {
- visitor(state.state);
- }
- }
-}
-
void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state) {
sp<Layer> layer = state.layer.promote();
if (!layer) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ea2e71a..011aaef 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -27,6 +27,7 @@
#include <android/gui/DisplayState.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
+#include <ftl/small_map.h>
#include <gui/BufferQueue.h>
#include <gui/FrameTimestamps.h>
#include <gui/ISurfaceComposer.h>
@@ -801,7 +802,8 @@
// Sets the masked bits, and schedules a commit if needed.
void setTransactionFlags(uint32_t mask, TransactionSchedule = TransactionSchedule::Late,
- const sp<IBinder>& applyToken = nullptr);
+ const sp<IBinder>& applyToken = nullptr,
+ FrameHint = FrameHint::kActive);
// Clears and returns the masked bits.
uint32_t clearTransactionFlags(uint32_t mask);
@@ -904,8 +906,8 @@
}
sp<DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) REQUIRES(mStateLock) {
- const auto it = mDisplays.find(displayToken);
- return it == mDisplays.end() ? nullptr : it->second;
+ const sp<DisplayDevice> nullDisplay;
+ return mDisplays.get(displayToken).value_or(std::cref(nullDisplay));
}
sp<const DisplayDevice> getDisplayDeviceLocked(PhysicalDisplayId id) const
@@ -1050,8 +1052,8 @@
*/
sp<IBinder> getPhysicalDisplayTokenLocked(PhysicalDisplayId displayId) const
REQUIRES(mStateLock) {
- const auto it = mPhysicalDisplayTokens.find(displayId);
- return it != mPhysicalDisplayTokens.end() ? it->second : nullptr;
+ const sp<IBinder> nullToken;
+ return mPhysicalDisplayTokens.get(displayId).value_or(std::cref(nullToken));
}
std::optional<PhysicalDisplayId> getPhysicalDisplayIdLocked(
@@ -1246,10 +1248,14 @@
std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mStateLock);
- // this may only be written from the main thread with mStateLock held
- // it may be read from other threads with mStateLock held
- std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays GUARDED_BY(mStateLock);
- std::unordered_map<PhysicalDisplayId, sp<IBinder>> mPhysicalDisplayTokens
+ // Displays are composited in `mDisplays` order. Internal displays are inserted at boot and
+ // never removed, so take precedence over external and virtual displays.
+ //
+ // The static capacities were chosen to exceed a typical number of physical/virtual displays.
+ //
+ // May be read from any thread, but must only be written from the main thread.
+ ftl::SmallMap<wp<IBinder>, const sp<DisplayDevice>, 5> mDisplays GUARDED_BY(mStateLock);
+ ftl::SmallMap<PhysicalDisplayId, const sp<IBinder>, 3> mPhysicalDisplayTokens
GUARDED_BY(mStateLock);
struct {
@@ -1382,7 +1388,7 @@
sp<os::IInputFlinger> mInputFlinger;
InputWindowCommands mInputWindowCommands;
- Hwc2::impl::PowerAdvisor mPowerAdvisor;
+ std::unique_ptr<Hwc2::PowerAdvisor> mPowerAdvisor;
void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock);
@@ -1422,10 +1428,8 @@
std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint;
bool isRefreshRateOverlayEnabled() const REQUIRES(mStateLock) {
- return std::any_of(mDisplays.begin(), mDisplays.end(),
- [](std::pair<wp<IBinder>, sp<DisplayDevice>> display) {
- return display.second->isRefreshRateOverlayEnabled();
- });
+ return hasDisplay(
+ [](const auto& display) { return display.isRefreshRateOverlayEnabled(); });
}
wp<IBinder> mActiveDisplayToken GUARDED_BY(mStateLock);
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index 04ca347..bab5326 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,12 +16,21 @@
#pragma once
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <vector>
+
#include <gui/LayerState.h>
+#include <system/window.h>
namespace android {
+
class CountDownLatch;
struct TransactionState {
+ TransactionState() = default;
+
TransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& composerStates,
const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
@@ -47,9 +56,30 @@
originUid(originUid),
id(transactionId) {}
- TransactionState() {}
+ // Invokes `void(const layer_state_t&)` visitor for matching layers.
+ template <typename Visitor>
+ void traverseStatesWithBuffers(Visitor&& visitor) const {
+ for (const auto& [state] : states) {
+ if (state.hasBufferChanges() && state.hasValidBuffer() && state.surface) {
+ visitor(state);
+ }
+ }
+ }
- void traverseStatesWithBuffers(std::function<void(const layer_state_t&)> visitor);
+ // TODO(b/185535769): Remove FrameHint. Instead, reset the idle timer (of the relevant physical
+ // display) on the main thread if commit leads to composite. Then, RefreshRateOverlay should be
+ // able to setFrameRate once, rather than for each transaction.
+ bool isFrameActive() const {
+ if (!displays.empty()) return true;
+
+ for (const auto& [state] : states) {
+ if (state.frameRateCompatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE) {
+ return true;
+ }
+ }
+
+ return false;
+ }
FrameTimelineInfo frameTimelineInfo;
Vector<ComposerState> states;
diff --git a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
index e25a0ae..9ab35d7 100644
--- a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
+++ b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "AidlPowerHalWrapperTest"
+#include <android-base/stringprintf.h>
#include <android/hardware/power/IPower.h>
#include <android/hardware/power/IPowerHintSession.h>
#include <gmock/gmock.h>
@@ -82,6 +83,15 @@
return duration;
}
+std::string printWorkDurations(const ::std::vector<WorkDuration>& durations) {
+ std::ostringstream os;
+ for (auto duration : durations) {
+ os << duration.toString();
+ os << "\n";
+ }
+ return os.str();
+}
+
namespace {
TEST_F(AidlPowerHalWrapperTest, supportsPowerHintSession) {
ASSERT_TRUE(mWrapper->supportsPowerHintSession());
@@ -143,8 +153,8 @@
{-1ms, false},
{200ms, true},
{2ms, true},
- {96ms, false},
- {104ms, false}};
+ {91ms, false},
+ {109ms, false}};
for (const auto& test : testCases) {
// reset to 100ms baseline
@@ -212,6 +222,40 @@
}
}
+TEST_F(AidlPowerHalWrapperTest, sendAdjustedActualWorkDuration) {
+ ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+ std::vector<int32_t> threadIds = {1, 2};
+ mWrapper->setPowerHintSessionThreadIds(threadIds);
+ EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+ ASSERT_TRUE(mWrapper->startPowerHintSession());
+ verifyAndClearExpectations();
+
+ std::chrono::nanoseconds lastTarget = 100ms;
+ EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(lastTarget.count())).Times(1);
+ mWrapper->setTargetWorkDuration(lastTarget.count());
+ std::chrono::nanoseconds newTarget = 105ms;
+ mWrapper->setTargetWorkDuration(newTarget.count());
+ EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(newTarget.count())).Times(0);
+ std::chrono::nanoseconds actual = 21ms;
+ // 100 / 105 * 21ms = 20ms
+ std::chrono::nanoseconds expectedActualSent = 20ms;
+ std::vector<WorkDuration> expectedDurations = {toWorkDuration(expectedActualSent, 1)};
+
+ EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
+ .WillOnce(DoAll(
+ [expectedDurations](const ::std::vector<WorkDuration>& durationsSent) {
+ EXPECT_EQ(expectedDurations, durationsSent)
+ << base::StringPrintf("actual sent: %s vs expected: %s",
+ printWorkDurations(durationsSent).c_str(),
+ printWorkDurations(expectedDurations)
+ .c_str());
+ },
+ Return(Status::ok())));
+ mWrapper->sendActualWorkDuration(actual.count(), 1);
+}
+
TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_exceedsStaleTime) {
ASSERT_TRUE(mWrapper->supportsPowerHintSession());
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index cc9d48c..7823363 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -103,6 +103,7 @@
"SurfaceFlinger_HotplugTest.cpp",
"SurfaceFlinger_NotifyPowerBoostTest.cpp",
"SurfaceFlinger_OnInitializeDisplaysTest.cpp",
+ "SurfaceFlinger_PowerHintTest.cpp",
"SurfaceFlinger_SetDisplayStateTest.cpp",
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
"SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 15c9d19..c541b92 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -113,8 +113,9 @@
mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
mComposer = new Hwc2::mock::Composer();
+ mPowerAdvisor = new Hwc2::mock::PowerAdvisor();
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
-
+ mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
mFlinger.mutableMaxRenderTargetSize() = 16384;
}
@@ -188,7 +189,7 @@
Hwc2::mock::Composer* mComposer = nullptr;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
mock::TimeStats* mTimeStats = new mock::TimeStats();
- Hwc2::mock::PowerAdvisor mPowerAdvisor;
+ Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr;
sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
@@ -300,7 +301,7 @@
.setId(DEFAULT_DISPLAY_ID)
.setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
.setIsSecure(Derived::IS_SECURE)
- .setPowerAdvisor(&test->mPowerAdvisor)
+ .setPowerAdvisor(test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
test_info->test_case_name() + "." + test_info->name())
.build();
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 2425862..f04221c 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -165,36 +165,39 @@
return displayDevice;
}
-bool DisplayTransactionTest::hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId) {
- return mFlinger.mutableHwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1;
+bool DisplayTransactionTest::hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId) const {
+ return mFlinger.hwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1;
}
-bool DisplayTransactionTest::hasTransactionFlagSet(int flag) {
- return mFlinger.mutableTransactionFlags() & flag;
+bool DisplayTransactionTest::hasTransactionFlagSet(int32_t flag) const {
+ return mFlinger.transactionFlags() & flag;
}
-bool DisplayTransactionTest::hasDisplayDevice(sp<IBinder> displayToken) {
- return mFlinger.mutableDisplays().count(displayToken) == 1;
+bool DisplayTransactionTest::hasDisplayDevice(const sp<IBinder>& displayToken) const {
+ return mFlinger.displays().contains(displayToken);
}
-sp<DisplayDevice> DisplayTransactionTest::getDisplayDevice(sp<IBinder> displayToken) {
- return mFlinger.mutableDisplays()[displayToken];
+const DisplayDevice& DisplayTransactionTest::getDisplayDevice(
+ const sp<IBinder>& displayToken) const {
+ return *mFlinger.displays().get(displayToken)->get();
}
-bool DisplayTransactionTest::hasCurrentDisplayState(sp<IBinder> displayToken) {
- return mFlinger.mutableCurrentState().displays.indexOfKey(displayToken) >= 0;
+bool DisplayTransactionTest::hasCurrentDisplayState(const sp<IBinder>& displayToken) const {
+ return mFlinger.currentState().displays.indexOfKey(displayToken) >= 0;
}
-const DisplayDeviceState& DisplayTransactionTest::getCurrentDisplayState(sp<IBinder> displayToken) {
- return mFlinger.mutableCurrentState().displays.valueFor(displayToken);
+const DisplayDeviceState& DisplayTransactionTest::getCurrentDisplayState(
+ const sp<IBinder>& displayToken) const {
+ return mFlinger.currentState().displays.valueFor(displayToken);
}
-bool DisplayTransactionTest::hasDrawingDisplayState(sp<IBinder> displayToken) {
- return mFlinger.mutableDrawingState().displays.indexOfKey(displayToken) >= 0;
+bool DisplayTransactionTest::hasDrawingDisplayState(const sp<IBinder>& displayToken) const {
+ return mFlinger.drawingState().displays.indexOfKey(displayToken) >= 0;
}
-const DisplayDeviceState& DisplayTransactionTest::getDrawingDisplayState(sp<IBinder> displayToken) {
- return mFlinger.mutableDrawingState().displays.valueFor(displayToken);
+const DisplayDeviceState& DisplayTransactionTest::getDrawingDisplayState(
+ const sp<IBinder>& displayToken) const {
+ return mFlinger.drawingState().displays.valueFor(displayToken);
}
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 565c244..f5235ce 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -95,14 +95,17 @@
// --------------------------------------------------------------------
// Postcondition helpers
- bool hasPhysicalHwcDisplay(hal::HWDisplayId hwcDisplayId);
- bool hasTransactionFlagSet(int flag);
- bool hasDisplayDevice(sp<IBinder> displayToken);
- sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
- bool hasCurrentDisplayState(sp<IBinder> displayToken);
- const DisplayDeviceState& getCurrentDisplayState(sp<IBinder> displayToken);
- bool hasDrawingDisplayState(sp<IBinder> displayToken);
- const DisplayDeviceState& getDrawingDisplayState(sp<IBinder> displayToken);
+ bool hasPhysicalHwcDisplay(hal::HWDisplayId) const;
+ bool hasTransactionFlagSet(int32_t flag) const;
+
+ bool hasDisplayDevice(const sp<IBinder>& displayToken) const;
+ const DisplayDevice& getDisplayDevice(const sp<IBinder>& displayToken) const;
+
+ bool hasCurrentDisplayState(const sp<IBinder>& displayToken) const;
+ const DisplayDeviceState& getCurrentDisplayState(const sp<IBinder>& displayToken) const;
+
+ bool hasDrawingDisplayState(const sp<IBinder>& displayToken) const;
+ const DisplayDeviceState& getDrawingDisplayState(const sp<IBinder>& displayToken) const;
// --------------------------------------------------------------------
// Test instances
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 825f145..b9a5f36 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -337,10 +337,22 @@
ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, ""));
EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+
+ // Privileged APIs.
+ EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+ EXPECT_FALSE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+
+ constexpr bool kPrivileged = true;
EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "",
- /*privileged=*/true));
+ kPrivileged));
+ EXPECT_TRUE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "",
+ kPrivileged));
+ // Invalid frame rate.
EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
@@ -348,15 +360,12 @@
EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
-
- // Invalid compatibility
+ // Invalid compatibility.
EXPECT_FALSE(
ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- // Invalid change frame rate strategy
+ // Invalid change frame rate strategy.
EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, -1, ""));
EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, 2, ""));
}
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 32d57b5..5872a47 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -61,7 +61,6 @@
protected:
void setupScheduler(std::shared_ptr<scheduler::RefreshRateConfigs>);
- void testChangeRefreshRate(bool isDisplayActive, bool isRefreshRequired);
sp<DisplayDevice> mDisplay;
mock::EventThread* mAppEventThread;
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
index 6959ee3..9ac2907 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
@@ -107,9 +107,10 @@
void DisplayTransactionCommitTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
// The display device should have been set up in the list of displays.
ASSERT_TRUE(hasDisplayDevice(displayToken));
- const auto& device = getDisplayDevice(displayToken);
- EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
- EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
+ const auto& display = getDisplayDevice(displayToken);
+
+ EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), display.isSecure());
+ EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), display.isPrimary());
std::optional<DisplayDeviceState::Physical> expectedPhysical;
if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
@@ -143,10 +144,11 @@
// SF should have a display token.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_EQ(mFlinger.mutablePhysicalDisplayTokens().count(displayId), 1);
- auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId];
- verifyDisplayIsConnected<Case>(displayToken);
+ const auto displayTokenOpt = mFlinger.mutablePhysicalDisplayTokens().get(displayId);
+ ASSERT_TRUE(displayTokenOpt);
+
+ verifyDisplayIsConnected<Case>(displayTokenOpt->get());
}
void DisplayTransactionCommitTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
@@ -248,9 +250,9 @@
// SF should not have a display token.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+ ASSERT_FALSE(mFlinger.mutablePhysicalDisplayTokens().contains(displayId));
- // The existing token should have been removed
+ // The existing token should have been removed.
verifyDisplayIsNotConnected(existing.token());
}
@@ -330,7 +332,7 @@
// SF should not have a display token.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+ ASSERT_FALSE(mFlinger.mutablePhysicalDisplayTokens().contains(displayId));
}(),
testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected.");
}
@@ -369,15 +371,16 @@
// --------------------------------------------------------------------
// Postconditions
- // The existing token should have been removed
+ // The existing token should have been removed.
verifyDisplayIsNotConnected(existing.token());
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
- EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]);
- // A new display should be connected in its place
+ const auto displayTokenOpt = mFlinger.mutablePhysicalDisplayTokens().get(displayId);
+ ASSERT_TRUE(displayTokenOpt);
+ EXPECT_NE(existing.token(), displayTokenOpt->get());
+ // A new display should be connected in its place.
verifyPhysicalDisplayIsConnected<Case>();
// --------------------------------------------------------------------
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
new file mode 100644
index 0000000..0a157c4
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "SurfaceFlingerPowerHintTest"
+
+#include <compositionengine/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <algorithm>
+#include <chrono>
+#include <memory>
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockTimeStats.h"
+#include "mock/MockVsyncController.h"
+#include "mock/system/window/MockNativeWindow.h"
+
+using namespace android;
+using namespace android::Hwc2::mock;
+using namespace android::hardware::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+namespace android {
+namespace {
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
+constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
+constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+
+class SurfaceFlingerPowerHintTest : public Test {
+public:
+ void SetUp() override;
+
+ void setupScheduler();
+
+protected:
+ TestableSurfaceFlinger mFlinger;
+ renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+ sp<DisplayDevice> mDisplay;
+ sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
+ new compositionengine::mock::DisplaySurface();
+ mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
+ mock::TimeStats* mTimeStats = new mock::TimeStats();
+ Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr;
+ Hwc2::mock::Composer* mComposer = nullptr;
+};
+
+void SurfaceFlingerPowerHintTest::SetUp() {
+ setupScheduler();
+ mComposer = new Hwc2::mock::Composer();
+ mPowerAdvisor = new Hwc2::mock::PowerAdvisor();
+ mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+ mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+ mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
+ static constexpr bool kIsPrimary = true;
+ FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, kIsPrimary)
+ .setPowerMode(hal::PowerMode::ON)
+ .inject(&mFlinger, mComposer);
+ auto compostionEngineDisplayArgs =
+ compositionengine::DisplayCreationArgsBuilder()
+ .setId(DEFAULT_DISPLAY_ID)
+ .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
+ .setPowerAdvisor(mPowerAdvisor)
+ .setName("injected display")
+ .build();
+ auto compositionDisplay =
+ compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(),
+ std::move(compostionEngineDisplayArgs));
+ mDisplay =
+ FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
+ ui::DisplayConnectionType::Internal, HWC_DISPLAY, kIsPrimary)
+ .setDisplaySurface(mDisplaySurface)
+ .setNativeWindow(mNativeWindow)
+ .setPowerMode(hal::PowerMode::ON)
+ .inject();
+}
+
+void SurfaceFlingerPowerHintTest::setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ auto vsyncController = std::make_unique<mock::VsyncController>();
+ auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
+
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*vsyncTracker, currentPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+
+ mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
+ std::move(eventThread), std::move(sfEventThread),
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
+ TestableSurfaceFlinger::kTwoDisplayModes);
+}
+
+TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) {
+ ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
+
+ const std::chrono::nanoseconds mockVsyncPeriod = 15ms;
+ const std::chrono::nanoseconds expectedTargetTime = 14ms;
+ EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(Gt(expectedTargetTime.count()))).Times(1);
+
+ const nsecs_t now = systemTime();
+ const std::chrono::nanoseconds mockHwcRunTime = 20ms;
+ EXPECT_CALL(*mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc))
+ .Times(1);
+ EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _))
+ .WillOnce([mockHwcRunTime] {
+ std::this_thread::sleep_for(mockHwcRunTime);
+ return hardware::graphics::composer::V2_1::Error::NONE;
+ });
+ EXPECT_CALL(*mPowerAdvisor,
+ sendActualWorkDuration(Gt(mockHwcRunTime.count()),
+ Gt(now + mockHwcRunTime.count())))
+ .Times(1);
+ static constexpr bool kVsyncId = 123; // arbitrary
+ mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 7948e60..583cf5f 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -406,7 +406,7 @@
display.inject();
// The display is set to PowerMode::ON
- getDisplayDevice(display.token())->setPowerMode(PowerMode::ON);
+ display.mutableDisplayDevice()->setPowerMode(PowerMode::ON);
// --------------------------------------------------------------------
// Invocation
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index bf2465f..f1a69fb 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -17,6 +17,7 @@
#pragma once
#include <algorithm>
+#include <chrono>
#include <variant>
#include <compositionengine/Display.h>
@@ -200,6 +201,10 @@
std::make_unique<impl::HWComposer>(std::move(composer)));
}
+ void setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor> powerAdvisor) {
+ mFlinger->mPowerAdvisor = std::move(powerAdvisor);
+ }
+
void setupTimeStats(const std::shared_ptr<TimeStats>& timeStats) {
mFlinger->mCompositionEngine->setTimeStats(timeStats);
}
@@ -328,11 +333,26 @@
/* ------------------------------------------------------------------------
* Forwarding for functions being tested
*/
+
+ nsecs_t commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVSyncTime) {
+ mFlinger->commit(frameTime, vsyncId, expectedVSyncTime);
+ return frameTime;
+ }
+
+ nsecs_t commit(nsecs_t frameTime, int64_t vsyncId) {
+ std::chrono::nanoseconds period = 10ms;
+ return commit(frameTime, vsyncId, frameTime + period.count());
+ }
+
nsecs_t commit() {
const nsecs_t now = systemTime();
const nsecs_t expectedVsyncTime = now + 10'000'000;
- mFlinger->commit(now, kVsyncId, expectedVsyncTime);
- return now;
+ return commit(now, kVsyncId, expectedVsyncTime);
+ }
+
+ void commitAndComposite(const nsecs_t frameTime, const int64_t vsyncId,
+ const nsecs_t expectedVsyncTime) {
+ mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), kVsyncId);
}
void commitAndComposite() { mFlinger->composite(commit(), kVsyncId); }
@@ -458,11 +478,6 @@
mFlinger->onActiveDisplayChangedLocked(activeDisplay);
}
- auto commit(nsecs_t frameTime, int64_t vsyncId) {
- const nsecs_t expectedVsyncTime = frameTime + 10'000'000;
- mFlinger->commit(frameTime, vsyncId, expectedVsyncTime);
- }
-
auto createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
const sp<IBinder>& parentHandle, int32_t* outLayerId,
const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
@@ -502,6 +517,12 @@
* post-conditions.
*/
+ const auto& displays() const { return mFlinger->mDisplays; }
+ const auto& currentState() const { return mFlinger->mCurrentState; }
+ const auto& drawingState() const { return mFlinger->mDrawingState; }
+ const auto& transactionFlags() const { return mFlinger->mTransactionFlags; }
+ const auto& hwcPhysicalDisplayIdMap() const { return getHwComposer().mPhysicalDisplayIdMap; }
+
auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
@@ -515,7 +536,6 @@
auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
- auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; }
@@ -741,7 +761,9 @@
return mFlinger.mutableCurrentState().displays.valueFor(mDisplayToken);
}
- auto& mutableDisplayDevice() { return mFlinger.mutableDisplays()[mDisplayToken]; }
+ const sp<DisplayDevice>& mutableDisplayDevice() {
+ return mFlinger.mutableDisplays().get(mDisplayToken)->get();
+ }
// If `configs` is nullptr, the injector creates RefreshRateConfigs from the `modes`.
// Otherwise, it uses `configs`, which the caller must create using the same `modes`.
@@ -848,12 +870,14 @@
if (!display->isVirtual()) {
display->setActiveMode(activeModeId);
}
- mFlinger.mutableDisplays().emplace(mDisplayToken, display);
+ mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display);
+
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
if (const auto& physical = state.physical) {
- mFlinger.mutablePhysicalDisplayTokens()[physical->id] = mDisplayToken;
+ mFlinger.mutablePhysicalDisplayTokens().emplace_or_replace(physical->id,
+ mDisplayToken);
}
return display;
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 45bc4c9..c4b1487 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -299,6 +299,7 @@
}
void ReleaseSwapchainImage(VkDevice device,
+ bool shared_present,
ANativeWindow* window,
int release_fence,
Swapchain::Image& image,
@@ -330,7 +331,8 @@
}
image.dequeue_fence = -1;
- if (window) {
+ // It's invalid to call cancelBuffer on a shared buffer
+ if (window && !shared_present) {
window->cancelBuffer(window, image.buffer.get(), release_fence);
} else {
if (release_fence >= 0) {
@@ -364,9 +366,10 @@
if (swapchain->surface.swapchain_handle != HandleFromSwapchain(swapchain))
return;
for (uint32_t i = 0; i < swapchain->num_images; i++) {
- if (!swapchain->images[i].dequeued)
- ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i],
- true);
+ if (!swapchain->images[i].dequeued) {
+ ReleaseSwapchainImage(device, swapchain->shared, nullptr, -1,
+ swapchain->images[i], true);
+ }
}
swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
swapchain->timing.clear();
@@ -1084,7 +1087,8 @@
}
for (uint32_t i = 0; i < swapchain->num_images; i++) {
- ReleaseSwapchainImage(device, window, -1, swapchain->images[i], false);
+ ReleaseSwapchainImage(device, swapchain->shared, window, -1,
+ swapchain->images[i], false);
}
if (active) {
@@ -1854,7 +1858,8 @@
WorstPresentResult(swapchain_result, VK_SUBOPTIMAL_KHR);
}
} else {
- ReleaseSwapchainImage(device, nullptr, fence, img, true);
+ ReleaseSwapchainImage(device, swapchain.shared, nullptr, fence,
+ img, true);
swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
}