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/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index bde07f2..80a20c9 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -18,7 +18,6 @@
 #define _UI_INPUT_DISPATCHER_H
 
 #include <ui/Input.h>
-#include <ui/InputDispatchPolicy.h>
 #include <ui/InputTransport.h>
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
@@ -35,6 +34,82 @@
 
 namespace android {
 
+/*
+ * An input target specifies how an input event is to be dispatched to a particular window
+ * including the window's input channel, control flags, a timeout, and an X / Y offset to
+ * be added to input event coordinates to compensate for the absolute position of the
+ * window area.
+ */
+struct InputTarget {
+    enum {
+        /* This flag indicates that subsequent event delivery should be held until the
+         * current event is delivered to this target or a timeout occurs. */
+        FLAG_SYNC = 0x01,
+
+        /* This flag indicates that a MotionEvent with ACTION_DOWN falls outside of the area of
+         * this target and so should instead be delivered as an ACTION_OUTSIDE to this target. */
+        FLAG_OUTSIDE = 0x02,
+
+        /* This flag indicates that a KeyEvent or MotionEvent is being canceled.
+         * In the case of a key event, it should be delivered with KeyEvent.FLAG_CANCELED set.
+         * In the case of a motion event, it should be delivered as MotionEvent.ACTION_CANCEL. */
+        FLAG_CANCEL = 0x04
+    };
+
+    // The input channel to be targeted.
+    sp<InputChannel> inputChannel;
+
+    // Flags for the input target.
+    int32_t flags;
+
+    // The timeout for event delivery to this target in nanoseconds.  Or -1 if none.
+    nsecs_t timeout;
+
+    // The x and y offset to add to a MotionEvent as it is delivered.
+    // (ignored for KeyEvents)
+    float xOffset, yOffset;
+};
+
+/*
+ * Input dispatcher policy interface.
+ *
+ * The input reader policy is used by the input reader to interact with the Window Manager
+ * and other system components.
+ *
+ * The actual implementation is partially supported by callbacks into the DVM
+ * via JNI.  This interface is also mocked in the unit tests.
+ */
+class InputDispatcherPolicyInterface : public virtual RefBase {
+protected:
+    InputDispatcherPolicyInterface() { }
+    virtual ~InputDispatcherPolicyInterface() { }
+
+public:
+    /* Notifies the system that a configuration change has occurred. */
+    virtual void notifyConfigurationChanged(nsecs_t when) = 0;
+
+    /* Notifies the system that an input channel is unrecoverably broken. */
+    virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0;
+
+    /* Notifies the system that an input channel is not responding. */
+    virtual void notifyInputChannelANR(const sp<InputChannel>& inputChannel) = 0;
+
+    /* Notifies the system that an input channel recovered from ANR. */
+    virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) = 0;
+
+    /* Gets the key repeat timeout or -1 if automatic key repeating is disabled. */
+    virtual nsecs_t getKeyRepeatTimeout() = 0;
+
+    /* Gets the input targets for a key event. */
+    virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
+            Vector<InputTarget>& outTargets) = 0;
+
+    /* Gets the input targets for a motion event. */
+    virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+            Vector<InputTarget>& outTargets) = 0;
+};
+
+
 /* Notifies the system about input events generated by the input reader.
  * The dispatcher is expected to be mostly asynchronous. */
 class InputDispatcherInterface : public virtual RefBase {
@@ -51,14 +126,10 @@
     virtual void dispatchOnce() = 0;
 
     /* Notifies the dispatcher about new events.
-     * The dispatcher will process most of these events asynchronously although some
-     * policy processing may occur synchronously.
      *
      * These methods should only be called on the input reader thread.
      */
-    virtual void notifyConfigurationChanged(nsecs_t eventTime,
-            int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig) = 0;
-    virtual void notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen) = 0;
+    virtual void notifyConfigurationChanged(nsecs_t eventTime) = 0;
     virtual void notifyAppSwitchComing(nsecs_t eventTime) = 0;
     virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature,
             uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
@@ -76,19 +147,33 @@
     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
 };
 
-/* Dispatches events. */
+/* Dispatches events to input targets.  Some functions of the input dispatcher, such as
+ * identifying input targets, are controlled by a separate policy object.
+ *
+ * IMPORTANT INVARIANT:
+ *     Because the policy can potentially block or cause re-entrance into the input dispatcher,
+ *     the input dispatcher never calls into the policy while holding its internal locks.
+ *     The implementation is also carefully designed to recover from scenarios such as an
+ *     input channel becoming unregistered while identifying input targets or processing timeouts.
+ *
+ *     Methods marked 'Locked' must be called with the lock acquired.
+ *
+ *     Methods marked 'LockedInterruptible' must be called with the lock acquired but
+ *     may during the course of their execution release the lock, call into the policy, and
+ *     then reacquire the lock.  The caller is responsible for recovering gracefully.
+ *
+ *     A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa.
+ */
 class InputDispatcher : public InputDispatcherInterface {
 protected:
     virtual ~InputDispatcher();
 
 public:
-    explicit InputDispatcher(const sp<InputDispatchPolicyInterface>& policy);
+    explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
 
     virtual void dispatchOnce();
 
-    virtual void notifyConfigurationChanged(nsecs_t eventTime,
-            int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig);
-    virtual void notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen);
+    virtual void notifyConfigurationChanged(nsecs_t eventTime);
     virtual void notifyAppSwitchComing(nsecs_t eventTime);
     virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature,
             uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
@@ -119,12 +204,11 @@
         int32_t refCount;
         int32_t type;
         nsecs_t eventTime;
+
+        bool dispatchInProgress; // initially false, set to true while dispatching
     };
 
     struct ConfigurationChangedEntry : EventEntry {
-        int32_t touchScreenConfig;
-        int32_t keyboardConfig;
-        int32_t navigationConfig;
     };
 
     struct KeyEntry : EventEntry {
@@ -165,6 +249,7 @@
         MotionSample* lastSample;
     };
 
+    // Tracks the progress of dispatching a particular event to a particular connection.
     struct DispatchEntry : Link<DispatchEntry> {
         EventEntry* eventEntry; // the event to dispatch
         int32_t targetFlags;
@@ -189,6 +274,36 @@
         MotionSample* tailMotionSample;
     };
 
+    // A command entry captures state and behavior for an action to be performed in the
+    // dispatch loop after the initial processing has taken place.  It is essentially
+    // a kind of continuation used to postpone sensitive policy interactions to a point
+    // in the dispatch loop where it is safe to release the lock (generally after finishing
+    // the critical parts of the dispatch cycle).
+    //
+    // The special thing about commands is that they can voluntarily release and reacquire
+    // the dispatcher lock at will.  Initially when the command starts running, the
+    // dispatcher lock is held.  However, if the command needs to call into the policy to
+    // do some work, it can release the lock, do the work, then reacquire the lock again
+    // before returning.
+    //
+    // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch
+    // never calls into the policy while holding its lock.
+    //
+    // Commands are implicitly 'LockedInterruptible'.
+    struct CommandEntry;
+    typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry);
+
+    struct CommandEntry : Link<CommandEntry> {
+        CommandEntry();
+        ~CommandEntry();
+
+        Command command;
+
+        // parameters for the command (usage varies by command)
+        sp<InputChannel> inputChannel;
+    };
+
+    // Generic queue implementation.
     template <typename T>
     struct Queue {
         T head;
@@ -242,17 +357,17 @@
         KeyEntry* obtainKeyEntry();
         MotionEntry* obtainMotionEntry();
         DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry);
+        CommandEntry* obtainCommandEntry(Command command);
 
         void releaseEventEntry(EventEntry* entry);
         void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry);
         void releaseKeyEntry(KeyEntry* entry);
         void releaseMotionEntry(MotionEntry* entry);
         void releaseDispatchEntry(DispatchEntry* entry);
+        void releaseCommandEntry(CommandEntry* entry);
 
         void appendMotionSample(MotionEntry* motionEntry,
                 nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords);
-        void freeMotionSample(MotionSample* sample);
-        void freeMotionSampleList(MotionSample* head);
 
     private:
         Pool<ConfigurationChangedEntry> mConfigurationChangeEntryPool;
@@ -260,6 +375,7 @@
         Pool<MotionEntry> mMotionEntryPool;
         Pool<MotionSample> mMotionSamplePool;
         Pool<DispatchEntry> mDispatchEntryPool;
+        Pool<CommandEntry> mCommandEntryPool;
     };
 
     /* Manages the dispatch state associated with a single input channel. */
@@ -291,7 +407,9 @@
 
         explicit Connection(const sp<InputChannel>& inputChannel);
 
-        inline const char* getInputChannelName() { return inputChannel->getName().string(); }
+        inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
+
+        const char* getStatusLabel() const;
 
         // Finds a DispatchEntry in the outbound queue associated with the specified event.
         // Returns NULL if not found.
@@ -323,22 +441,23 @@
         status_t initialize();
     };
 
-    sp<InputDispatchPolicyInterface> mPolicy;
+    sp<InputDispatcherPolicyInterface> mPolicy;
 
     Mutex mLock;
 
-    Queue<EventEntry> mInboundQueue;
     Allocator mAllocator;
-
     sp<PollLoop> mPollLoop;
 
+    Queue<EventEntry> mInboundQueue;
+    Queue<CommandEntry> mCommandQueue;
+
     // All registered connections mapped by receive pipe file descriptor.
     KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
 
     // Active connections are connections that have a non-empty outbound queue.
     Vector<Connection*> mActiveConnections;
 
-    // Pool of key and motion event objects used only to ask the input dispatch policy
+    // Preallocated key and motion event objects used only to ask the input dispatcher policy
     // for the targets of an event that is to be dispatched.
     KeyEvent mReusableKeyEvent;
     MotionEvent mReusableMotionEvent;
@@ -347,6 +466,7 @@
     // If there is a synchronous event dispatch in progress, the current input targets will
     // remain unchanged until the dispatch has completed or been aborted.
     Vector<InputTarget> mCurrentInputTargets;
+    bool mCurrentInputTargetsValid; // false while targets are being recomputed
 
     // Key repeat tracking.
     // XXX Move this up to the input reader instead.
@@ -357,17 +477,27 @@
 
     void resetKeyRepeatLocked();
 
+    // Deferred command processing.
+    bool runCommandsLockedInterruptible();
+    CommandEntry* postCommandLocked(Command command);
+
     // Process events that have just been dequeued from the head of the input queue.
-    void processConfigurationChangedLocked(nsecs_t currentTime, ConfigurationChangedEntry* entry);
-    void processKeyLocked(nsecs_t currentTime, KeyEntry* entry);
-    void processKeyRepeatLocked(nsecs_t currentTime);
-    void processMotionLocked(nsecs_t currentTime, MotionEntry* entry);
+    void processConfigurationChangedLockedInterruptible(
+            nsecs_t currentTime, ConfigurationChangedEntry* entry);
+    void processKeyLockedInterruptible(
+            nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout);
+    void processKeyRepeatLockedInterruptible(
+            nsecs_t currentTime, nsecs_t keyRepeatTimeout);
+    void processMotionLockedInterruptible(
+            nsecs_t currentTime, MotionEntry* entry);
 
     // Identify input targets for an event and dispatch to them.
-    void identifyInputTargetsAndDispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry);
-    void identifyInputTargetsAndDispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry);
-    void dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime, EventEntry* entry,
-            bool resumeWithAppendedMotionSample);
+    void identifyInputTargetsAndDispatchKeyLockedInterruptible(
+            nsecs_t currentTime, KeyEntry* entry);
+    void identifyInputTargetsAndDispatchMotionLockedInterruptible(
+            nsecs_t currentTime, MotionEntry* entry);
+    void dispatchEventToCurrentInputTargetsLocked(
+            nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
 
     // Manage the dispatch cycle for a single connection.
     void prepareDispatchCycleLocked(nsecs_t currentTime, Connection* connection,
@@ -384,12 +514,22 @@
     void activateConnectionLocked(Connection* connection);
     void deactivateConnectionLocked(Connection* connection);
 
+    // Outbound policy interactions.
+    void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry);
+
     // Interesting events that we might like to log or tell the framework about.
-    void onDispatchCycleStartedLocked(nsecs_t currentTime, Connection* connection);
-    void onDispatchCycleFinishedLocked(nsecs_t currentTime, Connection* connection,
-            bool recoveredFromANR);
-    void onDispatchCycleANRLocked(nsecs_t currentTime, Connection* connection);
-    void onDispatchCycleBrokenLocked(nsecs_t currentTime, Connection* connection);
+    void onDispatchCycleStartedLocked(
+            nsecs_t currentTime, Connection* connection);
+    void onDispatchCycleFinishedLocked(
+            nsecs_t currentTime, Connection* connection, bool recoveredFromANR);
+    void onDispatchCycleANRLocked(
+            nsecs_t currentTime, Connection* connection);
+    void onDispatchCycleBrokenLocked(
+            nsecs_t currentTime, Connection* connection);
+
+    void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
+    void doNotifyInputChannelANRLockedInterruptible(CommandEntry* commandEntry);
+    void doNotifyInputChannelRecoveredFromANRLockedInterruptible(CommandEntry* commandEntry);
 };
 
 /* Enqueues and dispatches input events, endlessly. */