From b166c00440e3c01c6db04592ff48517350e3077f Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Tue, 9 May 2023 13:06:05 +0000 Subject: InputDispatcher: Only send touchpad nav gestures to trusted overlays Because we don't want apps using the touchpad navigation gestures (at the moment, any swipes with three or more fingers), we need to only send them to system UI windows. For now, determine this by checking for the TRUSTED_OVERLAY InputConfig flag. Bug: b/279803433 Test: atest inputflinger_tests Test: check that no events are sent to a test app when making three- or four-finger swipes on a touchpad Change-Id: I0830cb37d1ed615df0d6c546f1febbac89bab410 --- .../inputflinger/dispatcher/InputDispatcher.cpp | 28 +++++ .../inputflinger/tests/InputDispatcher_test.cpp | 130 ++++++++++++++++++++- 2 files changed, 157 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 326ca87c41..0dd3dde718 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -681,6 +681,25 @@ std::vector& operator+=(std::vector& left, const std::vector& 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& 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 --- @@ -2587,6 +2606,14 @@ std::vector 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)) { @@ -2594,6 +2621,7 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( // Do not send this event to those windows. continue; } + addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, touchedWindow.pointerIds, touchedWindow.firstDownTimeInTarget, targets); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index a6cdee5fb1..d4103fd19c 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -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; @@ -1660,6 +1662,11 @@ public: return *this; } + MotionArgsBuilder& classification(MotionClassification classification) { + mClassification = classification; + return *this; + } + NotifyMotionArgs build() { std::vector pointerProperties; std::vector pointerCoords; @@ -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=*/{}); @@ -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}; @@ -4003,6 +4011,126 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { EXPECT_EQ(-10, event->getY(1)); // -50 + 40 } +TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 400, 400)); + sp trustedOverlay = + sp::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 application = std::make_shared(); + sp window = + sp::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. * -- cgit v1.2.3-59-g8ed1b