From c2932a1be3e320679034212698aff376d5104dbe Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Thu, 20 Nov 2014 18:04:05 -0800 Subject: Hold a wake lock while dozing when display updates are pending. When the display state is DOZE or DOZE_SUSPEND, assume this means that the AP may go to sleep at any time so hold a wake lock for a little while starting when traversals are scheduled to ensure that the AP remains awake long enough to draw and post the frame to the display hardware. This patch is somewhat approximate but should be good enough for most devices today. Note that the implementation uses the window manager to ensure that the window which wants to draw is actually visible before acquiring the wake lock. There is a cost to this test (a round-trip) which should not be significant today since we do not expect apps to draw more than one frame or two while dozing. However, if we wanted to support animations in general, we might want to optimize it or eliminate the check altogether (since we can already account for the app's use of the wake lock). Another way to implement this functionality might be for the view hierarchy to listen for the power manager to report that it has entered a non-interactive power state before deciding to poke draw locks. This would be somewhat more accurate than watching the display state. Also, the draw lock timeout logic could be implemented more directly instead of using an ordinary timed wake lock. Bug: 18284212 Change-Id: I84b341c678303e8b7481bd1620e634fe82cc4350 --- core/java/android/os/PowerManager.java | 15 +++++++++++++++ core/java/android/view/IWindowSession.aidl | 15 +++++++++++++++ core/java/android/view/ViewRootImpl.java | 16 ++++++++++++++++ core/res/res/values/config.xml | 6 ++++++ core/res/res/values/symbols.xml | 1 + 5 files changed, 53 insertions(+) (limited to 'core') diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index d52dd30..e303f61 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -205,6 +205,20 @@ public final class PowerManager { public static final int DOZE_WAKE_LOCK = 0x00000040; /** + * Wake lock level: Keep the device awake enough to allow drawing to occur. + *

+ * This is used by the window manager to allow applications to draw while the + * system is dozing. It currently has no effect unless the power manager is in + * the dozing state. + *

+ * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. + *

+ * + * {@hide} + */ + public static final int DRAW_WAKE_LOCK = 0x00000080; + + /** * Mask for the wake lock level component of a combined wake lock level and flags integer. * * @hide @@ -489,6 +503,7 @@ public final class PowerManager { case FULL_WAKE_LOCK: case PROXIMITY_SCREEN_OFF_WAKE_LOCK: case DOZE_WAKE_LOCK: + case DRAW_WAKE_LOCK: break; default: throw new IllegalArgumentException("Must specify a valid wake lock level."); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 7b13e84..63e1a85 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -197,4 +197,19 @@ interface IWindowSession { void onRectangleOnScreenRequested(IBinder token, in Rect rectangle); IWindowId getWindowId(IBinder window); + + /** + * When the system is dozing in a low-power partially suspended state, pokes a short + * lived wake lock and ensures that the display is ready to accept the next frame + * of content drawn in the window. + * + * This mechanism is bound to the window rather than to the display manager or the + * power manager so that the system can ensure that the window is actually visible + * and prevent runaway applications from draining the battery. This is similar to how + * FLAG_KEEP_SCREEN_ON works. + * + * This method is synchronous because it may need to acquire a wake lock before returning. + * The assumption is that this method will be called rather infrequently. + */ + void pokeDrawLock(IBinder window); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index e4d82b1..90c2bd1 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -47,6 +47,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; +import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; @@ -831,6 +832,7 @@ public final class ViewRootImpl implements ViewParent, final int newDisplayState = mDisplay.getState(); if (oldDisplayState != newDisplayState) { mAttachInfo.mDisplayState = newDisplayState; + pokeDrawLockIfNeeded(); if (oldDisplayState != Display.STATE_UNKNOWN) { final int oldScreenState = toViewScreenState(oldDisplayState); final int newScreenState = toViewScreenState(newDisplayState); @@ -861,6 +863,19 @@ public final class ViewRootImpl implements ViewParent, } }; + void pokeDrawLockIfNeeded() { + final int displayState = mAttachInfo.mDisplayState; + if (mView != null && mAdded && mTraversalScheduled + && (displayState == Display.STATE_DOZE + || displayState == Display.STATE_DOZE_SUSPEND)) { + try { + mWindowSession.pokeDrawLock(mWindow); + } catch (RemoteException ex) { + // System server died, oh well. + } + } + } + @Override public void requestFitSystemWindows() { checkThread(); @@ -1035,6 +1050,7 @@ public final class ViewRootImpl implements ViewParent, scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); + pokeDrawLockIfNeeded(); } } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 0d8d725..17b87d6 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1844,6 +1844,12 @@ users + + 120 +