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

Commit 9ede1d26 authored by Adrian Roos's avatar Adrian Roos
Browse files

Fix wake lock logic during Dream startup

Fixes a crash that would happen in all dreams
that did not have permission to acquire wake locks.
Instead moves the wake lock logic into the system
process. Also fixes a bug in DozeService where the
wake lock was not held until dozing was actually
properly initialized.

Fixes: 31612287
Bug: 31044352
Related-CL: I85955a2b7d6bad5171accbc336117a9660b1b198
Test: adb shell settings put secure screensaver_components com.android.dreams.basic/.Colors; adb shell service call dreams 1

Change-Id: Idb3f921ee71b6da6c2ab0c44c332ef91f93ddbc0
parent 6f300c17
Loading
Loading
Loading
Loading
+83 −96
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -192,9 +193,6 @@ public class DreamService extends Service implements Window.Callback {

    private boolean mDebug = false;

    private PowerManager.WakeLock mWakeLock;
    private boolean mWakeLockAcquired;

    public DreamService() {
        mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
    }
@@ -789,8 +787,6 @@ public class DreamService extends Service implements Window.Callback {
    public void onCreate() {
        if (mDebug) Slog.v(TAG, "onCreate()");
        super.onCreate();
        mWakeLock = getSystemService(PowerManager.class)
                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DreamService");
    }

    /**
@@ -830,21 +826,9 @@ public class DreamService extends Service implements Window.Callback {
    @Override
    public final IBinder 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();
    }

    private void releaseWakeLockIfNeeded() {
        if (mWakeLockAcquired) {
            mWakeLock.release();
            mWakeLockAcquired = false;
        }
    }

    /**
     * Stops the dream and detaches from the window.
     * <p>
@@ -921,8 +905,6 @@ public class DreamService extends Service implements Window.Callback {
        detach();

        super.onDestroy();

        releaseWakeLockIfNeeded(); // for acquire in onBind()
    }

    // end public api
@@ -961,9 +943,9 @@ public class DreamService extends Service implements Window.Callback {
     * Must run on mHandler.
     *
     * @param windowToken A window token that will allow a window to be created in the correct layer.
     * @param started A callback that will be invoked once onDreamingStarted has completed.
     */
    private final void attach(IBinder windowToken, boolean canDoze) {
        try {
    private final void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started) {
        if (mWindowToken != null) {
            Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
            return;
@@ -990,10 +972,8 @@ public class DreamService extends Service implements Window.Callback {
            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",
            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;
@@ -1033,19 +1013,25 @@ public class DreamService extends Service implements Window.Callback {
        // 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(() -> {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (mWindow != null || mWindowless) {
                    if (mDebug) {
                        Slog.v(TAG, "Calling onDreamingStarted()");
                    }
                    if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
                    mStarted = true;
                    try {
                        onDreamingStarted();
                }
            }));
                    } finally {
            releaseWakeLockIfNeeded(); // for acquire in onBind
                        try {
                            started.sendResult(null);
                        } catch (RemoteException e) {
                            throw e.rethrowFromSystemServer();
                        }
                    }
                }
            }
        });
    }

    private boolean getWindowFlagValue(int flag, boolean defaultValue) {
        return mWindow == null ? defaultValue : (mWindow.getAttributes().flags & flag) != 0;
@@ -1116,11 +1102,12 @@ public class DreamService extends Service implements Window.Callback {

    private final class DreamServiceWrapper extends IDreamService.Stub {
        @Override
        public void attach(final IBinder windowToken, final boolean canDoze) {
        public void attach(final IBinder windowToken, final boolean canDoze,
                IRemoteCallback started) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    DreamService.this.attach(windowToken, canDoze);
                    DreamService.this.attach(windowToken, canDoze, started);
                }
            });
        }
+3 −1
Original line number Diff line number Diff line
@@ -16,11 +16,13 @@

package android.service.dreams;

import android.os.IRemoteCallback;

/**
 * @hide
 */
oneway interface IDreamService {
    void attach(IBinder windowToken, boolean canDoze);
    void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started);
    void detach();
    void wakeUp();
}
+7 −10
Original line number Diff line number Diff line
@@ -159,9 +159,7 @@ public class DozeService extends DreamService {
        // Ask the host to get things ready to start dozing.
        // Once ready, we call startDozing() at which point the CPU may suspend
        // and we will need to acquire a wakelock to do work.
        mHost.startDozing(new Runnable() {
            @Override
            public void run() {
        mHost.startDozing(mWakeLock.wrap(() -> {
            if (mDreaming) {
                startDozing();

@@ -169,8 +167,7 @@ public class DozeService extends DreamService {
                // wakelock whenever we are doing work.  Note that we never call
                // stopDozing because can we just keep dozing until the bitter end.
            }
            }
        });
        }));
    }

    @Override
+30 −17
Original line number Diff line number Diff line
@@ -24,8 +24,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.IBinder.DeathRecipient;
@@ -253,7 +255,8 @@ final class DreamController {
    private void attach(IDreamService service) {
        try {
            service.asBinder().linkToDeath(mCurrentDream, 0);
            service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze);
            service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze,
                    mCurrentDream.mDreamingStartedCallback);
        } catch (RemoteException ex) {
            Slog.e(TAG, "The dream service died unexpectedly.", ex);
            stopDream(true /*immediate*/);
@@ -298,10 +301,10 @@ final class DreamController {
            mCanDoze = canDoze;
            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.
            // Hold the lock while we're waiting for the service to connect and start dreaming.
            // Released after the service has started dreaming, we stop dreaming, or it timed out.
            mWakeLock.acquire();
            mHandler.postDelayed(mReleaseWakeLockIfNeeded, 10000);
        }

        // May be called on any thread.
@@ -324,25 +327,17 @@ final class DreamController {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    try {
                    mConnected = true;
                    if (mCurrentDream == DreamRecord.this && mService == null) {
                        attach(IDreamService.Stub.asInterface(service));
                        }
                    } finally {
                        // Wake lock will be released once dreaming starts.
                    } else {
                        releaseWakeLockIfNeeded();
                    }
                }
            });
        }

        private void releaseWakeLockIfNeeded() {
            if (mWakeLock != null) {
                mWakeLock.release();
                mWakeLock = null;
            }
        }

        // May be called on any thread.
        @Override
        public void onServiceDisconnected(ComponentName name) {
@@ -356,5 +351,23 @@ final class DreamController {
                }
            });
        }

        void releaseWakeLockIfNeeded() {
            if (mWakeLock != null) {
                mWakeLock.release();
                mWakeLock = null;
                mHandler.removeCallbacks(mReleaseWakeLockIfNeeded);
            }
        }

        final Runnable mReleaseWakeLockIfNeeded = this::releaseWakeLockIfNeeded;

        final IRemoteCallback mDreamingStartedCallback = new IRemoteCallback.Stub() {
            // May be called on any thread.
            @Override
            public void sendResult(Bundle data) throws RemoteException {
                mHandler.post(mReleaseWakeLockIfNeeded);
            }
        };
    }
}
 No newline at end of file