AMS的Activity管理情景1在現有task上啟動到同一個task上
分析了棧的管家和棧.有些摸不到頭腦,我們順著一個情景來分析.本文重點關注啟動過程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);