OSDN Git Service

Reduce latency from doze to screen on.
authorJeff Brown <jeffbrown@google.com>
Tue, 30 Sep 2014 21:42:27 +0000 (14:42 -0700)
committerJeff Brown <jeffbrown@google.com>
Wed, 1 Oct 2014 01:00:40 +0000 (18:00 -0700)
Don't wait for the brightness ramp to complete before reporting
display ready.  Keep track of whether we have any unfinished
brightness changes and take care to grab a wakelock to ensure
they are eventually applied.

Ideally we would rewrite the whole state machine to more carefully
coordinate screen state and brightness changes but that's too
risky for now.

The pixel fairies are having a bad day.

Bug: 17718416

(cherry picked from commit 875f80c2732a3fbe652a6e8fc14031041f791308)

Change-Id: I7a2d8ba4591a12b773653d3dbf86c7db016f967e

services/core/java/com/android/server/display/DisplayPowerController.java
services/core/java/com/android/server/display/DisplayPowerState.java
services/core/java/com/android/server/display/RampAnimator.java

index e2a548a..e3a25c0 100644 (file)
@@ -227,6 +227,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
     // turning off the screen.
     private boolean mPendingScreenOff;
 
+    // True if we have unfinished business and are holding a suspend blocker.
+    private boolean mUnfinishedBusiness;
+
     // The elapsed real time when the screen on was blocked.
     private long mScreenOnBlockStartRealTime;
 
@@ -633,22 +636,42 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
             mAppliedLowPower = true;
         }
 
-        // Animate the screen brightness when the screen is on.
-        if (state != Display.STATE_OFF) {
-            animateScreenBrightness(brightness, slowChange
-                    ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
-        }
-
         // Animate the screen state change unless already animating.
         animateScreenStateChange(state, performScreenOffTransition);
 
-        // Report whether the display is ready for use and all changes have been applied.
-        if (mustNotify
-                && mPendingScreenOnUnblocker == null
+        // Animate the screen brightness when the screen is on or dozing.
+        // Skip the animation when the screen is off or suspended.
+        final int actualState = mPowerState.getScreenState();
+        if (actualState == Display.STATE_ON || actualState == Display.STATE_DOZE) {
+            animateScreenBrightness(brightness,
+                    slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
+        } else {
+            animateScreenBrightness(brightness, 0);
+        }
+
+        // Determine whether the display is ready for use in the newly requested state.
+        // Note that we do not wait for the brightness ramp animation to complete before
+        // reporting the display is ready because we only need to ensure the screen is in the
+        // right power state even as it continues to converge on the desired brightness.
+        final boolean ready = mPendingScreenOnUnblocker == null
                 && !mColorFadeOnAnimator.isStarted()
                 && !mColorFadeOffAnimator.isStarted()
-                && !mScreenBrightnessRampAnimator.isAnimating()
-                && mPowerState.waitUntilClean(mCleanListener)) {
+                && mPowerState.waitUntilClean(mCleanListener);
+        final boolean finished = ready
+                && !mScreenBrightnessRampAnimator.isAnimating();
+
+        // Grab a wake lock if we have unfinished business.
+        if (!finished && !mUnfinishedBusiness) {
+            if (DEBUG) {
+                Slog.d(TAG, "Unfinished business...");
+            }
+            mCallbacks.acquireSuspendBlocker();
+            mUnfinishedBusiness = true;
+        }
+
+        // Notify the power manager when ready.
+        if (ready && mustNotify) {
+            // Send state change.
             synchronized (mLock) {
                 if (!mPendingRequestChangedLocked) {
                     mDisplayReadyLocked = true;
@@ -660,6 +683,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
             }
             sendOnStateChangedWithWakelock();
         }
+
+        // Release the wake lock when we have no unfinished business.
+        if (finished && mUnfinishedBusiness) {
+            if (DEBUG) {
+                Slog.d(TAG, "Finished business...");
+            }
+            mUnfinishedBusiness = false;
+            mCallbacks.releaseSuspendBlocker();
+        }
     }
 
     @Override
@@ -723,6 +755,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
     }
 
     private void animateScreenBrightness(int target, int rate) {
+        if (DEBUG) {
+            Slog.d(TAG, "Animating brightness: target=" + target +", rate=" + rate);
+        }
         if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
             try {
                 mBatteryStats.noteScreenBrightness(target);
index a7651e4..fc068af 100644 (file)
@@ -80,6 +80,7 @@ final class DisplayPowerState {
         mBacklight = backlight;
         mColorFade = electronBeam;
         mPhotonicModulator = new PhotonicModulator();
+        mPhotonicModulator.start();
 
         // At boot time, we know that the screen is on and the electron beam
         // animation is not playing.  We don't know the screen's brightness though,
@@ -336,7 +337,7 @@ final class DisplayPowerState {
     /**
      * Updates the state of the screen and backlight asynchronously on a separate thread.
      */
-    private final class PhotonicModulator {
+    private final class PhotonicModulator extends Thread {
         private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
         private static final int INITIAL_BACKLIGHT = -1; // unknown
 
@@ -361,7 +362,7 @@ final class DisplayPowerState {
 
                     if (!mChangeInProgress) {
                         mChangeInProgress = true;
-                        AsyncTask.THREAD_POOL_EXECUTOR.execute(mTask);
+                        mLock.notifyAll();
                     }
                 }
                 return !mChangeInProgress;
@@ -369,75 +370,78 @@ final class DisplayPowerState {
         }
 
         public void dump(PrintWriter pw) {
-            pw.println();
-            pw.println("Photonic Modulator State:");
-            pw.println("  mPendingState=" + Display.stateToString(mPendingState));
-            pw.println("  mPendingBacklight=" + mPendingBacklight);
-            pw.println("  mActualState=" + Display.stateToString(mActualState));
-            pw.println("  mActualBacklight=" + mActualBacklight);
-            pw.println("  mChangeInProgress=" + mChangeInProgress);
+            synchronized (mLock) {
+                pw.println();
+                pw.println("Photonic Modulator State:");
+                pw.println("  mPendingState=" + Display.stateToString(mPendingState));
+                pw.println("  mPendingBacklight=" + mPendingBacklight);
+                pw.println("  mActualState=" + Display.stateToString(mActualState));
+                pw.println("  mActualBacklight=" + mActualBacklight);
+                pw.println("  mChangeInProgress=" + mChangeInProgress);
+            }
         }
 
-        private final Runnable mTask = new Runnable() {
-            @Override
-            public void run() {
-                // Apply pending changes until done.
-                for (;;) {
-                    final int state;
-                    final boolean stateChanged;
-                    final int backlight;
-                    final boolean backlightChanged;
-                    synchronized (mLock) {
-                        state = mPendingState;
-                        stateChanged = (state != mActualState);
-                        backlight = mPendingBacklight;
-                        backlightChanged = (backlight != mActualBacklight);
-                        if (!stateChanged && !backlightChanged) {
-                            mChangeInProgress = false;
-                            break;
-                        }
-                        mActualState = state;
-                        mActualBacklight = backlight;
-                    }
-
-                    if (DEBUG) {
-                        Slog.d(TAG, "Updating screen state: state="
-                                + Display.stateToString(state) + ", backlight=" + backlight);
-                    }
-                    boolean suspending = Display.isSuspendedState(state);
-                    if (stateChanged && !suspending) {
-                        requestDisplayState(state);
-                    }
-                    if (backlightChanged) {
-                        setBrightness(backlight);
-                    }
-                    if (stateChanged && suspending) {
-                        requestDisplayState(state);
+        @Override
+        public void run() {
+            for (;;) {
+                // Get pending change.
+                final int state;
+                final boolean stateChanged;
+                final int backlight;
+                final boolean backlightChanged;
+                synchronized (mLock) {
+                    state = mPendingState;
+                    stateChanged = (state != mActualState);
+                    backlight = mPendingBacklight;
+                    backlightChanged = (backlight != mActualBacklight);
+                    if (!stateChanged && !backlightChanged) {
+                        // All changed applied, notify outer class and wait for more.
+                        mChangeInProgress = false;
+                        postScreenUpdateThreadSafe();
+                        try {
+                            mLock.wait();
+                        } catch (InterruptedException ex) { }
+                        continue;
                     }
+                    mActualState = state;
+                    mActualBacklight = backlight;
                 }
 
-                // Let the outer class know that all changes have been applied.
-                postScreenUpdateThreadSafe();
+                // Apply pending change.
+                if (DEBUG) {
+                    Slog.d(TAG, "Updating screen state: state="
+                            + Display.stateToString(state) + ", backlight=" + backlight);
+                }
+                boolean suspending = Display.isSuspendedState(state);
+                if (stateChanged && !suspending) {
+                    requestDisplayState(state);
+                }
+                if (backlightChanged) {
+                    setBrightness(backlight);
+                }
+                if (stateChanged && suspending) {
+                    requestDisplayState(state);
+                }
             }
+        }
 
-            private void requestDisplayState(int state) {
-                Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
-                        + Display.stateToString(state) + ")");
-                try {
-                    mBlanker.requestDisplayState(state);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_POWER);
-                }
+        private void requestDisplayState(int state) {
+            Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
+                    + Display.stateToString(state) + ")");
+            try {
+                mBlanker.requestDisplayState(state);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_POWER);
             }
+        }
 
-            private void setBrightness(int backlight) {
-                Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")");
-                try {
-                    mBacklight.setBrightness(backlight);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_POWER);
-                }
+        private void setBrightness(int backlight) {
+            Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")");
+            try {
+                mBacklight.setBrightness(backlight);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_POWER);
             }
-        };
+        }
     }
 }
index ad1e857..d71269f 100644 (file)
@@ -50,20 +50,32 @@ final class RampAnimator<T> {
     /**
      * Starts animating towards the specified value.
      *
-     * If this is the first time the property is being set, the value jumps
-     * directly to the target.
+     * If this is the first time the property is being set or if the rate is 0,
+     * the value jumps directly to the target.
      *
      * @param target The target value.
-     * @param rate The convergence rate, in units per second.
+     * @param rate The convergence rate in units per second, or 0 to set the value immediately.
      * @return True if the target differs from the previous target.
      */
     public boolean animateTo(int target, int rate) {
         // Immediately jump to the target the first time.
-        if (mFirstTime) {
-            mFirstTime = false;
-            mProperty.setValue(mObject, target);
-            mCurrentValue = target;
-            return true;
+        if (mFirstTime || rate <= 0) {
+            if (mFirstTime || target != mCurrentValue) {
+                mFirstTime = false;
+                mRate = 0;
+                mTargetValue = target;
+                mCurrentValue = target;
+                mProperty.setValue(mObject, target);
+                if (mAnimating) {
+                    mAnimating = false;
+                    cancelAnimationCallback();
+                }
+                if (mListener != null) {
+                    mListener.onAnimationEnd();
+                }
+                return true;
+            }
+            return false;
         }
 
         // Adjust the rate based on the closest target.
@@ -88,7 +100,7 @@ final class RampAnimator<T> {
             mAnimating = true;
             mAnimatedValue = mCurrentValue;
             mLastFrameTimeNanos = System.nanoTime();
-            postCallback();
+            postAnimationCallback();
         }
 
         return changed;
@@ -108,11 +120,15 @@ final class RampAnimator<T> {
         mListener = listener;
     }
 
-    private void postCallback() {
-        mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mCallback, null);
+    private void postAnimationCallback() {
+        mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);
+    }
+
+    private void cancelAnimationCallback() {
+        mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);
     }
 
-    private final Runnable mCallback = new Runnable() {
+    private final Runnable mAnimationCallback = new Runnable() {
         @Override // Choreographer callback
         public void run() {
             final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
@@ -144,7 +160,7 @@ final class RampAnimator<T> {
             }
 
             if (mTargetValue != mCurrentValue) {
-                postCallback();
+                postAnimationCallback();
             } else {
                 mAnimating = false;
                 if (mListener != null) {