Ensure wallpaper connection is valid before canceling its events
The InputDispatcher function
'synthesizeCancelationEventsForConnectionLocked' expects non-null
connection. Ideally, we would refactor this function to receive
Connection&. However, this connection needs to be passed to other
functions called within, so for simplicity, we are keeping the incoming
parameter as sp<Connection>.
That means that the called must ensure that the connection is not null.
Fix the previous wallpaper CL by checking if the connection is null.
Bug: 206651192
Test: atest inputflinger_tests
Change-Id: Id6d9235144606a629dfbd2614e211412def1a68e
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c5d9e66..ffacfb1 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1628,6 +1628,53 @@
}
/**
+ * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above,
+ * with the following differences:
+ * After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to
+ * clean up the connection.
+ * This later may crash dispatcher during ACTION_CANCEL synthesis, if the dispatcher is not careful.
+ * Ensure that there's no crash in the dispatcher.
+ */
+TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> foregroundWindow =
+ new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
+ foregroundWindow->setHasWallpaper(true);
+ sp<FakeWindowHandle> wallpaperWindow =
+ new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+ wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ constexpr int expectedWallpaperFlags =
+ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}});
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ // Both foreground window and its wallpaper should receive the touch down
+ foregroundWindow->consumeMotionDown();
+ wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {110, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ foregroundWindow->consumeMotionMove();
+ wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+
+ // Wallpaper closes its channel, but the window remains.
+ wallpaperWindow->destroyReceiver();
+ mFakePolicy->assertNotifyInputChannelBrokenWasCalled(wallpaperWindow->getInfo()->token);
+
+ // Now the foreground window goes away, but the wallpaper stays, even though its channel
+ // is no longer valid.
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wallpaperWindow}}});
+ foregroundWindow->consumeMotionCancel();
+}
+
+/**
* A single window that receives touch (on top), and a wallpaper window underneath it.
* The top window gets a multitouch gesture.
* Ensure that wallpaper gets the same gesture.