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

Commit a43a5a4b authored by Bernardo Rufino's avatar Bernardo Rufino
Browse files

Add InputDispatcher unit tests for untrusted touches [5/n]

This is the unit test compliment of ag/12198106.

Test that taps *inside* windows with flags FLAG_WATCH_OUTSIDE_TOUCH |
FLAG_NOT_TOUCHABLE result in ACTION_OUTSIDE events. This is important
for security to make sure apps can't learn the position of touches
(outside vs inside) while letting them pass-through.

Bug: 158002302
Bug: 177840583
Fix: 110901409
Test: atest InputDispatcherUntrustedTouchesTest
Change-Id: Iaa59fa4c057c2f1d81d0e7010fddf0248adf23e5
parent 7dc57eff
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
@@ -908,6 +908,8 @@ public:
        mInfo.addTouchableRegion(frame);
    }

    void addFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags |= flags; }

    void setFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags = flags; }

    void setInputFeatures(InputWindowInfo::Feature features) { mInfo.inputFeatures = features; }
@@ -4318,6 +4320,17 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMod
    mTouchWindow->assertNoEvents();
}

TEST_F(InputDispatcherUntrustedTouchesTest,
       WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
    const sp<FakeWindowHandle>& w =
            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});

    touch();

    w->assertNoEvents();
}

TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
    const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
@@ -4358,6 +4371,48 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
    mTouchWindow->consumeAnyMotionDown();
}

TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
    const sp<FakeWindowHandle>& w =
            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});

    touch();

    w->assertNoEvents();
}

/**
 * This is important to make sure apps can't indirectly learn the position of touches (outside vs
 * inside) while letting them pass-through. Note that even though touch passes through the occluding
 * window, the occluding window will still receive ACTION_OUTSIDE event.
 */
TEST_F(InputDispatcherUntrustedTouchesTest,
       WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
    const sp<FakeWindowHandle>& w =
            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
    w->addFlags(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});

    touch();

    w->consumeMotionOutside();
}

TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
    const sp<FakeWindowHandle>& w =
            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
    w->addFlags(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});

    touch();

    InputEvent* event = w->consume();
    ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
    MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
    EXPECT_EQ(0.0f, motionEvent.getRawPointerCoords(0)->getX());
    EXPECT_EQ(0.0f, motionEvent.getRawPointerCoords(0)->getY());
}

TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
    const sp<FakeWindowHandle>& w =
            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);