Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 344812d2 authored by Jeff Brown's avatar Jeff Brown
Browse files

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
parent c013eaad
Loading
Loading
Loading
Loading
+39 −35
Original line number Diff line number Diff line
@@ -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,25 +701,26 @@ 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 (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;
        }

        // force our window to be removed synchronously
        mWindowManager.removeViewImmediate(mWindow.getDecorView());
        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");

        mWindow = null;
            mWindowToken = null;
        }
    }

    /**
     * Called when the Dream is ready to be shown.
@@ -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,27 +771,29 @@ 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);

        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()");
        mStarted = true;
        onDreamingStarted();
    }
        });
    }

    private void safelyFinish() {
        if (mDebug) Slog.v(TAG, "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);
        }
    }