SleepToken机制 - 安卓R

重要类介绍

SleepToken

SleepToken是frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java的内部静态类,其定义如下:

    static final class SleepToken {
        private final String mTag;
        private final long mAcquireTime;
        private final int mDisplayId;
        final int mHashKey;

        SleepToken(String tag, int displayId) {
            mTag = tag;
            mDisplayId = displayId;
            mAcquireTime = SystemClock.uptimeMillis();
            mHashKey = makeSleepTokenKey(mTag, mDisplayId);
        }

        @Override
        public String toString() {
            return "{\"" + mTag + "\", display " + mDisplayId
                    + ", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
        }
    }

SleepTokenAcquirer

SleepTokenAcquirer是在frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java的内部接口,其定义如下:

    /**
     * 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.
     * The Acquirer provides an interface that encapsulates the underlying work, so the user does
     * not need to handle the token by him/herself.
     */
    public interface SleepTokenAcquirer {

        /**
         * Acquires a sleep token.
         * @param displayId The display to apply to.
         */
        void acquire(int displayId);

        /**
         * Releases the sleep token.
         * @param displayId The display to apply to.
         */
        void release(int displayId);
    }

有两个方法分别是acquirerelease

其实现类是SleepTokenAcquirerImpl,是frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java的内部类,其定义如下:

    final class SleepTokenAcquirerImpl implements ActivityTaskManagerInternal.SleepTokenAcquirer {
        private final String mTag;
        private final SparseArray<RootWindowContainer.SleepToken> mSleepTokens =
                new SparseArray<>();

        SleepTokenAcquirerImpl(@NonNull String tag) {
            mTag = tag;
        }

        @Override
        public void acquire(int displayId) {
            synchronized (mGlobalLock) {
                if (!mSleepTokens.contains(displayId)) {
                    mSleepTokens.append(displayId,
                            mRootWindowContainer.createSleepToken(mTag, displayId));
                    updateSleepIfNeededLocked();
                }
            }
        }

        @Override
        public void release(int displayId) {
            synchronized (mGlobalLock) {
                final RootWindowContainer.SleepToken token = mSleepTokens.get(displayId);
                if (token != null) {
                    mRootWindowContainer.removeSleepToken(token);
                    mSleepTokens.remove(displayId);
                }
            }
        }
    }

在SleepTokenAcquirerImpl的acquire方法中会调用RootWindowContainer的createSleepToken方法:

    SleepToken createSleepToken(String tag, int displayId) {
        final DisplayContent display = getDisplayContent(displayId);
        if (display == null) {
            throw new IllegalArgumentException("Invalid display: " + displayId);
        }

        final int tokenKey = makeSleepTokenKey(tag, displayId);
        SleepToken token = mSleepTokens.get(tokenKey);
        if (token == null) {
            token = new SleepToken(tag, displayId);
            mSleepTokens.put(tokenKey, token);
            display.mAllSleepTokens.add(token);
        } else {
            throw new RuntimeException("Create the same sleep token twice: " + token);
        }
        return token;
    }

创建了SleepToken对象,然后在SleepTokenAcquirerImpl的acquire方法中调用ActivityTaskManagerService的updateSleepIfNeededLocked方法对resume的Activity进行pause。

在SleepTokenAcquirerImpl的release方法中会调用RootWindowContainer的removeSleepToken方法:

    void removeSleepToken(SleepToken token) {
        if (!mSleepTokens.contains(token.mHashKey)) {
            Slog.d(TAG, "Remove non-exist sleep token: " + token + " from " + Debug.getCallers(6));
        }
        mSleepTokens.remove(token.mHashKey);

        final DisplayContent display = getDisplayContent(token.mDisplayId);
        if (display != null) {
            display.mAllSleepTokens.remove(token);
            if (display.mAllSleepTokens.isEmpty()) {
                mService.updateSleepIfNeededLocked();
            }
        }
    }

如果发现所有的SleepToken都被移除了,那么会调用ActivityTaskManagerService的updateSleepIfNeededLocked方法尝试resume前台Activity,但是一般此时的场景是刚刚亮屏,会存在keyguard,所以此时一般也不会去resume前台Activity。(快速亮灭屏的时候,灭屏会触发keyguard显示,如果在keyguard出来之前就亮屏了,会因为SleepToken的完全移除而去resume前台Activity,等keyguard出来了又去stop前台Activity,导致出现闪app的问题)

在灭屏时的作用

灭屏流程中,会调用frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java的screenTurnedOff方法:

    // Called on the DisplayManager's DisplayPowerController thread.
    @Override
    public void screenTurnedOff() {
        if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");

        updateScreenOffSleepToken(true);
        mDefaultDisplayPolicy.screenTurnedOff();
        synchronized (mLock) {
            if (mKeyguardDelegate != null) {
                mKeyguardDelegate.onScreenTurnedOff();
            }
        }
        mDefaultDisplayRotation.updateOrientationListener();
        reportScreenStateToVrManager(false);
    }

调用了PhoneWindowManager的updateScreenOffSleepToken方法并传入true:

    // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
    private void updateScreenOffSleepToken(boolean acquire) {
        if (acquire) {
            mScreenOffSleepTokenAcquirer.acquire(DEFAULT_DISPLAY);
        } else {
            mScreenOffSleepTokenAcquirer.release(DEFAULT_DISPLAY);
        }
    }

调用了frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java的内部类SleepTokenAcquirerImpl的acquire方法:

        @Override
        public void acquire(int displayId) {
            synchronized (mGlobalLock) {
                if (!mSleepTokens.contains(displayId)) {
                    mSleepTokens.append(displayId,
                            mRootWindowContainer.createSleepToken(mTag, displayId));
                    updateSleepIfNeededLocked();
                }
            }
        }

调用了ActivityTaskManagerService的updateSleepIfNeededLocked方法:

    void updateSleepIfNeededLocked() {
        final boolean shouldSleep = !mRootWindowContainer.hasAwakeDisplay();
        final boolean wasSleeping = mSleeping;
        boolean updateOomAdj = false;

        if (!shouldSleep) {
            ......
        } else if (!mSleeping && shouldSleep) {
            mSleeping = true;
            FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_MANAGER_SLEEP_STATE_CHANGED,
                    FrameworkStatsLog.ACTIVITY_MANAGER_SLEEP_STATE_CHANGED__STATE__ASLEEP);
            if (mCurAppTimeTracker != null) {
                mCurAppTimeTracker.stop();
            }
            mTopProcessState = ActivityManager.PROCESS_STATE_TOP_SLEEPING;
            Slog.d(TAG, "Top Process State changed to PROCESS_STATE_TOP_SLEEPING");
            mStackSupervisor.goingToSleepLocked();
            updateResumedAppTrace(null /* resumed */);
            updateOomAdj = true;
        }
        if (updateOomAdj) {
            updateOomAdj();
        }
    }

调用了frameworks/base/services/core/java/com/android/server/wm/ActivityStackSupervisor.java的goingToSleepLocked方法:

    void goingToSleepLocked() {
        scheduleSleepTimeout();
        if (!mGoingToSleepWakeLock.isHeld()) {
            mGoingToSleepWakeLock.acquire();
            if (mLaunchingActivityWakeLock.isHeld()) {
                if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
                    throw new IllegalStateException("Calling must be system uid");
                }
                mLaunchingActivityWakeLock.release();
                mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
            }
        }

        mRootWindowContainer.applySleepTokens(false /* applyToStacks */);

        checkReadyForSleepLocked(true /* allowDelay */);
    }

调用了ActivityStackSupervisor的checkReadyForSleepLocked方法:

    void checkReadyForSleepLocked(boolean allowDelay) {
        if (!mService.isSleepingOrShuttingDownLocked()) {
            // Do not care.
            return;
        }

        if (!mRootWindowContainer.putStacksToSleep(
                allowDelay, false /* shuttingDown */)) {
            return;
        }

        // Send launch end powerhint before going sleep
        mRootWindowContainer.sendPowerHintForLaunchEndIfNeeded();

        removeSleepTimeouts();

        if (mGoingToSleepWakeLock.isHeld()) {
            mGoingToSleepWakeLock.release();
        }
        if (mService.mShuttingDown) {
            mService.mGlobalLock.notifyAll();
        }
    }

调用了frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java的putStacksToSleep方法:

    // Tries to put all activity stacks to sleep. Returns true if all stacks were
    // successfully put to sleep.
    boolean putStacksToSleep(boolean allowDelay, boolean shuttingDown) {
        boolean allSleep = true;
        for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
            final DisplayContent display = getChildAt(displayNdx);
            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
                    // Stacks and activities could be removed while putting activities to sleep if
                    // the app process was gone. This prevents us getting exception by accessing an
                    // invalid stack index.
                    if (sNdx >= taskDisplayArea.getStackCount()) {
                        continue;
                    }
                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
                    if (allowDelay) {
                        allSleep &= stack.goToSleepIfPossible(shuttingDown);
                    } else {
                        stack.goToSleep();
                    }
                }
            }
        }
        return allSleep;
    }

调用了frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java的goToSleepIfPossible方法:

    /**
     * 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 the stack finished going to sleep, false if the stack only started the
     * process of going to sleep (checkReadyForSleep will be called when that process finishes).
     */
    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);
            if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                    "Sleep => pause with userLeaving=false");

            startPausingLocked(false /* userLeaving */, true /* uiSleeping */, null /* resuming */);
            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);
            shouldSleep = 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.scheduleIdle();
                shouldSleep = false;
            }
        }

        if (shouldSleep) {
            goToSleep();
        }

        return shouldSleep;
    }

如果mResumedActivity不为null,则调用startPausingLocked方法将其pause掉。

在亮屏时的作用

亮屏流程中,会调用frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java的screenTurningOn方法:

    // Called on the DisplayManager's DisplayPowerController thread.
    @Override
    public void screenTurningOn(final ScreenOnListener screenOnListener) {
        if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");

        Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
        updateScreenOffSleepToken(false);
        mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);

        synchronized (mLock) {
            if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) {
                mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
                mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
                        getKeyguardDrawnTimeout());
                mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
            } else {
                if (DEBUG_WAKEUP) Slog.d(TAG,
                        "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
                mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
            }
        }
    }

调用了PhoneWindowManager的updateScreenOffSleepToken方法并传入false:

    // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
    private void updateScreenOffSleepToken(boolean acquire) {
        if (acquire) {
            mScreenOffSleepTokenAcquirer.acquire(DEFAULT_DISPLAY);
        } else {
            mScreenOffSleepTokenAcquirer.release(DEFAULT_DISPLAY);
        }
    }

调用了frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java的内部类SleepTokenAcquirerImpl的release方法:

        @Override
        public void release(int displayId) {
            synchronized (mGlobalLock) {
                final RootWindowContainer.SleepToken token = mSleepTokens.get(displayId);
                if (token != null) {
                    mRootWindowContainer.removeSleepToken(token);
                    mSleepTokens.remove(displayId);
                }
            }
        }

调用了frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java的removeSleepToken方法:

    void removeSleepToken(SleepToken token) {
        if (!mSleepTokens.contains(token.mHashKey)) {
            Slog.d(TAG, "Remove non-exist sleep token: " + token + " from " + Debug.getCallers(6));
        }
        mSleepTokens.remove(token.mHashKey);

        final DisplayContent display = getDisplayContent(token.mDisplayId);
        if (display != null) {
            display.mAllSleepTokens.remove(token);
            if (display.mAllSleepTokens.isEmpty()) {
                mService.updateSleepIfNeededLocked();
            }
        }
    }

如果此时没有SleepToken了,会调用ActivityTaskManagerService的updateSleepIfNeededLocked方法:

    void updateSleepIfNeededLocked() {
        final boolean shouldSleep = !mRootWindowContainer.hasAwakeDisplay();
        final boolean wasSleeping = mSleeping;
        boolean updateOomAdj = false;

        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;
                FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_MANAGER_SLEEP_STATE_CHANGED,
                        FrameworkStatsLog.ACTIVITY_MANAGER_SLEEP_STATE_CHANGED__STATE__AWAKE);
                startTimeTrackingFocusedActivityLocked();
                mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
                Slog.d(TAG, "Top Process State changed to PROCESS_STATE_TOP");
                mStackSupervisor.comeOutOfSleepIfNeededLocked();
            }
            mRootWindowContainer.applySleepTokens(true /* applyToStacks */);
            if (wasSleeping) {
                updateOomAdj = true;
            }
        } else if (!mSleeping && shouldSleep) {
            ......
        }
        if (updateOomAdj) {
            updateOomAdj();
        }
    }

调用了RootWindowContainer的applySleepTokens方法:

    void applySleepTokens(boolean applyToStacks) {
        for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
            // Set the sleeping state of the display.
            final DisplayContent display = getChildAt(displayNdx);
            final boolean displayShouldSleep = display.shouldSleep();
            if (displayShouldSleep == display.isSleeping()) {
                continue;
            }
            display.setIsSleeping(displayShouldSleep);

            if (!applyToStacks) {
                continue;
            }

            // Set the sleeping state of the stacks on the display.
            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
                    if (displayShouldSleep) {
                        stack.goToSleepIfPossible(false /* shuttingDown */);
                    } else {
                        // When the display which can only contain one task turns on, start a
                        // special transition.
                        // {@link AppTransitionController#handleAppTransitionReady} later picks up
                        // the transition, and schedules
                        // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is
                        // triggered after contents are drawn on the display.
                        if (display.isSingleTaskInstance()) {
                            display.mDisplayContent.prepareAppTransition(
                                    TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false,
                                    0 /* flags */, true /* forceOverride*/);
                        }
                        stack.awakeFromSleepingLocked();
                        if (display.isSingleTaskInstance()) {
                            display.executeAppTransition();
                        }
                        if (stack.isFocusedStackOnDisplay()
                                && !mStackSupervisor.getKeyguardController()
                                .isKeyguardOrAodShowing(display.mDisplayId)) {
                            // If the keyguard is unlocked - resume immediately.
                            // It is possible that the display will not be awake at the time we
                            // process the keyguard going away, which can happen before the sleep
                            // token is released. As a result, it is important we resume the
                            // activity here.
                            stack.resumeTopActivityUncheckedLocked(null, null);
                        }
                        // The visibility update must not be called before resuming the top, so the
                        // display orientation can be updated first if needed. Otherwise there may
                        // have redundant configuration changes due to apply outdated display
                        // orientation (from keyguard) to activity.
                        stack.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
                                false /* preserveWindows */);
                    }
                }
            }
        }
    }

此时如果没有keyguard会调用frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java的resumeTopActivityUncheckedLocked方法,对前台Activity进行resume。

总结

1 在获取了SleepToken后,会将resume的Activity进入pause状态。

2 在释放了SleepToken后,如果此时没有SleepToken了,并且也没有keyguard,会对前台Activity进行resume。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SSSxCCC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值