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

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

Add basic ANR test

To reduce the delta of the upcoming ANR refactor, add a basic ANR test
here. This will also help highlight the difference in behaviour from the
current code to the new code.

To cause an ANR today, the socket needs to be blocked, which means that
we need to send ~ 50 events to the unresponsive window.

These workarounds will be removed when the ANRs are refactored.

Bug: 143459140
Test: adb shell -t /data/nativetest64/inputflinger_tests/inputflinger_tests --gtest_filter="*InputDispatcherSingleWindowAnr*" --gtest_repeat=1000
--gtest_break_on_failure

Change-Id: I0a1b28c2785d03d8870691641e0f7c6b1ca3b85e
Merged-In: I0a1b28c2785d03d8870691641e0f7c6b1ca3b85e
parent 0b257105
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -61,6 +61,11 @@ public:
        return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
        return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
    }
    }


    inline std::chrono::nanoseconds getDispatchingTimeout(
            std::chrono::nanoseconds defaultValue) const {
        return mInfo.token ? std::chrono::nanoseconds(mInfo.dispatchingTimeout) : defaultValue;
    }

    inline sp<IBinder> getApplicationToken() const {
    inline sp<IBinder> getApplicationToken() const {
        return mInfo.token;
        return mInfo.token;
    }
    }
+5 −0
Original line number Original line Diff line number Diff line
@@ -222,6 +222,11 @@ public:
        return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
        return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
    }
    }


    inline std::chrono::nanoseconds getDispatchingTimeout(
            std::chrono::nanoseconds defaultValue) const {
        return mInfo.token ? std::chrono::nanoseconds(mInfo.dispatchingTimeout) : defaultValue;
    }

    /**
    /**
     * Requests that the state of this object be updated to reflect
     * Requests that the state of this object be updated to reflect
     * the most current available information about the application.
     * the most current available information about the application.
+6 −0
Original line number Original line Diff line number Diff line
@@ -102,6 +102,12 @@ EventEntry::~EventEntry() {
    releaseInjectionState();
    releaseInjectionState();
}
}


std::string EventEntry::getDescription() const {
    std::string result;
    appendDescription(result);
    return result;
}

void EventEntry::release() {
void EventEntry::release() {
    refCount -= 1;
    refCount -= 1;
    if (refCount == 0) {
    if (refCount == 0) {
+2 −0
Original line number Original line Diff line number Diff line
@@ -83,6 +83,8 @@ struct EventEntry {


    virtual void appendDescription(std::string& msg) const = 0;
    virtual void appendDescription(std::string& msg) const = 0;


    std::string getDescription() const;

protected:
protected:
    EventEntry(int32_t id, Type type, nsecs_t eventTime, uint32_t policyFlags);
    EventEntry(int32_t id, Type type, nsecs_t eventTime, uint32_t policyFlags);
    virtual ~EventEntry();
    virtual ~EventEntry();
+41 −40
Original line number Original line Diff line number Diff line
@@ -78,7 +78,7 @@ namespace android::inputdispatcher {


// Default input dispatching timeout if there is no focused application or paused window
// Default input dispatching timeout if there is no focused application or paused window
// from which to determine an appropriate dispatching timeout.
// from which to determine an appropriate dispatching timeout.
constexpr nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec
constexpr std::chrono::nanoseconds DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5s;


// Amount of time to allow for all pending events to be processed when an app switch
// Amount of time to allow for all pending events to be processed when an app switch
// key is on the way.  This is used to preempt input dispatch and drop input events
// key is on the way.  This is used to preempt input dispatch and drop input events
@@ -1295,11 +1295,9 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(
        }
        }
    } else {
    } else {
        if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
        if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
            if (DEBUG_FOCUS) {
            ALOGI("Waiting for application to become ready for input: %s.  Reason: %s",
                ALOGD("Waiting for application to become ready for input: %s.  Reason: %s",
                  getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), reason);
                  getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), reason);
            }
            std::chrono::nanoseconds timeout;
            nsecs_t timeout;
            if (windowHandle != nullptr) {
            if (windowHandle != nullptr) {
                timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
                timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
            } else if (applicationHandle != nullptr) {
            } else if (applicationHandle != nullptr) {
@@ -1311,7 +1309,7 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(


            mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
            mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
            mInputTargetWaitStartTime = currentTime;
            mInputTargetWaitStartTime = currentTime;
            mInputTargetWaitTimeoutTime = currentTime + timeout;
            mInputTargetWaitTimeoutTime = currentTime + timeout.count();
            mInputTargetWaitTimeoutExpired = false;
            mInputTargetWaitTimeoutExpired = false;
            mInputTargetWaitApplicationToken.clear();
            mInputTargetWaitApplicationToken.clear();


@@ -1353,10 +1351,10 @@ void InputDispatcher::removeWindowByTokenLocked(const sp<IBinder>& token) {
}
}


void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(
void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(
        nsecs_t newTimeout, const sp<IBinder>& inputConnectionToken) {
        nsecs_t timeoutExtension, const sp<IBinder>& inputConnectionToken) {
    if (newTimeout > 0) {
    if (timeoutExtension > 0) {
        // Extend the timeout.
        // Extend the timeout.
        mInputTargetWaitTimeoutTime = now() + newTimeout;
        mInputTargetWaitTimeoutTime = now() + timeoutExtension;
    } else {
    } else {
        // Give up.
        // Give up.
        mInputTargetWaitTimeoutExpired = true;
        mInputTargetWaitTimeoutExpired = true;
@@ -4048,11 +4046,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
            const int32_t displayId = it.first;
            const int32_t displayId = it.first;
            const sp<InputApplicationHandle>& applicationHandle = it.second;
            const sp<InputApplicationHandle>& applicationHandle = it.second;
            dump += StringPrintf(INDENT2 "displayId=%" PRId32
            dump += StringPrintf(INDENT2 "displayId=%" PRId32
                                         ", name='%s', dispatchingTimeout=%0.3fms\n",
                                         ", name='%s', dispatchingTimeout=%" PRId64 "ms\n",
                                 displayId, applicationHandle->getName().c_str(),
                                 displayId, applicationHandle->getName().c_str(),
                                 applicationHandle->getDispatchingTimeout(
                                 ns2ms(applicationHandle
                                         DEFAULT_INPUT_DISPATCHING_TIMEOUT) /
                                               ->getDispatchingTimeout(
                                         1000000.0);
                                                       DEFAULT_INPUT_DISPATCHING_TIMEOUT)
                                               .count()));
        }
        }
    } else {
    } else {
        dump += StringPrintf(INDENT "FocusedApplications: <none>\n");
        dump += StringPrintf(INDENT "FocusedApplications: <none>\n");
@@ -4132,9 +4131,10 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
                                         windowInfo->windowXScale, windowInfo->windowYScale);
                                         windowInfo->windowXScale, windowInfo->windowYScale);
                    dumpRegion(dump, windowInfo->touchableRegion);
                    dumpRegion(dump, windowInfo->touchableRegion);
                    dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
                    dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
                    dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
                    dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
                                         "ms\n",
                                         windowInfo->ownerPid, windowInfo->ownerUid,
                                         windowInfo->ownerPid, windowInfo->ownerUid,
                                         windowInfo->dispatchingTimeout / 1000000.0);
                                         ns2ms(windowInfo->dispatchingTimeout));
                }
                }
            } else {
            } else {
                dump += INDENT2 "Windows: <none>\n";
                dump += INDENT2 "Windows: <none>\n";
@@ -4167,7 +4167,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
        for (EventEntry* entry : mRecentQueue) {
        for (EventEntry* entry : mRecentQueue) {
            dump += INDENT2;
            dump += INDENT2;
            entry->appendDescription(dump);
            entry->appendDescription(dump);
            dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f);
            dump += StringPrintf(", age=%" PRId64 "ms\n", ns2ms(currentTime - entry->eventTime));
        }
        }
    } else {
    } else {
        dump += INDENT "RecentQueue: <empty>\n";
        dump += INDENT "RecentQueue: <empty>\n";
@@ -4178,8 +4178,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
        dump += INDENT "PendingEvent:\n";
        dump += INDENT "PendingEvent:\n";
        dump += INDENT2;
        dump += INDENT2;
        mPendingEvent->appendDescription(dump);
        mPendingEvent->appendDescription(dump);
        dump += StringPrintf(", age=%0.1fms\n",
        dump += StringPrintf(", age=%" PRId64 "ms\n",
                             (currentTime - mPendingEvent->eventTime) * 0.000001f);
                             ns2ms(currentTime - mPendingEvent->eventTime));
    } else {
    } else {
        dump += INDENT "PendingEvent: <none>\n";
        dump += INDENT "PendingEvent: <none>\n";
    }
    }
@@ -4190,7 +4190,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
        for (EventEntry* entry : mInboundQueue) {
        for (EventEntry* entry : mInboundQueue) {
            dump += INDENT2;
            dump += INDENT2;
            entry->appendDescription(dump);
            entry->appendDescription(dump);
            dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f);
            dump += StringPrintf(", age=%" PRId64 "ms\n", ns2ms(currentTime - entry->eventTime));
        }
        }
    } else {
    } else {
        dump += INDENT "InboundQueue: <empty>\n";
        dump += INDENT "InboundQueue: <empty>\n";
@@ -4225,9 +4225,10 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
                for (DispatchEntry* entry : connection->outboundQueue) {
                for (DispatchEntry* entry : connection->outboundQueue) {
                    dump.append(INDENT4);
                    dump.append(INDENT4);
                    entry->eventEntry->appendDescription(dump);
                    entry->eventEntry->appendDescription(dump);
                    dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n",
                    dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, age=%" PRId64
                                         "ms\n",
                                         entry->targetFlags, entry->resolvedAction,
                                         entry->targetFlags, entry->resolvedAction,
                                         (currentTime - entry->eventEntry->eventTime) * 0.000001f);
                                         ns2ms(currentTime - entry->eventEntry->eventTime));
                }
                }
            } else {
            } else {
                dump += INDENT3 "OutboundQueue: <empty>\n";
                dump += INDENT3 "OutboundQueue: <empty>\n";
@@ -4240,10 +4241,10 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
                    dump += INDENT4;
                    dump += INDENT4;
                    entry->eventEntry->appendDescription(dump);
                    entry->eventEntry->appendDescription(dump);
                    dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, "
                    dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, "
                                         "age=%0.1fms, wait=%0.1fms\n",
                                         "age=%" PRId64 "ms, wait=%" PRId64 "ms\n",
                                         entry->targetFlags, entry->resolvedAction,
                                         entry->targetFlags, entry->resolvedAction,
                                         (currentTime - entry->eventEntry->eventTime) * 0.000001f,
                                         ns2ms(currentTime - entry->eventEntry->eventTime),
                                         (currentTime - entry->deliveryTime) * 0.000001f);
                                         ns2ms(currentTime - entry->deliveryTime));
                }
                }
            } else {
            } else {
                dump += INDENT3 "WaitQueue: <empty>\n";
                dump += INDENT3 "WaitQueue: <empty>\n";
@@ -4254,16 +4255,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
    }
    }


    if (isAppSwitchPendingLocked()) {
    if (isAppSwitchPendingLocked()) {
        dump += StringPrintf(INDENT "AppSwitch: pending, due in %0.1fms\n",
        dump += StringPrintf(INDENT "AppSwitch: pending, due in %" PRId64 "ms\n",
                             (mAppSwitchDueTime - now()) / 1000000.0);
                             ns2ms(mAppSwitchDueTime - now()));
    } else {
    } else {
        dump += INDENT "AppSwitch: not pending\n";
        dump += INDENT "AppSwitch: not pending\n";
    }
    }


    dump += INDENT "Configuration:\n";
    dump += INDENT "Configuration:\n";
    dump += StringPrintf(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f);
    dump += StringPrintf(INDENT2 "KeyRepeatDelay: %" PRId64 "ms\n", ns2ms(mConfig.keyRepeatDelay));
    dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %0.1fms\n",
    dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %" PRId64 "ms\n",
                         mConfig.keyRepeatTimeout * 0.000001f);
                         ns2ms(mConfig.keyRepeatTimeout));
}
}


void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) {
void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) {
@@ -4365,8 +4366,7 @@ status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& i
        return BAD_VALUE;
        return BAD_VALUE;
    }
    }


    [[maybe_unused]] const bool removed = removeByValue(mConnectionsByFd, connection);
    removeConnectionLocked(connection);
    ALOG_ASSERT(removed);
    mInputChannelsByToken.erase(inputChannel->getConnectionToken());
    mInputChannelsByToken.erase(inputChannel->getConnectionToken());


    if (connection->monitor) {
    if (connection->monitor) {
@@ -4468,7 +4468,7 @@ std::optional<int32_t> InputDispatcher::findGestureMonitorDisplayByTokenLocked(
    return std::nullopt;
    return std::nullopt;
}
}


sp<Connection> InputDispatcher::getConnectionLocked(const sp<IBinder>& inputConnectionToken) {
sp<Connection> InputDispatcher::getConnectionLocked(const sp<IBinder>& inputConnectionToken) const {
    if (inputConnectionToken == nullptr) {
    if (inputConnectionToken == nullptr) {
        return nullptr;
        return nullptr;
    }
    }
@@ -4483,6 +4483,10 @@ sp<Connection> InputDispatcher::getConnectionLocked(const sp<IBinder>& inputConn
    return nullptr;
    return nullptr;
}
}


void InputDispatcher::removeConnectionLocked(const sp<Connection>& connection) {
    removeByValue(mConnectionsByFd, connection);
}

void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
                                                    const sp<Connection>& connection, uint32_t seq,
                                                    const sp<Connection>& connection, uint32_t seq,
                                                    bool handled) {
                                                    bool handled) {
@@ -4587,12 +4591,12 @@ void InputDispatcher::doNotifyAnrLockedInterruptible(CommandEntry* commandEntry)
            commandEntry->inputChannel ? commandEntry->inputChannel->getConnectionToken() : nullptr;
            commandEntry->inputChannel ? commandEntry->inputChannel->getConnectionToken() : nullptr;
    mLock.unlock();
    mLock.unlock();


    nsecs_t newTimeout =
    const nsecs_t timeoutExtension =
            mPolicy->notifyAnr(commandEntry->inputApplicationHandle, token, commandEntry->reason);
            mPolicy->notifyAnr(commandEntry->inputApplicationHandle, token, commandEntry->reason);


    mLock.lock();
    mLock.lock();


    resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, token);
    resumeAfterTargetsNotReadyTimeoutLocked(timeoutExtension, token);
}
}


void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
@@ -4647,11 +4651,8 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* c


    const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
    const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
    if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
    if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
        std::string msg =
        ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(),
                StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
              ns2ms(eventDuration), dispatchEntry->eventEntry->getDescription().c_str());
                             connection->getWindowName().c_str(), eventDuration * 0.000001f);
        dispatchEntry->eventEntry->appendDescription(msg);
        ALOGI("%s", msg.c_str());
    }
    }
    reportDispatchStatistics(std::chrono::nanoseconds(eventDuration), *connection, handled);
    reportDispatchStatistics(std::chrono::nanoseconds(eventDuration), *connection, handled);


Loading