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

Commit 2f5bc8b8 authored by Vishnu Nair's avatar Vishnu Nair
Browse files

InputDispatcher: Blame the window from the focus request for ANR

If there are no focusable windows, then try to blame the window that
was requested to become focused. This will avoid blaming the wrong
process when WM requests focus on a window that is placed on top
of the focused app and the window fails to become focusable.

Test: atest inputflinger_tests
Fixes: b/239907039

Change-Id: Ie2bc3dc66516b51784159a875c7cf865b4cb5b35
parent 05c7f984
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ sp<IBinder> FocusResolver::getFocusedWindowToken(int32_t displayId) const {
    return it != mFocusedWindowTokenByDisplay.end() ? it->second.second : nullptr;
}

std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) {
std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) const {
    auto it = mFocusRequestByDisplay.find(displayId);
    return it != mFocusRequestByDisplay.end() ? std::make_optional<>(it->second) : std::nullopt;
}
+1 −1
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ public:
    std::optional<FocusResolver::FocusChanges> setFocusedWindow(
            const android::gui::FocusRequest& request,
            const std::vector<sp<android::gui::WindowInfoHandle>>& windows);
    std::optional<android::gui::FocusRequest> getFocusRequest(int32_t displayId) const;

    // Display has been removed from the system, clean up old references.
    void displayRemoved(int32_t displayId);
@@ -112,7 +113,6 @@ private:
    std::optional<FocusResolver::FocusChanges> updateFocusedWindow(
            int32_t displayId, const std::string& reason, const sp<IBinder>& token,
            const std::string& tokenName = "");
    std::optional<android::gui::FocusRequest> getFocusRequest(int32_t displayId);
};

} // namespace android::inputdispatcher
+26 −0
Original line number Diff line number Diff line
@@ -659,6 +659,13 @@ void InputDispatcher::processNoFocusedWindowAnrLocked() {
    if (focusedWindowHandle != nullptr) {
        return; // We now have a focused window. No need for ANR.
    }
    std::optional<FocusRequest> pendingRequest =
            mFocusResolver.getFocusRequest(mAwaitedApplicationDisplayId);
    if (pendingRequest.has_value() && onAnrLocked(*pendingRequest)) {
        // We don't have a focusable window but we know which window should have
        // been focused. Blame that process in case it doesn't belong to the focused app.
        return;
    }
    onAnrLocked(mAwaitedFocusedApplication);
}

@@ -5848,6 +5855,25 @@ void InputDispatcher::sendDropWindowCommandLocked(const sp<IBinder>& token, floa
    postCommandLocked(std::move(command));
}

bool InputDispatcher::onAnrLocked(const android::gui::FocusRequest& pendingFocusRequest) {
    if (pendingFocusRequest.token == nullptr) {
        return false;
    }

    const std::string reason = android::base::StringPrintf("%s is not focusable.",
                                                           pendingFocusRequest.windowName.c_str());
    updateLastAnrStateLocked(pendingFocusRequest.windowName, reason);
    sp<Connection> connection = getConnectionLocked(pendingFocusRequest.token);
    if (connection != nullptr) {
        processConnectionUnresponsiveLocked(*connection, std::move(reason));
        // Stop waking up for events on this connection, it is already unresponsive
        cancelEventsForAnrLocked(connection);
    } else {
        sendWindowUnresponsiveCommandLocked(pendingFocusRequest.token, std::nullopt, reason);
    }
    return true;
}

void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
    if (connection == nullptr) {
        LOG_ALWAYS_FATAL("Caller must check for nullness");
+1 −0
Original line number Diff line number Diff line
@@ -658,6 +658,7 @@ private:
    void sendDropWindowCommandLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock);
    void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
    void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock);
    bool onAnrLocked(const android::gui::FocusRequest& pendingFocusRequest) REQUIRES(mLock);
    void updateLastAnrStateLocked(const sp<android::gui::WindowInfoHandle>& window,
                                  const std::string& reason) REQUIRES(mLock);
    void updateLastAnrStateLocked(const InputApplicationHandle& application,
+36 −7
Original line number Diff line number Diff line
@@ -4718,6 +4718,36 @@ TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {

// We have a focused application, but no focused window
TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
    FocusRequest request;
    request.token = nullptr;
    request.windowName = "";
    request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
    request.displayId = mWindow->getInfo()->displayId;
    mDispatcher->setFocusedWindow(request);
    mWindow->consumeFocusEvent(false);

    // taps on the window work as normal
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                               WINDOW_LOCATION));
    ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
    mDispatcher->waitForIdle();
    mFakePolicy->assertNotifyAnrWasNotCalled();

    // Once a focused event arrives, we get an ANR for this application
    // We specify the injection timeout to be smaller than the application timeout, to ensure that
    // injection times out (instead of failing).
    const InputEventInjectionResult result =
            injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
    ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
    const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
    ASSERT_TRUE(mDispatcher->waitForIdle());
}

// We have a focused application, but we are waiting on the requested window to become focusable
TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_PendingFocusedRequest) {
    mWindow->setFocusable(false);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
    mWindow->consumeFocusEvent(false);
@@ -4738,7 +4768,7 @@ TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
    ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
    const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
    ASSERT_TRUE(mDispatcher->waitForIdle());
}

@@ -4788,11 +4818,10 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr)
            injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
    ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
    const std::chrono::duration appTimeout =
            mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(appTimeout, mApplication);
    const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);

    std::this_thread::sleep_for(appTimeout);
    std::this_thread::sleep_for(timeout);
    // ANR should not be raised again. It is up to policy to do that if it desires.
    mFakePolicy->assertNotifyAnrWasNotCalled();

@@ -4813,8 +4842,8 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms);
    ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);

    const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
    const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);

    // Future focused events get dropped right away
    ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(mDispatcher));