From 074b8b7cf19d128f16e0de12bc2fc58e7438ec37 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Wed, 31 Oct 2012 19:01:31 -0700 Subject: [PATCH] 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 --- services/input/InputDispatcher.cpp | 21 +++++++++++++++------ services/input/InputDispatcher.h | 1 + 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 7862e172ea90f..0465215a8e8cb 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -224,10 +224,16 @@ void InputDispatcher::dispatchOnce() { 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 @@ bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) 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 @@ status_t InputDispatcher::registerInputChannel(const sp& inputChan } 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 @@ status_t InputDispatcher::unregisterInputChannelLocked(const sp& i nsecs_t currentTime = now(); abortBrokenDispatchCycleLocked(currentTime, connection, notify); - runCommandsLockedInterruptible(); - connection->status = Connection::STATUS_ZOMBIE; return OK; } diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 6099c43b3db73..d4f932eb9068b 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -899,6 +899,7 @@ private: KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime); // Deferred command processing. + bool haveCommandsLocked() const; bool runCommandsLockedInterruptible(); CommandEntry* postCommandLocked(Command command);