Eliminate potential reentrance from unregisterInputChannel.
Ensure that all callbacks into the window manager policy occur
on the input dispatcher thread in the right place. This fixes
a potential deadlock that may occur if the window manager
unregisters an input channel while holding its own lock.
The change is simply to defer running asynchronous commands
(usually callbacks into the policy) until the next iteration
of the dispatch looper thread.
Bug: 7382388
Change-Id: I90095580d717fcddb2209ef332df56400f837a34
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 7862e17..0465215 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -224,10 +224,16 @@
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
- dispatchOnceInnerLocked(&nextWakeupTime);
+ // Run a dispatch loop if there are no pending commands.
+ // The dispatch loop might enqueue commands to run afterwards.
+ if (!haveCommandsLocked()) {
+ dispatchOnceInnerLocked(&nextWakeupTime);
+ }
+ // Run all pending commands if there are any.
+ // If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) {
- nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
+ nextWakeupTime = LONG_LONG_MIN;
}
} // release lock
@@ -562,6 +568,10 @@
return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT;
}
+bool InputDispatcher::haveCommandsLocked() const {
+ return !mCommandQueue.isEmpty();
+}
+
bool InputDispatcher::runCommandsLockedInterruptible() {
if (mCommandQueue.isEmpty()) {
return false;
@@ -3247,9 +3257,10 @@
}
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
-
- runCommandsLockedInterruptible();
} // release lock
+
+ // Wake the looper because some connections have changed.
+ mLooper->wake();
return OK;
}
@@ -3294,8 +3305,6 @@
nsecs_t currentTime = now();
abortBrokenDispatchCycleLocked(currentTime, connection, notify);
- runCommandsLockedInterruptible();
-
connection->status = Connection::STATUS_ZOMBIE;
return OK;
}