Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d0d65e1 authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

Reject invalid events injected by accessibility

This will avoid the processing of inconsistent event streams inside
dispatcher, which can lead to crashes. Going forward, we should reject
all inconsistent injected events, not just those from a11y.

Bug: 356662669
Flag: EXEMPT bugfix
Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST --gtest_filter="*InvalidA11yEventsGetRejected"
Change-Id: Ia127bcedf2288a2522d33d046fbbc8eb389babfb
parent 9b4b4909
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -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;
    }

+4 −0
Original line number Diff line number Diff line
@@ -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;
                    }
                }
            }

+48 −0
Original line number Diff line number Diff line
@@ -5036,6 +5036,54 @@ TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash,
    window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
}
/**
 * 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.
 */