surfaceflinger: Replace blank/unblank with setPowerMode

We replace the blank/unblank calls in surfaceFlinger with a more generic
setPowerMode() routine.

Some displays support different power modes (for example, with reduced
color palettes). Depending on the use case we should be able to toggle
these modes, so as to achieve incremental power savings.

Initially, three power modes will be supported:
- HWC_POWER_MODE_OFF
- HWC_POWER_MODE_DOZE
- HWC_POWER_MODE_NORMAL

HWC_POWER_MODE_OFF will correspond to blanking the display, while
HWC_POWER_MODE_NORMAL will correspond to unblanking. HWC_POWER_MODE_DOZE
will put the display into a low power setting, if it is supported in
hardware.

If such a low power mode is not supported, it should be treated as a
call to set the mode to HWC_POWER_MODE_NORMAL.

As a consequence of adding the mPowerMode field, the mScreenAcquired is
no longer required, and thus references to it are removed and replaced
equivalent references to mPowerMode.

We also add the glue code to connect the services invocation of setting
a power mode and the HAL implementation in HWComposer.

Bug: 13472578
Change-Id: I431595ecf16d2f2c94259272db3dd42f29636204
Signed-off-by: Prashant Malani <pmalani@google.com>
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7152f93..06435ab 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -437,7 +437,7 @@
                 // for displays other than the main display, so we always
                 // assume a connected display is unblanked.
                 ALOGD("marking display %zu as acquired/unblanked", i);
-                hw->acquireScreen();
+                hw->setPowerMode(HWC_POWER_MODE_NORMAL);
             }
             mDisplays.add(token, hw);
         }
@@ -793,7 +793,7 @@
     const bool repaintEverything = mRepaintEverything;
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
         const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (hw->canDraw()) {
+        if (hw->isDisplayOn()) {
             // transform the dirty region into this screen's coordinate space
             const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
             if (!dirtyRegion.isEmpty()) {
@@ -860,7 +860,7 @@
 
     if (runningWithoutSyncFramework) {
         const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
-        if (hw->isScreenAcquired()) {
+        if (hw->isDisplayOn()) {
             enableHardwareVsync();
         }
     }
@@ -895,7 +895,7 @@
             const sp<DisplayDevice>& hw(mDisplays[dpy]);
             const Transform& tr(hw->getTransform());
             const Rect bounds(hw->getBounds());
-            if (hw->canDraw()) {
+            if (hw->isDisplayOn()) {
                 SurfaceFlinger::computeVisibleRegions(layers,
                         hw->getLayerStack(), dirtyRegion, opaqueRegion);
 
@@ -991,7 +991,7 @@
     const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
         const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (hw->canDraw()) {
+        if (hw->isDisplayOn()) {
             // transform the dirty region into this screen's coordinate space
             const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
 
@@ -2082,7 +2082,7 @@
     d.viewport.makeInvalid();
     displays.add(d);
     setTransactionState(state, displays, 0);
-    onScreenAcquired(getDefaultDisplayDevice());
+    setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);
 
     const nsecs_t period =
             getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
@@ -2103,42 +2103,35 @@
     postMessageAsync(msg);  // we may be called from main thread, use async message
 }
 
+void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
+        int mode) {
+    ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
+            this);
+    int32_t type = hw->getDisplayType();
+    int currentMode = hw->getPowerMode();
 
-void SurfaceFlinger::onScreenAcquired(const sp<const DisplayDevice>& hw) {
-    ALOGD("Screen acquired, type=%d flinger=%p", hw->getDisplayType(), this);
-    if (hw->isScreenAcquired()) {
-        // this is expected, e.g. when power manager wakes up during boot
-        ALOGD(" screen was previously acquired");
+    if (mode == currentMode) {
+        ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
         return;
     }
 
-    hw->acquireScreen();
-    int32_t type = hw->getDisplayType();
-    if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
-        // built-in display, tell the HWC
-        getHwComposer().acquire(type);
+    hw->setPowerMode(mode);
+    if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+        ALOGW("Trying to set power mode for virtual display");
+        return;
+    }
 
+    if (currentMode == HWC_POWER_MODE_OFF) {
+        getHwComposer().setPowerMode(type, mode);
         if (type == DisplayDevice::DISPLAY_PRIMARY) {
             // FIXME: eventthread only knows about the main display right now
             mEventThread->onScreenAcquired();
-
             resyncToHardwareVsync(true);
         }
-    }
-    mVisibleRegionsDirty = true;
-    repaintEverything();
-}
 
-void SurfaceFlinger::onScreenReleased(const sp<const DisplayDevice>& hw) {
-    ALOGD("Screen released, type=%d flinger=%p", hw->getDisplayType(), this);
-    if (!hw->isScreenAcquired()) {
-        ALOGD(" screen was previously released");
-        return;
-    }
-
-    hw->releaseScreen();
-    int32_t type = hw->getDisplayType();
-    if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+        mVisibleRegionsDirty = true;
+        repaintEverything();
+    } else if (mode == HWC_POWER_MODE_OFF) {
         if (type == DisplayDevice::DISPLAY_PRIMARY) {
             disableHardwareVsync(true); // also cancels any in-progress resync
 
@@ -2146,56 +2139,38 @@
             mEventThread->onScreenReleased();
         }
 
-        // built-in display, tell the HWC
-        getHwComposer().release(type);
+        getHwComposer().setPowerMode(type, mode);
+        mVisibleRegionsDirty = true;
+        // from this point on, SF will stop drawing on this display
+    } else {
+        getHwComposer().setPowerMode(type, mode);
     }
-    mVisibleRegionsDirty = true;
-    // from this point on, SF will stop drawing on this display
 }
 
-void SurfaceFlinger::unblank(const sp<IBinder>& display) {
-    class MessageScreenAcquired : public MessageBase {
+void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
+    class MessageSetPowerMode: public MessageBase {
         SurfaceFlinger& mFlinger;
         sp<IBinder> mDisplay;
+        int mMode;
     public:
-        MessageScreenAcquired(SurfaceFlinger& flinger,
-                const sp<IBinder>& disp) : mFlinger(flinger), mDisplay(disp) { }
+        MessageSetPowerMode(SurfaceFlinger& flinger,
+                const sp<IBinder>& disp, int mode) : mFlinger(flinger),
+                    mDisplay(disp) { mMode = mode; }
         virtual bool handler() {
-            const sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
+            sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
             if (hw == NULL) {
-                ALOGE("Attempt to unblank null display %p", mDisplay.get());
+                ALOGE("Attempt to set power mode = %d for null display %p",
+                        mDisplay.get(), mMode);
             } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
-                ALOGW("Attempt to unblank virtual display");
+                ALOGW("Attempt to set power mode = %d for virtual display",
+                        mMode);
             } else {
-                mFlinger.onScreenAcquired(hw);
+                mFlinger.setPowerModeInternal(hw, mMode);
             }
             return true;
         }
     };
-    sp<MessageBase> msg = new MessageScreenAcquired(*this, display);
-    postMessageSync(msg);
-}
-
-void SurfaceFlinger::blank(const sp<IBinder>& display) {
-    class MessageScreenReleased : public MessageBase {
-        SurfaceFlinger& mFlinger;
-        sp<IBinder> mDisplay;
-    public:
-        MessageScreenReleased(SurfaceFlinger& flinger,
-                const sp<IBinder>& disp) : mFlinger(flinger), mDisplay(disp) { }
-        virtual bool handler() {
-            const sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
-            if (hw == NULL) {
-                ALOGE("Attempt to blank null display %p", mDisplay.get());
-            } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
-                ALOGW("Attempt to blank virtual display");
-            } else {
-                mFlinger.onScreenReleased(hw);
-            }
-            return true;
-        }
-    };
-    sp<MessageBase> msg = new MessageScreenReleased(*this, display);
+    sp<MessageBase> msg = new MessageSetPowerMode(*this, display, mode);
     postMessageSync(msg);
 }
 
@@ -2456,8 +2431,8 @@
     mRenderEngine->dump(result);
 
     hw->undefinedRegion.dump(result, "undefinedRegion");
-    result.appendFormat("  orientation=%d, canDraw=%d\n",
-            hw->getOrientation(), hw->canDraw());
+    result.appendFormat("  orientation=%d, isDisplayOn=%d\n",
+            hw->getOrientation(), hw->isDisplayOn());
     result.appendFormat(
             "  last eglSwapBuffers() time: %f us\n"
             "  last transaction time     : %f us\n"
@@ -2549,10 +2524,9 @@
         case CREATE_DISPLAY:
         case SET_TRANSACTION_STATE:
         case BOOT_FINISHED:
-        case BLANK:
-        case UNBLANK:
         case CLEAR_ANIMATION_FRAME_STATS:
         case GET_ANIMATION_FRAME_STATS:
+        case SET_POWER_MODE:
         {
             // codes that require permission check
             IPCThreadState* ipc = IPCThreadState::self();