Activity 組件的啟動過程
基于 Android 2.3.1
當(dāng)我們在 Launcher 中點擊一個 app 時,發(fā)生了什么?
1. 參與角色
- Activity
- Launcher
- AMS
- Instrumentation:監(jiān)控應(yīng)用程序和系統(tǒng)之間的交互操作
- ActivityThread:ActivityThread 用來描述一個應(yīng)用程序進(jìn)程崔赌,系統(tǒng)每當(dāng)啟動一個應(yīng)用程序進(jìn)程時,都會在該進(jìn)程里加載一個 ActivityThread 實例,并且執(zhí)行 main 方法揣苏,從而開啟主線程 looper 循環(huán)。并且每一個在該進(jìn)程中啟動的 Activity 組件件舵,都會保存這個 ActivityThread 實例在成員變量 mMainThread 中
- ApplicationThread:看名字會很困惑以為也是一個線程卸察,實則不然,它是一個 Binder 本地對象铅祸,可與 AMS 進(jìn)行 IPC 通信坑质。(繼承 IApplicationThread.Stub)
- ActivityStack:用來描述一個 Activity 組件堆棧
- ResolveInfo:PMS.resolveIntent(),解析 intent 得到的一個信息
- ProcessRecord:在 AMS 中临梗,每一個應(yīng)用程序進(jìn)程都用 ProcessRecord 來描述涡扼,并且保存在 AMS 內(nèi)部
- TaskRecord:任務(wù)棧的表現(xiàn)形式
- ActivityRecord:AMS 中的一個 Binder 本地對象,每一個已經(jīng)啟動的 Activity 組件在 AMS 中都有一個對應(yīng)的 ActivityRecord 對象盟庞,用來維護(hù)對應(yīng)的 Activity 組件的運行狀態(tài)和信息吃沪。通常 Activity 中的 mToken 成員變量會指向它,mToken 是一個 Binder 代理對象
2. 啟動流程
2.1 Launcher 發(fā)生的事
當(dāng)我們在 Launcher 中點擊一個 app 圖標(biāo)時什猖,會調(diào)用 startActivitySafely
來啟動這個 app 的根 Activity票彪。
void startActivitySafely(Intent intent, Object tag) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
......
} catch (SecurityException e) {
......
}
}
因此參數(shù) intent 所包含的信息有
action = "android.intent.action.MAIN"
category = "android.intent.category.LAUNCHER"
cmp = "com.yjnull.demo.activity.MainActivity"
Launcher 是怎么獲得這些信息的呢?Launcher 在最開始啟動的過程中會向 PMS 查詢所有 Activity 名稱等于 "android.intent.action.MAIN"不狮,并且 Category 等于 "android.intent.category.LAUNCHER" 的 Activity 組件降铸。這樣當(dāng)用戶點擊一個快捷圖標(biāo)時,就可以拿到相應(yīng) Activity 組件的信息并啟動起來摇零。
接著上述代碼講推掸,調(diào)用父類的 startActivity(intent)
,即 Activity.startActivity(intent)
遂黍,這里經(jīng)過層層調(diào)用會走到 Activity.startActivityForResult(Intent intent, int requestCode)
這里去终佛。
public void startActivityForResult(Intent intent, int requestCode) {
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
......
}
} else {
......
}
}
這里通過方法名其實就可以知道,會把啟動 Activity 的操作委托給 Instrumentation
去做雾家。所以 Instrumentation
是什么鬼铃彰。。這里有段代碼上的原文注釋:
Base class for implementing application instrumentation code. When running with instrumentation turned on, this class will be instantiated for you before any of the application code, allowing you to monitor all of the interaction the system has with the application. An Instrumentation implementation is described to the system through an AndroidManifest.xml's <instrumentation> tag.
大意就是它用來監(jiān)控應(yīng)用程序和系統(tǒng)之間的交互操作芯咧。因為 Activity 的啟動最后需要通過 AMS 啟動牙捉,而 AMS 又是運行在系統(tǒng)進(jìn)程 (system 進(jìn)程) 的竹揍,所以算是和系統(tǒng)的交互操作,因此需要交給 Instrumentation
來執(zhí)行邪铲。
execStartActivity
方法里有幾個參數(shù)需要注意:
- mMainThread.getApplicationThread():Launcher 組件所在的應(yīng)用程序進(jìn)程的 ApplicationThread 的 Binder 本地對象芬位。為了將它傳遞給 AMS,這樣 AMS 接下來就可以通過它來通知 Launcher 組件進(jìn)入 Paused 狀態(tài)带到。
- mToken:類型為 IBinder昧碉,是一個 Binder 代理對象,指向 AMS 中一個類型為 ActivityRecord 的 Binder 本地對象揽惹。將它傳遞給 AMS 的話被饿,AMS 就可以通過它獲得 Launcher 組件的詳細(xì)信息了。
接下來我們走進(jìn) Instrumentation
的 execStartActivity
方法
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
......
try {
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
null, 0, token, target != null ? target.mEmbeddedID : null,
requestCode, false, false);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}
這里可以看到會通知 AMS 來將一個 Activity 組件啟動起來搪搏。當(dāng)然中間還有一些過程狭握,無非就是 ActivityManagerProxy 將一些參數(shù)進(jìn)行封裝寫入到 Parcel 對象中,然后通過 mRemote 向 AMS 發(fā)送一個類型為 START_ACTIVITY_TRANSACTION 的進(jìn)程間通信請求疯溺。
2.2 AMS 中做的事
接著上述來论颅,Launcher 通過 Instrumentation 發(fā)起了一個 START_ACTIVITY_TRANSACTION 的進(jìn)程間通信,因此會回調(diào)到 AMS 中的 startActivity 方法中去囱嫩,如下所示:
public final int startActivity(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug) {
return mMainStack.startActivityMayWait(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded, debug, null, null);
}
這里可以看到將啟動操作委托給 mMainStack 了恃疯,mMainStack 是什么呢?它是一個類型為 ActivityStack 的成員變量墨闲,用來描述一個 Activity 組件堆棧澡谭。OK,那我們進(jìn)到 ActivityStack 中的 startActivityMayWait 方法看看损俭,這個方法挺長蛙奖,所以分析就在注釋里了:
Step 1 frameworks/base/services/java/com/android/server/am/ActivityStack.java
/**
* caller: mMainThread.getApplicationThread(), Launcher 組件所在的應(yīng)用程序進(jìn)程ApplicationThread 的 Binder 本地對象。
* intent: 前面所構(gòu)造的 Intent
* resolvedType: null
* grantedUriPermissions: null
* grantedMode: 0
* resultTo: Launcher Activity 中的 mToken杆兵,指向 AMS 中一個類型為 ActivityRecord 的 Binder 本地對象
* resultWho: null
* requestCode: -1
* onlyIfNeeded: false
* debug: false
* outResult: null
* config: null
*/
final int startActivityMayWait(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug, WaitResult outResult, Configuration config) {
......
// 省略部分代碼
boolean componentSpecified = intent.getComponent() != null;
// Don't modify the client's object!
intent = new Intent(intent);
// 這里定義了一個 ActivityInfo 對象雁仲,目測是用來整合前面?zhèn)鬟M(jìn)來的 Intent 中所描述的信息
ActivityInfo aInfo;
try {
// 這里通過 PMS 去解析參數(shù) intent 的內(nèi)容,以便可以獲得即將啟動的 Activity 組件的更多信息
ResolveInfo rInfo =
AppGlobals.getPackageManager().resolveIntent(
intent, resolvedType,
PackageManager.MATCH_DEFAULT_ONLY
| ActivityManagerService.STOCK_PM_FLAGS);
// 將上面解析出來的信息保存在 ActivityInfo 中
aInfo = rInfo != null ? rInfo.activityInfo : null;
} catch (RemoteException e) {
aInfo = null;
}
......
synchronized (mService) {
int callingPid;
int callingUid;
if (caller == null) {
......
} else {
callingPid = callingUid = -1;
}
......
int res = startActivityLocked(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, aInfo,
resultTo, resultWho, requestCode, callingPid, callingUid,
onlyIfNeeded, componentSpecified);
......
return res;
}
}
其實總結(jié)下來無非就是通過 PMS 將 Intent 中的參數(shù)解析出來琐脏,并獲取到即將啟動的 Activity 組件的更多信息攒砖,也就是 com.yjnull.demo.activity.MainActivity
的更多信息。
Step 2 frameworks/base/services/java/com/android/server/am/ActivityStack.java
/**
* ...... 同上
* aInfo: 通過 PMS 去解析參數(shù) intent 的內(nèi)容日裙,得到 ResolveInfo.activityInfo
* resultTo: Launcher Activity 中的 mToken吹艇,指向 AMS 中一個類型為 ActivityRecord 的 Binder 本地對象
* resultWho: null
* requestCode: -1
* callingPid: -1
* callingUid: -1
* onlyIfNeeded: false
* componentSpecified: true
*/
final int startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType,
Uri[] grantedUriPermissions,
int grantedMode, ActivityInfo aInfo, IBinder resultTo,
String resultWho, int requestCode,
int callingPid, int callingUid, boolean onlyIfNeeded,
boolean componentSpecified) {
int err = START_SUCCESS;
ProcessRecord callerApp = null;
if (caller != null) {
// 這里的 mService 指向 AMS,所獲得的 ProcessRecord 對象實際上指向了 Launcher 組件所在的應(yīng)用程序進(jìn)程信息昂拂。
callerApp = mService.getRecordForAppLocked(caller);
if (callerApp != null) {
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else {
......
}
}
......
// sourceRecord 用來描述 Launcher 組件的一個 ActivityRecord
ActivityRecord sourceRecord = null;
......
if (resultTo != null) {
// 通過 resultTo 找到 Launcher 在 Activity 組件堆棧中的 index受神,這里的 resultTo 就是前面在 Launcher 進(jìn)程中 Instrumentation 傳遞的 mToken 參數(shù)。
int index = indexOfTokenLocked(resultTo);
......
if (index >= 0) {
sourceRecord = (ActivityRecord)mHistory.get(index);
......
}
}
......
// 這里創(chuàng)建一個 ActivityRecord 用來描述即將啟動的 Activity 組件格侯,即 MainActivity 組件鼻听,可以注意财著,前面我們說過 mToken 就是指向 ActivityRecord 的,所以可以關(guān)注這個 ActivityRecord 對象撑碴,看看它是怎么傳遞給 Activity 類的成員變量
// 這里的幾個參數(shù)如下:AMS; ActivityStack; 描述 Launcher 的 ProcessRecord; Launcher 進(jìn)程的 uid; intent; null; ActivityInfo 即將要啟動的 Activity 相關(guān)信息; AMS.mConfiguration; null; null; -1; true
ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
intent, resolvedType, aInfo, mService.mConfiguration,
resultRecord, resultWho, requestCode, componentSpecified);
......
return startActivityUncheckedLocked(r, sourceRecord,
grantedUriPermissions, grantedMode, onlyIfNeeded, true);
}
這一段首先是通過 resultTo 參數(shù)撑教,在 Activity 堆棧中拿到 Launcher 這個 Activity 的相關(guān)信息并保存在 sourceRecod 中,然后創(chuàng)建一個新的 ActivityRecord 用來描述即將要啟動的 Activity 的相關(guān)信息醉拓,并保存在變量 r 中伟姐。 接著調(diào)用 startActivityUncheckedLocked 函數(shù)進(jìn)行下一步操作。
Step 3 frameworks/base/services/java/com/android/server/am/ActivityStack.java
/**
* r: 上面新建的 ActivityRecord亿卤,用來描述即將要啟動的 Activity 組件
* sourceRecord: 用來描述 Launcher 組件的一個 ActivityRecord
* grantedUriPermissions: null
* grantedMode: 0
* onlyIfNeeded: false
* doResume: true
*/
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
int grantedMode, boolean onlyIfNeeded, boolean doResume) {
final Intent intent = r.intent;
final int callingUid = r.launchedFromUid;
// 首先獲得 intent 的標(biāo)志位
int launchFlags = intent.getFlags();
// mUserLeaving = true
mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
......
// notTop = null
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
// 這里 onlyIfNeeded 為 false玫镐,所以不看里面的內(nèi)容
if (onlyIfNeeded) {
......
}
if (sourceRecord == null) {
// 原文注釋以及 Slog 打印的內(nèi)容說的很清楚了,這正好是當(dāng)我們以 ApplicationContext 啟動一個 Activity 的情況怠噪,這種情況下,launchFlags 必須設(shè)置 FLAG_ACTIVITY_NEW_TASK
// This activity is not being started from another... in this
// case we -always- start a new task.
if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
+ intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// 如果 Launcher 的啟動模式是 SINGLE_INSTANCE杜跷,那么我們要啟動的 Activity 必須得在一個新的 task 中去啟動傍念。
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
// The activity being started is a single instance... it always
// gets launched into its own task.
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
......
}
// 由于我們將要啟動的 MainActivity 沒有配置 launchMode 屬性,所以這里的 r.launchMode == ActivityInfo.LAUNCH_MULTIPLE
boolean addingToTask = false;
if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// r.resultTo 就是上面構(gòu)造函數(shù)中的 resultRecord葛闷,可知是為 null 的憋槐,表示 Launcher 不需要等這個即將要啟動的 MainActivity 的執(zhí)行結(jié)果
if (r.resultTo == null) {
// 這里 r.launchMode 是不等于 SINGLE_INSTANCE 的,所以通過 findTaskLocked 來查找是否有 Task 可以用來執(zhí)行這個將要啟動的 Activity 組件淑趾。我們的場景是在 Launcher 中第一次啟動一個 app阳仔,因此這里返回的 null,即 taskTop == null扣泊,因此需要創(chuàng)建一個新的 task 來啟動 Activity
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info);
if (taskTop != null) {
......
}
}
}
if (r.packageName != null) {
// 當(dāng)前在堆棧頂端的 Activity 是否就是即將要啟動的 Activity近范,因為有些情況下,如果即將要啟動的 Activity 就在堆棧的頂端延蟹,那么就不會重新啟動這個 Activity 的另一個實例了评矩。我們的場景下,當(dāng)前處在堆棧頂端的 Activity 是 Launcher阱飘,因此不繼續(xù)往下看
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
if (top.realActivity.equals(r.realActivity)) {
......
}
}
} else {
......
}
boolean newTask = false;
// 首先 addingToTask 在我們的場景下斥杜,現(xiàn)在是 false
// 執(zhí)行到這里,其實就是要在一個新的 Task 里面來啟動這個 Activity 了沥匈。
if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
// todo: should do better management of integers.
mService.mCurTask++;
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
// 新建一個 TaskRecord
r.task = new TaskRecord(mService.mCurTask, r.info, intent,
(r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
......
newTask = true;
if (mMainStack) {
// 并且添加到 AMS 中
mService.addRecentTaskLocked(r.task);
}
} else if (sourceRecord != null) {
......
} else {
......
}
if (grantedUriPermissions != null && callingUid > 0) {
......
}
......
startActivityLocked(r, newTask, doResume);
return START_SUCCESS;
}
這一段主要是結(jié)合 Launcher 的 launchMode 以及將要啟動的 MainActivity 的 launchMode 來判斷是否需要在一個新的 Task 中啟動這個 MainActivity蔗喂,如果需要就 new 一個新的 TaskRecord,保存在 r.task 中高帖,并添加到 AMS中缰儿,然后進(jìn)入 startActivityLocked(r, newTask, doResume)
進(jìn)一步處理。
總結(jié)這一段就是判斷你的 LaunchMode散址,然后決定要不要新建 Task返弹。
Step 4 frameworks/base/services/java/com/android/server/am/ActivityStack.java
/**
* r: 上面的 ActivityRecord锈玉,現(xiàn)在 r.task 有值了
* newTask: true
* doResume: true
*/
private final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume) {
// mHistory 是一個 ArrayList ,存放著 ActivityRecord
final int NH = mHistory.size();
int addPos = -1;
if (!newTask) {
......
}
// 這里 NH 肯定大于 0义起,因為 Launcher 已經(jīng)跑起來了拉背。
if (addPos < 0) {
addPos = NH;
}
if (addPos < NH) {
......
}
// Slot the activity into the history stack and proceed
mHistory.add(addPos, r);
r.inHistory = true;
r.frontOfTask = newTask;
r.task.numActivities++;
if (NH > 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.
// 這一段是當(dāng)切換新任務(wù)時,要做一些任務(wù)切換的界面操作默终,主要是操作 AMS 中的 WindowManager
......
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
......
}
......
if (doResume) {
resumeTopActivityLocked(null);
}
}
這一段主要是將 ActivityRecord 添加到 mHistory 中椅棺,并做一些界面切換的操作,然后調(diào)用 resumeTopActivityLocked
進(jìn)一步操作
Step 5 frameworks/base/services/java/com/android/server/am/ActivityStack.java
/*
* prev: null
*/
final boolean resumeTopActivityLocked(ActivityRecord prev) {
// Find the first activity that is not finishing.
// 這邊獲取到的 next 就是要啟動的 MainActivity 了
ActivityRecord next = topRunningActivityLocked(null);
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
// 這里的 mUserLeaving 在上面的分析中得出是 true
final boolean userLeaving = mUserLeaving;
mUserLeaving = false;
if (next == null) {
......
}
next.delayedResume = false;
// mResumedActivity 這里是 Launcher
// 這段主要是查看當(dāng)前要啟動的 Activity 是否就是當(dāng)前處于 Resume 狀態(tài)的 Activity齐蔽,如果是的話就什么都不用做两疚,直接返回了
if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
mService.mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
return false;
}
// 這里是處理休眠狀態(tài)時的情況,mLastPausedActivity 保存堆棧頂端的 Activity
if ((mService.mSleeping || mService.mShuttingDown)
&& mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
mService.mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
return false;
}
......
// 在我們的情景中含滴,上面兩個情況肯定都不滿足诱渤,因此執(zhí)行到這里
// We need to start pausing the current activity so the top one
// can be resumed...
if (mResumedActivity != null) {
if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
startPausingLocked(userLeaving, false);
return true;
}
......
}
return true;
}
這一段主要做的事情是將當(dāng)前處于 Resume 狀態(tài)的 Activity 推入 Paused 狀態(tài)去。這個過程也反映了當(dāng)啟動一個新的 Activity 時谈况,舊 Activity 是先進(jìn)入 Paused 狀態(tài)勺美,新 Activity 才 create 的。
到這里可以分個小階段碑韵,因為我們要啟動的 Activity 的信息保存下來了赡茸,Task 也建立起來了。接下來還是轉(zhuǎn)場給 Launcher 這個應(yīng)用程序進(jìn)程了祝闻,得讓它進(jìn)入 Paused 狀態(tài)占卧。
2.3 回到 Launcher 讓它 Pause
Step 6 frameworks/base/services/java/com/android/server/am/ActivityStack.java
/*
* userLeaving: true
* uiSleeping: false
*/
private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
if (mPausingActivity != null) {
......
}
// 這里的 prev 是 Launcher Activity
ActivityRecord prev = mResumedActivity;
if (prev == null) {
......
}
......
mResumedActivity = null;
// 這個賦值在下面 2.4 小節(jié)有用
mPausingActivity = prev;
mLastPausedActivity = prev;
prev.state = ActivityState.PAUSING;
prev.task.touchActiveTime();
mService.updateCpuStats();
if (prev.app != null && prev.app.thread != null) {
......
try {
......
// 這里其實就是通過 Launcher 進(jìn)程中的 ApplicationThread 來通知 Launcher 進(jìn)入 Paused 狀態(tài)。其中參數(shù) prev.finishing 代表當(dāng)前 Activity 是否正在等待結(jié)束的 Activity 列表中联喘,由于 Launcher 正在運行华蜒,所以這里為 false
prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving, prev.configChangeFlags);
......
} catch (Exception e) {
......
}
} else {
......
}
......
}
這里其實就是通過 ApplicationThread 發(fā)起一個 IPC,通知 Launcher 進(jìn)程進(jìn)入 paused 狀態(tài)豁遭。
Step 7 frameworks/base/core/java/android/app/ApplicationThreadNative.java
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
data.writeInt(finished ? 1 : 0);
data.writeInt(userLeaving ? 1 :0);
data.writeInt(configChanges);
mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
沒啥說的友多,通過 Binder 進(jìn)入到 ApplicationThread.schedulePauseActivity 方法。
Step 8 frameworks/base/core/java/android/app/ActivityThread.java
/*
* token: Launcher 的 ActivityRecord堤框。
* finished: false
* userLeaving: true
* configChanges: 暫不關(guān)心
!!! 到這里是否可以猜測 mToken 是怎么賦值的了域滥,前面我們知道給將要啟動的 MainActivity 新建了一個 ActivityRecord 并且存在了 mHistory 中,想必接下來在給那個將要啟動的 MainActivity 發(fā)送 Create 消息時蜈抓,會把這個 ActivityRecord 帶過來启绰,這樣 mToken 就給賦值了 !!!
*/
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) {
queueOrSendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? 1 : 0),
configChanges);
}
這里無非就是通過 Handler 將消息發(fā)送出去了,最后是由 H.handleMessage 來處理這個消息沟使。H 收到 Paused 消息后委可,會交給 handlePauseActivity 來處理。
Step 9 frameworks/base/core/java/android/app/ActivityThread.java
private final void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
if (userLeaving) {
// 我們前面知道 userLeaving 是為 true 的。
// 執(zhí)行這個方法會回調(diào) Activity 的 onUserLeaveHint 通知 Activity着倾,用戶要離開它了
performUserLeavingActivity(r);
}
r.activity.mConfigChangeFlags |= configChanges;
// 回調(diào) Activity 的生命周期拾酝,進(jìn)入 onPause()
Bundle state = performPauseActivity(token, finished, true);
......
// 告訴 AMS 我們已經(jīng)進(jìn)入 Paused 了
try {
ActivityManagerNative.getDefault().activityPaused(token, state);
} catch (RemoteException ex) {
}
}
}
這里又可以告一段落了,Launcher 已經(jīng)進(jìn)入 onPause 了卡者,并且去通知 AMS蒿囤,AMS 接到這個通知就可以繼續(xù)完成未完成的事情了,即啟動 MainActivity崇决。
2.4 Launcher 通知 AMS 我暫停好了材诽,你繼續(xù)做你接下來要做的事吧
Step 10 frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
/*
* token: 是 Launcher 的 ActivityRecord
*/
public final void activityPaused(IBinder token, Bundle icicle) {
// Refuse possible leaked file descriptors
if (icicle != null && icicle.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
}
final long origId = Binder.clearCallingIdentity();
mMainStack.activityPaused(token, icicle, false);
Binder.restoreCallingIdentity(origId);
}
這里可以看到再次進(jìn)入到 ActivityStack 類中,去執(zhí)行 activityPaused 函數(shù)恒傻。
Step 11 frameworks/base/services/java/com/android/server/am/ActivityStack.java
/*
* token: 是 Launcher 的 ActivityRecord
* icicle: 不關(guān)心
* timeout: false
*/
final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
......
ActivityRecord r = null;
synchronized (mService) {
// 這里拿到的是 Launcher 在 mHistory 列表中的 index
int index = indexOfTokenLocked(token);
if (index >= 0) {
// 拿到 Launcher 的 ActivityRecord
r = (ActivityRecord)mHistory.get(index);
if (!timeout) {
r.icicle = icicle;
r.haveState = true;
}
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
// 在前面的 2.3 小節(jié)中脸侥,我們讓 Launcher 進(jìn)入 Paused 狀態(tài)時,把 Launcher 賦值給了 mPausingActivity盈厘,因此下面這個判斷是相等的
if (mPausingActivity == r) {
r.state = ActivityState.PAUSED;
completePauseLocked();
} else {
......
}
}
}
}
這一段主要是判斷 mPausingActivity 是否等于 token 代表的 Activity睁枕,如果是相等就代表完成了 Pause,進(jìn)入 completePauseLocked 方法沸手。
Step 12 frameworks/base/services/java/com/android/server/am/ActivityStack.java
private final void completePauseLocked() {
// 代表 Launcher
ActivityRecord prev = mPausingActivity;
......
if (prev != null) {
......
// 這邊把 mPausingActivity 置空外遇,因為已經(jīng)不需要了
mPausingActivity = null;
}
if (!mService.mSleeping && !mService.mShuttingDown) {
resumeTopActivityLocked(prev);
} else {
......
}
......
}
這里 AMS 肯定還沒有在睡眠也沒有 shutdown,因此進(jìn)入 resumeTopActivityLocked(prev)
Step 13 frameworks/base/services/java/com/android/server/am/ActivityStack.java
/*
* prev: Launcher Activity
*/
final boolean resumeTopActivityLocked(ActivityRecord prev) {
// 這邊獲取到的 next 就是要啟動的 MainActivity 了
ActivityRecord next = topRunningActivityLocked(null);
// 這里的 mUserLeaving 在上面的分析中得出是 true
final boolean userLeaving = mUserLeaving;
mUserLeaving = false;
......
next.delayedResume = false;
// mResumedActivity 這里是 null罐氨,因為之前最后一個 Resumed 狀態(tài)的 Activity 是 Launcher,現(xiàn)在它已經(jīng)處于 Paused 狀態(tài)了滩援。
if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
......
return false;
}
// 這里是處理休眠狀態(tài)時的情況栅隐,這里 mLastPausedActivity 是 Launcher
if ((mService.mSleeping || mService.mShuttingDown)
&& mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
......
return false;
}
......
// 在 Step 5 的時候,這里是滿足情況的玩徊,會去執(zhí)行 startPausingLocked租悄,但是現(xiàn)在不滿足了,mResumedActivity 已經(jīng)為 null 了
if (mResumedActivity != null) {
......
startPausingLocked(userLeaving, false);
return true;
}
......
// next 是將要啟動的 MainActivity恩袱,前面我們只是為它創(chuàng)建了 ActivityRecord泣棋,然后就讓 Launcher 去 Pause 了,因此這里的 app 域還是為 null 的畔塔。也很容易理解潭辈,我們還沒啟動起來呢,怎么可能不為 null
if (next.app != null && next.app.thread != null) {
......
} else {
......
// 調(diào)用這個去啟動 Activity
startSpecificActivityLocked(next, true, true);
}
return true;
}
這里在 Step 5 的時候分析過澈吨,那個時候 prev 是為 null 的把敢,現(xiàn)在有值了,是 Launcher Activity谅辣,所以會走不同的邏輯了修赞。
Step 14 frameworks/base/services/java/com/android/server/am/ActivityStack.java
/*
* r: 要啟動的 MainActivity 的 ActivityRecord
* andResume: true
* checkConfig: true
*/
private final void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// 這里我們的是第一次啟動應(yīng)用程序的 Activity,所以取到的 app 為 null
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid);
......
if (app != null && app.thread != null) {
try {
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
.......
}
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false);
}
Step 15 frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
/*
* processName: com.yjnull.demo
* info: null
* knownToBeDead: true
* intentFlags: 0
* hostingType: "activity"
* hostingName: ComponentName 對象
* allowWhileBooting: false
*/
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
// 這里再次檢查 process+uid 命名的進(jìn)程是否存在桑阶,取到的 app 還是等于 null
ProcessRecord app = getProcessRecordLocked(processName, info.uid);
......
// 這里的 hostingNameStr = com.yjnull.demo/.activity.MainActivity
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
......
if (app == null) {
// 創(chuàng)建一個 processRecord
app = newProcessRecordLocked(null, info, processName);
// mProcessNames 是一個 ProcessMap<ProcessRecord> 類型的變量
mProcessNames.put(processName, info.uid, app);
} else {
// If this is a new package in the process, add the package to the list
app.addPackage(info.packageName);
}
......
// 這里應(yīng)該是去真正創(chuàng)建一個新的進(jìn)程了
startProcessLocked(app, hostingType, hostingNameStr);
return (app.pid != 0) ? app : null;
}
// --- 接著看 startProcessLocked 方法 ---------------------------------------------
/*
* app: 上面新創(chuàng)建的 ProcessRecord
* hostingType: "activity"
* hostingNameStr: "com.yjnull.demo/.activity.MainActivity"
*/
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
......
try {
int uid = app.info.uid;
int[] gids = null;
try {
gids = mContext.getPackageManager().getPackageGids(
app.info.packageName);
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Unable to retrieve gids", e);
}
......
int debugFlags = 0;
......
// 這里主要是通過 Process.start 來創(chuàng)建一個新的進(jìn)程柏副,新的進(jìn)程會導(dǎo)入 android.app.ActivityThread 類勾邦,并執(zhí)行它的 main 函數(shù)
int pid = Process.start("android.app.ActivityThread",
mSimpleProcessManagement ? app.processName : null, uid, uid,
gids, debugFlags, null);
......
if (pid == 0 || pid == MY_PID) {
// Processes are being emulated with threads.
app.pid = MY_PID;
app.removed = false;
mStartingProcesses.add(app);
} else if (pid > 0) {
app.pid = pid;
app.removed = false;
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(pid, app);
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
}
} else {
app.pid = 0;
......
}
} catch (RuntimeException e) {
......
}
}
2.5 創(chuàng)建新進(jìn)程去了
創(chuàng)建新進(jìn)程的主要過程:
- 把一些參數(shù)拼接好,通過 socket 發(fā)出去割择。ZygoteInit 類在 runSelectLoopMode 函數(shù)會一直偵聽是否有請求眷篇,當(dāng)偵聽到有請求來臨時,會交給 ZygoteConnection 的 runOnce 函數(shù)去處理锨推。這里面會通過 Zygote.forkAndSpecialize 真正創(chuàng)建進(jìn)程铅歼。
- Zygote.forkAndSpecialize 創(chuàng)建一個進(jìn)程后,會有兩個返回值换可,一個是在當(dāng)前進(jìn)程中返回的椎椰,一個是在新創(chuàng)建的進(jìn)程中返回的。在當(dāng)前進(jìn)程中返回的是新創(chuàng)建進(jìn)程的 pid沾鳄,而在新創(chuàng)建進(jìn)程中返回的是 0慨飘。 當(dāng) pid 不等于 0 時,會調(diào)用 handleParentProc 译荞,這里面會通過
mSocketOutStream.writeInt(pid);
將 pid 發(fā)送回去瓤的。這樣上面所講的 AMS 去啟動一個新進(jìn)程的流程就結(jié)束了,AMS 拿到了 pid吞歼,并賦給了 ProcessRecord圈膏。然鵝,新進(jìn)程開始繼續(xù)運行了呢篙骡。 - 創(chuàng)建好新進(jìn)程后稽坤,肯定還需要一些處理,前面我們有拼接過一些參數(shù)糯俗,那些參數(shù)里有一個
--runtime-init
尿褪,因此新進(jìn)程通過這個參數(shù)就知道要去初始化運行時庫,于是繼續(xù)執(zhí)行 RuntimeInit.zygoteInit 進(jìn)一步處理得湘。這里面主要做了兩件事杖玲,一個 zygoteInitNative(),一個 invokeStaticMain()淘正。前者是執(zhí)行 Binder 驅(qū)動程序初始化相關(guān)的工作摆马。后者就是執(zhí)行進(jìn)程的入口函數(shù),在這個場景下就是android.app.ActivityThread
的 main 函數(shù)鸿吆。 - 這樣新進(jìn)程就進(jìn)入到 ActivityThread 的 main 函數(shù)了今膊,在 main 里面,我們會創(chuàng)建一個 ActivityThread 實例伞剑,然后調(diào)用它的 attach 函數(shù)斑唬,接著就通過 Looper 進(jìn)入消息循環(huán)了,直到最后進(jìn)程退出。
在創(chuàng)建新進(jìn)程這里我們好像斷流程了恕刘。 AMS 在拿到 pid 后就結(jié)束了缤谎。
為什么會覺得斷流程了,因為 MainActivity 還是沒啟動起來褐着。但是仔細(xì)想想坷澡,我們運行 MainActivity 的進(jìn)程已經(jīng)啟動起來了,并且調(diào)用了 attach 函數(shù)含蓉,那么我們新的流程就從 attach 開始分析频敛。
2.6 新進(jìn)程調(diào)用 ActivityThread.attach(),向 AMS 發(fā)送消息馅扣,在 AMS 中繼續(xù)處理
函數(shù) attach 最終會調(diào)用 AMS 的 attachApplication 函數(shù)斟赚,傳入的參數(shù)是 mAppThread。
Step 16 frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
/*
* thread: 新進(jìn)程的 ApplicationThread
* pid: 新進(jìn)程的 Binder.getCallingPid()
*/
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
// 前面在 Step15 創(chuàng)建一個新進(jìn)程獲得 pid 時差油,將 ProcessRecord put 進(jìn) mPidsSelfLocked 了拗军。這里通過 pid 取出來
app = mPidsSelfLocked.get(pid);
}
} else if (mStartingProcesses.size() > 0) {
......
} else {
......
}
if (app == null) {
......
return false;
}
......
String processName = app.processName;
try {
thread.asBinder().linkToDeath(new AppDeathRecipient(
app, pid, thread), 0);
} catch (RemoteException e) {
......
return false;
}
......
// 主要進(jìn)行一些初始化,把 thread 設(shè)置為 ApplicationThread 是關(guān)鍵蓄喇,這樣发侵,AMS 就可以通過這個 thread 與新創(chuàng)建的應(yīng)用程序進(jìn)程通信了
app.thread = thread;
app.curAdj = app.setAdj = -100;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.forcingToForeground = null;
app.foregroundServices = false;
app.debugging = false;
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
......
boolean badApp = false;
boolean didSomething = false;
// See if the top visible activity is waiting to run in this process...
// 這里取棧頂?shù)?ActivityRecord,其實就是對應(yīng)的 MainActivity
ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
if (hr != null && normalMode) {
if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (Exception e) {
......
badApp = true;
}
} else {
......
}
}
......
return true;
}
這一段實際是通過 pid 找到之前創(chuàng)建的 ProcessRecord妆偏,然后初始化一些值刃鳄,主要是把 ApplicationThread 設(shè)置進(jìn)去。最后交給 realStartActivityLocked 進(jìn)一步處理钱骂。
Step 17 frameworks/base/services/java/com/android/server/am/ActivityStack.java
/**
* r: MainActivity 代表的 ActivityRecord
* app: 新創(chuàng)建的進(jìn)程叔锐,即 MainActivity 將要運行在的進(jìn)程
* andResume: true
* checkConfig: true
*/
final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
......
r.app = app;
......
int idx = app.activities.indexOf(r);
if (idx < 0) {
app.activities.add(r);
}
......
try {
......
List<ResultInfo> results = null;
List<Intent> newIntents = null;
if (andResume) {
results = r.results;
newIntents = r.newIntents;
}
......
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
System.identityHashCode(r),
r.info, r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward());
......
} catch (RemoteException e) {
......
}
......
return true;
}
這里最后把啟動 MainActivity 的任務(wù)交給了應(yīng)用程序進(jìn)程的 ApplicationThread 中去了。
到這里我們想想罐柳,前面創(chuàng)建了一個新進(jìn)程后掌腰,新進(jìn)程已經(jīng)進(jìn)入了 looper 消息循環(huán)狰住,一直在等待消息來處理张吉,此時這個新進(jìn)程還沒有任何 Activity 啟動起來。但是 AMS 已經(jīng)有了 MainActivity 的記錄 ActivityRecord催植,也有了這個新進(jìn)程的記錄 ProcessRecord肮蛹。因此 AMS 通過 ApplicationThread 向新進(jìn)程發(fā)了一個 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 的消息通信。所以后面我們就轉(zhuǎn)場到 新進(jìn)程 中去分析创南。
2.7 回到新進(jìn)程中處理 啟動 Activity 的請求
Step 18 frameworks/base/core/java/android/app/ActivityThread.java
/**
* intent: 就是最初的 intent
* token: MainActivity 在 AMS 中的表現(xiàn)形式 [ActivityRecord]
* ident: System.identityHashCode(r)
* info: ActivityRecord.info
* state: ActivityRecord.icicle
* pendingResults: ActivityRecord.results
* pendingNewIntents: ActivityRecord.newIntents
* notResumed: false
* isForwar: mService.isNextTransitionForward()
*/
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
ActivityClientRecord r = new ActivityClientRecord();
// 到這里我們應(yīng)該知道 mToken 是怎么來的了
r.token = token;
r.ident = ident;
r.intent = intent;
r.activityInfo = info;
r.state = state;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
將要啟動的 Activity 組件的信息封裝成一個 ActivityClientRecord 對象伦忠。然后往主線程的消息隊列 H 發(fā)送一個 LAUNCH_ACTIVITY 的消息。
H 收到這個消息稿辙,會分發(fā)給 handleLaunchActivity
處理昆码。
Step 19 frameworks/base/core/java/android/app/ActivityThread.java
/**
* r: MainActivity 組件信息
* customIntent: null
*/
private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
// 執(zhí)行啟動 Activity
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
// 處理 resume
handleResumeActivity(r.token, false, r.isForward);
......
} else {
......
}
}
// --- 啟動 Activity ------------------------------------------
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
// 首先獲得要啟動 Activity 的包名和類名
ComponentName component = r.intent.getComponent();
......
Activity activity = null;
try {
// 終于生成了我們需要的 MainActivity 實例
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
......
} catch (Exception e) {
......
}
try {
// 這里會根據(jù) Manifest 文件中解析出來的 ApplicationInfo 去生成 Application。并且完成 Application 的 attach 、onCreate 生命周期
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
......
if (activity != null) {
// 創(chuàng)建 ContextImpl赋咽,這就是我們平常熟悉的 Context 了
ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mConfiguration);
......
// 初始化 Activity 對象
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
......
// ok, 終于回調(diào)到 onCreate 了
mInstrumentation.callActivityOnCreate(activity, r.state);
......
}
......
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
......
} catch (Exception e) {
......
}
return activity;
}
無 f**k 說
問題
- mToken 是怎么初始化的旧噪。
參考
Android 系統(tǒng)源代碼情景分析(第三版)
老羅的博客