Ensure setFocusedApplication resets no focused window timeout
If we are waiting for a focused window, the call to
'setFocusedApplication' should stop the wait.
Bug: 160561987
Test: adb shell -t /data/nativetest64/inputflinger_tests/inputflinger_tests --gtest_filter="*WhenFocusedApplicationChanges_NoAnr*" --gtest_repeat=10000
Change-Id: I14e13a9af20dd676e4f8e8584aa5d6948adb0d0d
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6460fe9..a10da66 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -364,6 +364,17 @@
}
}
+template <typename T>
+static bool sharedPointersEqual(const std::shared_ptr<T>& lhs, const std::shared_ptr<T>& rhs) {
+ if (lhs == nullptr && rhs == nullptr) {
+ return true;
+ }
+ if (lhs == nullptr || rhs == nullptr) {
+ return false;
+ }
+ return *lhs == *rhs;
+}
+
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -3885,31 +3896,26 @@
ALOGD("setFocusedApplication displayId=%" PRId32 " %s", displayId,
inputApplicationHandle ? inputApplicationHandle->getName().c_str() : "<nullptr>");
}
- if (inputApplicationHandle != nullptr &&
- inputApplicationHandle->getApplicationToken() != nullptr) {
- // acquire lock
+ { // acquire lock
std::scoped_lock _l(mLock);
std::shared_ptr<InputApplicationHandle> oldFocusedApplicationHandle =
getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
- // If oldFocusedApplicationHandle already exists
- if (oldFocusedApplicationHandle != nullptr) {
- // If a new focused application handle is different from the old one and
- // old focus application info is awaited focused application info.
- if (*oldFocusedApplicationHandle != *inputApplicationHandle &&
- mAwaitedFocusedApplication != nullptr &&
- *oldFocusedApplicationHandle == *mAwaitedFocusedApplication) {
- resetNoFocusedWindowTimeoutLocked();
- }
- // Erase the old application from container first
- mFocusedApplicationHandlesByDisplay.erase(displayId);
- // Should already get freed after removed from container but just double check.
- oldFocusedApplicationHandle.reset();
+ if (sharedPointersEqual(oldFocusedApplicationHandle, inputApplicationHandle)) {
+ return; // This application is already focused. No need to wake up or change anything.
}
// Set the new application handle.
- mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
+ if (inputApplicationHandle != nullptr) {
+ mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
+ } else {
+ mFocusedApplicationHandlesByDisplay.erase(displayId);
+ }
+
+ // No matter what the old focused application was, stop waiting on it because it is
+ // no longer focused.
+ resetNoFocusedWindowTimeoutLocked();
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
@@ -4234,6 +4240,7 @@
"hasWallpaper=%s, visible=%s, "
"flags=%s, type=0x%08x, "
"frame=[%d,%d][%d,%d], globalScale=%f, "
+ "applicationInfo=%s, "
"touchableRegion=",
i, windowInfo->name.c_str(), windowInfo->displayId,
windowInfo->portalToDisplayId,
@@ -4245,7 +4252,8 @@
static_cast<int32_t>(windowInfo->type),
windowInfo->frameLeft, windowInfo->frameTop,
windowInfo->frameRight, windowInfo->frameBottom,
- windowInfo->globalScaleFactor);
+ windowInfo->globalScaleFactor,
+ windowInfo->applicationInfo.name.c_str());
dumpRegion(dump, windowInfo->touchableRegion);
dump += StringPrintf(", inputFeatures=%s",
windowInfo->inputFeatures.string().c_str());
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 6e08e1b..ad6a602 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2810,6 +2810,26 @@
mFakePolicy->assertNotifyAnrWasNotCalled();
}
+TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
+ mWindow->setFocusable(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
+ mWindow->consumeFocusEvent(false);
+
+ int32_t result =
+ injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /*repeatCount*/, ADISPLAY_ID_DEFAULT,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 10ms /*injectionTimeout*/);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, result);
+ // Key will not go to window because we have no focused window.
+ // The 'no focused window' ANR timer should start instead.
+
+ // Now, the focused application goes away.
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, nullptr);
+ // The key should get dropped and there should be no ANR.
+
+ ASSERT_TRUE(mDispatcher->waitForIdle());
+ mFakePolicy->assertNotifyAnrWasNotCalled();
+}
+
// Send an event to the app and have the app not respond right away.
// When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
// So InputDispatcher will enqueue ACTION_CANCEL event as well.