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

Commit e41c4518 authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

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
parent 3982f0e9
Loading
Loading
Loading
Loading
+26 −18
Original line number Diff line number Diff line
@@ -364,6 +364,17 @@ const char* InputDispatcher::typeToString(InputDispatcher::FocusResult result) {
    }
}

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 @@ void InputDispatcher::setFocusedApplication(
        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.
        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 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
                                                 "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 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
                                         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());
+20 −0
Original line number Diff line number Diff line
@@ -2810,6 +2810,26 @@ TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
    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.