Merge "qdutils: Refactor idletimeout fallback mechanism."
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 438c9d2..469ffba 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -38,6 +38,7 @@
 
 IdleInvalidator *MDPComp::idleInvalidator = NULL;
 bool MDPComp::sIdleFallBack = false;
+bool MDPComp::sHandleTimeout = false;
 bool MDPComp::sDebugLogs = false;
 bool MDPComp::sEnabled = false;
 bool MDPComp::sEnableMixedMode = true;
@@ -171,7 +172,12 @@
         ALOGE("%s: received empty data in timer callback", __FUNCTION__);
         return;
     }
-
+    Locker::Autolock _l(ctx->mDrawLock);
+    // Handle timeout event only if the previous composition is MDP or MIXED.
+    if(!sHandleTimeout) {
+        ALOGD_IF(isDebug(), "%s:Do not handle this timeout", __FUNCTION__);
+        return;
+    }
     if(!ctx->proc) {
         ALOGE("%s: HWC proc not registered", __FUNCTION__);
         return;
@@ -1616,9 +1622,10 @@
         return true;
     }
 
-    /* reset Invalidator */
-    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
-        idleInvalidator->handleUpdateEvent();
+    // Set the Handle timeout to true for MDP or MIXED composition.
+    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
+        sHandleTimeout = true;
+    }
 
     overlay::Overlay& ov = *ctx->mOverlay;
     LayerProp *layerProp = ctx->layerProp[mDpy];
@@ -1862,9 +1869,10 @@
         return true;
     }
 
-    /* reset Invalidator */
-    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
-        idleInvalidator->handleUpdateEvent();
+    // Set the Handle timeout to true for MDP or MIXED composition.
+    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
+        sHandleTimeout = true;
+    }
 
     overlay::Overlay& ov = *ctx->mOverlay;
     LayerProp *layerProp = ctx->layerProp[mDpy];
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index c941bd5..4215881 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -52,7 +52,7 @@
     /* Initialize MDP comp*/
     static bool init(hwc_context_t *ctx);
     static void resetIdleFallBack() { sIdleFallBack = false; }
-    static void reset() { sBwClaimed = 0.0; };
+    static void reset() { sBwClaimed = 0.0; sHandleTimeout = false; };
 
 protected:
     enum { MAX_SEC_LAYERS = 1 }; //TODO add property support
@@ -231,6 +231,8 @@
     static bool sEnablePartialFrameUpdate;
     static bool sDebugLogs;
     static bool sIdleFallBack;
+    /* Handles the timeout event from kernel, if the value is set to true */
+    static bool sHandleTimeout;
     static int sMaxPipesPerMixer;
     //Max bandwidth. Value is in GBPS. For ex: 2.3 means 2.3GBPS
     static double sMaxBw;
diff --git a/libqdutils/idle_invalidator.cpp b/libqdutils/idle_invalidator.cpp
index b53f1a3..d30375e 100644
--- a/libqdutils/idle_invalidator.cpp
+++ b/libqdutils/idle_invalidator.cpp
@@ -29,91 +29,99 @@
 
 #include "idle_invalidator.h"
 #include <unistd.h>
+#include <poll.h>
+#include <string.h>
+#include <fcntl.h>
 
 #define II_DEBUG 0
+#define IDLE_NOTIFY_PATH "/sys/devices/virtual/graphics/fb0/idle_notify"
+#define IDLE_TIME_PATH "/sys/devices/virtual/graphics/fb0/idle_time"
 
-static const char *threadName = "Invalidator";
+
+static const char *threadName = "IdleInvalidator";
 InvalidatorHandler IdleInvalidator::mHandler = NULL;
 android::sp<IdleInvalidator> IdleInvalidator::sInstance(0);
 
 IdleInvalidator::IdleInvalidator(): Thread(false), mHwcContext(0),
-    mSleepAgain(false), mSleepTime(0) {
-        ALOGD_IF(II_DEBUG, "%s", __func__);
-    }
+    mTimeoutEventFd(-1) {
+    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
+}
 
 int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data,
-                          unsigned int idleSleepTime) {
-    ALOGD_IF(II_DEBUG, "%s", __func__);
-
-    Locker::Autolock _l(mLock);
-    /* store registered handler */
+                         unsigned int idleSleepTime) {
+    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s idleSleepTime %d",
+        __FUNCTION__, idleSleepTime);
     mHandler = reg_handler;
     mHwcContext = user_data;
-    mSleepTime = idleSleepTime; //Time in millis
+
+    // Open a sysfs node to receive the timeout notification from driver.
+    mTimeoutEventFd = open(IDLE_NOTIFY_PATH, O_RDONLY);
+    if (mTimeoutEventFd < 0) {
+        ALOGE ("%s:not able to open %s node %s",
+                __FUNCTION__, IDLE_NOTIFY_PATH, strerror(errno));
+        return -1;
+    }
+
+    // Open a sysfs node to send the timeout value to driver.
+    int fd = open(IDLE_TIME_PATH, O_WRONLY);
+    if (fd < 0) {
+        ALOGE ("%s:not able to open %s node %s",
+                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+        close(mTimeoutEventFd);
+        mTimeoutEventFd = -1;
+        return -1;
+    }
+    char strSleepTime[64];
+    snprintf(strSleepTime, sizeof(strSleepTime), "%d", idleSleepTime);
+    // Notify driver about the timeout value
+    ssize_t len = pwrite(fd, strSleepTime, strlen(strSleepTime), 0);
+    if(len < -1) {
+        ALOGE ("%s:not able to write into %s node %s",
+                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+        close(mTimeoutEventFd);
+        mTimeoutEventFd = -1;
+        close(fd);
+        return -1;
+    }
+    close(fd);
+
+    //Triggers the threadLoop to run, if not already running.
+    run(threadName, android::PRIORITY_LOWEST);
     return 0;
 }
 
 bool IdleInvalidator::threadLoop() {
-    struct timeval lastUpdateTime;
-    ALOGD_IF(II_DEBUG, "%s", __func__);
-
-    {
-        //If we are here, update(s) happened, i.e mSleepAgain is set
-        Locker::Autolock _l(mLock);
-        mSleepAgain = false;
-        lastUpdateTime = mLastUpdateTime;
+    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
+    struct pollfd pFd;
+    pFd.fd = mTimeoutEventFd;
+    if (pFd.fd >= 0)
+        pFd.events = POLLPRI | POLLERR;
+    // Poll for an timeout event from driver
+    int err = poll(&pFd, 1, -1);
+    if(err > 0) {
+        if (pFd.revents & POLLPRI) {
+            char data[64];
+            // Consume the node by reading it
+            ssize_t len = pread(pFd.fd, data, 64, 0);
+            ALOGD_IF(II_DEBUG, "IdleInvalidator::%s Idle Timeout fired len %zu",
+                __FUNCTION__, len);
+            mHandler((void*)mHwcContext);
+        }
     }
-
-    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;
+    return true;
 }
 
 int IdleInvalidator::readyToRun() {
-    ALOGD_IF(II_DEBUG, "%s", __func__);
+    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
     return 0; /*NO_ERROR*/
 }
 
 void IdleInvalidator::onFirstRef() {
-    ALOGD_IF(II_DEBUG, "%s", __func__);
-}
-
-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);
+    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
 }
 
 IdleInvalidator *IdleInvalidator::getInstance() {
-    ALOGD_IF(II_DEBUG, "%s", __func__);
+    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
     if(sInstance.get() == NULL)
         sInstance = new IdleInvalidator();
     return sInstance.get();
diff --git a/libqdutils/idle_invalidator.h b/libqdutils/idle_invalidator.h
index f41c15e..a881c4b 100644
--- a/libqdutils/idle_invalidator.h
+++ b/libqdutils/idle_invalidator.h
@@ -38,19 +38,15 @@
 
 class IdleInvalidator : public android::Thread {
     void *mHwcContext;
-    struct timeval mLastUpdateTime;
-    bool mSleepAgain;
-    unsigned int mSleepTime;
+    int mTimeoutEventFd;
     static InvalidatorHandler mHandler;
     static android::sp<IdleInvalidator> sInstance;
-    mutable Locker mLock;
 
     public:
     IdleInvalidator();
     /* init timer obj */
     int init(InvalidatorHandler reg_handler, void* user_data, unsigned int
              idleSleepTime);
-    void handleUpdateEvent();
     /*Overrides*/
     virtual bool        threadLoop();
     virtual int         readyToRun();