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

Commit 061ea995 authored by Jeff Brown's avatar Jeff Brown
Browse files

Make activity manager sleep top activity when dreaming.

Added the concept of a sleep token to represent a demand to sleep.
We grab this token whenever a dream window is visible.

This change also deletes a special condition in shouldSleepLocked()
which would tend to keep activities running when the lock screen
was shown unless they had previously been sleeping.  I believe this
condition is no longer necessary and the policy is much simpler
without it.  Let's see if anything breaks.

NOTE: This can currently only be used within the system server process
but it might make sense to move it to IActivityManager (guarded by
DEVICE_POWER permission) so that keyguard can use it.  If we added
a callback on release to inform the client that the underlying activity
has finished drawing then we could untangle a bunch of keyguard
specific logic.

Bug: 18866521
Change-Id: I84b2118f5b990a71a1647d1cee536ad3d99f3a24
parent 250dd262
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.app;

import android.annotation.NonNull;

/**
 * Activity manager local system service interface.
 *
@@ -27,4 +29,23 @@ public abstract class ActivityManagerInternal {

    public abstract int startIsolatedProcess(String entryPoint, String[] mainArgs,
            String processName, String abiOverride, int uid, Runnable crashHandler);

    /**
     * Acquires a sleep token with the specified tag.
     *
     * @param tag A string identifying the purpose of the token (eg. "Dream").
     */
    public abstract SleepToken acquireSleepToken(@NonNull String tag);

    /**
     * Sleep tokens cause the activity manager to put the top activity to sleep.
     * They are used by components such as dreams that may hide and block interaction
     * with underlying activities.
     */
    public static abstract class SleepToken {
        /**
         * Releases the sleep token.
         */
        public abstract void release();
    }
}
+49 −5
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@ import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.SleepToken;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.ActivityThread;
@@ -1009,6 +1010,13 @@ public final class ActivityManagerService extends ActivityManagerNative
     */
    private int mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
    /**
     * A list of tokens that cause the top activity to be put to sleep.
     * They are used by components that may hide and block interaction with underlying
     * activities.
     */
    final ArrayList<SleepToken> mSleepTokens = new ArrayList<SleepToken>();
    static final int LOCK_SCREEN_HIDDEN = 0;
    static final int LOCK_SCREEN_LEAVING = 1;
    static final int LOCK_SCREEN_SHOWN = 2;
@@ -9810,15 +9818,14 @@ public final class ActivityManagerService extends ActivityManagerNative
            return false;
        }
        // TODO: Transform the lock screen state into a sleep token instead.
        switch (mWakefulness) {
            case PowerManagerInternal.WAKEFULNESS_AWAKE:
            case PowerManagerInternal.WAKEFULNESS_DREAMING:
                // If we're interactive but applications are already paused then defer
                // resuming them until the lock screen is hidden.
                return mSleeping && mLockScreenShown != LOCK_SCREEN_HIDDEN;
            case PowerManagerInternal.WAKEFULNESS_DOZING:
                // If we're dozing then pause applications whenever the lock screen is shown.
                return mLockScreenShown != LOCK_SCREEN_HIDDEN;
                // Pause applications whenever the lock screen is shown or any sleep
                // tokens have been acquired.
                return (mLockScreenShown != LOCK_SCREEN_HIDDEN || !mSleepTokens.isEmpty());
            case PowerManagerInternal.WAKEFULNESS_ASLEEP:
            default:
                // If we're asleep then pause applications unconditionally.
@@ -12947,6 +12954,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        if (dumpPackage == null) {
            pw.println("  mWakefulness="
                    + PowerManagerInternal.wakefulnessToString(mWakefulness));
            pw.println("  mSleepTokens=" + mSleepTokens);
            pw.println("  mSleeping=" + mSleeping + " mLockScreenShown="
                    + lockScreenShownToString());
            pw.println("  mShuttingDown=" + mShuttingDown + " mTestPssMode=" + mTestPssMode);
@@ -19720,6 +19728,42 @@ public final class ActivityManagerService extends ActivityManagerNative
            return ActivityManagerService.this.startIsolatedProcess(entryPoint, entryPointArgs,
                    processName, abiOverride, uid, crashHandler);
        }
        @Override
        public SleepToken acquireSleepToken(String tag) {
            Preconditions.checkNotNull(tag);
            synchronized (ActivityManagerService.this) {
                SleepTokenImpl token = new SleepTokenImpl(tag);
                mSleepTokens.add(token);
                updateSleepIfNeededLocked();
                return token;
            }
        }
    }
    private final class SleepTokenImpl extends SleepToken {
        private final String mTag;
        private final long mAcquireTime;
        public SleepTokenImpl(String tag) {
            mTag = tag;
            mAcquireTime = SystemClock.uptimeMillis();
        }
        @Override
        public void release() {
            synchronized (ActivityManagerService.this) {
                if (mSleepTokens.remove(this)) {
                    updateSleepIfNeededLocked();
                }
            }
        }
        @Override
        public String toString() {
            return "{\"" + mTag + "\", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
        }
    }
    /**
+33 −1
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.server.policy;

import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.SleepToken;
import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.IUiModeManager;
@@ -251,6 +253,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    WindowManagerFuncs mWindowManagerFuncs;
    WindowManagerInternal mWindowManagerInternal;
    PowerManager mPowerManager;
    ActivityManagerInternal mActivityManagerInternal;
    DreamManagerInternal mDreamManagerInternal;
    IStatusBarService mStatusBarService;
    boolean mPreloadedRecentApps;
@@ -492,6 +495,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    boolean mShowingLockscreen;
    boolean mShowingDream;
    boolean mDreamingLockscreen;
    boolean mDreamingSleepTokenNeeded;
    SleepToken mDreamingSleepToken;
    boolean mKeyguardSecure;
    boolean mKeyguardSecureIncludingHidden;
    volatile boolean mKeyguardOccluded;
@@ -598,6 +603,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
    private static final int MSG_POWER_DELAYED_PRESS = 13;
    private static final int MSG_POWER_LONG_PRESS = 14;
    private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 15;

    private class PolicyHandler extends Handler {
        @Override
@@ -646,6 +652,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                case MSG_POWER_LONG_PRESS:
                    powerLongPress();
                    break;
                case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
                    updateDreamingSleepToken(msg.arg1 != 0);
                    break;
            }
        }
    }
@@ -1219,6 +1228,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        mWindowManager = windowManager;
        mWindowManagerFuncs = windowManagerFuncs;
        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
        mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);

        // Init display burn-in protection
@@ -4235,6 +4245,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        // while the dream is showing.
        if (!mShowingDream) {
            mDreamingLockscreen = mShowingLockscreen;
            if (mDreamingSleepTokenNeeded) {
                mDreamingSleepTokenNeeded = false;
                mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
            }
        } else {
            if (!mDreamingSleepTokenNeeded) {
                mDreamingSleepTokenNeeded = true;
                mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
            }
        }

        if (mStatusBar != null) {
@@ -5847,6 +5866,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }
    }

    private void updateDreamingSleepToken(boolean acquire) {
        if (acquire) {
            if (mDreamingSleepToken == null) {
                mDreamingSleepToken = mActivityManagerInternal.acquireSleepToken("Dream");
            }
        } else {
            if (mDreamingSleepToken != null) {
                mDreamingSleepToken.release();
            }
        }
    }

    /** {@inheritDoc} */
    @Override
    public void enableScreenAfterBoot() {
@@ -6483,7 +6514,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                pw.print(" mStatusBarLayer="); pw.println(mStatusBarLayer);
        pw.print(prefix); pw.print("mShowingLockscreen="); pw.print(mShowingLockscreen);
                pw.print(" mShowingDream="); pw.print(mShowingDream);
                pw.print(" mDreamingLockscreen="); pw.println(mDreamingLockscreen);
                pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
                pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
        if (mLastInputMethodWindow != null) {
            pw.print(prefix); pw.print("mLastInputMethodWindow=");
                    pw.println(mLastInputMethodWindow);