qdutils: idle_invalidator: Use fixed timeout rather than range

Currently the idle timeout is in a range from idle_timeout / 2
to idle_timeout, since we didn't need precise values.

Change this to a fixed value using timestamps, because the timeout
is too low and warrants precision.

Change-Id: I9cec1db7f1d7fda2996ab80449c61269915f6be4
diff --git a/libqdutils/idle_invalidator.cpp b/libqdutils/idle_invalidator.cpp
index 97176a4..b53f1a3 100644
--- a/libqdutils/idle_invalidator.cpp
+++ b/libqdutils/idle_invalidator.cpp
@@ -54,16 +54,43 @@
 }
 
 bool IdleInvalidator::threadLoop() {
+    struct timeval lastUpdateTime;
     ALOGD_IF(II_DEBUG, "%s", __func__);
-    usleep(mSleepTime * 500);
+
+    {
+        //If we are here, update(s) happened, i.e mSleepAgain is set
+        Locker::Autolock _l(mLock);
+        mSleepAgain = false;
+        lastUpdateTime = mLastUpdateTime;
+    }
+
+    struct timeval currentTime;
+    gettimeofday(&currentTime, NULL);
+    int timeSinceUpdateUs = (currentTime.tv_sec - lastUpdateTime.tv_sec) *
+            1000000 + (currentTime.tv_usec - lastUpdateTime.tv_usec);
+    int sleepDurationUs = mSleepTime * 1000 - timeSinceUpdateUs;
+
+    //Sleep only if the duration required is > 1ms, otherwise its not worth it.
+    if(sleepDurationUs > 1000) {
+        usleep(sleepDurationUs);
+        ALOGD_IF(II_DEBUG, "Slept for %d ms", sleepDurationUs / 1000);
+    }
 
     Locker::Autolock _l(mLock);
+    //If an update happened while we were asleep, sleep again
     if(mSleepAgain) {
         //We need to sleep again!
         mSleepAgain = false;
         return true;
     }
 
+#if II_DEBUG
+    gettimeofday(&currentTime, NULL);
+    timeSinceUpdateUs = (currentTime.tv_sec - lastUpdateTime.tv_sec) *
+            1000000 + (currentTime.tv_usec - lastUpdateTime.tv_usec);
+    ALOGD("Idle refresh after %dms", timeSinceUpdateUs / 1000);
+#endif
+
     mHandler((void*)mHwcContext);
     return false;
 }
@@ -77,8 +104,9 @@
     ALOGD_IF(II_DEBUG, "%s", __func__);
 }
 
-void IdleInvalidator::markForSleep() {
+void IdleInvalidator::handleUpdateEvent() {
     Locker::Autolock _l(mLock);
+    gettimeofday(&mLastUpdateTime, NULL);
     mSleepAgain = true;
     //Triggers the threadLoop to run, if not already running.
     run(threadName, android::PRIORITY_AUDIO);
diff --git a/libqdutils/idle_invalidator.h b/libqdutils/idle_invalidator.h
index abd9b29..f41c15e 100644
--- a/libqdutils/idle_invalidator.h
+++ b/libqdutils/idle_invalidator.h
@@ -38,6 +38,7 @@
 
 class IdleInvalidator : public android::Thread {
     void *mHwcContext;
+    struct timeval mLastUpdateTime;
     bool mSleepAgain;
     unsigned int mSleepTime;
     static InvalidatorHandler mHandler;
@@ -49,7 +50,7 @@
     /* init timer obj */
     int init(InvalidatorHandler reg_handler, void* user_data, unsigned int
              idleSleepTime);
-    void markForSleep();
+    void handleUpdateEvent();
     /*Overrides*/
     virtual bool        threadLoop();
     virtual int         readyToRun();