Merge "Hold WakeLock while DreamService starts" into nyc-mr1-dev

This commit is contained in:
Adrian Roos
2016-09-19 22:47:28 +00:00
committed by Android (Google) Code Review
4 changed files with 154 additions and 84 deletions

View File

@@ -1358,5 +1358,34 @@ public final class PowerManager {
+ " held=" + mHeld + ", refCount=" + mCount + "}"; + " held=" + mHeld + ", refCount=" + mCount + "}";
} }
} }
/**
* Wraps a Runnable such that this method immediately acquires the wake lock and then
* once the Runnable is done the wake lock is released.
*
* <p>Example:
*
* <pre>
* mHandler.post(mWakeLock.wrap(() -> {
* // do things on handler, lock is held while we're waiting for this
* // to get scheduled and until the runnable is done executing.
* });
* </pre>
*
* <p>Note: you must make sure that the Runnable eventually gets executed, otherwise you'll
* leak the wakelock!
*
* @hide
*/
public Runnable wrap(Runnable r) {
acquire();
return () -> {
try {
r.run();
} finally {
release();
}
};
}
} }
} }

View File

@@ -192,6 +192,9 @@ public class DreamService extends Service implements Window.Callback {
private boolean mDebug = false; private boolean mDebug = false;
private PowerManager.WakeLock mWakeLock;
private boolean mWakeLockAcquired;
public DreamService() { public DreamService() {
mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE)); mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
} }
@@ -786,6 +789,8 @@ public class DreamService extends Service implements Window.Callback {
public void onCreate() { public void onCreate() {
if (mDebug) Slog.v(TAG, "onCreate()"); if (mDebug) Slog.v(TAG, "onCreate()");
super.onCreate(); super.onCreate();
mWakeLock = getSystemService(PowerManager.class)
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DreamService");
} }
/** /**
@@ -825,9 +830,21 @@ public class DreamService extends Service implements Window.Callback {
@Override @Override
public final IBinder onBind(Intent intent) { public final IBinder onBind(Intent intent) {
if (mDebug) Slog.v(TAG, "onBind() intent = " + intent); if (mDebug) Slog.v(TAG, "onBind() intent = " + intent);
// Need to stay awake until we dispatch onDreamingStarted. This is released either in
// attach() or onDestroy().
mWakeLock.acquire(5000);
mWakeLockAcquired = true;
return new DreamServiceWrapper(); return new DreamServiceWrapper();
} }
private void releaseWakeLockIfNeeded() {
if (mWakeLockAcquired) {
mWakeLock.release();
mWakeLockAcquired = false;
}
}
/** /**
* Stops the dream and detaches from the window. * Stops the dream and detaches from the window.
* <p> * <p>
@@ -904,6 +921,8 @@ public class DreamService extends Service implements Window.Callback {
detach(); detach();
super.onDestroy(); super.onDestroy();
releaseWakeLockIfNeeded(); // for acquire in onBind()
} }
// end public api // end public api
@@ -944,6 +963,7 @@ public class DreamService extends Service implements Window.Callback {
* @param windowToken A window token that will allow a window to be created in the correct layer. * @param windowToken A window token that will allow a window to be created in the correct layer.
*/ */
private final void attach(IBinder windowToken, boolean canDoze) { private final void attach(IBinder windowToken, boolean canDoze) {
try {
if (mWindowToken != null) { if (mWindowToken != null) {
Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken); Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
return; return;
@@ -970,14 +990,16 @@ public class DreamService extends Service implements Window.Callback {
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000)); mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
mWindow.setFormat(PixelFormat.OPAQUE); mWindow.setFormat(PixelFormat.OPAQUE);
if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s", if (mDebug) {
Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
windowToken, WindowManager.LayoutParams.TYPE_DREAM)); windowToken, WindowManager.LayoutParams.TYPE_DREAM));
}
WindowManager.LayoutParams lp = mWindow.getAttributes(); WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.type = WindowManager.LayoutParams.TYPE_DREAM; lp.type = WindowManager.LayoutParams.TYPE_DREAM;
lp.token = windowToken; lp.token = windowToken;
lp.windowAnimations = com.android.internal.R.style.Animation_Dream; lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
lp.flags |= ( WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN lp.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
@@ -1011,16 +1033,18 @@ public class DreamService extends Service implements Window.Callback {
// which is posted to the handler by addView, so we post onDreamingStarted // which is posted to the handler by addView, so we post onDreamingStarted
// to the handler also. Need to watch out here in case detach occurs before // to the handler also. Need to watch out here in case detach occurs before
// this callback is invoked. // this callback is invoked.
mHandler.post(new Runnable() { mHandler.post(mWakeLock.wrap(() -> {
@Override
public void run() {
if (mWindow != null || mWindowless) { if (mWindow != null || mWindowless) {
if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()"); if (mDebug) {
Slog.v(TAG, "Calling onDreamingStarted()");
}
mStarted = true; mStarted = true;
onDreamingStarted(); onDreamingStarted();
} }
}));
} finally {
releaseWakeLockIfNeeded(); // for acquire in onBind
} }
});
} }
private boolean getWindowFlagValue(int flag, boolean defaultValue) { private boolean getWindowFlagValue(int flag, boolean defaultValue) {

View File

@@ -26,6 +26,7 @@ import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.IBinder.DeathRecipient; import android.os.IBinder.DeathRecipient;
import android.os.SystemClock; import android.os.SystemClock;
@@ -116,19 +117,19 @@ final class DreamController {
} }
public void startDream(Binder token, ComponentName name, public void startDream(Binder token, ComponentName name,
boolean isTest, boolean canDoze, int userId) { boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
stopDream(true /*immediate*/); stopDream(true /*immediate*/);
Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream"); Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
try { try {
// Close the notification shade. Don't need to send to all, but better to be explicit. // Close the notification shade. No need to send to all, but better to be explicit.
mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL); mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
Slog.i(TAG, "Starting dream: name=" + name Slog.i(TAG, "Starting dream: name=" + name
+ ", isTest=" + isTest + ", canDoze=" + canDoze + ", isTest=" + isTest + ", canDoze=" + canDoze
+ ", userId=" + userId); + ", userId=" + userId);
mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId); mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId, wakeLock);
mDreamStartTime = SystemClock.elapsedRealtime(); mDreamStartTime = SystemClock.elapsedRealtime();
MetricsLogger.visible(mContext, MetricsLogger.visible(mContext,
@@ -230,6 +231,7 @@ final class DreamController {
if (oldDream.mBound) { if (oldDream.mBound) {
mContext.unbindService(oldDream); mContext.unbindService(oldDream);
} }
oldDream.releaseWakeLockIfNeeded();
try { try {
mIWindowManager.removeWindowToken(oldDream.mToken); mIWindowManager.removeWindowToken(oldDream.mToken);
@@ -280,6 +282,7 @@ final class DreamController {
public final boolean mCanDoze; public final boolean mCanDoze;
public final int mUserId; public final int mUserId;
public PowerManager.WakeLock mWakeLock;
public boolean mBound; public boolean mBound;
public boolean mConnected; public boolean mConnected;
public IDreamService mService; public IDreamService mService;
@@ -288,12 +291,17 @@ final class DreamController {
public boolean mWakingGently; public boolean mWakingGently;
public DreamRecord(Binder token, ComponentName name, public DreamRecord(Binder token, ComponentName name,
boolean isTest, boolean canDoze, int userId) { boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
mToken = token; mToken = token;
mName = name; mName = name;
mIsTest = isTest; mIsTest = isTest;
mCanDoze = canDoze; mCanDoze = canDoze;
mUserId = userId; mUserId = userId;
mWakeLock = wakeLock;
// Hold the lock while we're waiting for the service to connect. Released either when
// DreamService connects (and is then responsible for keeping the device awake) or
// dreaming stops.
mWakeLock.acquire();
} }
// May be called on any thread. // May be called on any thread.
@@ -316,14 +324,25 @@ final class DreamController {
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
try {
mConnected = true; mConnected = true;
if (mCurrentDream == DreamRecord.this && mService == null) { if (mCurrentDream == DreamRecord.this && mService == null) {
attach(IDreamService.Stub.asInterface(service)); attach(IDreamService.Stub.asInterface(service));
} }
} finally {
releaseWakeLockIfNeeded();
}
} }
}); });
} }
private void releaseWakeLockIfNeeded() {
if (mWakeLock != null) {
mWakeLock.release();
mWakeLock = null;
}
}
// May be called on any thread. // May be called on any thread.
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {

View File

@@ -370,12 +370,10 @@ public final class DreamManagerService extends SystemService {
mCurrentDreamCanDoze = canDoze; mCurrentDreamCanDoze = canDoze;
mCurrentDreamUserId = userId; mCurrentDreamUserId = userId;
mHandler.post(new Runnable() { PowerManager.WakeLock wakeLock = mPowerManager
@Override .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
public void run() { mHandler.post(wakeLock.wrap(
mController.startDream(newToken, name, isTest, canDoze, userId); () -> mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock)));
}
});
} }
private void stopDreamLocked(final boolean immediate) { private void stopDreamLocked(final boolean immediate) {