Refactor how timeouts are calculated. (DO NOT MERGE)

Added a timeout mechanism to EventHub and InputReader so that
InputMappers can request timeouts to perform delayed processing of
input when needed.

Change-Id: I89c1171c9326c6e413042e3ee13aa9f7f1fc0454
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 853dda4..41993fd 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -445,7 +445,7 @@
     return NULL;
 }
 
-bool EventHub::getEvent(RawEvent* outEvent) {
+bool EventHub::getEvent(int timeoutMillis, RawEvent* outEvent) {
     outEvent->deviceId = 0;
     outEvent->type = 0;
     outEvent->scanCode = 0;
@@ -598,13 +598,20 @@
         // when this happens, the EventHub holds onto its own user wake lock while the client
         // is processing events.  Thus the system can only sleep if there are no events
         // pending or currently being processed.
+        //
+        // The timeout is advisory only.  If the device is asleep, it will not wake just to
+        // service the timeout.
         release_wake_lock(WAKE_LOCK_ID);
 
-        int pollResult = poll(mFds.editArray(), mFds.size(), -1);
+        int pollResult = poll(mFds.editArray(), mFds.size(), timeoutMillis);
 
         acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 
-        if (pollResult <= 0) {
+        if (pollResult == 0) {
+            // Timed out.
+            return false;
+        }
+        if (pollResult < 0) {
             if (errno != EINTR) {
                 LOGW("poll failed (errno=%d)\n", errno);
                 usleep(100000);
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 7053a94..1d287ac 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -186,8 +186,13 @@
      * This ensures that the device will not go to sleep while the event is being processed.
      * If the device needs to remain awake longer than that, then the caller is responsible
      * for taking care of it (say, by poking the power manager user activity timer).
+     *
+     * The timeout is advisory only.  If the device is asleep, it will not wake just to
+     * service the timeout.
+     *
+     * Returns true if an event was obtained, false if the timeout expired.
      */
-    virtual bool getEvent(RawEvent* outEvent) = 0;
+    virtual bool getEvent(int timeoutMillis, RawEvent* outEvent) = 0;
 
     /*
      * Query current input state.
@@ -244,7 +249,7 @@
     virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
             const int32_t* keyCodes, uint8_t* outFlags) const;
 
-    virtual bool getEvent(RawEvent* outEvent);
+    virtual bool getEvent(int timeoutMillis, RawEvent* outEvent);
 
     virtual bool hasLed(int32_t deviceId, int32_t led) const;
     virtual void setLedState(int32_t deviceId, int32_t led, bool on);
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 53dc769..ce8f076 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -246,15 +246,7 @@
 
     // Wait for callback or timeout or wake.  (make sure we round up, not down)
     nsecs_t currentTime = now();
-    int32_t timeoutMillis;
-    if (nextWakeupTime > currentTime) {
-        uint64_t timeout = uint64_t(nextWakeupTime - currentTime);
-        timeout = (timeout + 999999LL) / 1000000LL;
-        timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);
-    } else {
-        timeoutMillis = 0;
-    }
-
+    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
     mLooper->pollOnce(timeoutMillis);
 }
 
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 592939f..182bd50 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -231,7 +231,7 @@
         const sp<InputReaderPolicyInterface>& policy,
         const sp<InputDispatcherInterface>& dispatcher) :
         mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher),
-        mGlobalMetaState(0), mDisableVirtualKeysTimeout(-1) {
+        mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX) {
     configureExcludedDevices();
     updateGlobalMetaState();
     updateInputConfiguration();
@@ -244,16 +244,28 @@
 }
 
 void InputReader::loopOnce() {
+    int32_t timeoutMillis = -1;
+    if (mNextTimeout != LLONG_MAX) {
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
+    }
+
     RawEvent rawEvent;
-    mEventHub->getEvent(& rawEvent);
-
+    if (mEventHub->getEvent(timeoutMillis, &rawEvent)) {
 #if DEBUG_RAW_EVENTS
-    LOGD("Input event: device=%d type=0x%04x scancode=0x%04x keycode=0x%04x value=0x%04x",
-            rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,
-            rawEvent.value);
+        LOGD("Input event: device=%d type=0x%04x scancode=0x%04x keycode=0x%04x value=0x%04x",
+                rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,
+                rawEvent.value);
 #endif
-
-    process(& rawEvent);
+        process(&rawEvent);
+    } else {
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+#if DEBUG_RAW_EVENTS
+        LOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
+#endif
+        mNextTimeout = LLONG_MAX;
+        timeoutExpired(now);
+    }
 }
 
 void InputReader::process(const RawEvent* rawEvent) {
@@ -415,6 +427,19 @@
     } // release device registry reader lock
 }
 
+void InputReader::timeoutExpired(nsecs_t when) {
+    { // acquire device registry reader lock
+        RWLock::AutoRLock _rl(mDeviceRegistryLock);
+
+        for (size_t i = 0; i < mDevices.size(); i++) {
+            InputDevice* device = mDevices.valueAt(i);
+            if (!device->isIgnored()) {
+                device->timeoutExpired(when);
+            }
+        }
+    } // release device registry reader lock
+}
+
 void InputReader::handleConfigurationChanged(nsecs_t when) {
     // Reset global meta state because it depends on the list of all configured devices.
     updateGlobalMetaState();
@@ -525,6 +550,12 @@
     } // release device registry reader lock
 }
 
+void InputReader::requestTimeoutAtTime(nsecs_t when) {
+    if (when < mNextTimeout) {
+        mNextTimeout = when;
+    }
+}
+
 void InputReader::getInputConfiguration(InputConfiguration* outConfiguration) {
     { // acquire state lock
         AutoMutex _l(mStateLock);
@@ -762,6 +793,14 @@
     }
 }
 
+void InputDevice::timeoutExpired(nsecs_t when) {
+    size_t numMappers = mMappers.size();
+    for (size_t i = 0; i < numMappers; i++) {
+        InputMapper* mapper = mMappers[i];
+        mapper->timeoutExpired(when);
+    }
+}
+
 void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
     outDeviceInfo->initialize(mId, mName);
 
@@ -853,6 +892,9 @@
 void InputMapper::reset() {
 }
 
+void InputMapper::timeoutExpired(nsecs_t when) {
+}
+
 int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
     return AKEY_STATE_UNKNOWN;
 }
@@ -2556,6 +2598,19 @@
 }
 
 void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
+#if DEBUG_RAW_EVENTS
+    if (!havePointerIds) {
+        LOGD("syncTouch: pointerCount=%d, no pointer ids", mCurrentTouch.pointerCount);
+    } else {
+        LOGD("syncTouch: pointerCount=%d, up=0x%08x, down=0x%08x, move=0x%08x, "
+                "last=0x%08x, current=0x%08x", mCurrentTouch.pointerCount,
+                mLastTouch.idBits.value & ~mCurrentTouch.idBits.value,
+                mCurrentTouch.idBits.value & ~mLastTouch.idBits.value,
+                mLastTouch.idBits.value & mCurrentTouch.idBits.value,
+                mLastTouch.idBits.value, mCurrentTouch.idBits.value);
+    }
+#endif
+
     // Preprocess pointer data.
     if (mParameters.useBadTouchFilter) {
         if (applyBadTouchFilter()) {
@@ -2569,7 +2624,7 @@
         }
     }
 
-    if (! havePointerIds) {
+    if (!havePointerIds) {
         calculatePointerIds();
     }
 
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 55ab479..fdb4cfc 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -159,6 +159,8 @@
 
     virtual void fadePointer() = 0;
 
+    virtual void requestTimeoutAtTime(nsecs_t when) = 0;
+
     virtual InputReaderPolicyInterface* getPolicy() = 0;
     virtual InputDispatcherInterface* getDispatcher() = 0;
     virtual EventHubInterface* getEventHub() = 0;
@@ -233,6 +235,7 @@
     void configureExcludedDevices();
 
     void consumeEvent(const RawEvent* rawEvent);
+    void timeoutExpired(nsecs_t when);
 
     void handleConfigurationChanged(nsecs_t when);
 
@@ -253,6 +256,9 @@
     virtual bool shouldDropVirtualKey(nsecs_t now,
             InputDevice* device, int32_t keyCode, int32_t scanCode);
 
+    nsecs_t mNextTimeout;
+    virtual void requestTimeoutAtTime(nsecs_t when);
+
     // state queries
     typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code);
     int32_t getState(int32_t deviceId, uint32_t sourceMask, int32_t code,
@@ -296,6 +302,7 @@
     void configure();
     void reset();
     void process(const RawEvent* rawEvent);
+    void timeoutExpired(nsecs_t when);
 
     void getDeviceInfo(InputDeviceInfo* outDeviceInfo);
     int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
@@ -352,6 +359,7 @@
     virtual void configure();
     virtual void reset();
     virtual void process(const RawEvent* rawEvent) = 0;
+    virtual void timeoutExpired(nsecs_t when);
 
     virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
     virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 60d5ede..4d92207 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -622,7 +622,7 @@
         mExcludedDevices.add(String8(deviceName));
     }
 
-    virtual bool getEvent(RawEvent* outEvent) {
+    virtual bool getEvent(int timeoutMillis, RawEvent* outEvent) {
         if (mEvents.empty()) {
             return false;
         }
@@ -780,6 +780,9 @@
 
     virtual void fadePointer() {
     }
+
+    virtual void requestTimeoutAtTime(nsecs_t when) {
+    }
 };