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

Commit 2b03097e authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

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
parent 7aa3e949
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -4689,11 +4689,13 @@ void InputDispatcher::setInputWindowsLocked(
                        if (wallpaper != nullptr) {
                            sp<Connection> wallpaperConnection =
                                    getConnectionLocked(wallpaper->getToken());
                            if (wallpaperConnection != nullptr) {
                                synthesizeCancelationEventsForConnectionLocked(wallpaperConnection,
                                                                               options);
                            }
                        }
                    }
                }
                state.windows.erase(state.windows.begin() + i);
            } else {
                ++i;
+47 −0
Original line number Diff line number Diff line
@@ -1627,6 +1627,53 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance
    wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
}

/**
 * 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.