More work in progress on native events.
Refactored the code to eliminate potential deadlocks due to re-entrant
calls from the policy into the dispatcher. Also added some plumbing
that will be used to notify the framework about ANRs.
Change-Id: Iba7a10de0cb3c56cd7520d6ce716db52fdcc94ff
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 0ccde0d..f058271 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -19,6 +19,9 @@
// Log debug messages about the dispatch cycle.
#define DEBUG_DISPATCH_CYCLE 1
+// Log debug messages about registrations.
+#define DEBUG_REGISTRATION 1
+
// Log debug messages about performance statistics.
#define DEBUG_PERFORMANCE_STATISTICS 1
@@ -42,7 +45,7 @@
// --- InputDispatcher ---
-InputDispatcher::InputDispatcher(const sp<InputDispatchPolicyInterface>& policy) :
+InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy) {
mPollLoop = new PollLoop();
@@ -55,6 +58,8 @@
mInboundQueue.tail.eventTime = LONG_LONG_MAX;
mKeyRepeatState.lastKeyEntry = NULL;
+
+ mCurrentInputTargetsValid = false;
}
InputDispatcher::~InputDispatcher() {
@@ -72,8 +77,9 @@
}
void InputDispatcher::dispatchOnce() {
- bool allowKeyRepeat = mPolicy->allowKeyRepeat();
+ nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
+ bool skipPoll = false;
nsecs_t currentTime;
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
@@ -84,7 +90,7 @@
// is not a key. This is to ensure that we abort a key repeat if the device is just coming
// out of sleep.
// XXX we should handle resetting input state coming out of sleep more generally elsewhere
- if (! allowKeyRepeat) {
+ if (keyRepeatTimeout < 0) {
resetKeyRepeatLocked();
}
@@ -121,8 +127,8 @@
if (mInboundQueue.isEmpty()) {
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
- processKeyRepeatLocked(currentTime);
- return; // dispatched once
+ processKeyRepeatLockedInterruptible(currentTime, keyRepeatTimeout);
+ skipPoll = true;
} else {
if (mKeyRepeatState.nextRepeatTime < nextWakeupTime) {
nextWakeupTime = mKeyRepeatState.nextRepeatTime;
@@ -130,31 +136,30 @@
}
}
} else {
- // Inbound queue has at least one entry. Dequeue it and begin dispatching.
- // Note that we do not hold the lock for this process because dispatching may
- // involve making many callbacks.
- EventEntry* entry = mInboundQueue.dequeueAtHead();
+ // Inbound queue has at least one entry.
+ // Start processing it but leave it on the queue until later so that the
+ // input reader can keep appending samples onto a motion event between the
+ // time we started processing it and the time we finally enqueue dispatch
+ // entries for it.
+ EventEntry* entry = mInboundQueue.head.next;
switch (entry->type) {
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
ConfigurationChangedEntry* typedEntry =
static_cast<ConfigurationChangedEntry*>(entry);
- processConfigurationChangedLocked(currentTime, typedEntry);
- mAllocator.releaseConfigurationChangedEntry(typedEntry);
+ processConfigurationChangedLockedInterruptible(currentTime, typedEntry);
break;
}
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(entry);
- processKeyLocked(currentTime, typedEntry);
- mAllocator.releaseKeyEntry(typedEntry);
+ processKeyLockedInterruptible(currentTime, typedEntry, keyRepeatTimeout);
break;
}
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(entry);
- processMotionLocked(currentTime, typedEntry);
- mAllocator.releaseMotionEntry(typedEntry);
+ processMotionLockedInterruptible(currentTime, typedEntry);
break;
}
@@ -162,30 +167,67 @@
assert(false);
break;
}
- return; // dispatched once
+
+ // Dequeue and release the event entry that we just processed.
+ mInboundQueue.dequeue(entry);
+ mAllocator.releaseEventEntry(entry);
+ skipPoll = true;
}
}
+
+ // Run any deferred commands.
+ skipPoll |= runCommandsLockedInterruptible();
} // release lock
+ // If we dispatched anything, don't poll just now. Wait for the next iteration.
+ // Contents may have shifted during flight.
+ if (skipPoll) {
+ return;
+ }
+
// Wait for callback or timeout or wake.
nsecs_t timeout = nanoseconds_to_milliseconds(nextWakeupTime - currentTime);
int32_t timeoutMillis = timeout > INT_MAX ? -1 : timeout > 0 ? int32_t(timeout) : 0;
mPollLoop->pollOnce(timeoutMillis);
}
-void InputDispatcher::processConfigurationChangedLocked(nsecs_t currentTime,
- ConfigurationChangedEntry* entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- LOGD("processConfigurationChanged - eventTime=%lld, touchScreenConfig=%d, "
- "keyboardConfig=%d, navigationConfig=%d", entry->eventTime,
- entry->touchScreenConfig, entry->keyboardConfig, entry->navigationConfig);
-#endif
+bool InputDispatcher::runCommandsLockedInterruptible() {
+ if (mCommandQueue.isEmpty()) {
+ return false;
+ }
- mPolicy->notifyConfigurationChanged(entry->eventTime, entry->touchScreenConfig,
- entry->keyboardConfig, entry->navigationConfig);
+ do {
+ CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
+
+ Command command = commandEntry->command;
+ (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
+
+ mAllocator.releaseCommandEntry(commandEntry);
+ } while (! mCommandQueue.isEmpty());
+ return true;
}
-void InputDispatcher::processKeyLocked(nsecs_t currentTime, KeyEntry* entry) {
+InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
+ CommandEntry* commandEntry = mAllocator.obtainCommandEntry(command);
+ mCommandQueue.enqueueAtTail(commandEntry);
+ return commandEntry;
+}
+
+void InputDispatcher::processConfigurationChangedLockedInterruptible(
+ nsecs_t currentTime, ConfigurationChangedEntry* entry) {
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ LOGD("processConfigurationChanged - eventTime=%lld", entry->eventTime);
+#endif
+
+ mLock.unlock();
+
+ mPolicy->notifyConfigurationChanged(entry->eventTime);
+
+ mLock.lock();
+}
+
+void InputDispatcher::processKeyLockedInterruptible(
+ nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
LOGD("processKey - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, "
"flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
@@ -209,7 +251,7 @@
} else {
// Not a repeat. Save key down state in case we do see a repeat later.
resetKeyRepeatLocked();
- mKeyRepeatState.nextRepeatTime = entry->eventTime + mPolicy->getKeyRepeatTimeout();
+ mKeyRepeatState.nextRepeatTime = entry->eventTime + keyRepeatTimeout;
}
mKeyRepeatState.lastKeyEntry = entry;
entry->refCount += 1;
@@ -217,10 +259,11 @@
resetKeyRepeatLocked();
}
- identifyInputTargetsAndDispatchKeyLocked(currentTime, entry);
+ identifyInputTargetsAndDispatchKeyLockedInterruptible(currentTime, entry);
}
-void InputDispatcher::processKeyRepeatLocked(nsecs_t currentTime) {
+void InputDispatcher::processKeyRepeatLockedInterruptible(
+ nsecs_t currentTime, nsecs_t keyRepeatTimeout) {
// TODO Old WindowManagerServer code sniffs the input queue for following key up
// events and drops the repeat if one is found. We should do something similar.
// One good place to do it is in notifyKey as soon as the key up enters the
@@ -252,7 +295,7 @@
entry->downTime = currentTime;
entry->policyFlags = 0;
- mKeyRepeatState.nextRepeatTime = currentTime + mPolicy->getKeyRepeatTimeout();
+ mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatTimeout;
#if DEBUG_OUTBOUND_EVENT_DETAILS
LOGD("processKeyRepeat - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, "
@@ -263,10 +306,11 @@
entry->repeatCount, entry->downTime);
#endif
- identifyInputTargetsAndDispatchKeyLocked(currentTime, entry);
+ identifyInputTargetsAndDispatchKeyLockedInterruptible(currentTime, entry);
}
-void InputDispatcher::processMotionLocked(nsecs_t currentTime, MotionEntry* entry) {
+void InputDispatcher::processMotionLockedInterruptible(
+ nsecs_t currentTime, MotionEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
LOGD("processMotion - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, "
"metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
@@ -296,15 +340,19 @@
}
#endif
- identifyInputTargetsAndDispatchMotionLocked(currentTime, entry);
+ identifyInputTargetsAndDispatchMotionLockedInterruptible(currentTime, entry);
}
-void InputDispatcher::identifyInputTargetsAndDispatchKeyLocked(
+void InputDispatcher::identifyInputTargetsAndDispatchKeyLockedInterruptible(
nsecs_t currentTime, KeyEntry* entry) {
#if DEBUG_DISPATCH_CYCLE
LOGD("identifyInputTargetsAndDispatchKey");
#endif
+ entry->dispatchInProgress = true;
+ mCurrentInputTargetsValid = false;
+ mLock.unlock();
+
mReusableKeyEvent.initialize(entry->deviceId, entry->nature, entry->action, entry->flags,
entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
entry->downTime, entry->eventTime);
@@ -313,15 +361,22 @@
mPolicy->getKeyEventTargets(& mReusableKeyEvent, entry->policyFlags,
mCurrentInputTargets);
+ mLock.lock();
+ mCurrentInputTargetsValid = true;
+
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
}
-void InputDispatcher::identifyInputTargetsAndDispatchMotionLocked(
+void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
nsecs_t currentTime, MotionEntry* entry) {
#if DEBUG_DISPATCH_CYCLE
LOGD("identifyInputTargetsAndDispatchMotion");
#endif
+ entry->dispatchInProgress = true;
+ mCurrentInputTargetsValid = false;
+ mLock.unlock();
+
mReusableMotionEvent.initialize(entry->deviceId, entry->nature, entry->action,
entry->edgeFlags, entry->metaState,
entry->firstSample.pointerCoords[0].x, entry->firstSample.pointerCoords[0].y,
@@ -333,17 +388,22 @@
mPolicy->getMotionEventTargets(& mReusableMotionEvent, entry->policyFlags,
mCurrentInputTargets);
+ mLock.lock();
+ mCurrentInputTargetsValid = true;
+
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
}
void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("dispatchEventToCurrentInputTargets, "
+ LOGD("dispatchEventToCurrentInputTargets - "
"resumeWithAppendedMotionSample=%s",
resumeWithAppendedMotionSample ? "true" : "false");
#endif
+ assert(eventEntry->dispatchInProgress); // should already have been set to true
+
for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
@@ -365,7 +425,7 @@
EventEntry* eventEntry, const InputTarget* inputTarget,
bool resumeWithAppendedMotionSample) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ prepareDispatchCycle, flags=%d, timeout=%lldns, "
+ LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, timeout=%lldns, "
"xOffset=%f, yOffset=%f, resumeWithAppendedMotionSample=%s",
connection->getInputChannelName(), inputTarget->flags, inputTarget->timeout,
inputTarget->xOffset, inputTarget->yOffset,
@@ -377,7 +437,7 @@
// not responding.
if (connection->status != Connection::STATUS_NORMAL) {
LOGV("channel '%s' ~ Dropping event because the channel status is %s",
- connection->status == Connection::STATUS_BROKEN ? "BROKEN" : "NOT RESPONDING");
+ connection->getStatusLabel());
return;
}
@@ -631,14 +691,15 @@
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, Connection* connection) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ finishDispatchCycle: %01.1fms since event, "
+ LOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, "
"%01.1fms since dispatch",
connection->getInputChannelName(),
connection->getEventLatencyMillis(currentTime),
connection->getDispatchLatencyMillis(currentTime));
#endif
- if (connection->status == Connection::STATUS_BROKEN) {
+ if (connection->status == Connection::STATUS_BROKEN
+ || connection->status == Connection::STATUS_ZOMBIE) {
return;
}
@@ -722,34 +783,37 @@
bool InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime, Connection* connection,
bool broken) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ abortDispatchCycle, broken=%s",
+ LOGD("channel '%s' ~ abortDispatchCycle - broken=%s",
connection->getInputChannelName(), broken ? "true" : "false");
#endif
- if (connection->status == Connection::STATUS_BROKEN) {
- return false;
- }
-
// Clear the pending timeout.
connection->nextTimeoutTime = LONG_LONG_MAX;
// Clear the outbound queue.
- while (! connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
- mAllocator.releaseDispatchEntry(dispatchEntry);
- }
+ bool deactivated = ! connection->outboundQueue.isEmpty();
+ if (deactivated) {
+ do {
+ DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
+ mAllocator.releaseDispatchEntry(dispatchEntry);
+ } while (! connection->outboundQueue.isEmpty());
- // Outbound queue is empty, deactivate the connection.
- deactivateConnectionLocked(connection);
+ deactivateConnectionLocked(connection);
+ }
// Handle the case where the connection appears to be unrecoverably broken.
+ // Ignore already broken or zombie connections.
if (broken) {
- connection->status = Connection::STATUS_BROKEN;
+ if (connection->status == Connection::STATUS_NORMAL
+ || connection->status == Connection::STATUS_NOT_RESPONDING) {
+ connection->status = Connection::STATUS_BROKEN;
- // Notify other system components.
- onDispatchCycleBrokenLocked(currentTime, connection);
+ // Notify other system components.
+ onDispatchCycleBrokenLocked(currentTime, connection);
+ }
}
- return true; /*deactivated*/
+
+ return deactivated;
}
bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
@@ -772,6 +836,7 @@
LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. "
"events=0x%x", connection->getInputChannelName(), events);
d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
+ d->runCommandsLockedInterruptible();
return false; // remove the callback
}
@@ -786,20 +851,19 @@
LOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
connection->getInputChannelName(), status);
d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
+ d->runCommandsLockedInterruptible();
return false; // remove the callback
}
d->finishDispatchCycleLocked(currentTime, connection.get());
+ d->runCommandsLockedInterruptible();
return true;
} // release lock
}
-void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime, int32_t touchScreenConfig,
- int32_t keyboardConfig, int32_t navigationConfig) {
+void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime) {
#if DEBUG_INBOUND_EVENT_DETAILS
- LOGD("notifyConfigurationChanged - eventTime=%lld, touchScreenConfig=%d, "
- "keyboardConfig=%d, navigationConfig=%d", eventTime,
- touchScreenConfig, keyboardConfig, navigationConfig);
+ LOGD("notifyConfigurationChanged - eventTime=%lld", eventTime);
#endif
bool wasEmpty;
@@ -808,9 +872,6 @@
ConfigurationChangedEntry* newEntry = mAllocator.obtainConfigurationChangedEntry();
newEntry->eventTime = eventTime;
- newEntry->touchScreenConfig = touchScreenConfig;
- newEntry->keyboardConfig = keyboardConfig;
- newEntry->navigationConfig = navigationConfig;
wasEmpty = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(newEntry);
@@ -821,16 +882,6 @@
}
}
-void InputDispatcher::notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- LOGD("notifyLidSwitchChanged - eventTime=%lld, open=%s", eventTime,
- lidOpen ? "true" : "false");
-#endif
-
- // Send lid switch notification immediately and synchronously.
- mPolicy->notifyLidSwitchChanged(eventTime, lidOpen);
-}
-
void InputDispatcher::notifyAppSwitchComing(nsecs_t eventTime) {
#if DEBUG_INBOUND_EVENT_DETAILS
LOGD("notifyAppSwitchComing - eventTime=%lld", eventTime);
@@ -949,13 +1000,25 @@
}
// The last motion event is a move and is compatible for appending.
- // Do the batching magic and exit.
+ // Do the batching magic.
mAllocator.appendMotionSample(motionEntry, eventTime, pointerCount, pointerCoords);
#if DEBUG_BATCHING
LOGD("Appended motion sample onto batch for most recent "
"motion event for this device in the inbound queue.");
#endif
- return; // done
+
+ // Sanity check for special case because dispatch is interruptible.
+ // The dispatch logic is partially interruptible and releases its lock while
+ // identifying targets. However, as soon as the targets have been identified,
+ // the dispatcher proceeds to write a dispatch entry into all relevant outbound
+ // queues and then promptly removes the motion entry from the queue.
+ //
+ // Consequently, we should never observe the case where the inbound queue contains
+ // an in-progress motion entry unless the current input targets are invalid
+ // (currently being computed). Check for this!
+ assert(! (motionEntry->dispatchInProgress && mCurrentInputTargetsValid));
+
+ return; // done!
}
// STREAMING CASE
@@ -977,34 +1040,38 @@
// Note: This code crucially depends on the invariant that an outbound queue always
// contains at most one synchronous event and it is always last (but it might
// not be first!).
- for (size_t i = 0; i < mActiveConnections.size(); i++) {
- Connection* connection = mActiveConnections.itemAt(i);
- if (! connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev;
- if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) {
- if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) {
- goto NoBatchingOrStreaming;
- }
+ if (mCurrentInputTargetsValid) {
+ for (size_t i = 0; i < mActiveConnections.size(); i++) {
+ Connection* connection = mActiveConnections.itemAt(i);
+ if (! connection->outboundQueue.isEmpty()) {
+ DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev;
+ if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) {
+ if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) {
+ goto NoBatchingOrStreaming;
+ }
- MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>(
- dispatchEntry->eventEntry);
- if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE
- || syncedMotionEntry->deviceId != deviceId
- || syncedMotionEntry->pointerCount != pointerCount) {
- goto NoBatchingOrStreaming;
- }
+ MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>(
+ dispatchEntry->eventEntry);
+ if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE
+ || syncedMotionEntry->deviceId != deviceId
+ || syncedMotionEntry->pointerCount != pointerCount) {
+ goto NoBatchingOrStreaming;
+ }
- // Found synced move entry. Append sample and resume dispatch.
- mAllocator.appendMotionSample(syncedMotionEntry, eventTime,
- pointerCount, pointerCoords);
-#if DEBUG_BATCHING
- LOGD("Appended motion sample onto batch for most recent synchronously "
- "dispatched motion event for this device in the outbound queues.");
-#endif
- nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
- dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry,
- true /*resumeWithAppendedMotionSample*/);
- return; // done!
+ // Found synced move entry. Append sample and resume dispatch.
+ mAllocator.appendMotionSample(syncedMotionEntry, eventTime,
+ pointerCount, pointerCoords);
+ #if DEBUG_BATCHING
+ LOGD("Appended motion sample onto batch for most recent synchronously "
+ "dispatched motion event for this device in the outbound queues.");
+ #endif
+ nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry,
+ true /*resumeWithAppendedMotionSample*/);
+
+ runCommandsLockedInterruptible();
+ return; // done!
+ }
}
}
}
@@ -1049,6 +1116,10 @@
}
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
+#if DEBUG_REGISTRATION
+ LOGD("channel '%s' - Registered", inputChannel->getName().string());
+#endif
+
int receiveFd;
{ // acquire lock
AutoMutex _l(mLock);
@@ -1069,6 +1140,8 @@
}
mConnectionsByReceiveFd.add(receiveFd, connection);
+
+ runCommandsLockedInterruptible();
} // release lock
mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
@@ -1076,6 +1149,10 @@
}
status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
+#if DEBUG_REGISTRATION
+ LOGD("channel '%s' - Unregistered", inputChannel->getName().string());
+#endif
+
int32_t receiveFd;
{ // acquire lock
AutoMutex _l(mLock);
@@ -1095,6 +1172,8 @@
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
+
+ runCommandsLockedInterruptible();
} // release lock
mPollLoop->removeCallback(receiveFd);
@@ -1123,11 +1202,12 @@
}
}
-void InputDispatcher::onDispatchCycleStartedLocked(nsecs_t currentTime, Connection* connection) {
+void InputDispatcher::onDispatchCycleStartedLocked(
+ nsecs_t currentTime, Connection* connection) {
}
-void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
- Connection* connection, bool recoveredFromANR) {
+void InputDispatcher::onDispatchCycleFinishedLocked(
+ nsecs_t currentTime, Connection* connection, bool recoveredFromANR) {
if (recoveredFromANR) {
LOGI("channel '%s' ~ Recovered from ANR. %01.1fms since event, "
"%01.1fms since dispatch, %01.1fms since ANR",
@@ -1136,26 +1216,65 @@
connection->getDispatchLatencyMillis(currentTime),
connection->getANRLatencyMillis(currentTime));
- // TODO tell framework
+ CommandEntry* commandEntry = postCommandLocked(
+ & InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible);
+ commandEntry->inputChannel = connection->inputChannel;
}
}
-void InputDispatcher::onDispatchCycleANRLocked(nsecs_t currentTime, Connection* connection) {
+void InputDispatcher::onDispatchCycleANRLocked(
+ nsecs_t currentTime, Connection* connection) {
LOGI("channel '%s' ~ Not responding! %01.1fms since event, %01.1fms since dispatch",
connection->getInputChannelName(),
connection->getEventLatencyMillis(currentTime),
connection->getDispatchLatencyMillis(currentTime));
- // TODO tell framework
+ CommandEntry* commandEntry = postCommandLocked(
+ & InputDispatcher::doNotifyInputChannelANRLockedInterruptible);
+ commandEntry->inputChannel = connection->inputChannel;
}
-void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime, Connection* connection) {
+void InputDispatcher::onDispatchCycleBrokenLocked(
+ nsecs_t currentTime, Connection* connection) {
LOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
connection->getInputChannelName());
- // TODO tell framework
+ CommandEntry* commandEntry = postCommandLocked(
+ & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
+ commandEntry->inputChannel = connection->inputChannel;
}
+void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(
+ CommandEntry* commandEntry) {
+ mLock.unlock();
+
+ mPolicy->notifyInputChannelBroken(commandEntry->inputChannel);
+ commandEntry->inputChannel.clear();
+
+ mLock.lock();
+}
+
+void InputDispatcher::doNotifyInputChannelANRLockedInterruptible(
+ CommandEntry* commandEntry) {
+ mLock.unlock();
+
+ mPolicy->notifyInputChannelANR(commandEntry->inputChannel);
+ commandEntry->inputChannel.clear();
+
+ mLock.lock();
+}
+
+void InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible(
+ CommandEntry* commandEntry) {
+ mLock.unlock();
+
+ mPolicy->notifyInputChannelRecoveredFromANR(commandEntry->inputChannel);
+ commandEntry->inputChannel.clear();
+
+ mLock.lock();
+}
+
+
// --- InputDispatcher::Allocator ---
InputDispatcher::Allocator::Allocator() {
@@ -1166,6 +1285,7 @@
ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc();
entry->refCount = 1;
entry->type = EventEntry::TYPE_CONFIGURATION_CHANGED;
+ entry->dispatchInProgress = false;
return entry;
}
@@ -1173,6 +1293,7 @@
KeyEntry* entry = mKeyEntryPool.alloc();
entry->refCount = 1;
entry->type = EventEntry::TYPE_KEY;
+ entry->dispatchInProgress = false;
return entry;
}
@@ -1181,6 +1302,7 @@
entry->refCount = 1;
entry->type = EventEntry::TYPE_MOTION;
entry->firstSample.next = NULL;
+ entry->dispatchInProgress = false;
return entry;
}
@@ -1192,6 +1314,12 @@
return entry;
}
+InputDispatcher::CommandEntry* InputDispatcher::Allocator::obtainCommandEntry(Command command) {
+ CommandEntry* entry = mCommandEntryPool.alloc();
+ entry->command = command;
+ return entry;
+}
+
void InputDispatcher::Allocator::releaseEventEntry(EventEntry* entry) {
switch (entry->type) {
case EventEntry::TYPE_CONFIGURATION_CHANGED:
@@ -1231,7 +1359,11 @@
void InputDispatcher::Allocator::releaseMotionEntry(MotionEntry* entry) {
entry->refCount -= 1;
if (entry->refCount == 0) {
- freeMotionSampleList(entry->firstSample.next);
+ for (MotionSample* sample = entry->firstSample.next; sample != NULL; ) {
+ MotionSample* next = sample->next;
+ mMotionSamplePool.free(sample);
+ sample = next;
+ }
mMotionEntryPool.free(entry);
} else {
assert(entry->refCount > 0);
@@ -1243,6 +1375,10 @@
mDispatchEntryPool.free(entry);
}
+void InputDispatcher::Allocator::releaseCommandEntry(CommandEntry* entry) {
+ mCommandEntryPool.free(entry);
+}
+
void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry,
nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords) {
MotionSample* sample = mMotionSamplePool.alloc();
@@ -1256,18 +1392,6 @@
motionEntry->lastSample = sample;
}
-void InputDispatcher::Allocator::freeMotionSample(MotionSample* sample) {
- mMotionSamplePool.free(sample);
-}
-
-void InputDispatcher::Allocator::freeMotionSampleList(MotionSample* head) {
- while (head) {
- MotionSample* next = head->next;
- mMotionSamplePool.free(head);
- head = next;
- }
-}
-
// --- InputDispatcher::Connection ---
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) :
@@ -1284,6 +1408,25 @@
return inputPublisher.initialize();
}
+const char* InputDispatcher::Connection::getStatusLabel() const {
+ switch (status) {
+ case STATUS_NORMAL:
+ return "NORMAL";
+
+ case STATUS_BROKEN:
+ return "BROKEN";
+
+ case STATUS_NOT_RESPONDING:
+ return "NOT_RESPONDING";
+
+ case STATUS_ZOMBIE:
+ return "ZOMBIE";
+
+ default:
+ return "UNKNOWN";
+ }
+}
+
InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchEntryForEvent(
const EventEntry* eventEntry) const {
for (DispatchEntry* dispatchEntry = outboundQueue.tail.prev;
@@ -1295,6 +1438,14 @@
return NULL;
}
+// --- InputDispatcher::CommandEntry ---
+
+InputDispatcher::CommandEntry::CommandEntry() {
+}
+
+InputDispatcher::CommandEntry::~CommandEntry() {
+}
+
// --- InputDispatcherThread ---