From 43ab1d665d410ed222552623ef24accd64f17728 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 3 Sep 2021 22:39:10 +0000 Subject: [PATCH 01/17] libbinder: uptimeMillis returns int64_t! am: 3ba4963f5b am: 17aa765fd3 am: d666af6990 Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/15720346 Bug: 197336441 Change-Id: I703760ecbfa007d27caf76556ed21bbf0558df80 (cherry picked from commit 62eaabc3242b5e4ae5da7d39928123fda570f0b2) --- libs/binder/IServiceManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index a9f2d73951..218970a1b2 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -215,7 +215,8 @@ sp ServiceManagerShim::getService(const String16& name) const const bool isVendorService = strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0; - const long timeout = uptimeMillis() + 5000; + const long timeout = 5000; + int64_t startTime = uptimeMillis(); // Vendor code can't access system properties if (!gSystemBootCompleted && !isVendorService) { #ifdef __ANDROID__ @@ -230,7 +231,7 @@ sp ServiceManagerShim::getService(const String16& name) const const long sleepTime = gSystemBootCompleted ? 1000 : 100; int n = 0; - while (uptimeMillis() < timeout) { + while (uptimeMillis() - startTime < timeout) { n++; ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(), ProcessState::self()->getDriverName().c_str()); From d3533d0aa4990c94089a82b40e75e43af43d7b4d Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 1 Nov 2021 18:17:23 -0700 Subject: [PATCH 02/17] avoid extra release of unowned objects in Parcel error path Another bug due to a huge amount of complexity in the Parcel implementation. Bug: 203847542 Test: added testcase fails on device w/o Parcel.cpp fix, and it passes on a device with the fix Merged-In: I34411675687cb3d18bffa082984ebdf308e1c1a6 Change-Id: I34411675687cb3d18bffa082984ebdf308e1c1a6 (cherry picked from commit 04390376b043bf6a15ff2943a9ed63d9d8173842) (cherry picked from commit d668098e4714025b41052207c9332de86dc3936a) Merged-In:I34411675687cb3d18bffa082984ebdf308e1c1a6 --- libs/binder/Parcel.cpp | 8 +++-- libs/binder/tests/binderLibTest.cpp | 45 +++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index b9b0734828..c78f971c94 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -2329,12 +2329,14 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, type == BINDER_TYPE_FD)) { // We should never receive other types (eg BINDER_TYPE_FDA) as long as we don't support // them in libbinder. If we do receive them, it probably means a kernel bug; try to - // recover gracefully by clearing out the objects, and releasing the objects we do - // know about. + // recover gracefully by clearing out the objects. android_errorWriteLog(0x534e4554, "135930648"); + android_errorWriteLog(0x534e4554, "203847542"); ALOGE("%s: unsupported type object (%" PRIu32 ") at offset %" PRIu64 "\n", __func__, type, (uint64_t)offset); - releaseObjects(); + + // WARNING: callers of ipcSetDataReference need to make sure they + // don't rely on mObjectsSize in their release_func. mObjectsSize = 0; break; } diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index c0446d361a..2083ab4e7d 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -85,7 +85,7 @@ enum BinderLibTestTranscationCode { BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, BINDER_LIB_TEST_GETPID, BINDER_LIB_TEST_ECHO_VECTOR, - BINDER_LIB_TEST_REJECT_BUF, + BINDER_LIB_TEST_REJECT_OBJECTS, }; pid_t start_server_process(int arg2, bool usePoll = false) @@ -1137,14 +1137,53 @@ TEST_F(BinderLibTest, BufRejected) { // And now, overwrite it with the buffer object memcpy(parcelData, &obj, sizeof(obj)); data.setDataSize(sizeof(obj)); + EXPECT_EQ(data.objectsCount(), 1); + + status_t ret = server->transact(BINDER_LIB_TEST_REJECT_OBJECTS, data, &reply); - status_t ret = server->transact(BINDER_LIB_TEST_REJECT_BUF, data, &reply); // Either the kernel should reject this transaction (if it's correct), but // if it's not, the server implementation should return an error if it // finds an object in the received Parcel. EXPECT_NE(NO_ERROR, ret); } +TEST_F(BinderLibTest, WeakRejected) { + Parcel data, reply; + sp server = addServer(); + ASSERT_TRUE(server != nullptr); + + sp binder = new BBinder(); + wp wpBinder(binder); + flat_binder_object obj{ + .hdr = {.type = BINDER_TYPE_WEAK_BINDER}, + .flags = 0, + .binder = reinterpret_cast(wpBinder.get_refs()), + .cookie = reinterpret_cast(wpBinder.unsafe_get()), + }; + data.setDataCapacity(1024); + // Write a bogus object at offset 0 to get an entry in the offset table + data.writeFileDescriptor(0); + EXPECT_EQ(data.objectsCount(), 1); + uint8_t *parcelData = const_cast(data.data()); + // And now, overwrite it with the weak binder + memcpy(parcelData, &obj, sizeof(obj)); + data.setDataSize(sizeof(obj)); + + // a previous bug caused other objects to be released an extra time, so we + // test with an object that libbinder will actually try to release + EXPECT_EQ(OK, data.writeStrongBinder(new BBinder())); + + EXPECT_EQ(data.objectsCount(), 2); + + // send it many times, since previous error was memory corruption, make it + // more likely that the server crashes + for (size_t i = 0; i < 100; i++) { + EXPECT_EQ(BAD_VALUE, server->transact(BINDER_LIB_TEST_REJECT_OBJECTS, data, &reply)); + } + + EXPECT_EQ(NO_ERROR, server->pingBinder()); +} + class BinderLibTestService : public BBinder { public: @@ -1443,7 +1482,7 @@ class BinderLibTestService : public BBinder reply->writeUint64Vector(vector); return NO_ERROR; } - case BINDER_LIB_TEST_REJECT_BUF: { + case BINDER_LIB_TEST_REJECT_OBJECTS: { return data.objectsCount() == 0 ? BAD_VALUE : NO_ERROR; } default: From d48a576a81785541ab9e66a7cda737401336e479 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 9 Dec 2020 08:07:46 -1000 Subject: [PATCH 03/17] Check if the window is partially obscured for slippery enters Currently, we only check whether a window is partially obscured during the initial tap down. However, there is another use case: slippery enter. During a slippery enter, the touch down is generated into the slipped-into window, and touch cancel is generated for the slipped-from window. The window receiving the slippery enter does not need to have any flags. Until we figure out whether we can restrict the usage of this flag to system components, add this check as an intermediate fix. Bug: 157929241 Test: atest FlagSlipperyTest Test: atest inputflinger_tests Change-Id: I93d9681479f41244ffed4b1f88cceb69be71adf2 Merged-In: I93d9681479f41244ffed4b1f88cceb69be71adf2 (cherry picked from commit d8c6ef21387db53930d728272db24cca1cd38a38) Merged-In:I93d9681479f41244ffed4b1f88cceb69be71adf2 --- .../dispatcher/InputDispatcher.cpp | 2 + .../tests/InputDispatcher_test.cpp | 205 ++++++++++++------ 2 files changed, 145 insertions(+), 62 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 4cd4781518..49cf973383 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1811,6 +1811,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; + } else if (isWindowObscuredLocked(newTouchedWindowHandle)) { + targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } BitSet32 pointerIds; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 668a7ab421..9c100d2a3e 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -19,10 +19,10 @@ #include #include #include -#include - #include +#include #include + #include #include #include @@ -68,12 +68,10 @@ class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { InputDispatcherConfiguration mConfig; protected: - virtual ~FakeInputDispatcherPolicy() { - } + virtual ~FakeInputDispatcherPolicy() {} public: - FakeInputDispatcherPolicy() { - } + FakeInputDispatcherPolicy() {} void assertFilterInputEventWasCalled(const NotifyKeyArgs& args) { assertFilterInputEventWasCalled(AINPUT_EVENT_TYPE_KEY, args.eventTime, args.action, @@ -367,7 +365,7 @@ class InputDispatcherTest : public testing::Test { mFakePolicy = new FakeInputDispatcherPolicy(); mDispatcher = new InputDispatcher(mFakePolicy); mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); - //Start InputDispatcher thread + // Start InputDispatcher thread ASSERT_EQ(OK, mDispatcher->start()); } @@ -392,7 +390,6 @@ class InputDispatcherTest : public testing::Test { } }; - TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { KeyEvent event; @@ -590,9 +587,7 @@ class FakeApplicationHandle : public InputApplicationHandle { } virtual ~FakeApplicationHandle() {} - virtual bool updateInfo() override { - return true; - } + virtual bool updateInfo() override { return true; } void setDispatchingTimeout(std::chrono::nanoseconds timeout) { mInfo.dispatchingTimeout = timeout.count(); @@ -823,39 +818,40 @@ class FakeWindowHandle : public InputWindowHandle { } void consumeMotionCancel(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, - int32_t expectedFlags = 0) { + int32_t expectedFlags = 0) { consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, expectedDisplayId, expectedFlags); } void consumeMotionMove(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, - int32_t expectedFlags = 0) { + int32_t expectedFlags = 0) { consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_MOVE, expectedDisplayId, expectedFlags); } void consumeMotionDown(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, - int32_t expectedFlags = 0) { + int32_t expectedFlags = 0) { consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN, expectedDisplayId, expectedFlags); } void consumeMotionPointerDown(int32_t pointerIdx, - int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { - int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN - | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, + int32_t expectedFlags = 0) { + int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | + (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); } void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, - int32_t expectedFlags = 0) { - int32_t action = AMOTION_EVENT_ACTION_POINTER_UP - | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + int32_t expectedFlags = 0) { + int32_t action = AMOTION_EVENT_ACTION_POINTER_UP | + (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); } void consumeMotionUp(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, - int32_t expectedFlags = 0) { + int32_t expectedFlags = 0) { consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_UP, expectedDisplayId, expectedFlags); } @@ -903,6 +899,11 @@ class FakeWindowHandle : public InputWindowHandle { const std::string& getName() { return mName; } + void setOwnerInfo(int32_t ownerPid, int32_t ownerUid) { + mInfo.ownerPid = ownerPid; + mInfo.ownerUid = ownerUid; + } + private: const std::string mName; std::unique_ptr mInputReceiver; @@ -1262,17 +1263,18 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { sp application = new FakeApplicationHandle(); // Create a couple of windows - sp firstWindow = new FakeWindowHandle(application, mDispatcher, - "First Window", ADISPLAY_ID_DEFAULT); - sp secondWindow = new FakeWindowHandle(application, mDispatcher, - "Second Window", ADISPLAY_ID_DEFAULT); + sp firstWindow = + new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + sp secondWindow = + new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); // Send down to the first window - NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); + NotifyMotionArgs downMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&downMotionArgs); // Only the first window should get the down event firstWindow->consumeMotionDown(); @@ -1285,8 +1287,9 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { secondWindow->consumeMotionDown(); // Send up event to the second window - NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); + 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 gets up firstWindow->assertNoEvents(); @@ -1299,26 +1302,29 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { PointF touchPoint = {10, 10}; // Create a couple of windows - sp firstWindow = new FakeWindowHandle(application, mDispatcher, - "First Window", ADISPLAY_ID_DEFAULT); - sp secondWindow = new FakeWindowHandle(application, mDispatcher, - "Second Window", ADISPLAY_ID_DEFAULT); + sp firstWindow = + new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + sp secondWindow = + new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); // Send down to the first window - NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint}); + NotifyMotionArgs downMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {touchPoint}); mDispatcher->notifyMotion(&downMotionArgs); // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Send pointer down to the first window - NotifyMotionArgs pointerDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN - | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); + NotifyMotionArgs pointerDownMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {touchPoint, touchPoint}); mDispatcher->notifyMotion(&pointerDownMotionArgs); // Only the first window should get the pointer down event firstWindow->consumeMotionPointerDown(1); @@ -1332,17 +1338,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { secondWindow->consumeMotionPointerDown(1); // Send pointer up to the second window - NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP - | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); + NotifyMotionArgs pointerUpMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {touchPoint, touchPoint}); mDispatcher->notifyMotion(&pointerUpMotionArgs); // The first window gets nothing and the second gets pointer up firstWindow->assertNoEvents(); secondWindow->consumeMotionPointerUp(1); // Send up event to the second window - NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); + NotifyMotionArgs upMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets nothing and the second gets up firstWindow->assertNoEvents(); @@ -1353,15 +1362,15 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { sp application = new FakeApplicationHandle(); // Create a non touch modal window that supports split touch - sp firstWindow = new FakeWindowHandle(application, mDispatcher, - "First Window", ADISPLAY_ID_DEFAULT); + sp firstWindow = + new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); firstWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | InputWindowInfo::FLAG_SPLIT_TOUCH); // Create a non touch modal window that supports split touch - sp secondWindow = new FakeWindowHandle(application, mDispatcher, - "Second Window", ADISPLAY_ID_DEFAULT); + sp secondWindow = + new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); secondWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | InputWindowInfo::FLAG_SPLIT_TOUCH); @@ -1373,17 +1382,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { PointF pointInSecond = {300, 600}; // Send down to the first window - NotifyMotionArgs firstDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst}); + NotifyMotionArgs firstDownMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {pointInFirst}); mDispatcher->notifyMotion(&firstDownMotionArgs); // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Send down to the second window - NotifyMotionArgs secondDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN - | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); + NotifyMotionArgs secondDownMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&secondDownMotionArgs); // The first window gets a move and the second a down firstWindow->consumeMotionMove(); @@ -1396,17 +1408,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { secondWindow->consumeMotionPointerDown(1); // Send pointer up to the second window - NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP - | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); + NotifyMotionArgs pointerUpMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&pointerUpMotionArgs); // The first window gets nothing and the second gets pointer up firstWindow->assertNoEvents(); secondWindow->consumeMotionPointerUp(1); // Send up event to the second window - NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); + NotifyMotionArgs upMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets nothing and the second gets up firstWindow->assertNoEvents(); @@ -1723,6 +1738,72 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); } +/** + * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY, + * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top + * of the 'slipperyEnterWindow'. + * + * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such + * a way so that the touched location is no longer covered by the top window. + * + * Next, inject a MOVE event. Because the top window already moved earlier, this event is now + * positioned over the bottom (slipperyEnterWindow) only. And because the top window had + * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive + * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting + * with ACTION_DOWN). + * Thus, the touch has been transferred from the top window into the bottom window, because the top + * window moved itself away from the touched location and had Flag::SLIPPERY. + * + * Even though the top window moved away from the touched location, it is still obscuring the bottom + * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_ + * OBSCURED should be set for the MotionEvent that reaches the bottom window. + * + * In this test, we ensure that the event received by the bottom window has + * FLAG_WINDOW_IS_PARTIALLY_OBSCURED. + */ +TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { + constexpr int32_t SLIPPERY_PID = INJECTOR_PID + 1; + constexpr int32_t SLIPPERY_UID = INJECTOR_UID + 1; + + sp application = new FakeApplicationHandle(); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + + sp slipperyExitWindow = + new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + slipperyExitWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | + InputWindowInfo::FLAG_SLIPPERY); + // Make sure this one overlaps the bottom window + slipperyExitWindow->setFrame(Rect(25, 25, 75, 75)); + // Change the owner uid/pid of the window so that it is considered to be occluding the bottom + // one. Windows with the same owner are not considered to be occluding each other. + slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID); + + sp slipperyEnterWindow = + new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); + slipperyExitWindow->setFrame(Rect(0, 0, 100, 100)); + + mDispatcher->setInputWindows( + {{ADISPLAY_ID_DEFAULT, {slipperyExitWindow, slipperyEnterWindow}}}); + + // Use notifyMotion instead of injecting to avoid dealing with injection permissions + NotifyMotionArgs args = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {{50, 50}}); + mDispatcher->notifyMotion(&args); + slipperyExitWindow->consumeMotionDown(); + slipperyExitWindow->setFrame(Rect(70, 70, 100, 100)); + mDispatcher->setInputWindows( + {{ADISPLAY_ID_DEFAULT, {slipperyExitWindow, slipperyEnterWindow}}}); + + args = generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {{51, 51}}); + mDispatcher->notifyMotion(&args); + + slipperyExitWindow->consumeMotionCancel(); + + slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, + AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED); +} + class InputDispatcherKeyRepeatTest : public InputDispatcherTest { protected: static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms @@ -1951,7 +2032,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { // Test per-display input monitors for key event. TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) { - //Input monitor per display. + // Input monitor per display. FakeMonitorReceiver monitorInPrimary = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); FakeMonitorReceiver monitorInSecondary = @@ -1973,11 +2054,11 @@ class InputFilterTest : public InputDispatcherTest { void testNotifyMotion(int32_t displayId, bool expectToBeFiltered) { NotifyMotionArgs motionArgs; - motionArgs = generateMotionArgs( - AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId); + motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId); mDispatcher->notifyMotion(&motionArgs); - motionArgs = generateMotionArgs( - AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId); + motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId); mDispatcher->notifyMotion(&motionArgs); ASSERT_TRUE(mDispatcher->waitForIdle()); if (expectToBeFiltered) { From 2a9cd7ec0928be0cf5d4bbad08bb536d2d51150f Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 6 Jun 2022 15:16:06 -0700 Subject: [PATCH 04/17] RESTRICT AUTOMERGE SurfaceFlinger: fix a potential race condition in stealReceiveChannel Add a mutex to prevent a potential race condition. Bug: 232541124 Test: See bug for details Change-Id: Ia338f124c786bf12d6adba10a67b9048fe9c34a5 (cherry picked from commit a820057ae00dba322b10d47b3711b04519324690) Merged-In: Ia338f124c786bf12d6adba10a67b9048fe9c34a5 --- services/surfaceflinger/Scheduler/EventThread.cpp | 5 +++++ services/surfaceflinger/Scheduler/EventThread.h | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 576a2ff8b9..afd25890ce 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -139,6 +139,11 @@ void EventThreadConnection::onFirstRef() { } status_t EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) { + std::scoped_lock lock(mLock); + if (mChannel.initCheck() != NO_ERROR) { + return NAME_NOT_FOUND; + } + outChannel->setReceiveFd(mChannel.moveReceiveFd()); outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd()))); return NO_ERROR; diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 49f624c35e..df7fb7dedd 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -92,7 +92,8 @@ class EventThreadConnection : public BnDisplayEventConnection { private: virtual void onFirstRef(); EventThread* const mEventThread; - gui::BitTube mChannel; + std::mutex mLock; + gui::BitTube mChannel GUARDED_BY(mLock); }; class EventThread { From aeecd73145f93d491529d8baf4920e5decad4807 Mon Sep 17 00:00:00 2001 From: Meghthedev Date: Fri, 19 May 2023 21:59:42 +0530 Subject: [PATCH 05/17] Blur: declare PRODUCT_SHIPPING_API_LEVEL * Retrieve and store PRODUCT_SHIPPING_API_LEVEL using property_get_int32 This fixes error: frameworks/native/libs/renderengine/gl/filters/BlurFilter.cpp:40:44: error: use of undeclared identifier 'PRODUCT_SHIPPING_API_LEVEL' ALOGI("PRODUCT_SHIPPING_API_LEVEL=%d", PRODUCT_SHIPPING_API_LEVEL); 1 error generated. --- libs/renderengine/gl/filters/BlurFilter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index 0a7ac309e7..602c5577a1 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -23,7 +23,7 @@ #include #include #include - +#include #include namespace android { @@ -37,6 +37,7 @@ BlurFilter::BlurFilter(GLESRenderEngine& engine) mPongFbo(engine), mMixProgram(engine), mBlurProgram(engine) { + static int PRODUCT_SHIPPING_API_LEVEL = property_get_int32("ro.build.version.sdk", 0); ALOGI("PRODUCT_SHIPPING_API_LEVEL=%d", PRODUCT_SHIPPING_API_LEVEL); mMixProgram.compile(getVertexShader(), getMixFragShader()); mMPosLoc = mMixProgram.getAttributeLocation("aPosition"); From 35de072c5e4f0fd5f4f5766bbc59962ef5cb83ea Mon Sep 17 00:00:00 2001 From: Chris Ye Date: Sun, 10 May 2020 15:16:04 -0700 Subject: [PATCH 06/17] Change InputWindowInfo::isTrustedOverlay() to be permission and flag based. Add private flag to WindowManager.LayoutParams. If the flag is set, check if caller has INTERNAL_SYSTEM_WINDOW permission. Bug: 155781676 Bug: 196389741 Test: atest WindowManagerServiceTests Change-Id: I58cf9f38c496e0ae8b2193dca45c0805e831bc9e Merged-In: I58cf9f38c496e0ae8b2193dca45c0805e831bc9e (cherry picked from commit 39bc6117dda8cf5f6f43846f18fc0fed87692efa) Merged-In: I58cf9f38c496e0ae8b2193dca45c0805e831bc9e --- include/input/InputWindow.h | 16 ++++++++-------- libs/input/InputWindow.cpp | 16 ++-------------- .../inputflinger/dispatcher/InputDispatcher.cpp | 2 +- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index 2dac5b62a7..271fdb3a2f 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -108,7 +108,6 @@ struct InputWindowInfo { TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32, TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34, TYPE_NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40, - TYPE_TRUSTED_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 42, LAST_SYSTEM_WINDOW = 2999, }; @@ -163,6 +162,12 @@ struct InputWindowInfo { bool hasFocus = false; bool hasWallpaper = false; bool paused = false; + /* This flag is set when the window is of a trusted type that is allowed to silently + * overlay other windows for the purpose of implementing the secure views feature. + * Trusted overlays, such as IME windows, can partly obscure other windows without causing + * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. + */ + bool trustedOverlay = false; int32_t ownerPid = -1; int32_t ownerUid = -1; int32_t inputFeatures = 0; @@ -175,20 +180,15 @@ struct InputWindowInfo { void addTouchableRegion(const Rect& region); bool touchableRegionContainsPoint(int32_t x, int32_t y) const; - bool frameContainsPoint(int32_t x, int32_t y) const; - /* Returns true if the window is of a trusted type that is allowed to silently - * overlay other windows for the purpose of implementing the secure views feature. - * Trusted overlays, such as IME windows, can partly obscure other windows without causing - * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - */ - bool isTrustedOverlay() const; + bool frameContainsPoint(int32_t x, int32_t y) const; bool supportsSplitTouch() const; bool overlaps(const InputWindowInfo* other) const; status_t write(Parcel& output) const; + static InputWindowInfo read(const Parcel& from); }; diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index 85a2015e43..301c3f56f2 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -42,20 +42,6 @@ bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { && y >= frameTop && y < frameBottom; } -// TODO(b/155781676): Remove and replace call points with trustedOverlay when that is ready. -bool InputWindowInfo::isTrustedOverlay() const { - return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG || - layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_STATUS_BAR || - layoutParamsType == TYPE_NOTIFICATION_SHADE || - layoutParamsType == TYPE_NAVIGATION_BAR || - layoutParamsType == TYPE_NAVIGATION_BAR_PANEL || - layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY || - layoutParamsType == TYPE_DOCK_DIVIDER || - layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY || - layoutParamsType == TYPE_INPUT_CONSUMER || - layoutParamsType == TYPE_TRUSTED_APPLICATION_OVERLAY; -} - bool InputWindowInfo::supportsSplitTouch() const { return layoutParamsFlags & FLAG_SPLIT_TOUCH; } @@ -92,6 +78,7 @@ status_t InputWindowInfo::write(Parcel& output) const { output.writeBool(hasFocus); output.writeBool(hasWallpaper); output.writeBool(paused); + output.writeBool(trustedOverlay); output.writeInt32(ownerPid); output.writeInt32(ownerUid); output.writeInt32(inputFeatures); @@ -130,6 +117,7 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { ret.hasFocus = from.readBool(); ret.hasWallpaper = from.readBool(); ret.paused = from.readBool(); + ret.trustedOverlay = from.readBool(); ret.ownerPid = from.readInt32(); ret.ownerUid = from.readInt32(); ret.inputFeatures = from.readInt32(); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 49cf973383..ece151f812 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2123,7 +2123,7 @@ static bool canBeObscuredBy(const sp& windowHandle, // If ownerPid is the same we don't generate occlusion events as there // is no in-process security boundary. return false; - } else if (otherInfo->isTrustedOverlay()) { + } else if (otherInfo->trustedOverlay) { return false; } else if (otherInfo->displayId != info->displayId) { return false; From f2e559dbd08233370239993a6f43a87d0a070683 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 29 Jun 2021 15:42:56 -0700 Subject: [PATCH 07/17] Add mechanism for a task's windows to be trusted overlays (SF) - Add a layer state to indicate that this layer and its children in the hierarchy are trusted. This can only be set by callers holding ACCESS_SURFACE_FLINGER, and will be used for the PIP task layer to indicate that activities in PIP are trusted (as they are controlled only by the user and SystemUI) Bug: 191529039 Bug: 196389741 Test: TBD Change-Id: Id92ccb087bd0d8dbaeeef3ba50b67fe015e53db8 Merged-In: Id92ccb087bd0d8dbaeeef3ba50b67fe015e53db8 (cherry picked from commit 7605fb4273cfdf922a041f201dbcc1e10fae1fe2) Merged-In: Id92ccb087bd0d8dbaeeef3ba50b67fe015e53db8 --- cmds/surfacereplayer/proto/src/trace.proto | 5 ++++ libs/gui/LayerState.cpp | 8 ++++++ libs/gui/SurfaceComposerClient.cpp | 13 ++++++++++ libs/gui/include/gui/LayerState.h | 8 +++++- libs/gui/include/gui/SurfaceComposerClient.h | 3 +++ services/surfaceflinger/Layer.cpp | 22 ++++++++++++++++ services/surfaceflinger/Layer.h | 5 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 9 +++++++ .../surfaceflinger/SurfaceInterceptor.cpp | 11 ++++++++ services/surfaceflinger/SurfaceInterceptor.h | 1 + .../layerproto/LayerProtoParser.cpp | 2 ++ .../include/layerproto/LayerProtoParser.h | 1 + .../surfaceflinger/layerproto/layers.proto | 2 ++ .../tests/SurfaceInterceptor_test.cpp | 26 +++++++++++++++++++ 14 files changed, 115 insertions(+), 1 deletion(-) diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto index b57409867f..372cecd63c 100644 --- a/cmds/surfacereplayer/proto/src/trace.proto +++ b/cmds/surfacereplayer/proto/src/trace.proto @@ -53,6 +53,7 @@ message SurfaceChange { ReparentChildrenChange reparent_children = 20; BackgroundBlurRadiusChange background_blur_radius = 21; ShadowRadiusChange shadow_radius = 22; + TrustedOverlayChange trusted_overlay = 23; } } @@ -208,4 +209,8 @@ message DetachChildrenChange { message ShadowRadiusChange { required float radius = 1; +} + +message TrustedOverlayChange { + required float is_trusted_overlay = 1; } \ No newline at end of file diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index e43446ac8c..a897d1025f 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -117,6 +117,8 @@ status_t layer_state_t::write(Parcel& output) const output.writeFloat(frameRate); output.writeByte(frameRateCompatibility); output.writeUint32(fixedTransformHint); + output.writeBool(isTrustedOverlay); + return NO_ERROR; } @@ -200,6 +202,8 @@ status_t layer_state_t::read(const Parcel& input) frameRate = input.readFloat(); frameRateCompatibility = input.readByte(); fixedTransformHint = static_cast(input.readUint32()); + isTrustedOverlay = input.readBool(); + return NO_ERROR; } @@ -439,6 +443,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFixedTransformHintChanged; fixedTransformHint = other.fixedTransformHint; } + if (other.what & eTrustedOverlayChanged) { + what |= eTrustedOverlayChanged; + isTrustedOverlay = other.isTrustedOverlay; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIu64 " what=0x%" PRIu64, diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 83bc06997a..78d932cc81 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1484,6 +1484,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixed return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrustedOverlay( + const sp& sc, bool isTrustedOverlay) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eTrustedOverlayChanged; + s->isTrustedOverlay = isTrustedOverlay; + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index e60f6777ae..a77e4b0462 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -105,6 +105,7 @@ struct layer_state_t { eBackgroundBlurRadiusChanged = 0x80'00000000, eProducerDisconnect = 0x100'00000000, eFixedTransformHintChanged = 0x200'00000000, + eTrustedOverlayChanged = 0x400'00000000, }; layer_state_t() @@ -139,7 +140,8 @@ struct layer_state_t { frameRateSelectionPriority(-1), frameRate(0.0f), frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), - fixedTransformHint(ui::Transform::ROT_INVALID) { + fixedTransformHint(ui::Transform::ROT_INVALID), + isTrustedOverlay(false) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -237,6 +239,10 @@ struct layer_state_t { // a buffer of a different size. -1 means the transform hint is not set, // otherwise the value will be a valid ui::Rotation. ui::Transform::RotationFlags fixedTransformHint; + + // An inherited state that indicates that this surface control and its children + // should be trusted for input occlusion detection purposes + bool isTrustedOverlay; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index adcb8982a0..eebd9ca774 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -529,6 +529,9 @@ class SurfaceComposerClient : public RefBase // a buffer of a different size. Transaction& setFixedTransformHint(const sp& sc, int32_t transformHint); + // Sets that this surface control and its children are trusted overlays for input + Transaction& setTrustedOverlay(const sp& sc, bool isTrustedOverlay); + status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b49234555f..1367629ed3 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1147,6 +1147,23 @@ bool Layer::setRelativeLayer(const sp& relativeToHandle, int32_t relati return true; } +bool Layer::setTrustedOverlay(bool isTrustedOverlay) { + if (mCurrentState.isTrustedOverlay == isTrustedOverlay) return false; + mCurrentState.isTrustedOverlay = isTrustedOverlay; + mCurrentState.modified = true; + mCurrentState.inputInfoChanged = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::isTrustedOverlay() const { + if (getDrawingState().isTrustedOverlay) { + return true; + } + const auto& p = mDrawingParent.promote(); + return (p != nullptr) && p->isTrustedOverlay(); +} + bool Layer::setSize(uint32_t w, uint32_t h) { if (mCurrentState.requested_legacy.w == w && mCurrentState.requested_legacy.h == h) return false; @@ -2250,6 +2267,7 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); layerInfo->set_corner_radius(getRoundedCornerState().radius); + layerInfo->set_is_trusted_overlay(isTrustedOverlay()); LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform()); LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), [&]() { return layerInfo->mutable_position(); }); @@ -2454,6 +2472,10 @@ InputWindowInfo Layer::fillInputInfo() { info.touchableRegion = info.touchableRegion.intersect(Rect{cropLayer->mScreenBounds}); } + // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state + // if it was set by WM for a known system overlay + info.trustedOverlay = info.trustedOverlay || isTrustedOverlay(); + // If the layer is a clone, we need to crop the input region to cloned root to prevent // touches from going outside the cloned area. if (isClone()) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index baed961f04..518cb5f349 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -280,6 +280,9 @@ class Layer : public virtual RefBase, compositionengine::LayerFE { // a buffer of a different size. ui::Transform::ROT_INVALID means the // a fixed transform hint is not set. ui::Transform::RotationFlags fixedTransformHint; + + // Whether or not this layer is a trusted overlay for input + bool isTrustedOverlay; }; explicit Layer(const LayerCreationArgs& args); @@ -357,6 +360,7 @@ class Layer : public virtual RefBase, compositionengine::LayerFE { // is specified in pixels. virtual bool setBackgroundBlurRadius(int backgroundBlurRadius); virtual bool setTransparentRegionHint(const Region& transparent); + virtual bool setTrustedOverlay(bool); virtual bool setFlags(uint8_t flags, uint8_t mask); virtual bool setLayerStack(uint32_t layerStack); virtual uint32_t getLayerStack() const; @@ -1101,6 +1105,7 @@ class Layer : public virtual RefBase, compositionengine::LayerFE { const std::vector& layersInTree); void updateTreeHasFrameRateVote(); + bool isTrustedOverlay() const; // Cached properties computed from drawing state // Effective transform taking into account parent transforms and any parent scaling. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d1be410787..b062f87028 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3904,6 +3904,15 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded | eTransformHintUpdateNeeded; } } + if (what & layer_state_t::eTrustedOverlayChanged) { + if (privileged) { + if (layer->setTrustedOverlay(s.isTrustedOverlay)) { + flags |= eTraversalNeeded; + } + } else { + ALOGE("Attempt to set trusted overlay without permission ACCESS_SURFACE_FLINGER"); + } + } // This has to happen after we reparent children because when we reparent to null we remove // child layers from current state and remove its relative z. If the children are reparented in // the same transaction, then we have to make sure we reparent the children first so we do not diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 80102bdbb6..0555acff43 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -130,6 +130,7 @@ void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment, getLayerIdFromWeakRef(layer->mCurrentState.zOrderRelativeOf), layer->mCurrentState.z); addShadowRadiusLocked(transaction, layerId, layer->mCurrentState.shadowRadius); + addTrustedOverlayLocked(transaction, layerId, layer->mDrawingState.isTrustedOverlay); } void SurfaceInterceptor::addInitialDisplayStateLocked(Increment* increment, @@ -388,6 +389,13 @@ void SurfaceInterceptor::addShadowRadiusLocked(Transaction* transaction, int32_t overrideChange->set_radius(shadowRadius); } +void SurfaceInterceptor::addTrustedOverlayLocked(Transaction* transaction, int32_t layerId, + bool isTrustedOverlay) { + SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); + TrustedOverlayChange* overrideChange(change->mutable_trusted_overlay()); + overrideChange->set_is_trusted_overlay(isTrustedOverlay); +} + void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state) { @@ -467,6 +475,9 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, if (state.what & layer_state_t::eShadowRadiusChanged) { addShadowRadiusLocked(transaction, layerId, state.shadowRadius); } + if (state.what & layer_state_t::eTrustedOverlayChanged) { + addTrustedOverlayLocked(transaction, layerId, state.isTrustedOverlay); + } } void SurfaceInterceptor::addDisplayChangesLocked(Transaction* transaction, diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index 896bdcc259..6b98b44420 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -168,6 +168,7 @@ class SurfaceInterceptor final : public android::SurfaceInterceptor { void addRelativeParentLocked(Transaction* transaction, int32_t layerId, int32_t parentId, int z); void addShadowRadiusLocked(Transaction* transaction, int32_t layerId, float shadowRadius); + void addTrustedOverlayLocked(Transaction* transaction, int32_t layerId, bool isTrustedOverlay); // Add display transactions to the trace DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t sequenceId); diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp index 8fce0c9bf3..2eceba848d 100644 --- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp +++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp @@ -105,6 +105,7 @@ LayerProtoParser::Layer LayerProtoParser::generateLayer(const LayerProto& layerP layer.queuedFrames = layerProto.queued_frames(); layer.refreshPending = layerProto.refresh_pending(); layer.isProtected = layerProto.is_protected(); + layer.isTrustedOverlay = layerProto.is_trusted_overlay(); layer.cornerRadius = layerProto.corner_radius(); layer.backgroundBlurRadius = layerProto.background_blur_radius(); for (const auto& entry : layerProto.metadata()) { @@ -288,6 +289,7 @@ std::string LayerProtoParser::Layer::to_string() const { StringAppendF(&result, "crop=%s, ", crop.to_string().c_str()); StringAppendF(&result, "cornerRadius=%f, ", cornerRadius); StringAppendF(&result, "isProtected=%1d, ", isProtected); + StringAppendF(&result, "isTrustedOverlay=%1d, ", isTrustedOverlay); StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate); StringAppendF(&result, "dataspace=%s, ", dataspace.c_str()); StringAppendF(&result, "defaultPixelFormat=%s, ", pixelFormat.c_str()); diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h index 52b916555f..67bbd76934 100644 --- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h +++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h @@ -109,6 +109,7 @@ class LayerProtoParser { int32_t queuedFrames; bool refreshPending; bool isProtected; + bool isTrustedOverlay; float cornerRadius; int backgroundBlurRadius; LayerMetadata metadata; diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto index 7f1f542e4b..780b066000 100644 --- a/services/surfaceflinger/layerproto/layers.proto +++ b/services/surfaceflinger/layerproto/layers.proto @@ -123,6 +123,8 @@ message LayerProto { bool is_relative_of = 51; // Layer's background blur radius in pixels. int32 background_blur_radius = 52; + + bool is_trusted_overlay = 53; } message PositionProto { diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 8d97f275ba..5bafbd8975 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -195,6 +195,7 @@ class SurfaceInterceptorTest : public ::testing::Test { bool detachChildrenUpdateFound(const SurfaceChange& change, bool found); bool reparentChildrenUpdateFound(const SurfaceChange& change, bool found); bool shadowRadiusUpdateFound(const SurfaceChange& change, bool found); + bool trustedOverlayUpdateFound(const SurfaceChange& change, bool found); bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase); // Find all of the updates in the single trace @@ -233,6 +234,7 @@ class SurfaceInterceptorTest : public ::testing::Test { void detachChildrenUpdate(Transaction&); void reparentChildrenUpdate(Transaction&); void shadowRadiusUpdate(Transaction&); + void trustedOverlayUpdate(Transaction&); void surfaceCreation(Transaction&); void displayCreation(Transaction&); void displayDeletion(Transaction&); @@ -421,6 +423,10 @@ void SurfaceInterceptorTest::shadowRadiusUpdate(Transaction& t) { t.setShadowRadius(mBGSurfaceControl, SHADOW_RADIUS_UPDATE); } +void SurfaceInterceptorTest::trustedOverlayUpdate(Transaction& t) { + t.setTrustedOverlay(mBGSurfaceControl, true); +} + void SurfaceInterceptorTest::displayCreation(Transaction&) { sp testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true); SurfaceComposerClient::destroyDisplay(testDisplay); @@ -452,6 +458,7 @@ void SurfaceInterceptorTest::runAllUpdates() { runInTransaction(&SurfaceInterceptorTest::detachChildrenUpdate); runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate); runInTransaction(&SurfaceInterceptorTest::shadowRadiusUpdate); + runInTransaction(&SurfaceInterceptorTest::trustedOverlayUpdate); } void SurfaceInterceptorTest::surfaceCreation(Transaction&) { @@ -695,6 +702,17 @@ bool SurfaceInterceptorTest::shadowRadiusUpdateFound(const SurfaceChange& change return foundShadowRadius; } +bool SurfaceInterceptorTest::trustedOverlayUpdateFound(const SurfaceChange& change, + bool foundTrustedOverlay) { + bool hasTrustedOverlay(change.trusted_overlay().is_trusted_overlay()); + if (hasTrustedOverlay && !foundTrustedOverlay) { + foundTrustedOverlay = true; + } else if (hasTrustedOverlay && foundTrustedOverlay) { + []() { FAIL(); }(); + } + return foundTrustedOverlay; +} + bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase) { bool foundUpdate = false; @@ -764,6 +782,9 @@ bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace, case SurfaceChange::SurfaceChangeCase::kShadowRadius: foundUpdate = shadowRadiusUpdateFound(change, foundUpdate); break; + case SurfaceChange::SurfaceChangeCase::kTrustedOverlay: + foundUpdate = trustedOverlayUpdateFound(change, foundUpdate); + break; case SurfaceChange::SurfaceChangeCase::SURFACECHANGE_NOT_SET: break; } @@ -976,6 +997,11 @@ TEST_F(SurfaceInterceptorTest, InterceptShadowRadiusUpdateWorks) { SurfaceChange::SurfaceChangeCase::kShadowRadius); } +TEST_F(SurfaceInterceptorTest, InterceptTrustedOverlayUpdateWorks) { + captureTest(&SurfaceInterceptorTest::trustedOverlayUpdate, + SurfaceChange::SurfaceChangeCase::kTrustedOverlay); +} + TEST_F(SurfaceInterceptorTest, InterceptAllUpdatesWorks) { captureTest(&SurfaceInterceptorTest::runAllUpdates, &SurfaceInterceptorTest::assertAllUpdatesFound); From 703807bda762294778c71863d1238a704ee3b0f4 Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Fri, 10 Sep 2021 12:03:42 +0000 Subject: [PATCH 08/17] DO NOT MERGE Initialize DrawingState::trustedOverlay to false in constructor To avoid it being initialised to true randomly. Bug: 199483370 Bug: 196389741 Change-Id: I75be2b1d305e22f8a71532b9f5b8ea6c469baaaa Merged-In: I75be2b1d305e22f8a71532b9f5b8ea6c469baaaa (cherry picked from commit 41f48c7b10132c94822ab109de99978ee65cc743) Merged-In: I75be2b1d305e22f8a71532b9f5b8ea6c469baaaa --- services/surfaceflinger/Layer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 1367629ed3..953483af38 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -118,6 +118,7 @@ Layer::Layer(const LayerCreationArgs& args) mCurrentState.shadowRadius = 0.f; mCurrentState.treeHasFrameRateVote = false; mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID; + mCurrentState.isTrustedOverlay = false; if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. From 79c976241582c3dbd44250bb4176f040f64c07ca Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 27 Jan 2022 16:20:46 +0000 Subject: [PATCH 09/17] SurfaceControl: Add setDropInputMode api Introduces an API to drop input events on this SurfaceControl. This policy will be inherited by its children. The caller must hold the ACCESS_SURFACE_FLINGER permission. Options include: ALL: SurfaceControl and its children will not receive any input regardless of whether it has a valid input channel. These policies are used to enable features that allow for a less trusted interaction model between apps. See the bug for more details. Note: this backport does not include the OBSCURED option since its not needed for the security fix. Test: atest libgui_test InputDispatcherDropInputFeatureTest Bug: 197296414 Merged-In: I443741d5ab51a45d37fb865f11c433c436d96c1e Change-Id: I443741d5ab51a45d37fb865f11c433c436d96c1e (cherry picked from commit 122c4d2da0405be75ae8c249e19ba692722c6e13) Merged-In: I443741d5ab51a45d37fb865f11c433c436d96c1e --- include/input/InputWindow.h | 1 + libs/gui/Android.bp | 11 +++++- libs/gui/LayerState.cpp | 9 ++++- libs/gui/SurfaceComposerClient.cpp | 15 ++++++++ libs/gui/android/gui/DropInputMode.aidl | 40 ++++++++++++++++++++ libs/gui/include/gui/LayerState.h | 8 +++- libs/gui/include/gui/SurfaceComposerClient.h | 3 +- services/surfaceflinger/Layer.cpp | 11 ++++++ services/surfaceflinger/Layer.h | 5 +++ services/surfaceflinger/SurfaceFlinger.cpp | 9 +++++ 10 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 libs/gui/android/gui/DropInputMode.aidl diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index 271fdb3a2f..bbf793e62b 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -115,6 +115,7 @@ struct InputWindowInfo { INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001, INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002, INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004, + INPUT_FEATURE_DROP_INPUT = 0x00000008, }; /* These values are filled in by the WM and passed through SurfaceFlinger diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 9e22fccbde..245649be1f 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -30,6 +30,14 @@ cc_library_headers { min_sdk_version: "29", } +// AIDL files that should be exposed to java +filegroup { + name: "guiconstants_aidl", + srcs: [ + "android/gui/DropInputMode.aidl", + ], +} + cc_defaults { name: "libgui_defaults", @@ -38,6 +46,7 @@ cc_defaults { defaults: ["libgui_bufferqueue-defaults"], srcs: [ + ":guiconstants_aidl", ":framework_native_aidl", ":libgui_bufferqueue_sources", @@ -286,4 +295,4 @@ cc_library_shared { defaults: ["libgui_defaults"] } -subdirs = ["tests"] +subdirs = ["tests"] \ No newline at end of file diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index a897d1025f..dfcef8fe7a 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -118,7 +118,7 @@ status_t layer_state_t::write(Parcel& output) const output.writeByte(frameRateCompatibility); output.writeUint32(fixedTransformHint); output.writeBool(isTrustedOverlay); - + output.writeUint32(static_cast(dropInputMode)); return NO_ERROR; } @@ -204,6 +204,9 @@ status_t layer_state_t::read(const Parcel& input) fixedTransformHint = static_cast(input.readUint32()); isTrustedOverlay = input.readBool(); + uint32_t mode; + mode = input.readUint32(); + dropInputMode = static_cast(mode); return NO_ERROR; } @@ -447,6 +450,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eTrustedOverlayChanged; isTrustedOverlay = other.isTrustedOverlay; } + if (other.what & eDropInputModeChanged) { + what |= eDropInputModeChanged; + dropInputMode = other.dropInputMode; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIu64 " what=0x%" PRIu64, diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 78d932cc81..d2c96218f4 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1497,6 +1497,21 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrust return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropInputMode( + const sp& sc, gui::DropInputMode mode) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eDropInputModeChanged; + s->dropInputMode = mode; + + registerSurfaceControlForCallback(sc); + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/android/gui/DropInputMode.aidl b/libs/gui/android/gui/DropInputMode.aidl new file mode 100644 index 0000000000..248a0318b7 --- /dev/null +++ b/libs/gui/android/gui/DropInputMode.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 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. + */ + +package android.gui; + + +/** + * Input event drop modes: Input event drop options for windows and its children. + * + * @hide + */ +@Backing(type="int") +enum DropInputMode { + /** + * Default mode, input events are sent to the target as usual. + */ + NONE, + + /** + * Window and its children will not receive any input even if it has a valid input channel. + * Touches and keys will be dropped. If a window is focused, it will remain focused but will + * not receive any keys. If the window has a touchable region and is the target of an input + * event, the event will be dropped and will not go to the window behind. ref: b/197296414 + */ + ALL, +} + diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index a77e4b0462..39dbe9e035 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -25,6 +25,7 @@ #include #include +#include #ifndef NO_INPUT #include