Merge "Hold a wake lock while dozing when display updates are pending." into lmp-mr1-modular-dev

This commit is contained in:
Joe LaPenna
2015-02-24 00:37:14 +00:00
committed by Android (Google) Code Review
10 changed files with 141 additions and 3 deletions

View File

@@ -204,6 +204,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.
* <p>
* 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.
* </p><p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
* </p>
*
* {@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.
*
@@ -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.");

View File

@@ -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);
}

View File

@@ -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();
}
}

View File

@@ -1844,6 +1844,12 @@
<item>users</item>
</string-array>
<!-- Number of milliseconds to hold a wake lock to ensure that drawing is fully
flushed to the display while dozing. This value needs to be large enough
to account for processing and rendering time plus a frame or two of latency
in the display pipeline plus some slack just to be sure. -->
<integer name="config_drawLockTimeoutMillis">120</integer>
<!-- default telephony hardware configuration for this platform.
-->
<!-- this string array should be overridden by the device to present a list

View File

@@ -345,6 +345,7 @@
<java-symbol type="integer" name="config_bluetooth_max_advertisers" />
<java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_drawLockTimeoutMillis" />
<java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
<java-symbol type="integer" name="config_extraFreeKbytesAdjust" />
<java-symbol type="integer" name="config_extraFreeKbytesAbsolute" />

View File

@@ -128,6 +128,7 @@ public final class PowerManagerService extends SystemService
private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
private static final int WAKE_LOCK_DOZE = 1 << 6;
private static final int WAKE_LOCK_DRAW = 1 << 7;
// Summarizes the user activity state.
private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -1398,12 +1399,15 @@ public final class PowerManagerService extends SystemService
case PowerManager.DOZE_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_DOZE;
break;
case PowerManager.DRAW_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_DRAW;
break;
}
}
// Cancel wake locks that make no sense based on the current state.
if (mWakefulness != WAKEFULNESS_DOZING) {
mWakeLockSummary &= ~WAKE_LOCK_DOZE;
mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
}
if (mWakefulness == WAKEFULNESS_ASLEEP
|| (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
@@ -1422,6 +1426,9 @@ public final class PowerManagerService extends SystemService
mWakeLockSummary |= WAKE_LOCK_CPU;
}
}
if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
mWakeLockSummary |= WAKE_LOCK_CPU;
}
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
@@ -1845,6 +1852,10 @@ public final class PowerManagerService extends SystemService
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND
&& (mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
}
mDisplayPowerRequest.dozeScreenBrightness =
mDozeScreenBrightnessOverrideFromDreamManager;
} else {
@@ -2712,6 +2723,8 @@ public final class PowerManagerService extends SystemService
return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
case PowerManager.DOZE_WAKE_LOCK:
return "DOZE_WAKE_LOCK ";
case PowerManager.DRAW_WAKE_LOCK:
return "DRAW_WAKE_LOCK ";
default:
return "??? ";
}

View File

@@ -475,6 +475,16 @@ final class Session extends IWindowSession.Stub
return mService.getWindowId(window);
}
@Override
public void pokeDrawLock(IBinder window) {
final long identity = Binder.clearCallingIdentity();
try {
mService.pokeDrawLock(this, window);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
void windowAddedLocked() {
if (mSurfaceSession == null) {
if (WindowManagerService.localLOGV) Slog.v(

View File

@@ -194,6 +194,7 @@ public class WindowManagerService extends IWindowManager.Stub
static final boolean DEBUG_TASK_MOVEMENT = false;
static final boolean DEBUG_STACK = false;
static final boolean DEBUG_DISPLAY = false;
static final boolean DEBUG_POWER = false;
static final boolean SHOW_SURFACE_ALLOC = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
@@ -338,6 +339,7 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean mHaveInputMethods;
final boolean mHasPermanentDpad;
final long mDrawLockTimeoutMillis;
final boolean mAllowBootMessages;
@@ -827,6 +829,8 @@ public class WindowManagerService extends IWindowManager.Stub
com.android.internal.R.bool.config_hasPermanentDpad);
mInTouchMode = context.getResources().getBoolean(
com.android.internal.R.bool.config_defaultInTouchMode);
mDrawLockTimeoutMillis = context.getResources().getInteger(
com.android.internal.R.integer.config_drawLockTimeoutMillis);
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mDisplaySettings = new DisplaySettings();
@@ -2992,6 +2996,15 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
public void pokeDrawLock(Session session, IBinder token) {
synchronized (mWindowMap) {
WindowState window = windowForClientLocked(session, token, false);
if (window != null) {
window.pokeDrawLockLw(mDrawLockTimeoutMillis);
}
}
}
public int relayoutWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, int flags,
@@ -10110,7 +10123,9 @@ public class WindowManagerService extends IWindowManager.Stub
if (mAllowTheaterModeWakeFromLayout
|| Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.THEATER_MODE_ON, 0) == 0) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
if (DEBUG_VISIBILITY || DEBUG_POWER) {
Slog.v(TAG, "Turning screen on after layout!");
}
mPowerManager.wakeUp(SystemClock.uptimeMillis());
}
mTurnOnScreen = false;

View File

@@ -19,9 +19,9 @@ package com.android.server.wm;
import static com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION;
import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerService.DEBUG_POWER;
import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
@@ -34,12 +34,15 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import android.app.AppOpsManager;
import android.os.Debug;
import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.SystemClock;
import android.os.WorkSource;
import android.util.TimeUtils;
import android.view.Display;
import android.view.IWindowFocusObserver;
import android.view.IWindowId;
import com.android.server.input.InputWindowHandle;
import android.content.Context;
@@ -345,6 +348,15 @@ final class WindowState implements WindowManagerPolicy.WindowState {
* the status bar */
boolean mUnderStatusBar = true;
/**
* Wake lock for drawing.
* Even though it's slightly more expensive to do so, we will use a separate wake lock
* for each app that is requesting to draw while dozing so that we can accurately track
* who is preventing the system from suspending.
* This lock is only acquired on first use.
*/
PowerManager.WakeLock mDrawLock;
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, final DisplayContent displayContent) {
@@ -1272,6 +1284,33 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
}
public void pokeDrawLockLw(long timeout) {
if (isVisibleOrAdding()) {
if (mDrawLock == null) {
// We want the tag name to be somewhat stable so that it is easier to correlate
// in wake lock statistics. So in particular, we don't want to include the
// window's hash code as in toString().
CharSequence tag = mAttrs.getTitle();
if (tag == null) {
tag = mAttrs.packageName;
}
mDrawLock = mService.mPowerManager.newWakeLock(
PowerManager.DRAW_WAKE_LOCK, "Window:" + tag);
mDrawLock.setReferenceCounted(false);
mDrawLock.setWorkSource(new WorkSource(mOwnerUid, mAttrs.packageName));
}
// Each call to acquire resets the timeout.
if (DEBUG_POWER) {
Slog.d(TAG, "pokeDrawLock: poking draw lock on behalf of visible window owned by "
+ mAttrs.packageName);
}
mDrawLock.acquire(timeout);
} else if (DEBUG_POWER) {
Slog.d(TAG, "pokeDrawLock: suppressed draw lock request for invisible window "
+ "owned by " + mAttrs.packageName);
}
}
@Override
public boolean isAlive() {
return mClient.asBinder().isBinderAlive();
@@ -1626,6 +1665,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
pw.print(" mWallpaperDisplayOffsetY=");
pw.println(mWallpaperDisplayOffsetY);
}
if (mDrawLock != null) {
pw.println("mDrawLock=" + mDrawLock);
}
}
String makeInputChannelName() {

View File

@@ -212,4 +212,9 @@ public final class BridgeWindowSession implements IWindowSession {
// pass for now.
return null;
}
@Override
public void pokeDrawLock(IBinder window) {
// pass for now.
}
}