Split monitor and window ANR notification paths

Currently, both monitors and windows share the same ANR notification
paths. This means that InputManagerService must be the one to determine
whether the ANR event belongs to a monitor or to a window.

We previously kept track of this by recording the pid inside
InputManagerService. However, there seems to be a path where the gesture
monitor process dies that does not lead to a notification of the java
layer. This resulted in having multiple registered processes.

Now, we will rely on the native layer to manage the pid and to notify
the java layer appropriately.

Bug: 175593831
Test: atest inputflinger_tests
Change-Id: Ie1f7e976dcadcf07a83f78b3ca856b5c43096e2f
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 4e55872..887bdd4 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -55,12 +55,18 @@
         ALOGE("There is no focused window for %s", applicationHandle->getName().c_str());
     }
 
-    void notifyConnectionUnresponsive(const sp<IBinder>& connectionToken,
-                                      const std::string& reason) override {
-        ALOGE("Connection is not responding: %s", reason.c_str());
+    void notifyWindowUnresponsive(const sp<IBinder>& connectionToken,
+                                  const std::string& reason) override {
+        ALOGE("Window is not responding: %s", reason.c_str());
     }
 
-    void notifyConnectionResponsive(const sp<IBinder>& connectionToken) override {}
+    void notifyWindowResponsive(const sp<IBinder>& connectionToken) override {}
+
+    void notifyMonitorUnresponsive(int32_t pid, const std::string& reason) override {
+        ALOGE("Monitor is not responding: %s", reason.c_str());
+    }
+
+    void notifyMonitorResponsive(int32_t pid) override {}
 
     void notifyInputChannelBroken(const sp<IBinder>&) override {}
 
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 3a860f0..26b641d 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -271,6 +271,7 @@
     sp<IBinder> newToken;
     std::string obscuringPackage;
     bool enabled;
+    int32_t pid;
 };
 
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f3d969e..cf901e7 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -453,6 +453,20 @@
     return event;
 }
 
+static std::optional<int32_t> findMonitorPidByToken(
+        const std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay,
+        const sp<IBinder>& token) {
+    for (const auto& it : monitorsByDisplay) {
+        const std::vector<Monitor>& monitors = it.second;
+        for (const Monitor& monitor : monitors) {
+            if (monitor.inputChannel->getConnectionToken() == token) {
+                return monitor.pid;
+            }
+        }
+    }
+    return std::nullopt;
+}
+
 // --- InputDispatcher ---
 
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -615,7 +629,7 @@
     connection->responsive = false;
     // Stop waking up for this unresponsive connection
     mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
-    onAnrLocked(*connection);
+    onAnrLocked(connection);
     return LONG_LONG_MIN;
 }
 
@@ -5148,6 +5162,14 @@
     return std::nullopt;
 }
 
+std::optional<int32_t> InputDispatcher::findMonitorPidByTokenLocked(const sp<IBinder>& token) {
+    std::optional<int32_t> gesturePid = findMonitorPidByToken(mGestureMonitorsByDisplay, token);
+    if (gesturePid.has_value()) {
+        return gesturePid;
+    }
+    return findMonitorPidByToken(mGlobalMonitorsByDisplay, token);
+}
+
 sp<Connection> InputDispatcher::getConnectionLocked(const sp<IBinder>& inputConnectionToken) const {
     if (inputConnectionToken == nullptr) {
         return nullptr;
@@ -5208,12 +5230,15 @@
     postCommandLocked(std::move(commandEntry));
 }
 
-void InputDispatcher::onAnrLocked(const Connection& connection) {
+void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
+    if (connection == nullptr) {
+        LOG_ALWAYS_FATAL("Caller must check for nullness");
+    }
     // Since we are allowing the policy to extend the timeout, maybe the waitQueue
     // is already healthy again. Don't raise ANR in this situation
-    if (connection.waitQueue.empty()) {
+    if (connection->waitQueue.empty()) {
         ALOGI("Not raising ANR because the connection %s has recovered",
-              connection.inputChannel->getName().c_str());
+              connection->inputChannel->getName().c_str());
         return;
     }
     /**
@@ -5224,21 +5249,20 @@
      * processes the events linearly. So providing information about the oldest entry seems to be
      * most useful.
      */
-    DispatchEntry* oldestEntry = *connection.waitQueue.begin();
+    DispatchEntry* oldestEntry = *connection->waitQueue.begin();
     const nsecs_t currentWait = now() - oldestEntry->deliveryTime;
     std::string reason =
             android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
-                                        connection.inputChannel->getName().c_str(),
+                                        connection->inputChannel->getName().c_str(),
                                         ns2ms(currentWait),
                                         oldestEntry->eventEntry->getDescription().c_str());
-    sp<IBinder> connectionToken = connection.inputChannel->getConnectionToken();
+    sp<IBinder> connectionToken = connection->inputChannel->getConnectionToken();
     updateLastAnrStateLocked(getWindowHandleLocked(connectionToken), reason);
 
-    std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
-            &InputDispatcher::doNotifyConnectionUnresponsiveLockedInterruptible);
-    commandEntry->connectionToken = connectionToken;
-    commandEntry->reason = std::move(reason);
-    postCommandLocked(std::move(commandEntry));
+    processConnectionUnresponsiveLocked(*connection, std::move(reason));
+
+    // Stop waking up for events on this connection, it is already unresponsive
+    cancelEventsForAnrLocked(connection);
 }
 
 void InputDispatcher::onAnrLocked(std::shared_ptr<InputApplicationHandle> application) {
@@ -5323,26 +5347,34 @@
     mLock.lock();
 }
 
-void InputDispatcher::doNotifyConnectionUnresponsiveLockedInterruptible(
-        CommandEntry* commandEntry) {
+void InputDispatcher::doNotifyWindowUnresponsiveLockedInterruptible(CommandEntry* commandEntry) {
     mLock.unlock();
 
-    mPolicy->notifyConnectionUnresponsive(commandEntry->connectionToken, commandEntry->reason);
+    mPolicy->notifyWindowUnresponsive(commandEntry->connectionToken, commandEntry->reason);
 
     mLock.lock();
-
-    // stop waking up for events in this connection, it is already not responding
-    sp<Connection> connection = getConnectionLocked(commandEntry->connectionToken);
-    if (connection == nullptr) {
-        return;
-    }
-    cancelEventsForAnrLocked(connection);
 }
 
-void InputDispatcher::doNotifyConnectionResponsiveLockedInterruptible(CommandEntry* commandEntry) {
+void InputDispatcher::doNotifyMonitorUnresponsiveLockedInterruptible(CommandEntry* commandEntry) {
     mLock.unlock();
 
-    mPolicy->notifyConnectionResponsive(commandEntry->connectionToken);
+    mPolicy->notifyMonitorUnresponsive(commandEntry->pid, commandEntry->reason);
+
+    mLock.lock();
+}
+
+void InputDispatcher::doNotifyWindowResponsiveLockedInterruptible(CommandEntry* commandEntry) {
+    mLock.unlock();
+
+    mPolicy->notifyWindowResponsive(commandEntry->connectionToken);
+
+    mLock.lock();
+}
+
+void InputDispatcher::doNotifyMonitorResponsiveLockedInterruptible(CommandEntry* commandEntry) {
+    mLock.unlock();
+
+    mPolicy->notifyMonitorResponsive(commandEntry->pid);
 
     mLock.lock();
 }
@@ -5447,13 +5479,8 @@
         if (!connection->responsive) {
             connection->responsive = isConnectionResponsive(*connection);
             if (connection->responsive) {
-                // The connection was unresponsive, and now it's responsive. Tell the policy
-                // about it so that it can stop ANR.
-                std::unique_ptr<CommandEntry> connectionResponsiveCommand =
-                        std::make_unique<CommandEntry>(
-                                &InputDispatcher::doNotifyConnectionResponsiveLockedInterruptible);
-                connectionResponsiveCommand->connectionToken = connectionToken;
-                postCommandLocked(std::move(connectionResponsiveCommand));
+                // The connection was unresponsive, and now it's responsive.
+                processConnectionResponsiveLocked(*connection);
             }
         }
         traceWaitQueueLength(connection);
@@ -5469,6 +5496,82 @@
     startDispatchCycleLocked(now(), connection);
 }
 
+void InputDispatcher::sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) {
+    std::unique_ptr<CommandEntry> monitorUnresponsiveCommand = std::make_unique<CommandEntry>(
+            &InputDispatcher::doNotifyMonitorUnresponsiveLockedInterruptible);
+    monitorUnresponsiveCommand->pid = pid;
+    monitorUnresponsiveCommand->reason = std::move(reason);
+    postCommandLocked(std::move(monitorUnresponsiveCommand));
+}
+
+void InputDispatcher::sendWindowUnresponsiveCommandLocked(sp<IBinder> connectionToken,
+                                                          std::string reason) {
+    std::unique_ptr<CommandEntry> windowUnresponsiveCommand = std::make_unique<CommandEntry>(
+            &InputDispatcher::doNotifyWindowUnresponsiveLockedInterruptible);
+    windowUnresponsiveCommand->connectionToken = std::move(connectionToken);
+    windowUnresponsiveCommand->reason = std::move(reason);
+    postCommandLocked(std::move(windowUnresponsiveCommand));
+}
+
+void InputDispatcher::sendMonitorResponsiveCommandLocked(int32_t pid) {
+    std::unique_ptr<CommandEntry> monitorResponsiveCommand = std::make_unique<CommandEntry>(
+            &InputDispatcher::doNotifyMonitorResponsiveLockedInterruptible);
+    monitorResponsiveCommand->pid = pid;
+    postCommandLocked(std::move(monitorResponsiveCommand));
+}
+
+void InputDispatcher::sendWindowResponsiveCommandLocked(sp<IBinder> connectionToken) {
+    std::unique_ptr<CommandEntry> windowResponsiveCommand = std::make_unique<CommandEntry>(
+            &InputDispatcher::doNotifyWindowResponsiveLockedInterruptible);
+    windowResponsiveCommand->connectionToken = std::move(connectionToken);
+    postCommandLocked(std::move(windowResponsiveCommand));
+}
+
+/**
+ * Tell the policy that a connection has become unresponsive so that it can start ANR.
+ * Check whether the connection of interest is a monitor or a window, and add the corresponding
+ * command entry to the command queue.
+ */
+void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& connection,
+                                                          std::string reason) {
+    const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken();
+    if (connection.monitor) {
+        ALOGW("Monitor %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
+              reason.c_str());
+        std::optional<int32_t> pid = findMonitorPidByTokenLocked(connectionToken);
+        if (!pid.has_value()) {
+            ALOGE("Could not find unresponsive monitor for connection %s",
+                  connection.inputChannel->getName().c_str());
+            return;
+        }
+        sendMonitorUnresponsiveCommandLocked(pid.value(), std::move(reason));
+        return;
+    }
+    // If not a monitor, must be a window
+    ALOGW("Window %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
+          reason.c_str());
+    sendWindowUnresponsiveCommandLocked(connectionToken, std::move(reason));
+}
+
+/**
+ * Tell the policy that a connection has become responsive so that it can stop ANR.
+ */
+void InputDispatcher::processConnectionResponsiveLocked(const Connection& connection) {
+    const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken();
+    if (connection.monitor) {
+        std::optional<int32_t> pid = findMonitorPidByTokenLocked(connectionToken);
+        if (!pid.has_value()) {
+            ALOGE("Could not find responsive monitor for connection %s",
+                  connection.inputChannel->getName().c_str());
+            return;
+        }
+        sendMonitorResponsiveCommandLocked(pid.value());
+        return;
+    }
+    // If not a monitor, must be a window
+    sendWindowResponsiveCommandLocked(connectionToken);
+}
+
 bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
                                                        DispatchEntry* dispatchEntry,
                                                        KeyEntry& keyEntry, bool handled) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index df0be99..c7299e9 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -233,6 +233,8 @@
     // Finds the display ID of the gesture monitor identified by the provided token.
     std::optional<int32_t> findGestureMonitorDisplayByTokenLocked(const sp<IBinder>& token)
             REQUIRES(mLock);
+    // Find a monitor pid by the provided token.
+    std::optional<int32_t> findMonitorPidByTokenLocked(const sp<IBinder>& token) REQUIRES(mLock);
 
     // Input channels that will receive a copy of all input events sent to the provided display.
     std::unordered_map<int32_t, std::vector<Monitor>> mGlobalMonitorsByDisplay GUARDED_BY(mLock);
@@ -433,6 +435,34 @@
     void processNoFocusedWindowAnrLocked() REQUIRES(mLock);
 
     /**
+     * Tell policy about a window or a monitor that just became unresponsive. Starts ANR.
+     */
+    void processConnectionUnresponsiveLocked(const Connection& connection, std::string reason)
+            REQUIRES(mLock);
+    /**
+     * Tell policy about a window or a monitor that just became responsive.
+     */
+    void processConnectionResponsiveLocked(const Connection& connection) REQUIRES(mLock);
+
+    /**
+     * Post `doNotifyMonitorUnresponsiveLockedInterruptible` command.
+     */
+    void sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) REQUIRES(mLock);
+    /**
+     * Post `doNotifyWindowUnresponsiveLockedInterruptible` command.
+     */
+    void sendWindowUnresponsiveCommandLocked(sp<IBinder> connectionToken, std::string reason)
+            REQUIRES(mLock);
+    /**
+     * Post `doNotifyMonitorResponsiveLockedInterruptible` command.
+     */
+    void sendMonitorResponsiveCommandLocked(int32_t pid) REQUIRES(mLock);
+    /**
+     * Post `doNotifyWindowResponsiveLockedInterruptible` command.
+     */
+    void sendWindowResponsiveCommandLocked(sp<IBinder> connectionToken) REQUIRES(mLock);
+
+    /**
      * This map will store the pending focus requests that cannot be currently processed. This can
      * happen if the window requested to be focused is not currently visible. Such a window might
      * become visible later, and these requests would be processed at that time.
@@ -577,7 +607,7 @@
                               int32_t displayId, std::string_view reason) REQUIRES(mLock);
     void notifyFocusChangedLocked(const sp<IBinder>& oldFocus, const sp<IBinder>& newFocus)
             REQUIRES(mLock);
-    void onAnrLocked(const Connection& connection) REQUIRES(mLock);
+    void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
     void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock);
     void onUntrustedTouchLocked(const std::string& obscuringPackage) REQUIRES(mLock);
     void updateLastAnrStateLocked(const sp<InputWindowHandle>& window, const std::string& reason)
@@ -592,11 +622,13 @@
             REQUIRES(mLock);
     void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+    // ANR-related callbacks - start
     void doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
-    void doNotifyConnectionUnresponsiveLockedInterruptible(CommandEntry* commandEntry)
-            REQUIRES(mLock);
-    void doNotifyConnectionResponsiveLockedInterruptible(CommandEntry* commandEntry)
-            REQUIRES(mLock);
+    void doNotifyWindowUnresponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+    void doNotifyMonitorUnresponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+    void doNotifyWindowResponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+    void doNotifyMonitorResponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+    // ANR-related callbacks - end
     void doNotifySensorLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     void doNotifyUntrustedTouchLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry)
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index d9ec020..b976129 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -50,20 +50,31 @@
     virtual void notifyNoFocusedWindowAnr(
             const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) = 0;
 
-    /* Notifies the system that a connection just became unresponsive. This indicates that ANR
-     * should be raised for this connection. The connection is identified via token.
+    /* Notifies the system that a window just became unresponsive. This indicates that ANR
+     * should be raised for this window. The window is identified via token.
      * The string reason contains information about the input event that we haven't received
      * a response for.
      */
-    virtual void notifyConnectionUnresponsive(const sp<IBinder>& token,
-                                              const std::string& reason) = 0;
+    virtual void notifyWindowUnresponsive(const sp<IBinder>& token, const std::string& reason) = 0;
+    /* Notifies the system that a monitor just became unresponsive. This indicates that ANR
+     * should be raised for this monitor. The monitor is identified via its pid.
+     * The string reason contains information about the input event that we haven't received
+     * a response for.
+     */
+    virtual void notifyMonitorUnresponsive(int32_t pid, const std::string& reason) = 0;
 
-    /* Notifies the system that a connection just became responsive. This is only called after the
-     * connection was first marked "unresponsive". This indicates that ANR dialog (if any) should
-     * no longer should be shown to the user. The connection is eligible to cause a new ANR in the
+    /* Notifies the system that a window just became responsive. This is only called after the
+     * window was first marked "unresponsive". This indicates that ANR dialog (if any) should
+     * no longer should be shown to the user. The window is eligible to cause a new ANR in the
      * future.
      */
-    virtual void notifyConnectionResponsive(const sp<IBinder>& token) = 0;
+    virtual void notifyWindowResponsive(const sp<IBinder>& token) = 0;
+    /* Notifies the system that a monitor just became responsive. This is only called after the
+     * monitor was first marked "unresponsive". This indicates that ANR dialog (if any) should
+     * no longer should be shown to the user. The monitor is eligible to cause a new ANR in the
+     * future.
+     */
+    virtual void notifyMonitorResponsive(int32_t pid) = 0;
 
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 6dbc88f..9181c1c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -140,27 +140,49 @@
         ASSERT_EQ(expectedApplication, application);
     }
 
-    void assertNotifyConnectionUnresponsiveWasCalled(std::chrono::nanoseconds timeout,
-                                                     const sp<IBinder>& expectedConnectionToken) {
-        sp<IBinder> connectionToken = getUnresponsiveConnectionToken(timeout);
+    void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout,
+                                                 const sp<IBinder>& expectedConnectionToken) {
+        sp<IBinder> connectionToken = getUnresponsiveWindowToken(timeout);
         ASSERT_EQ(expectedConnectionToken, connectionToken);
     }
 
-    void assertNotifyConnectionResponsiveWasCalled(const sp<IBinder>& expectedConnectionToken) {
-        sp<IBinder> connectionToken = getResponsiveConnectionToken();
+    void assertNotifyWindowResponsiveWasCalled(const sp<IBinder>& expectedConnectionToken) {
+        sp<IBinder> connectionToken = getResponsiveWindowToken();
         ASSERT_EQ(expectedConnectionToken, connectionToken);
     }
 
-    sp<IBinder> getUnresponsiveConnectionToken(std::chrono::nanoseconds timeout) {
-        std::unique_lock lock(mLock);
-        android::base::ScopedLockAssertion assumeLocked(mLock);
-        return getAnrTokenLockedInterruptible(timeout, mAnrConnectionTokens, lock);
+    void assertNotifyMonitorUnresponsiveWasCalled(std::chrono::nanoseconds timeout) {
+        int32_t pid = getUnresponsiveMonitorPid(timeout);
+        ASSERT_EQ(MONITOR_PID, pid);
     }
 
-    sp<IBinder> getResponsiveConnectionToken() {
+    void assertNotifyMonitorResponsiveWasCalled() {
+        int32_t pid = getResponsiveMonitorPid();
+        ASSERT_EQ(MONITOR_PID, pid);
+    }
+
+    sp<IBinder> getUnresponsiveWindowToken(std::chrono::nanoseconds timeout) {
         std::unique_lock lock(mLock);
         android::base::ScopedLockAssertion assumeLocked(mLock);
-        return getAnrTokenLockedInterruptible(0s, mResponsiveConnectionTokens, lock);
+        return getAnrTokenLockedInterruptible(timeout, mAnrWindowTokens, lock);
+    }
+
+    sp<IBinder> getResponsiveWindowToken() {
+        std::unique_lock lock(mLock);
+        android::base::ScopedLockAssertion assumeLocked(mLock);
+        return getAnrTokenLockedInterruptible(0s, mResponsiveWindowTokens, lock);
+    }
+
+    int32_t getUnresponsiveMonitorPid(std::chrono::nanoseconds timeout) {
+        std::unique_lock lock(mLock);
+        android::base::ScopedLockAssertion assumeLocked(mLock);
+        return getAnrTokenLockedInterruptible(timeout, mAnrMonitorPids, lock);
+    }
+
+    int32_t getResponsiveMonitorPid() {
+        std::unique_lock lock(mLock);
+        android::base::ScopedLockAssertion assumeLocked(mLock);
+        return getAnrTokenLockedInterruptible(0s, mResponsiveMonitorPids, lock);
     }
 
     // All three ANR-related callbacks behave the same way, so we use this generic function to wait
@@ -182,7 +204,7 @@
         const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
         if (storage.empty()) {
             ADD_FAILURE() << "Did not receive the ANR callback";
-            return nullptr;
+            return {};
         }
         // Ensure that the ANR didn't get raised too early. We can't be too strict here because
         // the dispatcher started counting before this function was called
@@ -201,10 +223,14 @@
     void assertNotifyAnrWasNotCalled() {
         std::scoped_lock lock(mLock);
         ASSERT_TRUE(mAnrApplications.empty());
-        ASSERT_TRUE(mAnrConnectionTokens.empty());
-        ASSERT_TRUE(mResponsiveConnectionTokens.empty())
+        ASSERT_TRUE(mAnrWindowTokens.empty());
+        ASSERT_TRUE(mAnrMonitorPids.empty());
+        ASSERT_TRUE(mResponsiveWindowTokens.empty())
                 << "ANR was not called, but please also consume the 'connection is responsive' "
                    "signal";
+        ASSERT_TRUE(mResponsiveMonitorPids.empty())
+                << "Monitor ANR was not called, but please also consume the 'monitor is responsive'"
+                   " signal";
     }
 
     void setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) {
@@ -251,8 +277,10 @@
 
     // ANR handling
     std::queue<std::shared_ptr<InputApplicationHandle>> mAnrApplications GUARDED_BY(mLock);
-    std::queue<sp<IBinder>> mAnrConnectionTokens GUARDED_BY(mLock);
-    std::queue<sp<IBinder>> mResponsiveConnectionTokens GUARDED_BY(mLock);
+    std::queue<sp<IBinder>> mAnrWindowTokens GUARDED_BY(mLock);
+    std::queue<sp<IBinder>> mResponsiveWindowTokens GUARDED_BY(mLock);
+    std::queue<int32_t> mAnrMonitorPids GUARDED_BY(mLock);
+    std::queue<int32_t> mResponsiveMonitorPids GUARDED_BY(mLock);
     std::condition_variable mNotifyAnr;
 
     void notifyConfigurationChanged(nsecs_t when) override {
@@ -260,16 +288,27 @@
         mConfigurationChangedTime = when;
     }
 
-    void notifyConnectionUnresponsive(const sp<IBinder>& connectionToken,
-                                      const std::string&) override {
+    void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, const std::string&) override {
         std::scoped_lock lock(mLock);
-        mAnrConnectionTokens.push(connectionToken);
+        mAnrWindowTokens.push(connectionToken);
         mNotifyAnr.notify_all();
     }
 
-    void notifyConnectionResponsive(const sp<IBinder>& connectionToken) override {
+    void notifyMonitorUnresponsive(int32_t pid, const std::string&) override {
         std::scoped_lock lock(mLock);
-        mResponsiveConnectionTokens.push(connectionToken);
+        mAnrMonitorPids.push(pid);
+        mNotifyAnr.notify_all();
+    }
+
+    void notifyWindowResponsive(const sp<IBinder>& connectionToken) override {
+        std::scoped_lock lock(mLock);
+        mResponsiveWindowTokens.push(connectionToken);
+        mNotifyAnr.notify_all();
+    }
+
+    void notifyMonitorResponsive(int32_t pid) override {
+        std::scoped_lock lock(mLock);
+        mResponsiveMonitorPids.push(pid);
         mNotifyAnr.notify_all();
     }
 
@@ -1962,11 +2001,10 @@
     std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
     ASSERT_TRUE(consumeSeq);
 
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(DISPATCHING_TIMEOUT,
-                                                             monitor.getToken());
+    mFakePolicy->assertNotifyMonitorUnresponsiveWasCalled(DISPATCHING_TIMEOUT);
     monitor.finishEvent(*consumeSeq);
     ASSERT_TRUE(mDispatcher->waitForIdle());
-    mFakePolicy->assertNotifyConnectionResponsiveWasCalled(monitor.getToken());
+    mFakePolicy->assertNotifyMonitorResponsiveWasCalled();
 }
 
 TEST_F(InputDispatcherTest, TestMoveEvent) {
@@ -3194,13 +3232,13 @@
     std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN
     ASSERT_TRUE(sequenceNum);
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
 
     mWindow->finishEvent(*sequenceNum);
     mWindow->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL,
                           ADISPLAY_ID_DEFAULT, 0 /*flags*/);
     ASSERT_TRUE(mDispatcher->waitForIdle());
-    mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
 }
 
 // Send a key to the app and have the app not respond right away.
@@ -3210,7 +3248,7 @@
     std::optional<uint32_t> sequenceNum = mWindow->receiveEvent();
     ASSERT_TRUE(sequenceNum);
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
     ASSERT_TRUE(mDispatcher->waitForIdle());
 }
 
@@ -3315,7 +3353,7 @@
     // We have now sent down and up. Let's consume first event and then ANR on the second.
     mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
 }
 
 // If an app is not responding to a key event, gesture monitors should continue to receive
@@ -3332,7 +3370,7 @@
 
     // Stuck on the ACTION_UP
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
 
     // New tap will go to the gesture monitor, but not to the window
     tapOnWindow();
@@ -3341,7 +3379,7 @@
 
     mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
     mDispatcher->waitForIdle();
-    mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
     mWindow->assertNoEvents();
     monitor.assertNoEvents();
 }
@@ -3360,7 +3398,7 @@
     mWindow->consumeMotionDown();
     // Stuck on the ACTION_UP
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
 
     // New tap will go to the gesture monitor, but not to the window
     tapOnWindow();
@@ -3369,7 +3407,7 @@
 
     mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
     mDispatcher->waitForIdle();
-    mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
     mWindow->assertNoEvents();
     monitor.assertNoEvents();
 }
@@ -3386,19 +3424,19 @@
     mWindow->consumeMotionDown();
     // Block on ACTION_UP
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
     mWindow->consumeMotionUp(); // Now the connection should be healthy again
     mDispatcher->waitForIdle();
-    mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
     mWindow->assertNoEvents();
 
     tapOnWindow();
     mWindow->consumeMotionDown();
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
     mWindow->consumeMotionUp();
 
     mDispatcher->waitForIdle();
-    mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
     mFakePolicy->assertNotifyAnrWasNotCalled();
     mWindow->assertNoEvents();
 }
@@ -3411,7 +3449,7 @@
                                WINDOW_LOCATION));
 
     const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(windowTimeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow->getToken());
     std::this_thread::sleep_for(windowTimeout);
     // 'notifyConnectionUnresponsive' should only be called once per connection
     mFakePolicy->assertNotifyAnrWasNotCalled();
@@ -3421,7 +3459,7 @@
                           ADISPLAY_ID_DEFAULT, 0 /*flags*/);
     mWindow->assertNoEvents();
     mDispatcher->waitForIdle();
-    mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
     mFakePolicy->assertNotifyAnrWasNotCalled();
 }
 
@@ -3589,7 +3627,7 @@
 
     const std::chrono::duration timeout =
             mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
     // Because we injected two DOWN events in a row, CANCEL is enqueued for the first event
     // sequence to make it consistent
     mFocusedWindow->consumeMotionCancel();
@@ -3600,7 +3638,7 @@
     mFocusedWindow->assertNoEvents();
     mUnfocusedWindow->assertNoEvents();
     ASSERT_TRUE(mDispatcher->waitForIdle());
-    mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken());
     mFakePolicy->assertNotifyAnrWasNotCalled();
 }
 
@@ -3614,8 +3652,8 @@
 
     tapOnFocusedWindow();
     // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
-    sp<IBinder> anrConnectionToken1 = mFakePolicy->getUnresponsiveConnectionToken(10ms);
-    sp<IBinder> anrConnectionToken2 = mFakePolicy->getUnresponsiveConnectionToken(0ms);
+    sp<IBinder> anrConnectionToken1 = mFakePolicy->getUnresponsiveWindowToken(10ms);
+    sp<IBinder> anrConnectionToken2 = mFakePolicy->getUnresponsiveWindowToken(0ms);
 
     // We don't know which window will ANR first. But both of them should happen eventually.
     ASSERT_TRUE(mFocusedWindow->getToken() == anrConnectionToken1 ||
@@ -3630,8 +3668,8 @@
     mFocusedWindow->consumeMotionUp();
     mUnfocusedWindow->consumeMotionOutside();
 
-    sp<IBinder> responsiveToken1 = mFakePolicy->getResponsiveConnectionToken();
-    sp<IBinder> responsiveToken2 = mFakePolicy->getResponsiveConnectionToken();
+    sp<IBinder> responsiveToken1 = mFakePolicy->getResponsiveWindowToken();
+    sp<IBinder> responsiveToken2 = mFakePolicy->getResponsiveWindowToken();
 
     // Both applications should be marked as responsive, in any order
     ASSERT_TRUE(mFocusedWindow->getToken() == responsiveToken1 ||
@@ -3655,7 +3693,7 @@
     ASSERT_TRUE(upEventSequenceNum);
     const std::chrono::duration timeout =
             mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
 
     // Tap once again
     // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
@@ -3676,7 +3714,7 @@
     // The second tap did not go to the focused window
     mFocusedWindow->assertNoEvents();
     // Since all events are finished, connection should be deemed healthy again
-    mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken());
     mFakePolicy->assertNotifyAnrWasNotCalled();
 }
 
@@ -3788,7 +3826,7 @@
 
     const std::chrono::duration timeout =
             mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
 
     mUnfocusedWindow->consumeMotionDown();
     mFocusedWindow->consumeMotionDown();
@@ -3807,7 +3845,7 @@
         ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
     }
     ASSERT_TRUE(mDispatcher->waitForIdle());
-    mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken());
 
     mUnfocusedWindow->assertNoEvents();
     mFocusedWindow->assertNoEvents();