Merge "Hold WakeLock while DreamService starts" into nyc-mr1-dev
This commit is contained in:
@@ -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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,83 +963,88 @@ 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) {
|
||||||
if (mWindowToken != null) {
|
try {
|
||||||
Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
|
if (mWindowToken != null) {
|
||||||
return;
|
Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
|
||||||
}
|
|
||||||
if (mFinished || mWaking) {
|
|
||||||
Slog.w(TAG, "attach() called after dream already finished");
|
|
||||||
try {
|
|
||||||
mSandman.finishSelf(windowToken, true /*immediate*/);
|
|
||||||
} catch (RemoteException ex) {
|
|
||||||
// system server died
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mWindowToken = windowToken;
|
|
||||||
mCanDoze = canDoze;
|
|
||||||
if (mWindowless && !mCanDoze) {
|
|
||||||
throw new IllegalStateException("Only doze dreams can be windowless");
|
|
||||||
}
|
|
||||||
if (!mWindowless) {
|
|
||||||
mWindow = new PhoneWindow(this);
|
|
||||||
mWindow.setCallback(this);
|
|
||||||
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
|
|
||||||
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
|
|
||||||
mWindow.setFormat(PixelFormat.OPAQUE);
|
|
||||||
|
|
||||||
if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
|
|
||||||
windowToken, WindowManager.LayoutParams.TYPE_DREAM));
|
|
||||||
|
|
||||||
WindowManager.LayoutParams lp = mWindow.getAttributes();
|
|
||||||
lp.type = WindowManager.LayoutParams.TYPE_DREAM;
|
|
||||||
lp.token = windowToken;
|
|
||||||
lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
|
|
||||||
lp.flags |= ( WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
|
|
||||||
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
|
|
||||||
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
|
|
||||||
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
|
|
||||||
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
|
|
||||||
| (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
|
|
||||||
| (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
|
|
||||||
);
|
|
||||||
mWindow.setAttributes(lp);
|
|
||||||
// Workaround: Currently low-profile and in-window system bar backgrounds don't go
|
|
||||||
// along well. Dreams usually don't need such bars anyways, so disable them by default.
|
|
||||||
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
|
||||||
mWindow.setWindowManager(null, windowToken, "dream", true);
|
|
||||||
|
|
||||||
applySystemUiVisibilityFlags(
|
|
||||||
(mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
|
|
||||||
View.SYSTEM_UI_FLAG_LOW_PROFILE);
|
|
||||||
|
|
||||||
try {
|
|
||||||
getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
|
|
||||||
} catch (WindowManager.BadTokenException ex) {
|
|
||||||
// This can happen because the dream manager service will remove the token
|
|
||||||
// immediately without necessarily waiting for the dream to start.
|
|
||||||
// We should receive a finish message soon.
|
|
||||||
Slog.i(TAG, "attach() called after window token already removed, dream will "
|
|
||||||
+ "finish soon");
|
|
||||||
mWindow = null;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
if (mFinished || mWaking) {
|
||||||
// We need to defer calling onDreamingStarted until after onWindowAttached,
|
Slog.w(TAG, "attach() called after dream already finished");
|
||||||
// which is posted to the handler by addView, so we post onDreamingStarted
|
try {
|
||||||
// to the handler also. Need to watch out here in case detach occurs before
|
mSandman.finishSelf(windowToken, true /*immediate*/);
|
||||||
// this callback is invoked.
|
} catch (RemoteException ex) {
|
||||||
mHandler.post(new Runnable() {
|
// system server died
|
||||||
@Override
|
}
|
||||||
public void run() {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mWindowToken = windowToken;
|
||||||
|
mCanDoze = canDoze;
|
||||||
|
if (mWindowless && !mCanDoze) {
|
||||||
|
throw new IllegalStateException("Only doze dreams can be windowless");
|
||||||
|
}
|
||||||
|
if (!mWindowless) {
|
||||||
|
mWindow = new PhoneWindow(this);
|
||||||
|
mWindow.setCallback(this);
|
||||||
|
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
|
||||||
|
mWindow.setFormat(PixelFormat.OPAQUE);
|
||||||
|
|
||||||
|
if (mDebug) {
|
||||||
|
Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
|
||||||
|
windowToken, WindowManager.LayoutParams.TYPE_DREAM));
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowManager.LayoutParams lp = mWindow.getAttributes();
|
||||||
|
lp.type = WindowManager.LayoutParams.TYPE_DREAM;
|
||||||
|
lp.token = windowToken;
|
||||||
|
lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
|
||||||
|
lp.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
|
||||||
|
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
|
||||||
|
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
|
||||||
|
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
|
||||||
|
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
|
||||||
|
| (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
|
||||||
|
| (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
|
||||||
|
);
|
||||||
|
mWindow.setAttributes(lp);
|
||||||
|
// Workaround: Currently low-profile and in-window system bar backgrounds don't go
|
||||||
|
// along well. Dreams usually don't need such bars anyways, so disable them by default.
|
||||||
|
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||||
|
mWindow.setWindowManager(null, windowToken, "dream", true);
|
||||||
|
|
||||||
|
applySystemUiVisibilityFlags(
|
||||||
|
(mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
|
||||||
|
View.SYSTEM_UI_FLAG_LOW_PROFILE);
|
||||||
|
|
||||||
|
try {
|
||||||
|
getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
|
||||||
|
} catch (WindowManager.BadTokenException ex) {
|
||||||
|
// This can happen because the dream manager service will remove the token
|
||||||
|
// immediately without necessarily waiting for the dream to start.
|
||||||
|
// We should receive a finish message soon.
|
||||||
|
Slog.i(TAG, "attach() called after window token already removed, dream will "
|
||||||
|
+ "finish soon");
|
||||||
|
mWindow = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We need to defer calling onDreamingStarted until after onWindowAttached,
|
||||||
|
// 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
|
||||||
|
// this callback is invoked.
|
||||||
|
mHandler.post(mWakeLock.wrap(() -> {
|
||||||
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) {
|
||||||
|
|||||||
@@ -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() {
|
||||||
mConnected = true;
|
try {
|
||||||
if (mCurrentDream == DreamRecord.this && mService == null) {
|
mConnected = true;
|
||||||
attach(IDreamService.Stub.asInterface(service));
|
if (mCurrentDream == DreamRecord.this && mService == null) {
|
||||||
|
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) {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user