???? Pause前臺顯示Activity,Resume目標Activity
Android四大組件原始碼實作詳解系列博客目錄:
Android應用行程創建流程大揭秘
Android四大組件之bindService原始碼實作詳解
Android四大組件之Activity啟動流程原始碼實作詳解概要
Android四大組件之Activity啟動流程原始碼實作詳解(一)
Android四大組件之Activity啟動流程原始碼實作詳解(二)
Activity啟動流程(三)- Activity Task調度演算法復盤分析
Activity啟動流程(四)- Pause前臺顯示Activity,Resume目標Activity
前言
??還記得我們在前面博客Android四大組件之Activity啟動流程原始碼實作詳解(二)和Activity啟動流程(三)- Activity Task調度演算法復盤分析中做的艱苦卓越的斗爭嗎!這場戰役之慘烈,戰況之持久前所未有!雖然程序是疼苦的,但是戰果也是顯赫和令人滿意的,通過上述戰役我們取得了如下的階段性成果:
- 初始化了Activity啟動狀態
- 計算了啟動launchFlag
- 計算了呼叫者的ActivityStack
- 檢查了是否存在復用的TaskRecord
- 對于存在復用的TaskRecord則進行相應的ActivityStack、TaskRecord的移動(說實話,我也沒有真的搞懂,希望這塊比較有經驗的小伙們能和我一起學習)
- 計算了當前啟動Activity所屬的TaskRecord
- 把當前啟動的Activity放到所屬TaskRecord的堆疊頂
- 并且前面的TaskRecord放到了ActivityStack的堆疊頂
總而言之經過上述一頓猛虎般的操作,此時要啟動的目標Actvity及其對應的task位置以及ActivityStack已經安排妥當,現在可以準備接下來的相關作業了,那么在本篇博客中我們將繼續分析system_server對Activity啟動請求的處理流程:
- system_server行程通過AMS處理啟動Activity請求:
5.Pause前臺Activity
6.Resume請求的目標Activity
7.AMS請求zygote行程為目標Activity創建所屬行程
注意:本篇的介紹是基于Android 7.xx平臺為基礎的,其中涉及的代碼路徑如下:
frameworks/base/services/core/java/com/android/server/am/
--- ActivityManagerService.java
--- ProcessRecord.java
--- ActivityRecord.java
--- ActivityResult.java
--- ActivityStack.java
--- ActivityStackSupervisor.java
--- ActivityStarter.java
--- TaskRecord.java
frameworks/base/services/core/java/com/android/server/pm/
--- PackageManagerService.java
frameworks/base/core/java/android/content/pm/
--- ActivityInfo.java
frameworks/base/core/java/android/app/
--- IActivityManager.java
--- ActivityManagerNative.java (內部包含AMP)
--- ActivityManager.java
--- AppGlobals.java
--- Activity.java
--- ActivityThread.java(內含AT)
--- LoadedApk.java
--- AppGlobals.java
--- Application.java
--- Instrumentation.java
--- IApplicationThread.java
--- ApplicationThreadNative.java (內部包含ATP)
--- ActivityThread.java (內含ApplicationThread)
--- ContextImpl.java
并且在后續的原始碼分析程序中為了簡述方便,會將做如下簡述:
- ApplicationThreadProxy簡稱為ATP
- ActivityManagerProxy簡稱為AMP
- ActivityManagerService簡稱為AMS
- ActivityManagerNative簡稱AMN
- ApplicationThreadNative簡稱ATN
- PackageManagerService簡稱為PKMS
- ApplicationThread簡稱為AT
- ActivityStarter簡稱為AS,這里不要和ActivityServices搞混淆了
- ActivityStackSupervisor簡稱為ASS
在正式開始今天博客相關原始碼分析前,還是先奉上呼叫的時序圖以便小伙們先從整體上有個清晰的概括,然后再從細節開擼!

一.Pause處于Resume狀態Actvity以及Resume目標Activity
??戰斗還沒有結束,革命尚未成功仍需努力!讓我們帶著前面博客Android四大組件之Activity啟動流程原始碼實作詳解(二)未完成使命繼續前進!
//[ActivityStarter.java]
/* 這里的sourceRecord是指發起呼叫者
r是指本次的將要啟動的Activity,startFlags取值為0,
doResume的值為true
*/
private int startActivityUnchecked(final ActivityRecord r,
ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume,
ActivityOptions options,
TaskRecord inTask) {
...
if (mDoResume) {
if (!mLaunchTaskBehind) {
/*
* 設定當前focused,因為經過以上幾步,啟動的activity已經轉移到
*堆疊頂端,這時候設定AMS當前focused的Activity
*另外呼叫這個函式也會有ActivityStack、Task堆疊的移動,即呼叫各自堆疊把當
*前正在啟動的Activity所屬的Task、ActivityStack移動到堆疊頂
*/
mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
}
final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
if (!mTargetStack.isFocusable()//當前的目標Stack被設定成了焦點所以不會走此分支
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) {
...
} else {
//開始resume,詳見章節1.1
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
} else {
mTargetStack.addRecentActivityLocked(mStartActivity);
}
return START_SUCCESS;
...
}
搞了這么久,發起端Activity和目標Actvity的生命周期一個都沒有看到,小伙們是不是心里有些慌了! 不急,這不它就來了,讓我們先來看看Acitivyt A啟動Activty B的正常生命周期調度:
---> Activity A onCreate
---> Activity A onStart
---> Activity A onResume
---> Activity A onPause
---> Activity B onCreate
---> Activity B onStart
---> Activity B onResume
---> Activty A onStop
而我們接下來會沿著上面的主線進行相關的分析,這里我們從A的onPause為起始段開始本篇博客的分析,此時我們將上述場景Activity A啟動Activity B帶入下面的相關分析中,
1.1 ASS.resumeFocusedStackTopActivityLocked
??讓我們對ActivityStackSupervisor中的resumeFocusedStackTopActivityLocked繼續分析,其中Android中對于Activity的啟動主要表現在如下兩個方面:
- 第一:AMS對于Activity比較復雜的部分即為Task任務堆疊和Stack的處理,這部分詳見Activity啟動流程(三)- Activity Task調度演算法復盤分析
- 第二:本章節要重點介紹的resumed相關操作,
并且關于這兩部分讀者最好參考我前面的博客先假定某種啟動模式,然后進行相關的分析,否則很容易陷入代碼中而不能自拔,而我們這里的resumeFocusedStackTopActivityLocked其實對應的就是Activity的生命周期,
//[ActivityStackSupervisor.java]
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack,
ActivityRecord target,
ActivityOptions targetOptions) {
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);//詳見章節1.1.1
}
...
}
讓我們單刀直入直搗黃龍,接著分析ActivityStack的resumeTopActivityUncheckedLocked方法(不是我不分析,確實是因為沒有啥好分析的),
1.1.1 ActivityStack.resumeTopActivityUncheckedLocked
//[ActivityStack.java]
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
...
result = resumeTopActivityInnerLocked(prev, options);//詳見章節1.2
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
return result;
}
這里沒有過多可以介紹的,讓我們單刀直入直搗黃龍,接著分析其方法resumeTopActivityInnerLocked,在分析這個方法之前小伙們該上廁所的可以上廁所了,喝水的可以喝水了,因為這又是一個重量級的方法,
1.2 ActivityStack.resumeTopActivityInnerLocked
??在正式開始分析該方法之前,我們先來看看該方法的入參,方法入參的名字挺奇怪的!
| 引數型別 | 引數名稱 | 引數功能 |
|---|---|---|
| ActivityRecord | prev | 目標Activity的相關資訊 |
| ActivityOptions | options | 額外附加資訊 |
不知各位小伙們發現沒有,在上一個方法中發起呼叫時,傳入的引數名稱是target,表示待啟動的ActivityRecord,但這里搖身一變,引數名稱卻是prev,看引數意思是表示之前啟動的ActivityRecord,即將要進入Pausing狀態的那個Activity,到底意欲幾何,是不是谷歌的哥哥搞錯了啊?這里小伙們先暫且將該疑問放在一邊,待我們后續的原始碼中一一揭秘,此時我們要重點關注,此時的入參為位目標ActivityRecord,雖然它換了一個馬甲叫做prev,
//[ActivityStack.java]
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
if (!mService.mBooting && !mService.mBooted) {
// 如果系統還未啟動完畢,那AMS還不能正常作業,所以也不能顯示Activity,主要是為防止沒有開機啟動完成
return false;
}
//此處忽略
ActivityRecord parent = mActivityContainer.mParentActivity;
...
// 當前AS中可能存在一些正處于Intializing狀態的ActivityRecord,
// 如果這些ActivityRecord不是位于堆疊頂,而且正在執行視窗啟動影片,
// 那么,就需要取消這些Activity的啟動影片,
mStackSupervisor.cancelInitializingActivities();
/*
找到第一個沒有finishing的堆疊頂activity,通常指向了要啟動的Activity目標組件
此場景下prev和next都是同一個,都指向了Activity B
*/
final ActivityRecord next = topRunningActivityLocked();
//這個變數是表示是否回呼Activity中的onUserLeaveHint和onUserInteraction函式
final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
final TaskRecord prevTask = prev != null ? prev.task : null;
if (next == null) {//這個表示如果當前ActivityStack不存在待啟動的Activity,那么會啟動Launcher桌面
final String reason = "noMoreActivities";
final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack()
? HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
// 當前AS不是全屏顯示,則需要將焦點切換到下一個待顯示的AS
if (!mFullscreen && adjustFocusToNextFocusableStackLocked(returnTaskType, reason)) {
return mStackSupervisor.resumeFocusedStackTopActivityLocked(
mStackSupervisor.getFocusedStack(), prev, null);
}
ActivityOptions.abort(options);
// 默認情況下,Stack都是占據全屏的,所以,當前Stack如果沒有要顯示的Activity,則會要求顯示桌面
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
}
next.delayedResume = false;
//檢查要啟動的Activity 組件是否等于當前被激活的 Activity 組件,如果等于
//并且處于 RESUMED 狀態,直接回傳,我們前面演示的啟動情況很顯然不滿足條件
if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
//當前正在顯示的Activity正好就是下一個待顯示的Activity,
// 那么,就中斷對目標ActivityRecord的調度
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return false;
}
final TaskRecord nextTask = next.task;
/*這個是對上一個resumed的Activity的相關處理
* 由于我們是第一次啟動B Activity,所以不可能處于finish跳過此處
*/
if (prevTask != null && prevTask.stack == this &&
prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
...
}
// 系統進入休眠狀態,當前Stack的堆疊頂Activity已經處于Paused狀態
// 那么,中斷待顯示Activity的相關調度(有點拗口,學習原始碼就是這么枯燥的事情)
if (mService.isSleepingOrShuttingDownLocked()
&& mLastPausedActivity == next
&& mStackSupervisor.allPausedActivitiesComplete()) {
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return false;
}
...
/*
在ASS中存在很多的資料結構,用來統一管理ActivityRecord的狀態
譬如mStoppingActivities記錄了當前所有處于Stopping狀態的ActivityRecord
mGoingToSleepActivities記錄了當前所有要進入休眠狀態的ActivityRecord
在某些場景下,待顯示的ActivityRecord可能處于這些陣列中,但需要從中剔除
*/
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
mStackSupervisor.mWaitingVisibleActivities.remove(next);
// 如果當前ASS中還有ActivityRecord不是處于PAUSED, STOPPED或STOPPING這三個狀態之一,
// 那么,需要先等這些ActivityRecord進入停止狀態
if (!mStackSupervisor.allPausedActivitiesComplete()) {
return false;
}
??分析至此,讓我們先緩緩,停下前進的腳步看看我們來時的路!前面的代碼片段,主要是做一些初始化和可能的"例外"處理作業,雖然我們待顯示的目標ActivityRecord已經位于堆疊頂,但要真正將其顯示到前臺來,即執行目標Activity的onCreate/onStart/onResume等狀態,這一路有很多障礙和初始化作業還處理,或者說還有很多前提條件需要滿足,譬如,系統要休眠時,當前啟動目標Activity程序要中斷;當前ASS中有Activity正處于Pausing狀態時,也需要等相關Activity執行完畢才行,我們可以將上述的相關作業認為是準備階段!前路漫漫是征途,我將上下而求索!
//[ActivityStack.java]
/*
setLaunchSource設定待啟動的Activity的資訊
跟進setLaunchSource原始碼發現它最侄訓獲取一個WakeLock,保證在顯示Activity的程序中,系統不會進行休眠狀態
*/
mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
/*
目標Activity的啟動引數中是否包含FLAG_RESUME_WHILE_PAUSING
如果存在FLAG_RESUME_WHILE_PAUSING的flag,表示可以在當前顯示的發起端Activity執行Pausing時,
能同時進行Resume操作
即變數dontWaitForPause的取意就是不需要等到Activity執行Pause完畢
*/
final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
/*
這個是pause掉不是FocusedStack的其它ActivityStack的堆疊頂activity
對于不是當前focusStack的并且存在有mResumedActivity不為null的都要paused
譬如從Luncher啟動一個新的App時會走入此分支
*/
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
/********************************************************************************/
//這里是為了演示使用
//ASS.java
boolean pauseBackStacks(boolean userLeaving, boolean resuming, boolean dontWait) {
boolean someActivityPaused = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!isFocusedStack(stack) && stack.mResumedActivity != null) {
someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
dontWait);
}
}
}
return someActivityPaused;
}
/********************************************************************************/
//此時要帶入真是場景了,此時的mResumedActivity表示目標Stack堆疊中處于Resume狀態的Activity,那么在此場景下就是Activity A,這個因該比較容易理解
if (mResumedActivity != null) {
//當前resumd狀態activity不為空,則需要先暫停該Activity
// pause當前堆疊的activity,即執行Activity的生命周期onPause
pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);//詳見章節1.3
}
if (pausing) {//當前有正在pause的Activity,尼瑪按照我們場景Activity A啟動Activity B,那不是到此就結束了啊,直接回傳了,事實就是這樣的,尼瑪是不是走錯片場了,后續你就知道了
if (next.app != null && next.app.thread != null) {
mService.updateLruProcessLocked(next.app, true, null);
}
return true;
}
//檢查要啟動的Activity 組件是否等于當前被激活的 Activity 組件,如果等于
//并且處于 RESUMED 狀態,直接回傳,我們前面演示的啟動情況很顯然不滿足條件
else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return true;
}
??我們在此就此打住,先不往后分析resumeTopActivityInnerLocked的相關邏輯了,實時上啟動目標Acitivity第一次進入該方法時也會從此處回傳,事實就是這樣的,尼瑪是不是走錯片場了,后續你就知道了,讓我們接著后續分析前面章節1.2提出的問題也會解決了,至于此處為啥在此就return也會解決了,
1.3 Pause前臺顯示的Activity
??我們對要顯示的目標Activity已經做好入堆疊作業了,就是放在Stack的堆疊頂,我們可以通過方法ActivityStack.topRunningActivityLocked可以找到它,然后如果當前要Resume的目標Activity不是之前已經Resume的Activity,那么必須將Pause之前的Activity才行,而這部分的具體作業分兩部分完成:
- Pause其他所有已經focus的任務堆疊的mResumedActivity,呼叫方法ASS.pauseBackStacks執行
- Pause當前任務堆疊的mResumedActivity
最后上述兩步都會調到核心方法,ActivityStack.startPausingLocked,而這也是我們本章節將要介紹的:
//[ActivityStack.java]
final boolean startPausingLocked(boolean userLeaving,
boolean uiSleeping, //此時傳遞進來的引數為false
boolean resuming,//此時傳遞進來的引數為true
boolean dontWait)
{
//判斷當前的Stack堆疊中是否存在正在pausing的Activity
if (mPausingActivity != null) {
if (!mService.isSleepingLocked()) {
completePauseLocked(false);
}
}
//獲取當前Stack堆疊中處于Resume狀態的Activity,在我們當前的環境下就是Activity A了
ActivityRecord prev = mResumedActivity;
if (prev == null) {
if (!resuming) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
return false;
}
...
// 變更ActivityStack中pauseActivity的記錄,此處是重點
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;
prev.state = ActivityState.PAUSING;
prev.task.touchActiveTime();
clearLaunchTime(prev);
...
// 通知APP執行發起端的pause操作
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);
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);//詳見章節1.3.1
} catch (Exception e) {
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
} else {
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
//獲取鎖,防止休眠
if (!uiSleeping && !mService.isSleepingOrShuttingDownLocked()) {
mStackSupervisor.acquireLaunchWakelock();
}
if (mPausingActivity != null) {
if (!uiSleeping) {
prev.pauseKeyDispatchingLocked();
} else if (DEBUG_PAUSE) {
}
if (dontWait) {
completePauseLocked(false);
return false;
} else {
//這個是經典的ANR埋雷,監控APP是否pause超時,時間只有500ms
Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
msg.obj = prev;
prev.pauseTime = SystemClock.uptimeMillis();
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
return true;
}
} else {
...
}
}
在正式開始上述的原始碼分析前,我們先來闡述一個重要的知識點,即在這個呼叫程序中涉及到兩個行程,不妨令發起startActivity的發起行程記為行程Process_A,AMS Service所屬行程記為行程Process_B;那么行程Process_A通過Binder機制(采用IActivityManager介面)向行程Process_B發起請求服務,行程Process_B則通過Binder機制(采用IApplicationThread介面)向行程Process_A發起請求服務,也就是說行程Process_A與行程Process_B能相互間主動發起請求,進而完成行程通信,但是這里有一點需要注意IApplicationThread的Binder物體端并沒有注冊到servicemanager行程中,它是一個依賴于實名Binder的匿名Binder,
這里涉及IApplicationThread很重要,它串聯起了AMS對App行程的生命周期及其其它的控制,那么下面直接把其相關的類圖展示如下:

這里的IApplicationThread與IActivityManager的Binder通信原理一樣,ATP作為Binder通信的客戶端,ATN作為Binder通信的服務端,其中ApplicationThread繼承ATN類,覆寫其中的部分方法,
并且在目標Activity A的行程創建的時候會存在如下的流程關系(這里小伙們可以先記住,后面再理解)

前面分析了一大堆主要想說明如下問題:
- 這里的IApplicationThread和IActivityManager類似,是可以實作Binder跨行程通信的
- 客戶端行程可以通過AMP實作和AMS(system_server行程)的通信
- AMS(system_server行程)可以通過ATP和客戶端發起行程AT通信
如果小伙們對上述Binder跨行程呼叫不是很清晰的,可以參見系列博客Android Binder框架實作原始碼分析,這里就不過多講述了,總之通過prev.app.thread.schedulePauseActivity實際上呼叫的就是ApplicationThread的schedulePauseActivity方法中去了,其呼叫程序可以使用下面的偽代碼來表示:
ATP.schedulePauseActivity()--->
BinderProxy.transact() --->
BpBinder.transact()--->
binder驅動傳輸--->
JavaBBinder.onTransact()--->
ATN.onTransact()--->
ATN.schedulePauseActivity()
1.3.1 AT.schedulePauseActivity處理Pause請求
??通過ATP的努力和我們的Binder框架的協助,我們跨越萬水千山,完成了system_server所在行程到發起端所在目的端行程呼叫程序,讓我們接著分析看看目的端行程是怎么處理schedulePauseActivity的RPC請求的,我好難啊!
//[ActivityThread.java]
private class ApplicationThread extends ApplicationThreadNative {
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
int seq = getLifecycleSeq();
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
configChanges,
seq);//詳見1.3.2
}
}
巧用ActivityThread的主執行緒的Handler發送訊息,這里我們可以總結一下規律,通常AMS通過ATP發送過來的訊息,遵循如下的處理邏輯,如下
scheduleXXX() ---> handleXXX()
1.3.2 H.handleMessage
//ActivityThread.java
private class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
...
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);//詳見章節1.3.3
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
}
}
}
1.3.3 AT.handlePauseActivity
//[ActivityThread.java]
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport, int seq) {
//獲取需要
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
if (userLeaving) {
performUserLeavingActivity(r);
}
r.activity.mConfigChangeFlags |= configChanges;
//執行Activity的onPause操作
performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");//詳見章節1.3.4
if (r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}
if (!dontReport) {
try {
//通知AMS已經Pause成功了
ActivityManagerNative.getDefault().activityPaused(token);//詳見章節1.3.5
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
mSomeActivitiesChanged = true;
}
}
無需多言,直接進入下一關,打怪升級!
1.3.4 AT.performPauseActivity
final Bundle performPauseActivity(IBinder token, boolean finished,
boolean saveState, String reason) {
ActivityClientRecord r = mActivities.get(token);
return r != null ? performPauseActivity(r, finished, saveState, reason) : null;
}
final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
boolean saveState, String reason) {
...
performPauseActivityIfNeeded(r, reason);
...
return !r.activity.mFinished && saveState ? r.state : null;
}
private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
if (r.paused) {
// You are already paused silly...
return;
}
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName(), reason);
if (!r.activity.mCalled) {
...
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
...
}
r.paused = true;
}
??還是原來的配方,還是原來的味道,最終通過Instrumentation類回呼了Activity實體的onPause方法,如下:
//[Instrumentation.java]
public void callActivityOnPause(Activity activity) {
activity.performPause();
}
見證奇跡的時刻要到了,讓我們拭目以待:
//[Activity.java]
final void performPause() {
mDoReportFullyDrawn = false;
mFragments.dispatchPause();
mCalled = false;
onPause();//執行Activity的onPause方法
mResumed = false;
if (!mCalled && getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.GINGERBREAD) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onPause()");
}
mResumed = false;
}
??尼瑪,太不容易了,終于回呼到了ASS中處于Resume狀態的Activity的onPause方法,這其中涉及的彎彎繞繞可真多啊,網上有有博主說我們在啟動一個Activity的時候最先被執行的是堆疊頂的Activity的onPause方法,我個人不是很贊同上述說法,應該是目標Activity所屬Stack堆疊存在Resume狀態的Activity時會執行其onPause方法,否則執行的就是其它Stack堆疊中的了,
1.3.5 AMS.activityPaused
??繼續回到章節1.3.3未完成之實名,在將當前顯示的Activity執行onPause之后,在該方法的最后面執行了ActivityManagerNative.getDefault().activityPaused(token);方法,這是應用行程告訴system_server服務行程,當前顯示的Activity已經執行完成onPause方法了,通過前面我們的分析,我們知道這句話最侄訓被ActivityManagerService的activityPaused方法執行了!,其呼叫流程可以使用如下的偽代碼來表述:
AMP.activityPaused(...)--->
BinderProxy.transact(...) --->
BpBinder.transact(...)--->
binder驅動傳輸--->
JavaBBinder.onTransact(...)--->
AMN.onTransact(..)--->
AMN.activityPaused(...)
//[AMS.java]
public final void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
//獲取已經pause的Activity所屬Stack
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
stack.activityPausedLocked(token, false);
}
}
Binder.restoreCallingIdentity(origId);
}
在activityPaused內部繼續呼叫ActivityStack的activityPausedLocked方法進行下一步的處理,讓我們接著分析:
final void activityPausedLocked(IBinder token, boolean timeout) {
final ActivityRecord r = isInStackLocked(token);
if (r != null) {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if (mPausingActivity == r) {
completePauseLocked(true);//此處傳入的引數為true
return;
} else {
...
}
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
接著繼續分析completePauseLocked,注意此時傳入的引數為true,我們繼續分析:
private void completePauseLocked(boolean resumeNext) {
ActivityRecord prev = mPausingActivity;
...
if (resumeNext) {
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
if (!mService.isSleepingOrShuttingDownLocked()) {//會進入此分支,繼續章節1.1.1的邏輯
//此時的prev為前臺顯示已經pause的Activity
mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
} else {
mStackSupervisor.checkReadyForSleepLocked();
ActivityRecord top = topStack.topRunningActivityLocked();
if (top == null || (prev != null && top != prev)) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
...
}
經過了一系列的邏輯之后,又呼叫了resumeFocusedStackTopActivityLocked方法,又回到了章節1.1決議的方法中了,此時的傳入的prev就是我們已經pause的Activity的了,而不是目標Activiyt了,現在章節1.2最后的謎題可以解決了,感覺resumeFocusedStackTopActivityLocked不是這么簡單啊!
1.3.6 Pause前臺顯示的Activity小結
??雖然本人也反對分析原始碼程序中大量堆砌原始碼,但是有時候又不得不為之,因為如果不放上原始碼呼叫邏輯,整個流程下來就不是很清晰了,這個也木有辦法,臣妾也不想啊!好嗎,我們來總結一下Pause前臺顯示的Activity的流程,如果站在行程互動的角度出發,其中Pause前臺顯示的Activity牽涉到兩次的跨行程呼叫:
-
AMS通過ATP通知前臺Activity進行相關的onPause操作
-
前臺顯示的Activity執行onPause成功之后通過AMP跨行程通知AMS已經成功執行
其中整個Pause前臺顯示的Activity的流程可以使用如下的偽代碼流程來表示,如下:
//AMS端
ActivityStack.startPausingLocked(...) --->
ATP.schedulePauseActivity(...) --->
BinderProxy.transact(...) --->
BpBinder.transact(...) --->
binder驅動傳輸 --->
//前臺顯示Activity端
JavaBBinder.onTransact(...) --->
ATN.onTransact(...) --->
ATN.schedulePauseActivity(...) --->
ApplicationThread.schedulePauseActivity(...) --->
ActivityThread.H.handleMessage(...) --->
ActivityThread.handlePauseActivity(...) --->
ActivityThread.performPauseActivity(...) --->
ActiivtyThread.performPauseActivityIfNeeded(...) --->
Instrumentation.callActivityOnPause(...) --->
Activity.performPause(...) --->
Activity.onPause(...) --->
AMP.activityPaused(...)--->
BinderProxy.transact(...) --->
BpBinder.transact(...)--->
binder驅動傳輸--->
//AMS端
JavaBBinder.onTransact(...)--->
AMN.onTransact(..)--->
AMN.activityPaused(...)
1.4 Resume目標Activity
??愛的魔力轉圈圈,讓我們繼續第二輪回,重新開始原始碼的分析
//[ActivityStackSupervisor.java]
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack,
ActivityRecord target, //此時的target為前臺已經處于pause狀態的Activity,如果在我們當前的場景下即為Activity A
ActivityOptions targetOptions) {
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
...
}
繼續往下分析此時我想各位應該明白我們在章節1.2的疑問了
//[ActivityStack.java]
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
...
boolean result = false;
try {
...
result = resumeTopActivityInnerLocked(prev, options);
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
return result;
}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
if (!mService.mBooting && !mService.mBooted) {
// 如果系統還未啟動完畢,那AMS還不能正常作業,所以也不能顯示Activity,主要是為防止沒有開機啟動完成
return false;
}
//此處忽略
ActivityRecord parent = mActivityContainer.mParentActivity;
...
// 當前AS中可能存在一些正處于Intializing狀態的ActivityRecord,
// 如果這些ActivityRecord不是位于堆疊頂,而且正在執行視窗啟動影片,
// 那么,就需要取消這些Activity的啟動影片,
mStackSupervisor.cancelInitializingActivities();
/*
找到第一個沒有finishing的堆疊頂activity,通常指向了要啟動的Activity目標組件
此場景下prev和next不是同一個了,prev指向前面已經
*/
final ActivityRecord next = topRunningActivityLocked();
//這個變數是表示是否回呼Activity中的onUserLeaveHint和onUserInteraction函式
final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
final TaskRecord prevTask = prev != null ? prev.task : null;
if (next == null) {//這個表示如果當前ActivityStack不存在待啟動的Activity,那么會啟動Launcher桌面
final String reason = "noMoreActivities";
final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack()
? HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
// 當前AS不是全屏顯示,則需要將焦點切換到下一個待顯示的AS
if (!mFullscreen && adjustFocusToNextFocusableStackLocked(returnTaskType, reason)) {
return mStackSupervisor.resumeFocusedStackTopActivityLocked(
mStackSupervisor.getFocusedStack(), prev, null);
}
ActivityOptions.abort(options);
// 默認情況下,Stack都是占據全屏的,所以,當前Stack如果沒有要顯示的Activity,則會要求顯示桌面
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
}
next.delayedResume = false;
//檢查要啟動的Activity 組件是否等于當前被激活的 Activity 組件,如果等于
//并且處于 RESUMED 狀態,直接回傳,我們前面演示的啟動情況很顯然不滿足條件
if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
//當前正在顯示的Activity正好就是下一個待顯示的Activity,
// 那么,就中斷對目標ActivityRecord的調度
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return false;
}
final TaskRecord nextTask = next.task;
/*這個是對上一個resumed的Activity的相關處理
* 由于我們是第一次啟動B Activity,所以不可能處于finish跳過此處
*/
if (prevTask != null && prevTask.stack == this &&
prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
...
}
// 系統進入休眠狀態,當前Stack的堆疊頂Activity已經處于Paused狀態
// 那么,中斷待顯示Activity的相關調度(有點拗口,學習原始碼就是這么枯燥的事情)
if (mService.isSleepingOrShuttingDownLocked()
&& mLastPausedActivity == next
&& mStackSupervisor.allPausedActivitiesComplete()) {
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return false;
}
...
/*
在ASS中存在很多的資料結構,用來統一管理ActivityRecord的狀態
譬如mStoppingActivities記錄了當前所有處于Stopping狀態的ActivityRecord
mGoingToSleepActivities記錄了當前所有要進入休眠狀態的ActivityRecord
在某些場景下,待顯示的ActivityRecord可能處于這些陣列中,但需要從中剔除
*/
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
mStackSupervisor.mWaitingVisibleActivities.remove(next);
// 如果當前ASS中還有ActivityRecord不是處于PAUSED, STOPPED或STOPPING這三個狀態之一,
// 那么,需要先等這些ActivityRecord進入停止狀態
if (!mStackSupervisor.allPausedActivitiesComplete()) {
return false;
}
??分析至此,讓我們先緩緩,停下前進的腳步看看我們來時的路!前面的代碼片段,主要是做一些初始化和可能的"例外"處理作業,雖然我們待顯示的目標ActivityRecord已經位于堆疊頂,但要真正將其顯示到前臺來,即執行目標Activity的onCreate/onStart/onResume等狀態,這一路有很多障礙和初始化作業還處理,或者說還有很多前提條件需要滿足,譬如,系統要休眠時,當前啟動目標Activity程序要中斷;當前ASS中有Activity正處于Pausing狀態時,也需要等相關Activity執行完畢才行,我們可以將上述的相關作業認為是準備階段!前路漫漫是征途,我將上下而求索!
//[ActivityStack.java]
/*
setLaunchSource設定待啟動的Activity的資訊
跟進setLaunchSource原始碼發現它最侄訓獲取一個WakeLock,保證在顯示Activity的程序中,系統不會進行休眠狀態
*/
mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
/*
目標Activity的啟動引數中是否包含FLAG_RESUME_WHILE_PAUSING
如果存在FLAG_RESUME_WHILE_PAUSING的flag,表示可以在當前顯示的發起端Activity執行Pausing時,
能同時進行Resume操作
即變數dontWaitForPause的取意就是不需要等到Activity執行Pause完畢
*/
final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
/*
這個是pause掉不是FocusedStack的其它ActivityStack的堆疊頂activity
對于不是當前focusStack的并且存在有mResumedActivity不為null的都要paused
此時下沒有需要要進行pause
*/
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
//此時要帶入真是場景了,此時的mResumedActivity表示目標Stack堆疊中處于Resume狀態的Activity,通過前面的分析可以此時沒有處于Resume狀態的Activty了,所以不會走入此分支
if (mResumedActivity != null) {
....
}
if (pausing) {//也不會進入此分支可以往后續分析了
if (next.app != null && next.app.thread != null) {
mService.updateLruProcessLocked(next.app, true, null);
}
return true;
}
//檢查要啟動的Activity 組件是否等于當前被激活的 Activity 組件,如果等于
//并且處于 RESUMED 狀態,直接回傳,我們前面演示的啟動情況很顯然不滿足條件
else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return true;
}
??在前面章節1.3的最后我們知道當前臺Activity被執行pause以后,會回呼activityPaused通知AMS,然后AMS會執行completePauseLocked,該函式也會呼叫resumeTopActivityInnerLocked,這一次,由于所有resumedActivity都已經paused了,所以回傳的結果pausing為false,所以可以繼續進行目標activity的resume作業,讓我們對相關的流程繼續分析!
//[ActivityStack.java]
//對已經Pause的Activity繼續處理,主要是通知WMS做進一步的處理
if (prev != null && prev != next) {
if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
&& next != null && !next.nowVisible) {
mStackSupervisor.mWaitingVisibleActivities.add(prev);
} else {
if (prev.finishing) {
mWindowManager.setAppVisibility(prev.appToken, false);
} else {
}
}
}
try {
// 通過PackageManager修改待啟動Package的狀態
AppGlobals.getPackageManager().setPackageStoppedState(
next.packageName, false, next.userId); /* TODO: Verify if correct userid */
} catch (RemoteException e1) {
} catch (IllegalArgumentException e) {
}
...
ActivityStack lastStack = mStackSupervisor.getLastStack();
if (next.app != null && next.app.thread != null) {//如果目的端行程已經創建,即要啟動的目標Activity所屬行程已經存在
...
next.state = ActivityState.RESUMED;
mResumedActivity = next;
next.task.touchActiveTime();
mRecentTasks.addLocked(next.task);
mService.updateLruProcessLocked(next.app, true, null);
updateLRUListLocked(next);
mService.updateOomAdjLocked();
...
try {
...
next.sleeping = false;
mService.showUnsupportedZoomDialogIfNeededLocked(next);
mService.showAskCompatModeDialogLocked(next);
next.app.pendingUiClean = true;
next.app.forceProcessStateUpTo(mService.mTopProcessState);
next.clearOptionsLocked();
//執行目的端Activity的scheduleResumeActivity操作
next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
mService.isNextTransitionForward(), resumeAnimOptions);
...
} catch (Exception e) {
...
}
try {
completeResumeLocked(next);
} catch (Exception e) {
//處理例外
requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
"resume-exception", true);
return true;
}
} else {//當目標Activity所屬行程沒有啟動的時候,則會創建行程
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
if (SHOW_APP_STARTING_PREVIEW) {
next.showStartingWindow(null, true);
}
}
//創建目標Activity行程
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
return true;
}
??到這里終于快要告一段落了,此處的邏輯主要分為兩個分支:
- 如果要啟動的目標Activity所屬行程已經創建,則直接通過ATP呼叫目標行程的ActivityThread執行相關的Activity的onCreate等相關生命周期
- 如果目標Activity所屬行程沒有創建,則通過startSpecificActivityLocked方法創建目標行程,經過層層呼叫最后會呼叫到AMS.attachApplicationLocked, 然后再執行resumeTopActivityInnerLocked繼續resume操作這個邏輯我想也是小伙們最關心的, 我們后續從這個地方開擼
注意,注意,注意:
Activity的啟動程序中,存在一種特殊情況就是假如目標Activity在AndroidManifest.xml中配置了android:process相關的屬性,那怕目標Activity所屬行程已經創建了依然會走startSpecificActivityLocked流程創建Activity專有的Process,這個一定要注意!
<activity android:name="com.example.test.BActivity"
android:process=":process"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
1.5 Pause前臺顯示Activity,Resume目標Activity小結
??Pause前臺顯示Activity,Resume目標Activity到這里就基本完結了,是時候停下前進的腳步回過頭來看看了!在上述程序中我們會進行兩次resumeTopActivityInnerLocked方法:
- 第一次是將所有resumedActivity進行pause,此時流程不會繼續往下進行而是待前臺顯示的Activity真正執行pause后,然后回呼AMS繼續第二執行resumeTopActivityInnerLocked相關操作
- 由于此時所有處于Resume狀態的Activity已經都被Pause了,所以繼續往下執行,此時會判斷目標Activity所屬行程是否創建,如果創建則直接執行目標Activity的生命周期,如果沒有創建則會創建目標Activity所屬行程,進而再執行下一步操作
對于上述的整個流程,可以使用下述的圖示來表達:

其中紅色箭頭表示Binder跨行程呼叫
黃色框表示的是發起端行程
紫色框表示的是AMS所屬system_server行程
紅色框表示的是目標Activity所屬行程
藍色框表示的前臺處于Resume的Activity所屬行程
總結
??Activity啟動流程(四)- Pause前臺顯示Activity,Resume目標Activity這里就要告一段落了,從前面的分析可以看出來,此時我們已將將需要Pause前臺Activity已經Pause,接下來就是專心的來Resume目標Activity了,如果此時是冷啟動的目標Activity那么就會先期進行目標Activity目標所屬行程的創建,然后接著繼續Resume目標Activity,如果是熱啟動就簡單一些了直接執行目標Activity相關的onCretate等相關的操作,好了今天就到這里了,是時候說再見了!希望小伙們能點贊和關注,謝謝!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/177402.html
標籤:python
