Loading services/inputflinger/dispatcher/InputDispatcher.cpp +28 −0 Original line number Diff line number Diff line Loading @@ -681,6 +681,25 @@ std::vector<T>& operator+=(std::vector<T>& left, const std::vector<T>& right) { return left; } // Filter windows in a TouchState and targets in a vector to remove untrusted windows/targets from // both. void filterUntrustedTargets(TouchState& touchState, std::vector<InputTarget>& targets) { std::erase_if(touchState.windows, [&](const TouchedWindow& window) { if (!window.windowHandle->getInfo()->inputConfig.test( WindowInfo::InputConfig::TRUSTED_OVERLAY)) { // In addition to TouchState, erase this window from the input targets! We don't have a // good way to do this today except by adding a nested loop. // TODO(b/282025641): simplify this code once InputTargets are being identified // separately from TouchedWindows. std::erase_if(targets, [&](const InputTarget& target) { return target.inputChannel->getConnectionToken() == window.windowHandle->getToken(); }); return true; } return false; }); } } // namespace // --- InputDispatcher --- Loading Loading @@ -2588,6 +2607,14 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( } } // If this is a touchpad navigation gesture, it needs to only be sent to trusted targets, as we // only want the system UI to handle these gestures. const bool isTouchpadNavGesture = isFromSource(entry.source, AINPUT_SOURCE_MOUSE) && entry.classification == MotionClassification::MULTI_FINGER_SWIPE; if (isTouchpadNavGesture) { filterUntrustedTargets(/* byref */ tempTouchState, /* byref */ targets); } // Output targets from the touch state. for (const TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.pointerIds.none() && !touchedWindow.hasHoveringPointers(entry.deviceId)) { Loading @@ -2595,6 +2622,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( // Do not send this event to those windows. continue; } addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, touchedWindow.pointerIds, touchedWindow.firstDownTimeInTarget, targets); Loading services/inputflinger/tests/InputDispatcher_test.cpp +129 −1 Original line number Diff line number Diff line Loading @@ -86,6 +86,8 @@ static constexpr int32_t POINTER_0_UP = AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_1_UP = AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_2_UP = AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); // The default pid and uid for windows created on the primary display by the test. static constexpr int32_t WINDOW_PID = 999; Loading Loading @@ -1660,6 +1662,11 @@ public: return *this; } MotionArgsBuilder& classification(MotionClassification classification) { mClassification = classification; return *this; } NotifyMotionArgs build() { std::vector<PointerProperties> pointerProperties; std::vector<PointerCoords> pointerCoords; Loading @@ -1678,7 +1685,7 @@ public: NotifyMotionArgs args(InputEvent::nextId(), mEventTime, /*readTime=*/mEventTime, mDeviceId, mSource, mDisplayId, mPolicyFlags, mAction, mActionButton, mFlags, AMETA_NONE, mButtonState, MotionClassification::NONE, /*edgeFlags=*/0, AMETA_NONE, mButtonState, mClassification, /*edgeFlags=*/0, mPointers.size(), pointerProperties.data(), pointerCoords.data(), /*xPrecision=*/0, /*yPrecision=*/0, mRawXCursorPosition, mRawYCursorPosition, mDownTime, /*videoFrames=*/{}); Loading @@ -1697,6 +1704,7 @@ private: int32_t mActionButton{0}; int32_t mButtonState{0}; int32_t mFlags{0}; MotionClassification mClassification{MotionClassification::NONE}; float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; Loading Loading @@ -4003,6 +4011,126 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { EXPECT_EQ(-10, event->getY(1)); // -50 + 40 } TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 400, 400)); sp<FakeWindowHandle> trustedOverlay = sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay", ADISPLAY_ID_DEFAULT); trustedOverlay->setSpy(true); trustedOverlay->setTrustedOverlay(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {trustedOverlay, window}}}); // Start a three-finger touchpad swipe mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN)); // Move the swipe a bit mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); // End the swipe mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP)); trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP)); trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP)); window->assertNoEvents(); } TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 400, 400)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); // Start a three-finger touchpad swipe mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); // Move the swipe a bit mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); // End the swipe mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); window->assertNoEvents(); } /** * Ensure the correct coordinate spaces are used by InputDispatcher. * Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +28 −0 Original line number Diff line number Diff line Loading @@ -681,6 +681,25 @@ std::vector<T>& operator+=(std::vector<T>& left, const std::vector<T>& right) { return left; } // Filter windows in a TouchState and targets in a vector to remove untrusted windows/targets from // both. void filterUntrustedTargets(TouchState& touchState, std::vector<InputTarget>& targets) { std::erase_if(touchState.windows, [&](const TouchedWindow& window) { if (!window.windowHandle->getInfo()->inputConfig.test( WindowInfo::InputConfig::TRUSTED_OVERLAY)) { // In addition to TouchState, erase this window from the input targets! We don't have a // good way to do this today except by adding a nested loop. // TODO(b/282025641): simplify this code once InputTargets are being identified // separately from TouchedWindows. std::erase_if(targets, [&](const InputTarget& target) { return target.inputChannel->getConnectionToken() == window.windowHandle->getToken(); }); return true; } return false; }); } } // namespace // --- InputDispatcher --- Loading Loading @@ -2588,6 +2607,14 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( } } // If this is a touchpad navigation gesture, it needs to only be sent to trusted targets, as we // only want the system UI to handle these gestures. const bool isTouchpadNavGesture = isFromSource(entry.source, AINPUT_SOURCE_MOUSE) && entry.classification == MotionClassification::MULTI_FINGER_SWIPE; if (isTouchpadNavGesture) { filterUntrustedTargets(/* byref */ tempTouchState, /* byref */ targets); } // Output targets from the touch state. for (const TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.pointerIds.none() && !touchedWindow.hasHoveringPointers(entry.deviceId)) { Loading @@ -2595,6 +2622,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( // Do not send this event to those windows. continue; } addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, touchedWindow.pointerIds, touchedWindow.firstDownTimeInTarget, targets); Loading
services/inputflinger/tests/InputDispatcher_test.cpp +129 −1 Original line number Diff line number Diff line Loading @@ -86,6 +86,8 @@ static constexpr int32_t POINTER_0_UP = AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_1_UP = AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_2_UP = AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); // The default pid and uid for windows created on the primary display by the test. static constexpr int32_t WINDOW_PID = 999; Loading Loading @@ -1660,6 +1662,11 @@ public: return *this; } MotionArgsBuilder& classification(MotionClassification classification) { mClassification = classification; return *this; } NotifyMotionArgs build() { std::vector<PointerProperties> pointerProperties; std::vector<PointerCoords> pointerCoords; Loading @@ -1678,7 +1685,7 @@ public: NotifyMotionArgs args(InputEvent::nextId(), mEventTime, /*readTime=*/mEventTime, mDeviceId, mSource, mDisplayId, mPolicyFlags, mAction, mActionButton, mFlags, AMETA_NONE, mButtonState, MotionClassification::NONE, /*edgeFlags=*/0, AMETA_NONE, mButtonState, mClassification, /*edgeFlags=*/0, mPointers.size(), pointerProperties.data(), pointerCoords.data(), /*xPrecision=*/0, /*yPrecision=*/0, mRawXCursorPosition, mRawYCursorPosition, mDownTime, /*videoFrames=*/{}); Loading @@ -1697,6 +1704,7 @@ private: int32_t mActionButton{0}; int32_t mButtonState{0}; int32_t mFlags{0}; MotionClassification mClassification{MotionClassification::NONE}; float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; Loading Loading @@ -4003,6 +4011,126 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { EXPECT_EQ(-10, event->getY(1)); // -50 + 40 } TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 400, 400)); sp<FakeWindowHandle> trustedOverlay = sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay", ADISPLAY_ID_DEFAULT); trustedOverlay->setSpy(true); trustedOverlay->setTrustedOverlay(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {trustedOverlay, window}}}); // Start a three-finger touchpad swipe mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN)); // Move the swipe a bit mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); // End the swipe mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP)); trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP)); trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP)); window->assertNoEvents(); } TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 400, 400)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); // Start a three-finger touchpad swipe mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); // Move the swipe a bit mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); // End the swipe mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) .classification(MotionClassification::MULTI_FINGER_SWIPE) .build()); window->assertNoEvents(); } /** * Ensure the correct coordinate spaces are used by InputDispatcher. * Loading