重要类介绍
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);
}
有两个方法分别是acquire和release。
其实现类是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。