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
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 674852a..d3495fe 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -55,6 +55,22 @@
     INPUT_EVENT_INJECTION_TIMED_OUT = 3
 };
 
+/*
+ * Constants used to determine the input event injection synchronization mode.
+ */
+enum {
+    /* Injection is asynchronous and is assumed always to be successful. */
+    INPUT_EVENT_INJECTION_SYNC_NONE = 0,
+
+    /* Waits for previous events to be dispatched so that the input dispatcher can determine
+     * whether input event injection willbe permitted based on the current input focus.
+     * Does not wait for the input event to finish processing. */
+    INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1,
+
+    /* Waits for the input event to be completely processed. */
+    INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2,
+};
+
 
 /*
  * An input target specifies how an input event is to be dispatched to a particular window
@@ -176,15 +192,14 @@
             float xPrecision, float yPrecision, nsecs_t downTime) = 0;
 
     /* Injects an input event and optionally waits for sync.
-     * This method may block even if sync is false because it must wait for previous events
-     * to be dispatched before it can determine whether input event injection will be
-     * permitted based on the current input focus.
+     * The synchronization mode determines whether the method blocks while waiting for
+     * input injection to proceed.
      * Returns one of the INPUT_EVENT_INJECTION_XXX constants.
      *
      * This method may be called on any thread (usually by the input manager).
      */
     virtual int32_t injectInputEvent(const InputEvent* event,
-            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;
+            int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) = 0;
 
     /* Preempts input dispatch in progress by making pending synchronous
      * dispatches asynchronous instead.  This method is generally called during a focus
@@ -241,7 +256,7 @@
             float xPrecision, float yPrecision, nsecs_t downTime);
 
     virtual int32_t 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);
 
     virtual void preemptInputDispatch();
 
@@ -267,11 +282,13 @@
         int32_t type;
         nsecs_t eventTime;
 
-        int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING
-        int32_t injectorPid;     // -1 if not injected
-        int32_t injectorUid;     // -1 if not injected
+        int32_t injectionResult;  // initially INPUT_EVENT_INJECTION_PENDING
+        bool    injectionIsAsync; // set to true if injection is not waiting for the result
+        int32_t injectorPid;      // -1 if not injected
+        int32_t injectorUid;      // -1 if not injected
 
         bool dispatchInProgress; // initially false, set to true while dispatching
+        int32_t pendingSyncDispatches; // the number of synchronous dispatches in progress
 
         inline bool isInjected() { return injectorPid >= 0; }
     };
@@ -340,6 +357,10 @@
         //   headMotionSample will be initialized to tailMotionSample and tailMotionSample
         //   will be set to NULL.
         MotionSample* tailMotionSample;
+
+        inline bool isSyncTarget() {
+            return targetFlags & InputTarget::FLAG_SYNC;
+        }
     };
 
     // A command entry captures state and behavior for an action to be performed in the
@@ -497,8 +518,7 @@
         // Since there can only ever be at most one such target at a time, if there is one,
         // it must be at the tail because nothing else can be enqueued after it.
         inline bool hasPendingSyncTarget() {
-            return ! outboundQueue.isEmpty()
-                    && (outboundQueue.tail.prev->targetFlags & InputTarget::FLAG_SYNC);
+            return ! outboundQueue.isEmpty() && outboundQueue.tail.prev->isSyncTarget();
         }
 
         // Gets the time since the current event was originally obtained from the input driver.
@@ -559,11 +579,12 @@
 
     // Event injection and synchronization.
     Condition mInjectionResultAvailableCondition;
-    Condition mFullySynchronizedCondition;
-    bool isFullySynchronizedLocked();
     EventEntry* createEntryFromInputEventLocked(const InputEvent* event);
     void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
 
+    Condition mInjectionSyncFinishedCondition;
+    void decrementPendingSyncDispatchesLocked(EventEntry* entry);
+
     // Key repeat tracking.
     // XXX Move this up to the input reader instead.
     struct KeyRepeatState {
diff --git a/include/ui/InputManager.h b/include/ui/InputManager.h
index 7ebec10..4012c69 100644
--- a/include/ui/InputManager.h
+++ b/include/ui/InputManager.h
@@ -79,13 +79,12 @@
     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
 
     /* Injects an input event and optionally waits for sync.
-     * This method may block even if sync is false because it must wait for previous events
-     * to be dispatched before it can determine whether input event injection will be
-     * permitted based on the current input focus.
+     * The synchronization mode determines whether the method blocks while waiting for
+     * input injection to proceed.
      * Returns one of the INPUT_EVENT_INJECTION_XXX constants.
      */
     virtual int32_t injectInputEvent(const InputEvent* event,
-            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;
+            int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) = 0;
 
     /* Preempts input dispatch in progress by making pending synchronous
      * dispatches asynchronous instead.  This method is generally called during a focus
@@ -142,7 +141,7 @@
     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
 
     virtual int32_t 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);
 
     virtual void preemptInputDispatch();
 
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 @@
 
         // 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 @@
     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 @@
             }
             // 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 @@
     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 @@
                     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 @@
 }
 
 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 @@
         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 @@
     { // acquire lock
         AutoMutex _l(mLock);
 
-        for (;;) {
-            injectionResult = injectedEntry->injectionResult;
-            if (injectionResult != INPUT_EVENT_INJECTION_PENDING) {
-                break;
-            }
+        if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
+            injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
+        } else {
+            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 (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 @@
                  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 @@
     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 @@
 }
 
 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() {