分析了栈的管家和栈.有些摸不到头脑,我们顺着一个情景来分析.本文重点关注启动过程actvity的生命周期和调用对于task和stack的管理.
对于怎么去选择task和stack我们在分析activity启动的文章中已经分析了,这里直接从对生命周期处理来分析
首先这种情况选择task是在setTaskFromSourceRecord函数中
private int setTaskFromSourceRecord() {
final TaskRecord sourceTask = mSourceRecord.task;
......
if (mTargetStack == null) {
mTargetStack = sourceTask.stack;
}
.....
if (mDoResume) {
//1 移动stack到前面
mTargetStack.moveToFront("sourceStackToFront");
}
final TaskRecord topTask = mTargetStack.topTask();
if (topTask != sourceTask && !mAvoidMoveToFront) {
//2 移动task到stack前面
mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "sourceTaskToFront");
}
......
// An existing activity is starting this new activity, so we want to keep the new one in
// the same task as the one that is starting it.
//3 设置activity的task
mStartActivity.setTask(sourceTask, null);
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
return START_SUCCESS;
}
1首先调用ActivityStack的moveToFront函数把stack移动到上边来
void moveToFront(String reason, TaskRecord task) {
if (!isAttached()) {
return;
}
mStacks.remove(this);
int addIndex = mStacks.size();
if (addIndex > 0) {
final ActivityStack topStack = mStacks.get(addIndex - 1);
if (StackId.isAlwaysOnTop(topStack.mStackId) && topStack != this) {
// If the top stack is always on top, we move this stack just below it.
addIndex--;
}
}
mStacks.add(addIndex, this);
// TODO(multi-display): Needs to also work if focus is moving to the non-home display.
if (isOnHomeDisplay()) {
mStackSupervisor.setFocusStackUnchecked(reason, this);
}
if (task != null) {
insertTaskAtTop(task, null);
} else {
task = topTask();
}
if (task != null) {
mWindowManager.moveTaskToTop(task.taskId);
}
}
函数首先计算出stack的位置,然后放到对应的位置,如果是在home display上则还要设置这个stack为焦点stack,之后把task插入到stack顶部,最后移动WMS中的task,者几个步骤在此情景都没有任何实质性的变化.
这里可以总结下过程
1 移动stack到前台,moveToFront函数
2 移动task到stack前边,对于window的移动 mWindowManager.moveTaskToTop(task.taskId)
3 移动activity到task上,请看startActivityLocked函数
mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
final void startActivityLocked(ActivityRecord r, boolean newTask, boolean keepCurTransition,
ActivityOptions options) {
......
TaskRecord task = null;
if (!newTask) {
// If starting in an existing task, find where that is...
boolean startIt = true;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
task = mTaskHistory.get(taskNdx);
if (task.getTopActivity() == null) {
// All activities in task are finishing.
continue;
}
//2 如果这个task不可见,被全屏的task遮挡,直接插入到task中
if (task == r.task) {
if (!startIt) {
task.addActivityToTop(r);
r.putInHistory();
addConfigOverride(r, task);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
ActivityOptions.abort(options);
return;
}
break;
} else if (task.numFullscreen > 0) {
startIt = false;
}
}
}
// Place a new activity at top of stack, so it is next to interact
// with the user.
// If we are not placing the new activity frontmost, we do not want
// to deliver the onUserLeaving callback to the actual frontmost
// activity
//3 task不在前台不需要执行Activity的onUserLeaving函数 设置mUserLeaving为false
if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
mStackSupervisor.mUserLeaving = false;
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
"startActivity() behind front, mUserLeaving=false");
}
task = r.task;
// Slot the activity into the history stack and proceed
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
new RuntimeException("here").fillInStackTrace());
//3 添加activity到task中
task.addActivityToTop(r);
//4 更新task中activity的frontOfTask变量,为true代表该activity在task最前面
task.setFrontOfTask();
r.putInHistory();
//5 如果stack不是home stack中,或者activity数量大于0,这种情况要启动starting window
//因为home stack下面是wall paper不需要启动starting window,而activity为0表示没有要启动的activity
if (!isHomeStack() || numActivities() > 0) {
// We want to show the starting preview window if we are
// switching to a new task, or the next activity's process is
// not currently running.
//6 进程没有启动或者新的task要显示starting icon
boolean showStartingIcon = newTask;
ProcessRecord proc = r.app;
if (proc == null) {
proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
}
if (proc == null || proc.thread == null) {
showStartingIcon = true;
}
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
//7 不需要执行动画设置动画为NONE
mWindowManager.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
mNoAnimActivities.add(r);
} else {
mWindowManager.prepareAppTransition(newTask
? r.mLaunchTaskBehind
? TRANSIT_TASK_OPEN_BEHIND
: TRANSIT_TASK_OPEN
: TRANSIT_ACTIVITY_OPEN, keepCurTransition);
mNoAnimActivities.remove(r);
}
//8 添加AppToken到WMS中
addConfigOverride(r, task);
boolean doShow = true;
if (newTask) {
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
resetTaskIfNeededLocked(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r;
}
} else if (options != null && options.getAnimationType()
== ActivityOptions.ANIM_SCENE_TRANSITION) {
doShow = false;
}
if (r.mLaunchTaskBehind) {
//9 通知wms,activity可见的.虽然是在后台启动
mWindowManager.setAppVisibility(r.appToken, true);
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {
//10 创建starting window
ActivityRecord prev = r.task.topRunningActivityWithStartingWindowLocked();
if (prev != null) {
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
if (prev.task != r.task) {
prev = null;
}
// (2) The current activity is already displayed.
else if (prev.nowVisible) {
prev = null;
}
}
//11 如果前面的activity不可见,但是有一个starting window,复用或者新创建一个starting window
r.showStartingWindow(prev, showStartingIcon);
}
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
//12 创建AppWindowToken
addConfigOverride(r, task);
ActivityOptions.abort(options);
options = null;
}
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
}
我们再在总结下这一步
1 添加activity到task,task.addActivityToTop(r);
2 创建动画
3 创建AppWindowToken到WMS,addConfigOverride(r, task);
4 创建starting window,r.showStartingWindow(prev, showStartingIcon)
下面一个步骤是调用 AMS的方法setFocusedActivityLocked(ActivityRecord r, String reason)
if (mStackSupervisor.moveActivityStackToFront(r, reason + " setFocusedActivity")) {
mWindowManager.setFocusedApp(r.appToken, true);
}
主要是更新AMS的mFocusedActivity和更新WMS的mWindowManager.setFocusedApp(r.appToken, true)
设置完成焦点Activity后就执行
resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions); 去真正的activity.
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || r.state != RESUMED) {
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
}
return false;
}
前面我们已经把stack移动到前台,设置为focuse activity,所以这里就直接使用resumeTopActivityUncheckedLocked去resume activity
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
// Protect against recursion.
mStackSupervisor.inResumeTopActivity = true;
if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
mService.updateSleepIfNeededLocked();
}
result = resumeTopActivityInnerLocked(prev, options);
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
return result;
}
inResumeTopActivity变量防止嵌套执行,最终还是执行resumeTopActivityInnerLocked(prev, options)函数创建activity
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
if (DEBUG_LOCKSCREEN) mService.logLockScreen("");
//1 没有启动完成直接返回
if (!mService.mBooting && !mService.mBooted) {
// Not ready yet!
return false;
}
//2 父activity不是RESUMED状态,子activity也不能resume
ActivityRecord parent = mActivityContainer.mParentActivity;
if ((parent != null && parent.state != ActivityState.RESUMED) ||
!mActivityContainer.isAttachedLocked()) {
// Do not resume this stack if its parent is not resumed.
// TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
return false;
}
//4 移除topActivity下面全屏activity下面的starting window
mStackSupervisor.cancelInitializingActivities();
// Find the first activity that is not finishing.
//5 这里为焦点stack,最上面的activity也是我们要启动的actvity
final ActivityRecord next = topRunningActivityLocked();
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
//6 从锁存中拿到userLeaving变量,恢复锁存
final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
//7 在我们这个情景中prev==next
final TaskRecord prevTask = prev != null ? prev.task : null;
......
next.delayedResume = false;
......
// The activity may be waiting for stop, but that is no longer
// appropriate for it.
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
mStackSupervisor.mWaitingVisibleActivities.remove(next);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
// If we are currently pausing an activity, then don't do anything until that is done.
//8 这里全部activity没有pause完成返回false,完成后还会调用该函数
if (!mStackSupervisor.allPausedActivitiesComplete()) {
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return false;
}
mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
// We need to start pausing the current activity so the top one can be resumed...
final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
//9 pause非focurestack上的resume activity,这里我们可以知道虽然不再焦点上的activity可见,但是确是pause状态的
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, dontWaitForPause);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
//10 pause 当前的mResumeActivity
pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
}
if (pausing) {
//11 我们当前分析的情景需要pause 完成后来处理,所以这里直接返回勒
if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
"resumeTopActivityLocked: Skip resume: need to start pausing");
// At this point we want to put the upcoming activity's process
// at the top of the LRU list, since we know we will be needing it
// very soon and it would be a waste to let it get killed if it
// happens to be sitting towards the end.
if (next.app != null && next.app.thread != null) {
mService.updateLruProcessLocked(next.app, true, null);
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
........
}
我们再来总结下这个过程其实很简单那
总结起来就是一步
pause当前所stack上的mResumeActivity.
从目前来看,调用resumeTopActivityUncheckedLocked的只能是焦点stack,
在ActivityStackSupervisor中通过resumeFocusedStackTopActivityLocked函数调用到ActivityStack的resumeTopActivityUncheckedLocked函数,所以只能作用在焦点stack上,所以前面需要先将stack移动到前台才能使用
现在我们来看一下pause的过程
ActivityStack的startPausingLocked函数,函数有四个参数
userLeaving代表是否要执行Activity的onUserLeaving函数
uiSleeping表示是否由于休眠(灭屏)引起的pause
resuming表示即将要resume的activity,也可能为空,不是由于要启动新的activity引起的pause可能为空
dontWait表示不需要等待客户端完成pause,直接善后处理
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming, boolean dontWait) {
......
//1 不存在mResumedActivity所以不需要pause ,但是如果没有要resume的activity,要找到一个进行resume
ActivityRecord prev = mResumedActivity;
if (prev == null) {
if (resuming == null) {
Slog.wtf(TAG, "Trying to pause when nothing is resumed");
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
return false;
}
//2 顶级activity要pause,先搞死子activity
if (mActivityContainer.mParentActivity == null) {
// Top level stack, not a child. Look for child stacks.
mStackSupervisor.pauseChildStacks(prev, userLeaving, uiSleeping, resuming, dontWait);
}
...
mResumedActivity = null;
mPausingActivity = prev;
mLastPausedActivity = prev;
mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
//3 更新状态为ActivityState.PAUSING
prev.state = ActivityState.PAUSING;
prev.task.touchActiveTime();
clearLaunchTime(prev);
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
//4 设置mUpdateTaskThumbnailWhenHidden表示要更新在最近任务中显示的任务图片
if (mService.mHasRecents
&& (next == null || next.noDisplay || next.task != prev.task || uiSleeping)) {
prev.mUpdateTaskThumbnailWhenHidden = true;
}
stopFullyDrawnTraceIfNeeded();
mService.updateCpuStats();
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
prev.userId, System.identityHashCode(prev),
prev.shortComponentName);
mService.updateUsageStats(prev, false);
//5调用客户端进行pause
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
} else {
//6 要pause的activity进程不存在,啥都不干,注意这时候已经不存在mResumeActivity了
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
// If we are not going to sleep, we want to ensure the device is
// awake until the next activity is started.
//7 获取lunch wake lock防止休眠
if (!uiSleeping && !mService.isSleepingOrShuttingDownLocked()) {
mStackSupervisor.acquireLaunchWakelock();
}
if (mPausingActivity != null) {
//8 已经进入了pause的过程
// Have the window manager pause its key dispatching until the new
// activity has started. If we're pausing the activity just because
// the screen is being turned off and the UI is sleeping, don't interrupt
// key dispatch; the same activity will pick it up again on wakeup.
if (!uiSleeping) {
//9 不是由于ui睡眠引起的pause,要停止key的接收
prev.pauseKeyDispatchingLocked();
} else if (DEBUG_PAUSE) {
Slog.v(TAG_PAUSE, "Key dispatch not paused for screen off");
}
if (dontWait) {
// If the caller said they don't want to wait for the pause, then complete
// the pause now.
//10 不需要等待客户端pause完成进行回调,直接调用completePauseLocked完成清理工作
completePauseLocked(false, resuming);
return false;
} else {
// 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.
//11 设置一个超时的时间,防止客户端搞事情
Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
msg.obj = prev;
prev.pauseTime = SystemClock.uptimeMillis();
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
return true;
}
} else {
//12 这里面一定是发生了异常,尝试选择一个activity进行resume,指定了resuming就不用管了,否则就请mStackSupervisor选择一个显示
// This activity failed to schedule the
// pause, so just treat it as being paused now.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
if (resuming == null) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
return false;
}
}
总结一下上面的流程,其实最核心的就是
1 调用客户端进行pause, prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait)
2 获取wake log防止cpu休眠
3 停止接收input event
4 发送一个超时检查消息,防止客户端搞事情
我们来看看ActivityThread这边如何处理
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
int seq = getLifecycleSeq();
if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this
+ " operation received seq: " + seq);
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
configChanges,
seq);
}
对于我们处理的情景是PAUSE_ACTIVITY的消息
case PAUSE_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != 0, args.argi2,
(args.argi1 & DONT_REPORT) != 0, args.argi3);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport, int seq) {
ActivityClientRecord r = mActivities.get(token);
if (DEBUG_ORDER) Slog.d(TAG, "handlePauseActivity " + r + ", seq: " + seq);
//1 检查seq是否已经过期
if (!checkAndUpdateLifecycleSeq(seq, r, "pauseActivity")) {
return;
}
if (r != null) {
//Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
if (userLeaving) { //2 执行onUserLeaving函数
performUserLeavingActivity(r);
}
//3 更新config flags
r.activity.mConfigChangeFlags |= configChanges;
//4 执行pause
performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
// Make sure any pending writes are now committed.
if (r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}
// Tell the activity manager we have paused.
if (!dontReport) { //5 dontReport为假报告ams pause完成
try {
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
mSomeActivitiesChanged = true;
}
}
final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
boolean saveState, String reason) {
if (r.paused) {
if (r.activity.mFinished) { //1 已经finish啥都不返回,否则抛出异常
// If we are finishing, we won't call onResume() in certain cases.
// So here we likewise don't want to call onPause() if the activity
// isn't resumed.
return null;
}
RuntimeException e = new RuntimeException(
"Performing pause of activity that is not resumed: "
+ r.intent.getComponent().toShortString());
Slog.e(TAG, e.getMessage(), e);
}
if (finished) { //2 需要finish设置状态
r.activity.mFinished = true;
}
// Next have the activity save its current state and managed dialogs...
if (!r.activity.mFinished && saveState) { //3调用OnSaveInstanceState保存数据
callCallActivityOnSaveInstanceState(r);
}
//4 真正调用activity方法
performPauseActivityIfNeeded(r, reason);
// Notify any outstanding on paused listeners
ArrayList<OnActivityPausedListener> listeners;
synchronized (mOnPauseListeners) {
listeners = mOnPauseListeners.remove(r.activity);
}
int size = (listeners != null ? listeners.size() : 0);
for (int i = 0; i < size; i++) { //5 通知监听者
listeners.get(i).onPaused(r.activity);
}
//6 返回保存的数据
return !r.activity.mFinished && saveState ? r.state : null;
}
函数主要做了一下几步操作
1 保存现场
2 执行pause
3 通知ams, ActivityManagerNative.getDefault().activityPaused(token);
再次回调activityPaused函数中去
@Override
public final void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
stack.activityPausedLocked(token, false);
}
}
Binder.restoreCallingIdentity(origId);
}
很简单,找到stack,然后调用stack.activityPausedLocked(token, false)函数
final void activityPausedLocked(IBinder token, boolean timeout) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
"Activity paused: token=" + token + ", timeout=" + timeout);
final ActivityRecord r = isInStackLocked(token);
if (r != null) { //1 移除超时消息
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if (mPausingActivity == r) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + r
+ (timeout ? " (due to timeout)" : " (pause complete)"));
//2 当前要关闭的activity正是这个activity,完成清理工作
completePauseLocked(true, null);
return;
} else {
//3 pause 其他activity,更新状态为PAUSED,然后如果需要finish activity,执行
//finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false)函数
EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
r.userId, System.identityHashCode(r), r.shortComponentName,
mPausingActivity != null
? mPausingActivity.shortComponentName : "(none)");
if (r.state == ActivityState.PAUSING) {
r.state = ActivityState.PAUSED;
if (r.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG,
"Executing finish of failed to pause activity: " + r);
//4 finish activity
finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false);
}
}
}
}
//4 确保activity的可见状态
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
注意这并非是timeout的情况处理,这个函数也很简单
1 调用 completePauseLocked(true, null)完成pause状态
2 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); 确保activity可见
再来看看completePauseLocked函数,函数有两个参数,boolean resumeNext,代表是否要找到一个activity进行显示
ActivityRecord resuming代表要进行resume 的activity
private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
ActivityRecord prev = mPausingActivity;
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
if (prev != null) {
final boolean wasStopping = prev.state == ActivityState.STOPPING;
prev.state = ActivityState.PAUSED; //1 更新state
if (prev.finishing) { //2 需要finsih执行finish,我们的情景不会finish
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
} else if (prev.app != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
+ " wasStopping=" + wasStopping + " visible=" + prev.visible);
//3 pause 完成不需要等待可见
if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG_PAUSE,
"Complete pause, no longer waiting: " + prev);
}
if (prev.deferRelaunchUntilPaused) {//4 需要重新显示的activity,要到pause才能重新启动
// Complete the deferred relaunch that was waiting for pause to complete.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
relaunchActivityLocked(prev, prev.configChangeFlags, false,
prev.preserveWindowOnDeferredRelaunch);
} else if (wasStopping) { //5 本来是stoping状态的现在变成pause???
// We are also stopping, the stop request must have gone soon after the pause.
// 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 = ActivityState.STOPPING;
} else if ((!prev.visible && !hasVisibleBehindActivity())
|| mService.isSleepingOrShuttingDownLocked()) {
// If we were visible then resumeTopActivities will release resources before
// stopping.
addToStopping(prev, true /* immediate */);
}
} else {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
prev = null;
}
// It is possible the activity was freezing the screen before it was paused.
// In that case go ahead and remove the freeze this activity has on the screen
// since it is no longer visible.
if (prev != null) {
prev.stopFreezingScreenLocked(true /*force*/);
}
mPausingActivity = null;
}
if (resumeNext) {
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
if (!mService.isSleepingOrShuttingDownLocked()) {
//4 没有休眠,显示栈顶的activity
mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
} else {
mStackSupervisor.checkReadyForSleepLocked();
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
// something. Also if the top activity on the stack is not the just paused
// activity, we need to go ahead and resume it to ensure we complete an
// in-flight app switch.
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
if (prev != null) { //5恢复key的接收
prev.resumeKeyDispatchingLocked();
//6 更新电量统计
if (prev.app != null && prev.cpuTimeAtResume > 0
&& mService.mBatteryStatsService.isOnBattery()) {
long diff = mService.mProcessCpuTracker.getCpuTimeForPid(prev.app.pid)
- prev.cpuTimeAtResume;
if (diff > 0) {
BatteryStatsImpl bsi = mService.mBatteryStatsService.getActiveStatistics();
synchronized (bsi) {
BatteryStatsImpl.Uid.Proc ps =
bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
prev.info.packageName);
if (ps != null) {
ps.addForegroundTimeLocked(diff);
}
}
}
}
prev.cpuTimeAtResume = 0; // reset it
}
// Notify when the task stack has changed, but only if visibilities changed (not just
// focus). Also if there is an active pinned stack - we always want to notify it about
// task stack changes, because its positioning may depend on it.
if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause
|| mService.mStackSupervisor.getStack(PINNED_STACK_ID) != null) {
mService.notifyTaskStackChangedLocked();
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
}
//7 确保activity的可见性
mStackSupervisor.ensureActivitiesVisibleLocked(resuming, 0, !PRESERVE_WINDOWS);
}
这里总结下来如下几步
1 更新activity状态
2 mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
3 统计电量
4 mStackSupervisor.ensureActivitiesVisibleLocked(resuming, 0, !PRESERVE_WINDOWS);
又一次回到这个调用栈我们已经很熟悉,直接分析ActivityStack的private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) 函数下半部分
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
......
if (prev != null && prev != next) { //1 需要等待下一个activity可见再去stop,添加到
//mWaitingVisibleActivities中
if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
&& next != null && !next.nowVisible) {
mStackSupervisor.mWaitingVisibleActivities.add(prev);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Resuming top, waiting visible to hide: " + prev);
} else {
// The next activity is already visible, so hide the previous
// activity's windows right now so we can show the new one ASAP.
// We only do this if the previous is finishing, which should mean
// it is on top of the one being resumed so hiding it quickly
// is good. Otherwise, we want to do the normal route of allowing
// the resumed activity to be shown so we can decide if the
// previous should actually be hidden depending on whether the
// new one is found to be full-screen or not.
if (prev.finishing) { //2 如果要resume的activity已经可见,尽快让pause的activity不可见
mWindowManager.setAppVisibility(prev.appToken, false);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Not waiting for visible to hide: " + prev + ", waitingVisible="
+ mStackSupervisor.mWaitingVisibleActivities.contains(prev)
+ ", nowVisible=" + next.nowVisible);
} else {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Previous already visible but still waiting to hide: " + prev
+ ", waitingVisible="
+ mStackSupervisor.mWaitingVisibleActivities.contains(prev)
+ ", nowVisible=" + next.nowVisible);
}
}
}
// Launching this app's activity, make sure the app is no longer
// considered stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
next.packageName, false, next.userId); /* TODO: Verify if correct userid */
} catch (RemoteException e1) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ next.packageName + ": " + e);
}
// We are starting up the next activity, so tell the window manager
// that the previous one will be hidden soon. This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = true;
if (prev != null) {
if (prev.finishing) {
....
mWindowManager.setAppVisibility(prev.appToken, false);
} else {
//3 准备动画
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: prev=" + prev);
if (mNoAnimActivities.contains(next)) {
anim = false;
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
} else {
mWindowManager.prepareAppTransition(prev.task == next.task
? TRANSIT_ACTIVITY_OPEN
: next.mLaunchTaskBehind
? TRANSIT_TASK_OPEN_BEHIND
: TRANSIT_TASK_OPEN, false);
}
}
} else {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
if (mNoAnimActivities.contains(next)) {
anim = false;
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
} else {
mWindowManager.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false);
}
}
Bundle resumeAnimOptions = null;
if (anim) {
ActivityOptions opts = next.getOptionsForTargetActivityLocked();
if (opts != null) {
resumeAnimOptions = opts.toBundle();
}
next.applyOptionsLocked();
} else {
next.clearOptionsLocked();
}
ActivityStack lastStack = mStackSupervisor.getLastStack();
if (next.app != null && next.app.thread != null) { //4注意只有activity被创建后这里app才不为空
....
} else {
// Whoops, need to restart this activity!
if (!next.hasBeenLaunched) { //5 设置activity已经启动
next.hasBeenLaunched = true;
} else {
if (SHOW_APP_STARTING_PREVIEW) {
next.showStartingWindow(null, true);
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
}
//6 启动activity
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
到了这里执行比较简单,就是更新activity状态,如果需要finish则finish,另外这里设置了动画,更新了activity动画的状态,最后调用startSpecificActivityLocked函数真心的启动activity,
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.task.stack.setLaunchTime(r);
if (app != null && app.thread != null) {
try {
.......
//1 进程已经起来直接启动activity
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
//2 进程已经起来,启动进程先,其实启动进程后还是调用resumeTopActivityInnerLocked函数去启动Activity
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
我们跳过进程的启动,这属于进程管理的部分,直接来看启动activity的过程
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
if (!allPausedActivitiesComplete()) { //1 没有全部pause完成直接跳过
// While there are activities pausing we skipping starting any new activities until
// pauses are complete. NOTE: that we also do this for activities that are starting in
// the paused state because they will first be resumed then paused on the client side.
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"realStartActivityLocked: Skipping start of r=" + r
+ " some activities pausing...");
return false;
}
if (andResume) { //2 需要显示,先冻结屏幕,注意这里并不一定会冻结,要看config和是否正在冻结过程中
r.startFreezingScreenLocked(app, 0);
mWindowManager.setAppVisibility(r.appToken, true);
// schedule launch ticks to collect information about slow apps.
r.startLaunchTickingLocked();
}
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order. Note that
// as a result of this, it can call back into the activity
// manager with a new orientation. We don't care about that,
// because the activity is not currently running so we are
// just restarting it anyway.
//2 更新config
if (checkConfig) {
Configuration config = mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
r.mayFreezeScreenLocked(app) ? r.appToken : null);
// Deferring resume here because we're going to launch new activity shortly.
// We don't want to perform a redundant launch of the same record while ensuring
// configurations and trying to resume top activity of focused stack.
mService.updateConfigurationLocked(config, r, false, true /* deferResume */);
}
......
//3 执行启动
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
......
if (andResume) {
// As part of the process of launching, ActivityThread also performs
// a resume.
//4 resume完成调用
stack.minimalResumeActivityLocked(r);
} else {
// This activity is not starting in the resumed state... which should look like we asked
// it to pause+stop (but remain visible), and it has done so and reported back the
// current icicle and other state.
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to PAUSED: " + r + " (starting in paused state)");
r.state = PAUSED;
}
return true;
}
这个过程客户端的代码有些复杂分析起来占用篇幅比较长,反正就是创建Activity执行生命周期到onResume之后创建ViewRootImpl,DecorView以及添加WindowState到WMS的过程,这里就不去具体说明了,执行完onResume之后就会执行
ActivityManagerNative.getDefault().activityResumed(token);
函数最终调用到ActivityManagerService中
@Override
public final void activityResumed(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
stack.activityResumedLocked(token);
}
}
Binder.restoreCallingIdentity(origId);
}
这个函数也是比较简单的,最终还是调用到了stack.activityResumedLocked(token)函数
final void activityResumedLocked(IBinder token) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
r.icicle = null;
r.haveState = false;
}
何其简单!!!
看完客户端的处理,我们再继续看下realStartActivityLocked的第四个函数ActivityStack的minimalResumeActivityLocked函数
void minimalResumeActivityLocked(ActivityRecord r) {
r.state = ActivityState.RESUMED;
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + r + " (starting new instance)"
+ " callers=" + Debug.getCallers(5));
mResumedActivity = r;
r.task.touchActiveTime();
mRecentTasks.addLocked(r.task);
completeResumeLocked(r);
mStackSupervisor.checkReadyForSleepLocked();
setLaunchTime(r);
if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
"Launch completed; removing icicle of " + r.icicle);
}
这里重新更新了mResumedActivity,stack上就又存在了resumeActivity,completeResumeLocked函数
private void completeResumeLocked(ActivityRecord next) {
next.visible = true;
next.idle = false;
next.results = null;
next.newIntents = null;
next.stopped = false;
if (next.isHomeActivity()) {
ProcessRecord app = next.task.mActivities.get(0).app;
if (app != null && app != mService.mHomeProcess) {
mService.mHomeProcess = app;
}
}
if (next.nowVisible) {
// We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now.
mStackSupervisor.reportActivityVisibleLocked(next);
mStackSupervisor.notifyActivityDrawnForKeyguard();
}
// schedule an idle timeout in case the app doesn't do it for us.
//1 安排一个空的超时
mStackSupervisor.scheduleIdleTimeoutLocked(next);
//2 报告resume 完成
mStackSupervisor.reportResumedActivityLocked(next);
//3 恢复key的分发
next.resumeKeyDispatchingLocked();
mNoAnimActivities.clear();
// Mark the point when the activity is resuming
// TODO: To be more accurate, the mark should be before the onCreate,
// not after the onResume. But for subsequent starts, onResume is fine.
if (next.app != null) {
next.cpuTimeAtResume = mService.mProcessCpuTracker.getCpuTimeForPid(next.app.pid);
} else {
next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
}
next.returningOptions = null;
if (getVisibleBehindActivity() == next) {
// When resuming an activity, require it to call requestVisibleBehind() again.
setVisibleBehindActivity(null);
}
}
boolean reportResumedActivityLocked(ActivityRecord r) {
final ActivityStack stack = r.task.stack;
if (isFocusedStack(stack)) {
mService.updateUsageStats(r, true);
}
if (allResumedActivitiesComplete()) {
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
//执行动画
mWindowManager.executeAppTransition();
return true;
}
return false;
}
整个流程大概就是这样的记住都是围绕着activity展开的就可以了.其中还穿插了一些WMS相关的显示动画周期相关的函数.我们这里不做重点分析,另外activity的stop函数我们还没有分析到,是因为有一个函数我们还没有进行分析,那就ActivityStackSupervisor类的ensureActivitiesVisibleLocked方法,这个方法有很多地方调用
我们这个流程中有三处会调用到该函数
1 ActivityStackSupervisor的 realStartActivityLocked方法中有这样一段
if (checkConfig) {
Configuration config = mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
r.mayFreezeScreenLocked(app) ? r.appToken : null);
// Deferring resume here because we're going to launch new activity shortly.
// We don't want to perform a redundant launch of the same record while ensuring
// configurations and trying to resume top activity of focused stack.
mService.updateConfigurationLocked(config, r, false, true /* deferResume */);
}
更新属性的时候
2 completeResumeLocked 函数中调用boolean reportResumedActivityLocked(ActivityRecord r)函数
3 private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) 函数中
就这三个地方也是我们情景栈先后顺序
这个函数还是挺关键的
final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
boolean preserveWindows) {
mTopActivityOccludesKeyguard = false;
mTopDismissingKeyguardActivity = null;
mStackSupervisor.mKeyguardController.beginActivityVisibilityUpdate();
try {
ActivityRecord top = topRunningActivityLocked(); //1 获取栈上top activity
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + top
+ " configChanges=0x" + Integer.toHexString(configChanges));
if (top != null) {
checkTranslucentActivityWaiting(top);
}
// If the top activity is not fullscreen, then we need to
// make sure any activities under it are now visible.
boolean aboveTop = top != null;
//2 新启动的Activity是否要被显示
final int stackVisibility = shouldBeVisible(starting);
final boolean stackInvisible = stackVisibility != STACK_VISIBLE; //3 该stack不可见
boolean behindFullscreenActivity = stackInvisible;
boolean resumeNextActivity = mStackSupervisor.isFocusedStack(this)
&& (isInStackLocked(starting) == null); //4 如果是焦点stack但是要启动的Activity不在这里面
boolean behindTranslucentActivity = false;
//5 遍历task
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.finishing) {
// Normally the screenshot will be taken in makeInvisible(). When an activity
// is finishing, we no longer change its visibility, but we still need to take
// the screenshots if startPausingLocked decided it should be taken.
//6 正在关闭的需要更新缩略图的更新之
if (r.mUpdateTaskThumbnailWhenHidden) {
r.updateThumbnailLocked(r.screenshotActivityLocked(),
null /* description */);
r.mUpdateTaskThumbnailWhenHidden = false;
}
continue;
}
final boolean isTop = r == top;
if (aboveTop && !isTop) {//7 toppingrunning上面的activity都是不能被显示的直接跳过
continue;
}
aboveTop = false;
// Check whether activity should be visible without Keyguard influence
final boolean visibleIgnoringKeyguard = r.shouldBeVisibleIgnoringKeyguard(
behindFullscreenActivity);
r.visibleIgnoringKeyguard = visibleIgnoringKeyguard;
//8根据keygurd判断可见性
// Now check whether it's really visible depending on Keyguard state.
final boolean reallyVisible = checkKeyguardVisibility(r,
visibleIgnoringKeyguard, isTop);
if (visibleIgnoringKeyguard) {
behindFullscreenActivity = updateBehindFullscreen(stackInvisible,
behindFullscreenActivity, task, r);
if (behindFullscreenActivity && !r.fullscreen) {
behindTranslucentActivity = true;
}
}
if (reallyVisible) { //9 真的需要activity可见的情况
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r
+ " finishing=" + r.finishing + " state=" + r.state);
// First: if this is not the current activity being started, make
// sure it matches the current configuration.
if (r != starting) { //10 因为要显示先更新config
r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindows);
}
if (r.app == null || r.app.thread == null) { //11 进程没有起来或者Activity还没有起来,重新启动
if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
resumeNextActivity, r)) {
if (activityNdx >= activities.size()) {
// Record may be removed if its process needs to restart.
activityNdx = activities.size() - 1;
} else {
resumeNextActivity = false;
}
}
} else if (r.visible) { //12 已经可见
// If this activity is already visible, then there is nothing to do here.
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Skipping: already visible at " + r);
if (r.handleAlreadyVisible()) {
resumeNextActivity = false;
}
} else {
//13 不可见 通知window可见
r.makeVisibleIfNeeded(starting);
}
// Aggregate current change flags.
configChanges |= r.configChangeFlags;
} else {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r
+ " finishing=" + r.finishing + " state=" + r.state + " stackInvisible="
+ stackInvisible + " behindFullscreenActivity="
+ behindFullscreenActivity + " mLaunchTaskBehind="
+ r.mLaunchTaskBehind);
//14 window不可见的情况
makeInvisible(r);
}
}
if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
// The visibility of tasks and the activities they contain in freeform stack are
// determined individually unlike other stacks where the visibility or fullscreen
// status of an activity in a previous task affects other.
behindFullscreenActivity = stackVisibility == STACK_INVISIBLE;
} else if (mStackId == HOME_STACK_ID) {
if (task.isHomeTask()) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task
+ " stackInvisible=" + stackInvisible
+ " behindFullscreenActivity=" + behindFullscreenActivity);
// No other task in the home stack should be visible behind the home activity.
// Home activities is usually a translucent activity with the wallpaper behind
// them. However, when they don't have the wallpaper behind them, we want to
// show activities in the next application stack behind them vs. another
// task in the home stack like recents.
behindFullscreenActivity = true;
} else if (task.isRecentsTask()
&& task.getTaskToReturnTo() == APPLICATION_ACTIVITY_TYPE) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Recents task returning to app: at " + task
+ " stackInvisible=" + stackInvisible
+ " behindFullscreenActivity=" + behindFullscreenActivity);
// We don't want any other tasks in the home stack visible if the recents
// activity is going to be returning to an application activity type.
// We do this to preserve the visible order the user used to get into the
// recents activity. The recents activity is normally translucent and if it
// doesn't have the wallpaper behind it the next activity in the home stack
// shouldn't be visible when the home stack is brought to the front to display
// the recents activity from an app.
behindFullscreenActivity = true;
}
} else if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Skipping after task=" + task
+ " returning to non-application type=" + task.getTaskToReturnTo());
// Once we reach a fullscreen stack task that has a running activity and should
// return to another stack task, then no other activities behind that one should
// be visible.
if (task.topRunningActivityLocked() != null &&
task.getTaskToReturnTo() != APPLICATION_ACTIVITY_TYPE) {
behindFullscreenActivity = true;
}
}
}
if (mTranslucentActivityWaiting != null &&
mUndrawnActivitiesBelowTopTranslucent.isEmpty()) {
// Nothing is getting drawn or everything was already visible, don't wait for timeout.
notifyActivityDrawnLocked(null);
}
} finally {
mStackSupervisor.mKeyguardController.endActivityVisibilityUpdate();
}
}
shouldBeVisible 有2种结果STACK_INVISIBLE,
1 STACK_INVISIBLE栈不可见
2 STACK_VISIBLE 栈可见
注意这里描述的是栈的可见性,starting参数只是给计算栈的可见性进行参考
int shouldBeVisible(ActivityRecord starting) {
if (!isAttached() || mForceHidden) { //1 栈没有attach到Wms上或者强制不可见返回STACK_INVISIBLE表示不可见
return STACK_INVISIBLE;
}
if (mStackSupervisor.isFrontStackOnDisplay(this) || mStackSupervisor.isFocusedStack(this)) { //2 栈在display的前台 或者是焦点栈是可见的
return STACK_VISIBLE;
}
final int stackIndex = mStacks.indexOf(this);
if (stackIndex == mStacks.size() - 1) {
Slog.wtf(TAG,
"Stack=" + this + " isn't front stack but is at the top of the stack list");
return STACK_INVISIBLE;
}
// Check position and visibility of this stack relative to the front stack on its display.
final ActivityStack topStack = getTopStackOnDisplay();
final int topStackId = topStack.mStackId;
if (mStackId == DOCKED_STACK_ID) {
// If the assistant stack is focused and translucent, then the docked stack is always
// visible
if (topStack.isAssistantStack()) { //3 当前栈是dockstack,并且最上面的栈是透明且是助手栈则docker stack是可见的
return (topStack.isStackTranslucent(starting, DOCKED_STACK_ID)) ? STACK_VISIBLE
: STACK_INVISIBLE;
}
return STACK_VISIBLE;
}
// Set home stack to invisible when it is below but not immediately below the docked stack
// A case would be if recents stack exists but has no tasks and is below the docked stack
// and home stack is below recents
if (mStackId == HOME_STACK_ID) { //4 判断home stack的可见性(除非在docker stack下面,否则在其他下面是不可见的)
int dockedStackIndex = mStacks.indexOf(mStackSupervisor.getStack(DOCKED_STACK_ID));
if (dockedStackIndex > stackIndex && stackIndex != dockedStackIndex - 1) {
return STACK_INVISIBLE;
}
}
// Find the first stack behind front stack that actually got something visible.
int stackBehindTopIndex = mStacks.indexOf(topStack) - 1;
while (stackBehindTopIndex >= 0 &&
mStacks.get(stackBehindTopIndex).topRunningActivityLocked() == null) {
stackBehindTopIndex--;
}
final int stackBehindTopId = (stackBehindTopIndex >= 0)
? mStacks.get(stackBehindTopIndex).mStackId : INVALID_STACK_ID;
if (topStackId == DOCKED_STACK_ID || StackId.isAlwaysOnTop(topStackId)) {
if (stackIndex == stackBehindTopIndex) {
// Stacks directly behind the docked or pinned stack are always visible.
//5 在docker后面和pinned后面的堆栈可见
return STACK_VISIBLE;
} else if (StackId.isAlwaysOnTop(topStackId) && stackIndex == stackBehindTopIndex - 1) {
// Otherwise, this stack can also be visible if it is directly behind a docked stack
// or translucent assistant stack behind an always-on-top top-most stack
if (stackBehindTopId == DOCKED_STACK_ID) {
return STACK_VISIBLE;
} else if (stackBehindTopId == ASSISTANT_STACK_ID) {
return mStacks.get(stackBehindTopIndex).isStackTranslucent(starting, mStackId)
? STACK_VISIBLE : STACK_INVISIBLE;
}
}
}
if (StackId.isBackdropToTranslucentActivity(topStackId)
&& topStack.isStackTranslucent(starting, stackBehindTopId)) {
// Stacks behind the fullscreen or assistant stack with a translucent activity are
// always visible so they can act as a backdrop to the translucent activity.
// For example, dialog activities
if (stackIndex == stackBehindTopIndex) {
return STACK_VISIBLE;
}
if (stackBehindTopIndex >= 0) {
if ((stackBehindTopId == DOCKED_STACK_ID
|| stackBehindTopId == PINNED_STACK_ID)
&& stackIndex == (stackBehindTopIndex - 1)) {
// The stack behind the docked or pinned stack is also visible so we can have a
// complete backdrop to the translucent activity when the docked stack is up.
return STACK_VISIBLE;
}
}
}
if (StackId.isStaticStack(mStackId)) {
// Visibility of any static stack should have been determined by the conditions above.
return STACK_INVISIBLE;
}
for (int i = stackIndex + 1; i < mStacks.size(); i++) {
final ActivityStack stack = mStacks.get(i);
if (!stack.mFullscreen && !stack.hasFullscreenTask()) {
continue;
}
if (!StackId.isDynamicStacksVisibleBehindAllowed(stack.mStackId)) {
// These stacks can't have any dynamic stacks visible behind them.
return STACK_INVISIBLE;
}
if (!stack.isStackTranslucent(starting, INVALID_STACK_ID)) {
return STACK_INVISIBLE;
}
}
return STACK_VISIBLE;
}
使window 不可见
private void makeInvisible(ActivityRecord r) {
if (!r.visible) { // 1 当前就是不可见情况直接返回
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + r);
return;
}
// Now for any activities that aren't visible to the user, make sure they no longer are
// keeping the screen frozen.
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state);
try {
final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState(
"makeInvisible", true /* beforeStopping */);
// Defer telling the client it is hidden if it can enter Pip and isn't current paused,
// stopped or stopping. This gives it a chance to enter Pip in onPause().
// TODO: There is still a question surrounding activities in multi-window mode that want
// to enter Pip after they are paused, but are still visible. I they should be okay to
// enter Pip in those cases, but not "auto-Pip" which is what this condition covers and
// the current contract for "auto-Pip" is that the app should enter it before onPause
// returns. Just need to confirm this reasoning makes sense.
final boolean deferHidingClient = canEnterPictureInPicture
&& r.state != STOPPING && r.state != STOPPED && r.state != PAUSED;
r.setDeferHidingClient(deferHidingClient);
r.setVisible(false); //2 设置不可见
switch (r.state) {
case STOPPING:
case STOPPED: //3 设置window不可见
if (r.app != null && r.app.thread != null) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Scheduling invisibility: " + r);
r.app.thread.scheduleWindowVisibility(r.appToken, false);
}
// Reset the flag indicating that an app can enter picture-in-picture once the
// activity is hidden
r.supportsEnterPipOnTaskSwitch = false;
break;
case INITIALIZING:
case RESUMED:
case PAUSING:
case PAUSED:
//4 设置stop状态
addToStopping(r, true /* scheduleIdle */,
canEnterPictureInPicture /* idleDelayed */);
break;
default:
break;
}
} catch (Exception e) {
// Just skip on any failure; we'll make it visible when it next restarts.
Slog.w(TAG, "Exception thrown making hidden: " + r.intent.getComponent(), e);
}
}
void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
mStackSupervisor.mStoppingActivities.add(r);
}
// If we already have a few activities waiting to stop, then give up
// on things going idle and start clearing them out. Or if r is the
// last of activity of the last task the stack will be empty and must
// be cleared immediately.
boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
|| (r.frontOfTask && mTaskHistory.size() <= 1);
if (scheduleIdle || forceIdle) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Scheduling idle now: forceIdle="
+ forceIdle + "immediate=" + !idleDelayed);
if (!idleDelayed) {
mStackSupervisor.scheduleIdleLocked();
} else {
mStackSupervisor.scheduleIdleTimeoutLocked(r);
}
} else {
checkReadyForSleep();
}
}
TODO
FLAG_RESUME_WHILE_PAUSING