diff options
| author | 2021-02-15 13:23:39 +0000 | |
|---|---|---|
| committer | 2021-02-15 13:23:39 +0000 | |
| commit | cfcb5c94fe2e543b05f4af3cc84ea5d483c77ac7 (patch) | |
| tree | 54adcbf207dfd3b2fe196d272b3b4d71b0265117 | |
| parent | 2804272fd6ddb209706343438d61bfd878845877 (diff) | |
| parent | c3b7b8cea8a231d30f6715bd642d661a5b8f594a (diff) | |
Merge "Add InputDispatcher unit tests for untrusted touches [1/n]" into sc-dev
| -rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 143 |
1 files changed, 136 insertions, 7 deletions
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 01945dbbf1..79a6774c36 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -31,6 +31,7 @@ using android::base::StringPrintf; using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; +using android::os::TouchOcclusionMode; using namespace android::flag_operators; namespace android::inputdispatcher { @@ -727,8 +728,9 @@ public: ASSERT_EQ(OK, status) << mName.c_str() << ": consumer sendFinishedSignal should return OK."; } - void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId, - int32_t expectedFlags) { + void consumeEvent(int32_t expectedEventType, int32_t expectedAction, + std::optional<int32_t> expectedDisplayId, + std::optional<int32_t> expectedFlags) { InputEvent* event = consume(); ASSERT_NE(nullptr, event) << mName.c_str() @@ -737,19 +739,25 @@ public: << mName.c_str() << " expected " << inputEventTypeToString(expectedEventType) << " event, got " << inputEventTypeToString(event->getType()) << " event"; - EXPECT_EQ(expectedDisplayId, event->getDisplayId()); + if (expectedDisplayId.has_value()) { + EXPECT_EQ(expectedDisplayId, event->getDisplayId()); + } switch (expectedEventType) { case AINPUT_EVENT_TYPE_KEY: { const KeyEvent& keyEvent = static_cast<const KeyEvent&>(*event); EXPECT_EQ(expectedAction, keyEvent.getAction()); - EXPECT_EQ(expectedFlags, keyEvent.getFlags()); + if (expectedFlags.has_value()) { + EXPECT_EQ(expectedFlags.value(), keyEvent.getFlags()); + } break; } case AINPUT_EVENT_TYPE_MOTION: { const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event); EXPECT_EQ(expectedAction, motionEvent.getAction()); - EXPECT_EQ(expectedFlags, motionEvent.getFlags()); + if (expectedFlags.has_value()) { + EXPECT_EQ(expectedFlags.value(), motionEvent.getFlags()); + } break; } case AINPUT_EVENT_TYPE_FOCUS: { @@ -854,6 +862,7 @@ public: mInfo.name = name; mInfo.type = InputWindowInfo::Type::APPLICATION; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; + mInfo.alpha = 1.0; mInfo.frameLeft = 0; mInfo.frameTop = 0; mInfo.frameRight = WIDTH; @@ -883,6 +892,12 @@ public: void setPaused(bool paused) { mInfo.paused = paused; } + void setAlpha(float alpha) { mInfo.alpha = alpha; } + + void setTouchOcclusionMode(android::os::TouchOcclusionMode mode) { + mInfo.touchOcclusionMode = mode; + } + void setFrame(const Rect& frame) { mInfo.frameLeft = frame.left; mInfo.frameTop = frame.top; @@ -928,6 +943,11 @@ public: void consumeMotionDown(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { + consumeAnyMotionDown(expectedDisplayId, expectedFlags); + } + + void consumeAnyMotionDown(std::optional<int32_t> expectedDisplayId = std::nullopt, + std::optional<int32_t> expectedFlags = std::nullopt) { consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN, expectedDisplayId, expectedFlags); } @@ -971,8 +991,9 @@ public: mInputReceiver->consumeCaptureEvent(hasCapture); } - void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId, - int32_t expectedFlags) { + void consumeEvent(int32_t expectedEventType, int32_t expectedAction, + std::optional<int32_t> expectedDisplayId, + std::optional<int32_t> expectedFlags) { ASSERT_NE(mInputReceiver, nullptr) << "Invalid consume event on window with no receiver"; mInputReceiver->consumeEvent(expectedEventType, expectedAction, expectedDisplayId, expectedFlags); @@ -4240,4 +4261,112 @@ TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) { mSecondWindow->consumeCaptureEvent(true); } +class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest { +protected: + constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8; + static const int32_t APP_A_UID = 10001; + static const int32_t APP_B_UID = 10002; + + sp<FakeWindowHandle> mTouchWindow; + + virtual void SetUp() override { + InputDispatcherTest::SetUp(); + mTouchWindow = getWindow(APP_A_UID, "Touched"); + mDispatcher->setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode::BLOCK); + mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY); + } + + virtual void TearDown() override { + InputDispatcherTest::TearDown(); + mTouchWindow.clear(); + } + + sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name, + os::TouchOcclusionMode mode) { + sp<FakeWindowHandle> window = getWindow(uid, name); + window->setFlags(InputWindowInfo::Flag::NOT_TOUCHABLE); + window->setTouchOcclusionMode(mode); + return window; + } + + sp<FakeWindowHandle> getWindow(int32_t uid, std::string name) { + std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window = + new FakeWindowHandle(app, mDispatcher, name, ADISPLAY_ID_DEFAULT); + // Generate an arbitrary PID based on the UID + window->setOwnerInfo(1777 + (uid % 10000), uid); + return window; + } + + void touch(const std::vector<PointF>& points = {PointF{100, 200}}) { + NotifyMotionArgs args = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, points); + mDispatcher->notifyMotion(&args); + } +}; + +TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) { + const sp<FakeWindowHandle>& window = + getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, mTouchWindow}}}); + + touch(); + + mTouchWindow->assertNoEvents(); +} + +TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) { + const sp<FakeWindowHandle>& window = + getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, mTouchWindow}}}); + + touch(); + + mTouchWindow->consumeAnyMotionDown(); +} + +TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) { + const sp<FakeWindowHandle>& window = + getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED); + window->setFrame(Rect(0, 0, 50, 50)); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, mTouchWindow}}}); + + touch({PointF{100, 100}}); + + mTouchWindow->consumeAnyMotionDown(); +} + +TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) { + const sp<FakeWindowHandle>& window = + getOccludingWindow(APP_A_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, mTouchWindow}}}); + + touch(); + + mTouchWindow->consumeAnyMotionDown(); +} + +TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) { + const sp<FakeWindowHandle>& window = + getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY); + window->setAlpha(0.7); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, mTouchWindow}}}); + + touch(); + + mTouchWindow->consumeAnyMotionDown(); +} + +TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) { + const sp<FakeWindowHandle>& window = + getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY); + window->setAlpha(0.9); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, mTouchWindow}}}); + + touch(); + + mTouchWindow->assertNoEvents(); +} + } // namespace android::inputdispatcher |