diff options
-rw-r--r-- | include/input/InputEventBuilders.h | 16 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 4 | ||||
-rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 48 |
3 files changed, 61 insertions, 7 deletions
diff --git a/include/input/InputEventBuilders.h b/include/input/InputEventBuilders.h index 25d35e9fe7..55e058332d 100644 --- a/include/input/InputEventBuilders.h +++ b/include/input/InputEventBuilders.h @@ -127,7 +127,7 @@ public: return *this; } - MotionEvent build() { + MotionEvent build() const { std::vector<PointerProperties> pointerProperties; std::vector<PointerCoords> pointerCoords; for (const PointerBuilder& pointer : mPointers) { @@ -135,20 +135,22 @@ public: pointerCoords.push_back(pointer.buildCoords()); } + auto [xCursorPosition, yCursorPosition] = + std::make_pair(mRawXCursorPosition, mRawYCursorPosition); // Set mouse cursor position for the most common cases to avoid boilerplate. if (mSource == AINPUT_SOURCE_MOUSE && - !MotionEvent::isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) { - mRawXCursorPosition = pointerCoords[0].getX(); - mRawYCursorPosition = pointerCoords[0].getY(); + !MotionEvent::isValidCursorPosition(xCursorPosition, yCursorPosition)) { + xCursorPosition = pointerCoords[0].getX(); + yCursorPosition = pointerCoords[0].getY(); } MotionEvent event; event.initialize(InputEvent::nextId(), mDeviceId, mSource, mDisplayId, INVALID_HMAC, mAction, mActionButton, mFlags, /*edgeFlags=*/0, AMETA_NONE, mButtonState, MotionClassification::NONE, mTransform, - /*xPrecision=*/0, /*yPrecision=*/0, mRawXCursorPosition, - mRawYCursorPosition, mRawTransform, mDownTime, mEventTime, - mPointers.size(), pointerProperties.data(), pointerCoords.data()); + /*xPrecision=*/0, /*yPrecision=*/0, xCursorPosition, yCursorPosition, + mRawTransform, mDownTime, mEventTime, mPointers.size(), + pointerProperties.data(), pointerCoords.data()); return event; } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index af4a04d9eb..faafa50eb8 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4879,6 +4879,10 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev logDispatchStateLocked(); LOG(ERROR) << "Inconsistent event: " << motionEvent << ", reason: " << result.error(); + if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) { + mLock.unlock(); + return InputEventInjectionResult::FAILED; + } } } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index e5058507eb..d418a9b5ec 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -5037,6 +5037,54 @@ TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash, } /** + * Invalid events injected by input filter are rejected. + */ +TEST_F(InputDispatcherTest, InvalidA11yEventsGetRejected) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window", + ui::LogicalDisplayId::DEFAULT); + + mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application); + + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + + // a11y sets 'POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY' policy flag during injection, so define + // a custom injection function here for convenience. + auto injectFromAccessibility = [&](int32_t action, float x, float y) { + MotionEvent event = MotionEventBuilder(action, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(x).y(y)) + .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT) + .build(); + return injectMotionEvent(*mDispatcher, event, 100ms, + InputEventInjectionSync::WAIT_FOR_RESULT, /*targetUid=*/{}, + POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_FILTERED | + POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY); + }; + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectFromAccessibility(ACTION_DOWN, /*x=*/300, /*y=*/400)); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectFromAccessibility(ACTION_MOVE, /*x=*/310, /*y=*/420)); + window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + window->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); + // finger is still down, so a new DOWN event should be rejected! + ASSERT_EQ(InputEventInjectionResult::FAILED, + injectFromAccessibility(ACTION_DOWN, /*x=*/340, /*y=*/410)); + + // if the gesture is correctly finished, new down event will succeed + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectFromAccessibility(ACTION_MOVE, /*x=*/320, /*y=*/430)); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectFromAccessibility(ACTION_UP, /*x=*/320, /*y=*/430)); + window->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); + window->consumeMotionEvent(WithMotionAction(ACTION_UP)); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectFromAccessibility(ACTION_DOWN, /*x=*/350, /*y=*/460)); + window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); +} + +/** * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT. */ TEST_F(InputDispatcherTest, TouchDownAfterMouseHover_legacy) { |