Loading services/inputflinger/dispatcher/InputDispatcher.cpp +34 −15 Original line number Diff line number Diff line Loading @@ -567,6 +567,17 @@ bool canReceiveForegroundTouches(const WindowInfo& info) { return !info.inputConfig.test(gui::WindowInfo::InputConfig::NOT_TOUCHABLE) && !info.isSpy(); } bool isWindowOwnedBy(const sp<WindowInfoHandle>& windowHandle, int32_t pid, int32_t uid) { if (windowHandle == nullptr) { return false; } const WindowInfo* windowInfo = windowHandle->getInfo(); if (pid == windowInfo->ownerPid && uid == windowInfo->ownerUid) { return true; } return false; } } // namespace // --- InputDispatcher --- Loading Loading @@ -4990,21 +5001,11 @@ bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission)); } if (!hasPermission) { const sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(mFocusedDisplayId); // TODO(b/218541064): if no window is currently focused, then we need to check the last // interacted window (within 1 second timeout). We should allow touch mode change // if the last interacted window owner's pid/uid match the calling ones. if (focusedToken == nullptr) { return false; } const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken); if (windowHandle == nullptr) { return false; } const WindowInfo* windowInfo = windowHandle->getInfo(); if (pid != windowInfo->ownerPid || uid != windowInfo->ownerUid) { if (!focusedWindowIsOwnedByLocked(pid, uid) && !recentWindowsAreOwnedByLocked(pid, uid)) { ALOGD("Touch mode switch rejected, caller (pid=%d, uid=%d) doesn't own the focused " "window nor none of the previously interacted window", pid, uid); return false; } } Loading @@ -5022,6 +5023,24 @@ bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, return true; } bool InputDispatcher::focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) { const sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(mFocusedDisplayId); if (focusedToken == nullptr) { return false; } sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken); return isWindowOwnedBy(windowHandle, pid, uid); } bool InputDispatcher::recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) { return std::find_if(mInteractionConnectionTokens.begin(), mInteractionConnectionTokens.end(), [&](const sp<IBinder>& connectionToken) REQUIRES(mLock) { const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(connectionToken); return isWindowOwnedBy(windowHandle, pid, uid); }) != mInteractionConnectionTokens.end(); } void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) { if (opacity < 0 || opacity > 1) { LOG_ALWAYS_FATAL("Maximum obscuring opacity for touch should be >= 0 and <= 1"); Loading services/inputflinger/dispatcher/InputDispatcher.h +6 −1 Original line number Diff line number Diff line Loading @@ -433,7 +433,8 @@ private: // Dispatcher state at time of last ANR. std::string mLastAnrState GUARDED_BY(mLock); // The connection tokens of the channels that the user last interacted, for debugging // The connection tokens of the channels that the user last interacted (used for debugging and // when switching touch mode state). std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> mInteractionConnectionTokens GUARDED_BY(mLock); void updateInteractionTokensLocked(const EventEntry& entry, Loading Loading @@ -677,6 +678,10 @@ private: void traceOutboundQueueLength(const Connection& connection); void traceWaitQueueLength(const Connection& connection); // Check window ownership bool focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock); bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock); sp<InputReporterInterface> mReporter; }; Loading services/inputflinger/tests/InputDispatcher_test.cpp +22 −2 Original line number Diff line number Diff line Loading @@ -6336,8 +6336,11 @@ protected: mWindow->consumeFocusEvent(true); // Set initial touch mode to InputDispatcher::kDefaultInTouchMode. mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID, INJECTOR_UID, /* hasPermission */ true); if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID, INJECTOR_UID, /* hasPermission */ true)) { mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); } } void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) { Loading Loading @@ -6382,6 +6385,23 @@ TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTou mSecondWindow->assertNoEvents(); } TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) { // Interact with the window first. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); // Then remove focus. mWindow->setFocusable(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); // Assert that caller can switch touch mode by owning one of the last interacted window. const WindowInfo& windowInfo = *mWindow->getInfo(); ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid, windowInfo.ownerUid, /* hasPermission= */ false)); } class InputDispatcherSpyWindowTest : public InputDispatcherTest { public: sp<FakeWindowHandle> createSpy() { Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +34 −15 Original line number Diff line number Diff line Loading @@ -567,6 +567,17 @@ bool canReceiveForegroundTouches(const WindowInfo& info) { return !info.inputConfig.test(gui::WindowInfo::InputConfig::NOT_TOUCHABLE) && !info.isSpy(); } bool isWindowOwnedBy(const sp<WindowInfoHandle>& windowHandle, int32_t pid, int32_t uid) { if (windowHandle == nullptr) { return false; } const WindowInfo* windowInfo = windowHandle->getInfo(); if (pid == windowInfo->ownerPid && uid == windowInfo->ownerUid) { return true; } return false; } } // namespace // --- InputDispatcher --- Loading Loading @@ -4990,21 +5001,11 @@ bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission)); } if (!hasPermission) { const sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(mFocusedDisplayId); // TODO(b/218541064): if no window is currently focused, then we need to check the last // interacted window (within 1 second timeout). We should allow touch mode change // if the last interacted window owner's pid/uid match the calling ones. if (focusedToken == nullptr) { return false; } const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken); if (windowHandle == nullptr) { return false; } const WindowInfo* windowInfo = windowHandle->getInfo(); if (pid != windowInfo->ownerPid || uid != windowInfo->ownerUid) { if (!focusedWindowIsOwnedByLocked(pid, uid) && !recentWindowsAreOwnedByLocked(pid, uid)) { ALOGD("Touch mode switch rejected, caller (pid=%d, uid=%d) doesn't own the focused " "window nor none of the previously interacted window", pid, uid); return false; } } Loading @@ -5022,6 +5023,24 @@ bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, return true; } bool InputDispatcher::focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) { const sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(mFocusedDisplayId); if (focusedToken == nullptr) { return false; } sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken); return isWindowOwnedBy(windowHandle, pid, uid); } bool InputDispatcher::recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) { return std::find_if(mInteractionConnectionTokens.begin(), mInteractionConnectionTokens.end(), [&](const sp<IBinder>& connectionToken) REQUIRES(mLock) { const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(connectionToken); return isWindowOwnedBy(windowHandle, pid, uid); }) != mInteractionConnectionTokens.end(); } void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) { if (opacity < 0 || opacity > 1) { LOG_ALWAYS_FATAL("Maximum obscuring opacity for touch should be >= 0 and <= 1"); Loading
services/inputflinger/dispatcher/InputDispatcher.h +6 −1 Original line number Diff line number Diff line Loading @@ -433,7 +433,8 @@ private: // Dispatcher state at time of last ANR. std::string mLastAnrState GUARDED_BY(mLock); // The connection tokens of the channels that the user last interacted, for debugging // The connection tokens of the channels that the user last interacted (used for debugging and // when switching touch mode state). std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> mInteractionConnectionTokens GUARDED_BY(mLock); void updateInteractionTokensLocked(const EventEntry& entry, Loading Loading @@ -677,6 +678,10 @@ private: void traceOutboundQueueLength(const Connection& connection); void traceWaitQueueLength(const Connection& connection); // Check window ownership bool focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock); bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock); sp<InputReporterInterface> mReporter; }; Loading
services/inputflinger/tests/InputDispatcher_test.cpp +22 −2 Original line number Diff line number Diff line Loading @@ -6336,8 +6336,11 @@ protected: mWindow->consumeFocusEvent(true); // Set initial touch mode to InputDispatcher::kDefaultInTouchMode. mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID, INJECTOR_UID, /* hasPermission */ true); if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID, INJECTOR_UID, /* hasPermission */ true)) { mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); } } void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) { Loading Loading @@ -6382,6 +6385,23 @@ TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTou mSecondWindow->assertNoEvents(); } TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) { // Interact with the window first. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); // Then remove focus. mWindow->setFocusable(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); // Assert that caller can switch touch mode by owning one of the last interacted window. const WindowInfo& windowInfo = *mWindow->getInfo(); ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid, windowInfo.ownerUid, /* hasPermission= */ false)); } class InputDispatcherSpyWindowTest : public InputDispatcherTest { public: sp<FakeWindowHandle> createSpy() { Loading