summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2010-07-28 15:48:59 -0700
committerJeff Brown <jeffbrown@google.com>2010-07-29 12:54:27 -0700
commit6ec402b5ae33c8927694d8522b4cc6a5c8ba974e (patch)
tree5d4b19eda9ade71d7e34635479426f1dd484e8c2 /libs
parent6dea6f4e71b53e421564d783c227cbe0a2469183 (diff)
downloadframeworks_base-6ec402b5ae33c8927694d8522b4cc6a5c8ba974e.zip
frameworks_base-6ec402b5ae33c8927694d8522b4cc6a5c8ba974e.tar.gz
frameworks_base-6ec402b5ae33c8927694d8522b4cc6a5c8ba974e.tar.bz2
DO NOT MERGE: Fix input event injection ANRs on UI thread.
Added a new asynchronous injection mode and made the existing synchronization mechanism more robust. Change-Id: Ia4aa04fd9b75ea2461a844c5b7933c831c1027e6
Diffstat (limited to 'libs')
-rw-r--r--libs/ui/InputDispatcher.cpp113
-rw-r--r--libs/ui/InputManager.cpp4
2 files changed, 86 insertions, 31 deletions
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index a55864b..b53f140 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -184,11 +184,6 @@ void InputDispatcher::dispatchOnce() {
// Run any deferred commands.
skipPoll |= runCommandsLockedInterruptible();
-
- // Wake up synchronization waiters, if needed.
- if (isFullySynchronizedLocked()) {
- mFullySynchronizedCondition.broadcast();
- }
} // release lock
// If we dispatched anything, don't poll just now. Wait for the next iteration.
@@ -560,6 +555,10 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
dispatchEntry->headMotionSample = NULL;
dispatchEntry->tailMotionSample = NULL;
+ if (dispatchEntry->isSyncTarget()) {
+ eventEntry->pendingSyncDispatches += 1;
+ }
+
// Handle the case where we could not stream a new motion sample because the consumer has
// already consumed the motion event (otherwise the corresponding dispatch entry would
// still be in the outbound queue for this connection). We set the head motion sample
@@ -789,6 +788,9 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
}
// Finished.
connection->outboundQueue.dequeueAtHead();
+ if (dispatchEntry->isSyncTarget()) {
+ decrementPendingSyncDispatchesLocked(dispatchEntry->eventEntry);
+ }
mAllocator.releaseDispatchEntry(dispatchEntry);
} else {
// If the head is not in progress, then we must have already dequeued the in
@@ -854,6 +856,9 @@ void InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime,
if (! connection->outboundQueue.isEmpty()) {
do {
DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
+ if (dispatchEntry->isSyncTarget()) {
+ decrementPendingSyncDispatchesLocked(dispatchEntry->eventEntry);
+ }
mAllocator.releaseDispatchEntry(dispatchEntry);
} while (! connection->outboundQueue.isEmpty());
@@ -1097,7 +1102,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t
Connection* connection = mActiveConnections.itemAt(i);
if (! connection->outboundQueue.isEmpty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev;
- if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) {
+ if (dispatchEntry->isSyncTarget()) {
if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) {
goto NoBatchingOrStreaming;
}
@@ -1148,11 +1153,11 @@ NoBatchingOrStreaming:;
}
int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
- int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) {
+ int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) {
#if DEBUG_INBOUND_EVENT_DETAILS
LOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
- "sync=%d, timeoutMillis=%d",
- event->getType(), injectorPid, injectorUid, sync, timeoutMillis);
+ "syncMode=%d, timeoutMillis=%d",
+ event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis);
#endif
nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
@@ -1167,6 +1172,10 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
injectedEntry->injectorPid = injectorPid;
injectedEntry->injectorUid = injectorUid;
+ if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
+ injectedEntry->injectionIsAsync = true;
+ }
+
wasEmpty = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(injectedEntry);
@@ -1180,37 +1189,59 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
{ // acquire lock
AutoMutex _l(mLock);
- for (;;) {
- injectionResult = injectedEntry->injectionResult;
- if (injectionResult != INPUT_EVENT_INJECTION_PENDING) {
- break;
- }
-
- nsecs_t remainingTimeout = endTime - now();
- if (remainingTimeout <= 0) {
- injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
- sync = false;
- break;
- }
-
- mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout);
- }
+ if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
+ injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
+ } else {
+ for (;;) {
+ injectionResult = injectedEntry->injectionResult;
+ if (injectionResult != INPUT_EVENT_INJECTION_PENDING) {
+ break;
+ }
- if (sync) {
- while (! isFullySynchronizedLocked()) {
nsecs_t remainingTimeout = endTime - now();
if (remainingTimeout <= 0) {
+#if DEBUG_INJECTION
+ LOGD("injectInputEvent - Timed out waiting for injection result "
+ "to become available.");
+#endif
injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
break;
}
- mFullySynchronizedCondition.waitRelative(mLock, remainingTimeout);
+ mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout);
+ }
+
+ if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED
+ && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) {
+ while (injectedEntry->pendingSyncDispatches != 0) {
+#if DEBUG_INJECTION
+ LOGD("injectInputEvent - Waiting for %d pending synchronous dispatches.",
+ injectedEntry->pendingSyncDispatches);
+#endif
+ nsecs_t remainingTimeout = endTime - now();
+ if (remainingTimeout <= 0) {
+#if DEBUG_INJECTION
+ LOGD("injectInputEvent - Timed out waiting for pending synchronous "
+ "dispatches to finish.");
+#endif
+ injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
+ break;
+ }
+
+ mInjectionSyncFinishedCondition.waitRelative(mLock, remainingTimeout);
+ }
}
}
mAllocator.releaseEventEntry(injectedEntry);
} // release lock
+#if DEBUG_INJECTION
+ LOGD("injectInputEvent - Finished with result %d. "
+ "injectorPid=%d, injectorUid=%d",
+ injectionResult, injectorPid, injectorUid);
+#endif
+
return injectionResult;
}
@@ -1222,13 +1253,35 @@ void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t inject
injectionResult, entry->injectorPid, entry->injectorUid);
#endif
+ if (entry->injectionIsAsync) {
+ // Log the outcome since the injector did not wait for the injection result.
+ switch (injectionResult) {
+ case INPUT_EVENT_INJECTION_SUCCEEDED:
+ LOGV("Asynchronous input event injection succeeded.");
+ break;
+ case INPUT_EVENT_INJECTION_FAILED:
+ LOGW("Asynchronous input event injection failed.");
+ break;
+ case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
+ LOGW("Asynchronous input event injection permission denied.");
+ break;
+ case INPUT_EVENT_INJECTION_TIMED_OUT:
+ LOGW("Asynchronous input event injection timed out.");
+ break;
+ }
+ }
+
entry->injectionResult = injectionResult;
mInjectionResultAvailableCondition.broadcast();
}
}
-bool InputDispatcher::isFullySynchronizedLocked() {
- return mInboundQueue.isEmpty() && mActiveConnections.isEmpty();
+void InputDispatcher::decrementPendingSyncDispatchesLocked(EventEntry* entry) {
+ entry->pendingSyncDispatches -= 1;
+
+ if (entry->isInjected() && entry->pendingSyncDispatches == 0) {
+ mInjectionSyncFinishedCondition.broadcast();
+ }
}
InputDispatcher::EventEntry* InputDispatcher::createEntryFromInputEventLocked(
@@ -1498,8 +1551,10 @@ void InputDispatcher::Allocator::initializeEventEntry(EventEntry* entry, int32_t
entry->dispatchInProgress = false;
entry->eventTime = eventTime;
entry->injectionResult = INPUT_EVENT_INJECTION_PENDING;
+ entry->injectionIsAsync = false;
entry->injectorPid = -1;
entry->injectorUid = -1;
+ entry->pendingSyncDispatches = 0;
}
InputDispatcher::ConfigurationChangedEntry*
diff --git a/libs/ui/InputManager.cpp b/libs/ui/InputManager.cpp
index bf23479..ed4f07b 100644
--- a/libs/ui/InputManager.cpp
+++ b/libs/ui/InputManager.cpp
@@ -81,8 +81,8 @@ status_t InputManager::unregisterInputChannel(const sp<InputChannel>& inputChann
}
int32_t InputManager::injectInputEvent(const InputEvent* event,
- int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) {
- return mDispatcher->injectInputEvent(event, injectorPid, injectorUid, sync, timeoutMillis);
+ int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) {
+ return mDispatcher->injectInputEvent(event, injectorPid, injectorUid, syncMode, timeoutMillis);
}
void InputManager::preemptInputDispatch() {