Android四大元件原始碼實現詳解系列部落格目錄:
Android應用程序建立流程大揭祕
Android四大元件之bindService原始碼實現詳解
Android四大元件之Activity啟動流程原始碼實現詳解概要
Android四大元件之Activity啟動流程原始碼實現詳解(一)
Android四大元件之Activity啟動流程原始碼實現詳解(二)
Activity啟動流程(三)- Activity Task排程演演算法覆盤分析
Activity啟動流程(四)- Pause前臺顯示Activity,Resume目標Activity
還記得我們在前面部落格Android四大元件之Activity啟動流程原始碼實現詳解(二)和Activity啟動流程(三)- Activity Task排程演演算法覆盤分析中做的艱苦卓越的鬥爭嗎!這場戰役之慘烈,戰況之持久前所未有!雖然過程是疼苦的,但是戰果也是顯赫和令人滿意的,通過上述戰役我們取得了如下的階段性成果:
總而言之經過上述一頓猛虎般的操作,此時要啟動的目標Actvity及其對應的task位置以及ActivityStack已經安排妥當,現在可以準備接下來的相關工作了,那麼在本篇部落格中我們將繼續分析system_server對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
並且在後續的原始碼分析過程中為了簡述方便,會將做如下簡述:
在正式開始今天部落格相關原始碼分析前,還是先奉上呼叫的時序圖以便小夥們先從整體上有個清晰的概括,然後再從細節開擼!
戰鬥還沒有結束,革命尚未成功仍需努力!讓我們帶著前面部落格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帶入下面的相關分析中。
讓我們對ActivityStackSupervisor中的resumeFocusedStackTopActivityLocked繼續分析,其中Android中對於Activity的啟動主要表現在如下兩個方面:
並且關於這兩部分讀者最好參考我前面的部落格先假定某種啟動模式,然後進行相關的分析,否則很容易陷入程式碼中而不能自拔。而我們這裡的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方法(不是我不分析,確實是因為沒有啥好分析的)。
//[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,在分析這個方法之前小夥們該上廁所的可以上廁所了,喝水的可以喝水了,因為這又是一個重量級的方法。
在正式開始分析該方法之前,我們先來看看該方法的入參,方法入參的名字挺奇怪的!
引數型別 | 引數名稱 | 引數功能 |
---|---|---|
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也會解決了。
我們對要顯示的目標Activity已經做好入棧工作了,就是放在Stack的棧頂,我們可以通過方法ActivityStack.topRunningActivityLocked可以找到它。然後如果當前要Resume的目標Activity不是之前已經Resume的Activity,那麼必須將Pause之前的Activity才行,而這部分的具體工作分兩部分完成:
最後上述兩步都會調到核心方法,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的程序建立的時候會存在如下的流程關係(這裡小夥們可以先記住,後面再理解)
前面分析了一大堆主要想說明如下問題:
如果小夥們對上述Binder跨程序呼叫不是很清晰的,可以參見系列部落格Android Binder框架實現原始碼分析,這裡就不過多講述了,總之通過prev.app.thread.schedulePauseActivity實際上呼叫的就是ApplicationThread的schedulePauseActivity方法中去了,其呼叫過程可以使用下面的虛擬碼來表示:
ATP.schedulePauseActivity()--->
BinderProxy.transact() --->
BpBinder.transact()--->
binder驅動傳輸--->
JavaBBinder.onTransact()--->
ATN.onTransact()--->
ATN.schedulePauseActivity()
通過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()
//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;
...
}
}
}
//[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;
}
}
無需多言,直接進入下一關,打怪升級!
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.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不是這麼簡單啊!
雖然本人也反對分析原始碼過程中大量堆砌原始碼,但是有時候又不得不為之,因為如果不放上原始碼呼叫邏輯,整個流程下來就不是很清晰了,這個也木有辦法,臣妾也不想啊!好嗎,我們來總結一下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(...)
愛的魔力轉圈圈,讓我們繼續第二輪迴,重新開始原始碼的分析
//[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;
}
到這裡終於快要告一段落了,此處的邏輯主要分為兩個分支:
Pause前臺顯示Activity,Resume目標Activity到這裡就基本完結了,是時候停下前進的腳步回過頭來看看了!在上述過程中我們會進行兩次resumeTopActivityInnerLocked方法:
對於上述的整個流程,可以使用下述的圖示來表達:
其中紅色箭頭表示Binder跨程序呼叫
黃色框表示的是發起端程序
紫色框表示的是AMS所屬system_server程序
紅色框表示的是目標Activity所屬程序
藍色框表示的前臺處於Resume的Activity所屬程序
Activity啟動流程(四)- Pause前臺顯示Activity,Resume目標Activity這裡就要告一段落了,從前面的分析可以看出來,此時我們已將將需要Pause前臺Activity已經Pause,接下來就是專心的來Resume目標Activity了,如果此時是冷啟動的目標Activity那麼就會先期進行目標Activity目標所屬程序的建立,然後接著繼續Resume目標Activity,如果是熱啟動就簡單一些了直接執行目標Activity相關的onCretate等相關的操作。好了今天就到這裡了,是時候說再見了!希望小夥們能點贊和關注,謝謝!