summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jeff Brown <jeffbrown@google.com> 2014-04-02 20:00:36 -0700
committer Jeff Brown <jeffbrown@google.com> 2014-04-02 20:17:32 -0700
commit344812d2f3a9e56cc53a86a8825fb73b16d3c0dd (patch)
tree2bb29339748a4071e81b370b6f1590e9788309e9
parentc013eaad574bcb40152d90105d6fbc82293cbb11 (diff)
Clean up certain state transitions in DreamService.
Instead of posting onDreamingStarted() to a handler from attach(), do the work immediately. This ensures that the dream is actually in the expected state when the callback runs. Previously it was possible for the callback to run after detach() occurred which could cause exceptions and unexpected behavior. As it happens, there's no need to post this callback since attach() already runs on the UI thread. Handle certain races involving the window token lifecycle a little better. When the dream manager shuts down a dream, it removes the window token. This can happen before the dream completes its attach() phase in which case a BadTokenException is thrown. We now handle this exception and abort the dream in anticipation of receiving a request to finish it immediately. Add a safeguard to getDozeHardware() to handle the case where it might inadvertently be called at the wrong point in the lifecycle. Bug: 13475612 Bug: 13760290 Change-Id: I9bc9c154370d08d7727b568d398c460a38592099
-rw-r--r--core/java/android/service/dreams/DreamService.java74
1 files changed, 39 insertions, 35 deletions
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 7647c2258270..de9eeff0be2d 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -153,11 +153,11 @@ public class DreamService extends Service implements Window.Callback {
private final Handler mHandler = new Handler();
private IBinder mWindowToken;
private Window mWindow;
- private WindowManager mWindowManager;
- private boolean mInteractive = false;
+ private boolean mInteractive;
private boolean mLowProfile = true;
- private boolean mFullscreen = false;
+ private boolean mFullscreen;
private boolean mScreenBright = true;
+ private boolean mStarted;
private boolean mFinished;
private boolean mCanDoze;
private boolean mDozing;
@@ -340,7 +340,7 @@ public class DreamService extends Service implements Window.Callback {
* @return The current window manager, or null if the dream is not started.
*/
public WindowManager getWindowManager() {
- return mWindowManager;
+ return mWindow != null ? mWindow.getWindowManager() : null;
}
/**
@@ -623,7 +623,7 @@ public class DreamService extends Service implements Window.Callback {
* @hide experimental
*/
public DozeHardware getDozeHardware() {
- if (mCanDoze && mDozeHardware == null) {
+ if (mCanDoze && mDozeHardware == null && mWindowToken != null) {
try {
IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken);
if (hardware != null) {
@@ -701,24 +701,25 @@ public class DreamService extends Service implements Window.Callback {
* Must run on mHandler.
*/
private final void detach() {
- if (mWindow == null) {
- // already detached!
- return;
+ if (mStarted) {
+ if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
+ mStarted = false;
+ onDreamingStopped();
}
- if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
- onDreamingStopped();
-
- if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
-
- // force our window to be removed synchronously
- mWindowManager.removeViewImmediate(mWindow.getDecorView());
- // the following will print a log message if it finds any other leaked windows
- WindowManagerGlobal.getInstance().closeAll(mWindowToken,
- this.getClass().getName(), "Dream");
+ if (mWindow != null) {
+ // force our window to be removed synchronously
+ if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
+ mWindow.getWindowManager().removeViewImmediate(mWindow.getDecorView());
+ mWindow = null;
+ }
- mWindow = null;
- mWindowToken = null;
+ if (mWindowToken != null) {
+ // the following will print a log message if it finds any other leaked windows
+ WindowManagerGlobal.getInstance().closeAll(mWindowToken,
+ this.getClass().getName(), "Dream");
+ mWindowToken = null;
+ }
}
/**
@@ -746,12 +747,13 @@ public class DreamService extends Service implements Window.Callback {
if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
mWindowToken = windowToken;
+ mCanDoze = canDoze;
+
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
mWindow.setFormat(PixelFormat.OPAQUE);
- mCanDoze = canDoze;
if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
windowToken, WindowManager.LayoutParams.TYPE_DREAM));
@@ -769,26 +771,28 @@ public class DreamService extends Service implements Window.Callback {
| (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
);
mWindow.setAttributes(lp);
-
- if (mDebug) Slog.v(TAG, "Created and attached window: " + mWindow);
-
mWindow.setWindowManager(null, windowToken, "dream", true);
- mWindowManager = mWindow.getWindowManager();
- if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
applySystemUiVisibilityFlags(
(mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
View.SYSTEM_UI_FLAG_LOW_PROFILE);
- getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+
+ 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;
+ }
// start it up
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
- onDreamingStarted();
- }
- });
+ if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+ mStarted = true;
+ onDreamingStarted();
}
private void safelyFinish() {
@@ -831,7 +835,7 @@ public class DreamService extends Service implements Window.Callback {
WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.flags = applyFlags(lp.flags, flags, mask);
mWindow.setAttributes(lp);
- mWindowManager.updateViewLayout(mWindow.getDecorView(), lp);
+ mWindow.getWindowManager().updateViewLayout(mWindow.getDecorView(), lp);
}
}