From 2f5bc8b8cfda7762213268842c13e2280ac02466 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 9 Aug 2022 00:03:11 +0000 Subject: 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 --- services/inputflinger/dispatcher/FocusResolver.cpp | 2 +- services/inputflinger/dispatcher/FocusResolver.h | 2 +- .../inputflinger/dispatcher/InputDispatcher.cpp | 26 +++++++++++++ services/inputflinger/dispatcher/InputDispatcher.h | 1 + .../inputflinger/tests/InputDispatcher_test.cpp | 43 ++++++++++++++++++---- 5 files changed, 65 insertions(+), 9 deletions(-) diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp index 4da846bcf8..85dcf8f4cf 100644 --- a/services/inputflinger/dispatcher/FocusResolver.cpp +++ b/services/inputflinger/dispatcher/FocusResolver.cpp @@ -39,7 +39,7 @@ sp FocusResolver::getFocusedWindowToken(int32_t displayId) const { return it != mFocusedWindowTokenByDisplay.end() ? it->second.second : nullptr; } -std::optional FocusResolver::getFocusRequest(int32_t displayId) { +std::optional FocusResolver::getFocusRequest(int32_t displayId) const { auto it = mFocusRequestByDisplay.find(displayId); return it != mFocusRequestByDisplay.end() ? std::make_optional<>(it->second) : std::nullopt; } diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h index 6d11a77aad..8a6dfa4ca9 100644 --- a/services/inputflinger/dispatcher/FocusResolver.h +++ b/services/inputflinger/dispatcher/FocusResolver.h @@ -62,6 +62,7 @@ public: std::optional setFocusedWindow( const android::gui::FocusRequest& request, const std::vector>& windows); + std::optional 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 updateFocusedWindow( int32_t displayId, const std::string& reason, const sp& token, const std::string& tokenName = ""); - std::optional getFocusRequest(int32_t displayId); }; } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index ff63967c2f..b52e3128db 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -659,6 +659,13 @@ void InputDispatcher::processNoFocusedWindowAnrLocked() { if (focusedWindowHandle != nullptr) { return; // We now have a focused window. No need for ANR. } + std::optional 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& 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 = 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) { if (connection == nullptr) { LOG_ALWAYS_FATAL("Caller must check for nullness"); diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index be619ae4c2..dc6dd5cdc0 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -658,6 +658,7 @@ private: void sendDropWindowCommandLocked(const sp& token, float x, float y) REQUIRES(mLock); void onAnrLocked(const sp& connection) REQUIRES(mLock); void onAnrLocked(std::shared_ptr application) REQUIRES(mLock); + bool onAnrLocked(const android::gui::FocusRequest& pendingFocusRequest) REQUIRES(mLock); void updateLastAnrStateLocked(const sp& window, const std::string& reason) REQUIRES(mLock); void updateLastAnrStateLocked(const InputApplicationHandle& application, diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 7ee6950b09..cd853a64e1 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -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)); -- cgit v1.2.3-59-g8ed1b