Refactor how timeouts are calculated.

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

Change-Id: Iec2045baaf4e67690b15eef3c09a58d5cac76897
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
index 9a9e07c..8b4d322 100644
--- a/include/utils/Timers.h
+++ b/include/utils/Timers.h
@@ -88,6 +88,16 @@
 nsecs_t systemTime(int clock);
 #endif // def __cplusplus
 
+/**
+ * Returns the number of milliseconds to wait between the reference time and the timeout time.
+ * If the timeout is in the past relative to the reference time, returns 0.
+ * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time,
+ * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay.
+ * Otherwise, returns the difference between the reference time and timeout time
+ * rounded up to the next millisecond.
+ */
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp
index 18f858b..d5dd126 100644
--- a/libs/utils/Looper.cpp
+++ b/libs/utils/Looper.cpp
@@ -218,14 +218,10 @@
     // Adjust the timeout based on when the next message is due.
     if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-        if (mNextMessageUptime <= now) {
-            timeoutMillis = 0;
-        } else {
-            uint64_t delay = (mNextMessageUptime - now + 999999LL) / 1000000LL;
-            if (delay < INT_MAX
-                    && (timeoutMillis < 0 || int(delay) < timeoutMillis)) {
-                timeoutMillis = int(delay);
-            }
+        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
+        if (messageTimeoutMillis >= 0
+                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
+            timeoutMillis = messageTimeoutMillis;
         }
 #if DEBUG_POLL_AND_WAKE
         LOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d",
@@ -444,12 +440,11 @@
                 return result;
             }
 
-            nsecs_t timeoutNanos = endTime - systemTime(SYSTEM_TIME_MONOTONIC);
-            if (timeoutNanos <= 0) {
+            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+            timeoutMillis = toMillisecondTimeoutDelay(now, endTime);
+            if (timeoutMillis == 0) {
                 return ALOOPER_POLL_TIMEOUT;
             }
-
-            timeoutMillis = int(nanoseconds_to_milliseconds(timeoutNanos + 999999LL));
         }
     }
 }
diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp
index 784f035..64a29f5 100644
--- a/libs/utils/Timers.cpp
+++ b/libs/utils/Timers.cpp
@@ -26,6 +26,7 @@
 #include <sys/time.h>
 #include <time.h>
 #include <errno.h>
+#include <limits.h>
 
 #ifdef HAVE_WIN32_THREADS
 #include <windows.h>
@@ -53,6 +54,23 @@
 #endif
 }
 
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
+{
+    int timeoutDelayMillis;
+    if (timeoutTime > referenceTime) {
+        uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
+        if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) {
+            timeoutDelayMillis = -1;
+        } else {
+            timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL;
+        }
+    } else {
+        timeoutDelayMillis = 0;
+    }
+    return timeoutDelayMillis;
+}
+
+
 /*
  * ===========================================================================
  *      DurationTimer
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index e2da740..b90571b 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 ff26fc9..456e0e6 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -238,15 +238,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 075eff3..120951d 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -610,7 +610,7 @@
         mExcludedDevices.add(String8(deviceName));
     }
 
-    virtual bool getEvent(RawEvent* outEvent) {
+    virtual bool getEvent(int timeoutMillis, RawEvent* outEvent) {
         if (mEvents.empty()) {
             return false;
         }
@@ -768,6 +768,9 @@
 
     virtual void fadePointer() {
     }
+
+    virtual void requestTimeoutAtTime(nsecs_t when) {
+    }
 };