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

Commit f62360ca authored by David Stevens's avatar David Stevens
Browse files

DO NOT MERGE Let external activities run when the primary display is off

- Make activity sleep state independent of power manager wakefulness
  state. The state is now entirely dependent on sleep tokens (and the
  voice interactor).
- Make sleep tokens operate on a per-display basis (and convert the
  keyguard to a sleep token).
- Make ActivityStackSupervisor acquire/release sleep tokens for
  non-default displays when the displays are turned on/off.
- Make WindowManagerService.okToDisplay operate on a per-display basis.

Bug: 34280365
Test: android.server.cts.ActivityManagerDisplayTests
Test: #testExternalDisplayActivityTurnPrimaryOff
Test: #testLaunchExternalDisplayActivityWhilePrimaryOff
Test: #testExternalDisplayToggleState
Change-Id: I92086d7006a67b4b4f320c9bb3aa606954f85012
(cherry picked from commit 9440dc87)
parent bcf01e7a
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -30,8 +30,6 @@ import android.util.SparseIntArray;

import com.android.internal.app.IVoiceInteractor;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

/**
@@ -90,11 +88,12 @@ public abstract class ActivityManagerInternal {
            String processName, String abiOverride, int uid, Runnable crashHandler);

    /**
     * Acquires a sleep token with the specified tag.
     * Acquires a sleep token for the specified display with the specified tag.
     *
     * @param tag A string identifying the purpose of the token (eg. "Dream").
     * @param displayId The display to apply the sleep token to.
     */
    public abstract SleepToken acquireSleepToken(@NonNull String tag);
    public abstract SleepToken acquireSleepToken(@NonNull String tag, int displayId);

    /**
     * Sleep tokens cause the activity manager to put the top activity to sleep.
+44 −84
Original line number Diff line number Diff line
@@ -1346,7 +1346,7 @@ public class ActivityManagerService extends IActivityManager.Stub
     * Set while we are running a voice interaction.  This overrides
     * sleeping while it is active.
     */
    private IVoiceInteractionSession mRunningVoice;
    IVoiceInteractionSession mRunningVoice;
    /**
     * For some direct access we need to power manager.
@@ -1365,13 +1365,6 @@ public class ActivityManagerService extends IActivityManager.Stub
     */
    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>();
    /**
     * Set if we are shutting down the system, similar to sleeping.
     */
@@ -12390,7 +12383,19 @@ public class ActivityManagerService extends IActivityManager.Stub
    void onWakefulnessChanged(int wakefulness) {
        synchronized(this) {
            mWakefulness = wakefulness;
            updateSleepIfNeededLocked();
            // Also update state in a special way for running foreground services UI.
            switch (mWakefulness) {
                case PowerManagerInternal.WAKEFULNESS_ASLEEP:
                case PowerManagerInternal.WAKEFULNESS_DREAMING:
                case PowerManagerInternal.WAKEFULNESS_DOZING:
                    mServices.updateScreenStateLocked(false /* screenOn */);
                    break;
                case PowerManagerInternal.WAKEFULNESS_AWAKE:
                default:
                    mServices.updateScreenStateLocked(true /* screenOn */);
                    break;
            }
        }
    }
@@ -12410,14 +12415,24 @@ public class ActivityManagerService extends IActivityManager.Stub
    }
    void updateSleepIfNeededLocked() {
        final boolean shouldSleep = shouldSleepLocked();
        if (mSleeping && !shouldSleep) {
        final boolean shouldSleep = !mStackSupervisor.hasAwakeDisplay();
        final boolean wasSleeping = mSleeping;
        if (!shouldSleep) {
            // If wasSleeping is true, we need to wake up activity manager state from when
            // we started sleeping. In either case, we need to apply the sleep tokens, which
            // will wake up stacks or put them to sleep as appropriate.
            if (wasSleeping) {
                mSleeping = false;
                startTimeTrackingFocusedActivityLocked();
                mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
                mStackSupervisor.comeOutOfSleepIfNeededLocked();
            }
            mStackSupervisor.applySleepTokensLocked(true /* applyToStacks */);
            if (wasSleeping) {
                sendNotifyVrManagerOfSleepState(false);
                updateOomAdjLocked();
            }
        } else if (!mSleeping && shouldSleep) {
            mSleeping = true;
            if (mCurAppTimeTracker != null) {
@@ -12428,40 +12443,6 @@ public class ActivityManagerService extends IActivityManager.Stub
            sendNotifyVrManagerOfSleepState(true);
            updateOomAdjLocked();
        }
        // Also update state in a special way for running foreground services UI.
        switch (mWakefulness) {
            case PowerManagerInternal.WAKEFULNESS_ASLEEP:
            case PowerManagerInternal.WAKEFULNESS_DREAMING:
            case PowerManagerInternal.WAKEFULNESS_DOZING:
                mServices.updateScreenStateLocked(false);
                break;
            case PowerManagerInternal.WAKEFULNESS_AWAKE:
            default:
                mServices.updateScreenStateLocked(true);
                break;
        }
    }
    private boolean shouldSleepLocked() {
        // Resume applications while running a voice interactor.
        if (mRunningVoice != null) {
            return false;
        }
        // TODO: Transform the lock screen state into a sleep token instead.
        switch (mWakefulness) {
            case PowerManagerInternal.WAKEFULNESS_AWAKE:
            case PowerManagerInternal.WAKEFULNESS_DREAMING:
                // Pause applications whenever the lock screen is shown or any sleep
                // tokens have been acquired.
                return mKeyguardController.isKeyguardShowing() || !mSleepTokens.isEmpty();
            case PowerManagerInternal.WAKEFULNESS_DOZING:
            case PowerManagerInternal.WAKEFULNESS_ASLEEP:
            default:
                // If we're asleep then pause applications unconditionally.
                return true;
        }
    }
    /** Pokes the task persister. */
@@ -12502,6 +12483,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        synchronized(this) {
            mShuttingDown = true;
            mStackSupervisor.prepareForShutdownLocked();
            updateEventDispatchingLocked();
            timedout = mStackSupervisor.shutdownLocked(timeout);
        }
@@ -14916,6 +14898,14 @@ public class ActivityManagerService extends IActivityManager.Stub
                this, in, out, err, args, callback, resultReceiver);
    }
    SleepToken acquireSleepToken(String tag, int displayId) {
        synchronized (this) {
            final SleepToken token = mStackSupervisor.createSleepTokenLocked(tag, displayId);
            updateSleepIfNeededLocked();
            return token;
        }
    }
    @Override
    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
@@ -15812,7 +15802,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        if (dumpPackage == null) {
            pw.println("  mWakefulness="
                    + PowerManagerInternal.wakefulnessToString(mWakefulness));
            pw.println("  mSleepTokens=" + mSleepTokens);
            pw.println("  mSleepTokens=" + mStackSupervisor.mSleepTokens);
            pw.println("  mSleeping=" + mSleeping);
            pw.println("  mShuttingDown=" + mShuttingDown + " mTestPssMode=" + mTestPssMode);
            if (mRunningVoice != null) {
@@ -23772,15 +23762,9 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
        @Override
        public SleepToken acquireSleepToken(String tag) {
        public SleepToken acquireSleepToken(String tag, int displayId) {
            Preconditions.checkNotNull(tag);
            synchronized (ActivityManagerService.this) {
                SleepTokenImpl token = new SleepTokenImpl(tag);
                mSleepTokens.add(token);
                updateSleepIfNeededLocked();
                return token;
            }
            return ActivityManagerService.this.acquireSleepToken(tag, displayId);
        }
        @Override
@@ -24217,30 +24201,6 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    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) + "}";
        }
    }
    /**
     * An implementation of IAppTask, that allows an app to manage its own tasks via
     * {@link android.app.ActivityManager.AppTask}.  We keep track of the callingUid to ensure that
+4 −2
Original line number Diff line number Diff line
@@ -1340,7 +1340,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
                intent, getUriPermissionsLocked(), userId);
        final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
        boolean unsent = true;
        final boolean isTopActivityWhileSleeping = service.isSleepingLocked() && isTopRunningActivity();
        final ActivityStack stack = getStack();
        final boolean isTopActivityWhileSleeping = isTopRunningActivity()
                && (stack != null ? stack.shouldSleepActivities() : service.isSleepingLocked());

        // We want to immediately deliver the intent to the activity if:
        // - It is currently resumed or paused. i.e. it is currently visible to the user and we want
@@ -1730,7 +1732,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
            // If the screen is going to turn on because the caller explicitly requested it and
            // the keyguard is not showing don't attempt to sleep. Otherwise the Activity will
            // pause and then resume again later, which will result in a double life-cycle event.
            mStackSupervisor.checkReadyForSleepLocked();
            stack.checkReadyForSleep();
        }
    }

+75 −21
Original line number Diff line number Diff line
@@ -1170,10 +1170,25 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        }
    }

    void checkReadyForSleep() {
        if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) {
            mStackSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
        }
    }

    /**
     * Tries to put the activities in the stack to sleep.
     *
     * If the stack is not in a state where its activities can be put to sleep, this function will
     * start any necessary actions to move the stack into such a state. It is expected that this
     * function get called again when those actions complete.
     *
     * @param shuttingDown true when the called because the device is shutting down.
     * @return true if something must be done before going to sleep.
     */
    boolean checkReadyForSleepLocked() {
    boolean goToSleepIfPossible(boolean shuttingDown) {
        boolean shouldSleep = true;

        if (mResumedActivity != null) {
            // Still have something resumed; can't sleep until it is paused.
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
@@ -1183,26 +1198,47 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            // If we are in the middle of resuming the top activity in
            // {@link #resumeTopActivityUncheckedLocked}, mResumedActivity will be set but not
            // resumed yet. We must not proceed pausing the activity here. This method will be
            // called again if necessary as part of
            // called again if necessary as part of {@link #checkReadyForSleep} or
            // {@link ActivityStackSupervisor#checkReadyForSleepLocked}.
            if (mStackSupervisor.inResumeTopActivity) {
                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "In the middle of resuming top activity "
                        + mResumedActivity);
                return true;
            }

            } else {
                startPausingLocked(false, true, null, false);
            return true;
            }
        if (mPausingActivity != null) {
            shouldSleep = false ;
        } else if (mPausingActivity != null) {
            // Still waiting for something to pause; can't sleep yet.
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity);
            return true;
            shouldSleep = false;
        }
        return false;

        if (!shuttingDown) {
            if (containsActivityFromStack(mStackSupervisor.mStoppingActivities)) {
                // Still need to tell some activities to stop; can't sleep yet.
                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
                        + mStackSupervisor.mStoppingActivities.size() + " activities");

                mStackSupervisor.scheduleIdleLocked();
                shouldSleep = false;
            }

    void goToSleep() {
            if (containsActivityFromStack(mStackSupervisor.mGoingToSleepActivities)) {
                // Still need to tell some activities to sleep; can't sleep yet.
                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to sleep "
                        + mStackSupervisor.mGoingToSleepActivities.size() + " activities");
                shouldSleep = false;
            }
        }

        if (shouldSleep) {
            goToSleep();
        }

        return !shouldSleep;
    }

    private void goToSleep() {
        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);

        // Make sure any paused or stopped but visible activities are now sleeping.
@@ -1219,6 +1255,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        }
    }

    private boolean containsActivityFromStack(List<ActivityRecord> rs) {
        for (ActivityRecord r : rs) {
            if (r.getStack() == this) {
                return true;
            }
        }
        return false;
    }

    /**
     * Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
     * this directly impacts the responsiveness seen by the user.
@@ -1251,7 +1296,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        if (mPausingActivity != null) {
            Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
                    + " state=" + mPausingActivity.state);
            if (!mService.isSleepingLocked()) {
            if (!shouldSleepActivities()) {
                // Avoid recursion among check for sleep and complete pause during sleeping.
                // Because activity will be paused immediately after resume, just let pause
                // be completed by the order of activity paused from clients.
@@ -1411,7 +1456,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                    // We can't clobber it, because the stop confirmation will not be handled.
                    // We don't need to schedule another stop, we only need to let it happen.
                    prev.state = STOPPING;
                } else if (!prev.visible || mService.isSleepingOrShuttingDownLocked()) {
                } else if (!prev.visible || shouldSleepOrShutDownActivities()) {
                    // Clear out any deferred client hide we might currently have.
                    prev.setDeferHidingClient(false);
                    // If we were visible then resumeTopActivities will release resources before
@@ -1433,10 +1478,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai

        if (resumeNext) {
            final ActivityStack topStack = mStackSupervisor.getFocusedStack();
            if (!mService.isSleepingOrShuttingDownLocked()) {
            if (!topStack.shouldSleepOrShutDownActivities()) {
                mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
            } else {
                mStackSupervisor.checkReadyForSleepLocked();
                checkReadyForSleep();
                ActivityRecord top = topStack.topRunningActivityLocked();
                if (top == null || (prev != null && top != prev)) {
                    // If there are no more activities available to run, do resume anyway to start
@@ -1502,7 +1547,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                mStackSupervisor.scheduleIdleTimeoutLocked(r);
            }
        } else {
            mStackSupervisor.checkReadyForSleepLocked();
            checkReadyForSleep();
        }
    }

@@ -2211,7 +2256,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        // is skipped.
        final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
        if (next == null || !next.canTurnScreenOn()) {
            mStackSupervisor.checkReadyForSleepLocked();
            checkReadyForSleep();
        }

        return result;
@@ -2296,7 +2341,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai

        // If we are sleeping, and there is no resumed activity, and the top
        // activity is paused, well that is the state we want.
        if (mService.isSleepingOrShuttingDownLocked()
        if (shouldSleepOrShutDownActivities()
                && mLastPausedActivity == next
                && mStackSupervisor.allPausedActivitiesComplete()) {
            // Make sure we have executed any pending transitions, since there
@@ -2388,7 +2433,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        // If the most recent activity was noHistory but was only stopped rather
        // than stopped+finished because the device went to sleep, we need to make
        // sure to finish it as we're making a new activity topmost.
        if (mService.isSleepingLocked() && mLastNoHistoryActivity != null &&
        if (shouldSleepActivities() && mLastNoHistoryActivity != null &&
                !mLastNoHistoryActivity.finishing) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "no-history finish of " + mLastNoHistoryActivity + " on new resume");
@@ -3400,7 +3445,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
            if (!r.finishing) {
                if (!mService.isSleepingLocked()) {
                if (!shouldSleepActivities()) {
                    if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r);
                    if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
                            "stop-no-history", false)) {
@@ -3432,7 +3477,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                EventLogTags.writeAmStopActivity(
                        r.userId, System.identityHashCode(r), r.shortComponentName);
                r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
                if (mService.isSleepingOrShuttingDownLocked()) {
                if (shouldSleepOrShutDownActivities()) {
                    r.setSleeping(true);
                }
                Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
@@ -5278,4 +5323,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        mNoAnimActivities.clear();
        ActivityOptions.abort(options);
    }

    boolean shouldSleepActivities() {
        final ActivityStackSupervisor.ActivityDisplay display = getDisplay();
        return display != null ? display.isSleeping() : mService.isSleepingLocked();
    }

    boolean shouldSleepOrShutDownActivities() {
        return shouldSleepActivities() || mService.isShuttingDownLocked();
    }
}
+203 −61

File changed.

Preview size limit exceeded, changes collapsed.

Loading