Android12 應(yīng)用啟動(dòng)流程分析
最近因?yàn)橐恍┬枨螅枰崂?Android 應(yīng)用的啟動(dòng)鏈路,從中尋找一些穩(wěn)定的錨點(diǎn)來(lái)實(shí)現(xiàn)一些特殊的功能。本文即為對(duì)應(yīng)用端啟動(dòng)全過(guò)程的一次代碼分析記錄。本文所分析的代碼基于?android_12.0.0_r14。
前言
之前的文章介紹過(guò)?Android 操作系統(tǒng)的啟動(dòng)流程,從 init 進(jìn)程開(kāi)始,一直到 zygote 和 system_server,有助于我們?nèi)ダ斫?Android 和 Linux 之間的異同。不過(guò),用戶和開(kāi)發(fā)者最直觀的感知是 UI、Framework 和四大組件,這些組件雖然大部分由 Java 代碼構(gòu)成,但對(duì)其分析的流程也是類(lèi)似的,核心在于識(shí)別出跨進(jìn)程的 RPC 調(diào)用,以及接口和繼承引出的多態(tài)調(diào)用。
應(yīng)用端
做過(guò)應(yīng)用開(kāi)發(fā)的對(duì)下面這句應(yīng)該不會(huì)陌生:
context.startActivity(new?Intent(context,?SomeActivity.class));這經(jīng)常用來(lái)啟動(dòng)一個(gè)新的界面(Activity),可以是當(dāng)前應(yīng)用的,也可以是其他應(yīng)用的:
Intent?intent?=?new?Intent();
intent.setComponent(new?ComponentName("com.android.settings",?"com.android.settings.DeviceAdminSettings"));
context.startActivity(intent);其中Context.startActivity是個(gè)虛函數(shù),Activity 本身也是 Context 的子類(lèi),也實(shí)現(xiàn)了該方法。
Activity
在?frameworks/base/core/java/android/app/Activity.java?中調(diào)用路徑如下:
?startActivity(intent)?startActivity(intent, null)?startActivityForResult(intent, -1)?startActivityForResult(intent, -1, null)
關(guān)鍵代碼:
public?void?startActivityForResult(@RequiresPermission?Intent?intent,?int?requestCode,?@Nullable?Bundle?options)?{
????//?...
????Instrumentation.ActivityResult?ar?=?mInstrumentation.execStartActivity(this,?mMainThread.getApplicationThread(),?mToken,?this,?intent,?requestCode,?options);
????if?(ar?!=?null)?{
????????mMainThread.sendActivityResult(mToken,?mEmbeddedID,?requestCode,?ar.getResultCode(),?ar.getResultData());
????}
}最終調(diào)用了 Instrumentation 的 execStartActivity。當(dāng)然,啟動(dòng)應(yīng)用的方法有很多,比如:
?startActivity[ForResult] - 開(kāi)發(fā)者所能接觸到的接口,啟動(dòng)一個(gè)應(yīng)用(Activity),可以選擇一個(gè)回調(diào)接收啟動(dòng)的結(jié)果;?startActivityAsUser[ForResult] - 以指定用戶的身份啟動(dòng)應(yīng)用,這是個(gè)隱藏接口,只對(duì)預(yù)裝的應(yīng)用開(kāi)放;?startActivityAsCaller[ForResult] - 以調(diào)用者(即啟動(dòng)本當(dāng)前 Activity 的 APP)的身份啟動(dòng)應(yīng)用,也是個(gè)隱藏接口,主要用于 resolver 和 chooser Activity;
這些接口的實(shí)現(xiàn)都和上面代碼類(lèi)似,即最終都會(huì)調(diào)用到 Instrumentation 的接口。
Instrumentation
Instrumentation 類(lèi)主要作用是實(shí)現(xiàn)代碼追蹤的一個(gè)收口,當(dāng)啟用跟蹤時(shí),該類(lèi)會(huì)在 APP 代碼之前被實(shí)例化,允許用戶監(jiān)控系統(tǒng)與應(yīng)用之間的所有交互。代碼追蹤的配置見(jiàn)?AndroidManifest.xml?的?instrumentation?參數(shù)。
execStartActivity 主要有兩個(gè)作用:
1.更新所有激活的 ActivityMonitor 對(duì)象,調(diào)用它們的 onStartActivity 回調(diào)以及更新對(duì)應(yīng)的計(jì)數(shù)信息;2.將當(dāng)前調(diào)用分發(fā)到 system activity manager 中;
簡(jiǎn)略的偽代碼如下:
????????@UnsupportedAppUsage
????public?ActivityResult?execStartActivity(
????????????Context?who,?IBinder?contextThread,?IBinder?token,?Activity?target,
????????????Intent?intent,?int?requestCode,?Bundle?options)?{
??????//?1.?更新?ActivityMonitor
??????for?(int?i?=?0;?i?????????ActivityMonitor?am?=?mActivityMonitors.get(i);
????????am.onStartActivity(intent);
??????}
??????//?2.?調(diào)用?System?Activity?Manager
??????int?result?=?ActivityTaskManager.getService().startActivity();
??????checkStartActivityResult(result,?intent);
????}在代碼注釋中提到我們可以覆寫(xiě)此方法來(lái)觀察 APP 啟動(dòng)新 Activity 的事件,并且可以修改啟動(dòng) Activity 的行為和返回。許多插件化框架就是通過(guò)修改此方法來(lái)實(shí)現(xiàn) Activity 的攔截。
ActivityTaskManager
由于我們關(guān)心的是實(shí)際的啟動(dòng)鏈路,因此暫時(shí)忽略監(jiān)控相關(guān)的代碼,直接進(jìn)入到 ActivityTaskManager (簡(jiǎn)稱(chēng) ATM)。其 getService 返回的實(shí)際上是:
final?IBinder?b?=?ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);?//?activity_task
return?IActivityTaskManager.Stub.asInterface(b);是這里是個(gè)常見(jiàn)的遠(yuǎn)程調(diào)用模式:
//?1.?獲取原始的IBinder對(duì)象
IBinder?b?=?ServiceManager.getService("service_name");
//?2.?轉(zhuǎn)換為?Service?的?RPC?接口
IXXInterface?in?=?IXXInterface.Stub.asInterface(b);所以返回的是一個(gè)類(lèi)型為IActivityTaskManager的對(duì)象,這其實(shí)是一個(gè) Service,即 activity_task,其接口為:
package?android.app;
/**
?*?System?private?API?for?talking?with?the?activity?task?manager?that?handles?how?activities?are
?*?managed?on?screen.
?*
?*?{@hide}
?*/
public?interface?IActivityTaskManager?extends?android.os.IInterface
{
??/**?Default?implementation?for?IActivityTaskManager.?*/
??public?static?class?Default?implements?android.app.IActivityTaskManager
??{
????//...
??}
??/**?Local-side?IPC?implementation?stub?class.?*/
??public?static?abstract?class?Stub?extends?android.os.Binder?implements?android.app.IActivityTaskManager
??{
????//...
??}
??public?static?final?java.lang.String?DESCRIPTOR?=?"android.app.IActivityTaskManager";
??public?int?startActivity(...);
}這個(gè)類(lèi)是自動(dòng)生成的,即使用 AIDL 生成的 RPC 接口,細(xì)節(jié)可以參考?Android HAL 與 HIDL 開(kāi)發(fā)筆記,HIDL 的實(shí)現(xiàn)和 AIDL 類(lèi)似,區(qū)別在于 HIDL 面向?Hardware,AIDL 面向?Application。
其定義文件為:?frameworks/base/core/java/android/app/IActivityTaskManager.aidl:
interface?IActivityTaskManager?{
????int?startActivity(in?IApplicationThread?caller,?in?String?callingPackage,
????????????in?String?callingFeatureId,?in?Intent?intent,?in?String?resolvedType,
????????????in?IBinder?resultTo,?in?String?resultWho,?int?requestCode,
????????????int?flags,?in?ProfilerInfo?profilerInfo,?in?Bundle?options);
??//?...
}既然到了 AIDL,那在 APP 進(jìn)程中也就走到頭了,下一步需要轉(zhuǎn)換視角,從 RPC 的另一端繼續(xù)分析。
服務(wù)端
根據(jù) AIDL 的原理,RPC 的另一端需要實(shí)現(xiàn)?IActivityTaskManager?接口,一般來(lái)說(shuō)是要繼承?IActivityTaskManager.Stub,搜索可以發(fā)現(xiàn)這個(gè)類(lèi)為?ActivityTaskManagerService。
ActivityTaskManagerService
該類(lèi)在 AOSP 中的路徑為:?frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java,看名稱(chēng)猜測(cè)這是一個(gè)系統(tǒng)服務(wù)。筆者在之前的文章(Android 用戶態(tài)啟動(dòng)流程分析) 中介紹了從 init 到 zygote 到 system_server 的一套流程,而這個(gè)?ActivityTaskManagerService?正好也是在 startBootstrapServices 中啟動(dòng)的其中一個(gè)服務(wù),代碼片段如下:
????private?void?startBootstrapServices(@NonNull?TimingsTraceAndSlog?t)?{
????????//?...
??????????
????????????????//?Activity?manager?runs?the?show.
????????t.traceBegin("StartActivityManager");
????????//?TODO:?Might?need?to?move?after?migration?to?WM.
????????ActivityTaskManagerService?atm?=?mSystemServiceManager.startService(
????????????????ActivityTaskManagerService.Lifecycle.class).getService();
????????mActivityManagerService?=?ActivityManagerService.Lifecycle.startService(
????????????????mSystemServiceManager,?atm);
????????mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
????????mActivityManagerService.setInstaller(installer);
????????mWindowManagerGlobalLock?=?atm.getGlobalLock();
????????t.traceEnd();
??????
??????????//?...
????}隨之啟動(dòng)的還有 ActivityManagerService。
在舊版本中實(shí)際上是在 ActivityManagerNative 中調(diào)用 ActivityManagerService,不過(guò)新版本已經(jīng)將其 startActivity 標(biāo)記為過(guò)時(shí)了。
回到代碼,ActivityTaskManagerService 的 startActivity 調(diào)用經(jīng)過(guò)了以下鏈路:
?startActivity?startActivityAsUser(..., userId=UserHandle.getCallingUserId())?startActivityAsUser(..., validateIncomingUser=true)
后者調(diào)用的代碼如下:
????private?int?startActivityAsUser(IApplicationThread?caller,?String?callingPackage,
????????????@Nullable?String?callingFeatureId,?Intent?intent,?String?resolvedType,
????????????IBinder?resultTo,?String?resultWho,?int?requestCode,?int?startFlags,
????????????ProfilerInfo?profilerInfo,?Bundle?bOptions,?int?userId,?boolean?validateIncomingUser)?{
????????assertPackageMatchesCallingUid(callingPackage);
????????enforceNotIsolatedCaller("startActivityAsUser");
????????userId?=?getActivityStartController().checkTargetUser(userId,?validateIncomingUser,
????????????????Binder.getCallingPid(),?Binder.getCallingUid(),?"startActivityAsUser");
????????//?TODO:?Switch?to?user?app?stacks?here.
????????return?getActivityStartController().obtainStarter(intent,?"startActivityAsUser")
????????????????.setCaller(caller)
????????????????.setCallingPackage(callingPackage)
????????????????.setCallingFeatureId(callingFeatureId)
????????????????.setResolvedType(resolvedType)
????????????????.setResultTo(resultTo)
????????????????.setResultWho(resultWho)
????????????????.setRequestCode(requestCode)
????????????????.setStartFlags(startFlags)
????????????????.setProfilerInfo(profilerInfo)
????????????????.setActivityOptions(bOptions)
????????????????.setUserId(userId)
????????????????.execute();
????}通過(guò)一系列 builder 獲取 starter 并設(shè)置對(duì)應(yīng)參數(shù),最終執(zhí)行 execute。
ActivityStarter
obtainStarter 返回的類(lèi)型是 ActivityStarter, 該類(lèi)定義在:?frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java,其 execute 函數(shù)的作用就是根據(jù)前面提供的的請(qǐng)求參數(shù)并開(kāi)始啟動(dòng)應(yīng)用。
關(guān)鍵調(diào)用路徑:
?exexute: 處理 Activity 啟動(dòng)請(qǐng)求的接口;?executeRequest: 執(zhí)行一系列權(quán)限檢查,對(duì)于合法的請(qǐng)求才繼續(xù);?startActivityUnchecked: 調(diào)用該方法時(shí)表示大部分初步的權(quán)限檢查已經(jīng)完成,執(zhí)行 Trace,以及異常處理;?startActivityInner: 啟動(dòng) Activity,并更新全局的 task 棧幀信息;
在 Android 中系統(tǒng)維護(hù)了所有應(yīng)用的狀態(tài)信息,因此用戶才可以在不同應(yīng)用中無(wú)縫切換和返回。同時(shí)在處理啟動(dòng)應(yīng)用請(qǐng)求的時(shí)候還需要進(jìn)行額外的判斷,比如當(dāng)前棧頂是否是同樣的 Activity,如果是則根據(jù)設(shè)置決定是否重復(fù)啟動(dòng)等等。
忽略 ActivityStack、WindowContainer 等任務(wù)窗口管理的代碼,只關(guān)注其中真正啟動(dòng)應(yīng)用相關(guān)的:
?mTargetRootTask.startActivityLocked()?mRootWindowContainer.resumeFocusedTasksTopActivities()
mTargetRootTask 是 Task 類(lèi)型,?Task?是?WindowContainer?的子類(lèi),用于管理和表示屬于同一棧幀的所有 activity,其中每個(gè) activity 使用?ActivityRecord?表示。mRootWindowContainer 是?RootWindowContainer?類(lèi)型,也是 WindowContainer 的子類(lèi),特別代表根窗口。
startActivityLocked 方法的主要作用是判斷當(dāng)前 activity 是否可見(jiàn)以及是否需要為其新建 Task,根據(jù)不同情況將 ActivityRecord 加入到對(duì)應(yīng)的 Task 棧頂中。
resumeFocusedTasksTopActivities 方法正如其名字一樣,將所有聚焦的 Task 的所有 Activity 恢復(fù)運(yùn)行,因?yàn)橛行﹦偧尤氲?Activity 是處于暫停狀態(tài)的。
Task
Task 從宏觀來(lái)說(shuō)是一系列 Activity 界面的集合,根據(jù)先進(jìn)后出的棧結(jié)構(gòu)進(jìn)行組織。注意 task 和 進(jìn)程/線程是不同的概念,大多數(shù) task 可以認(rèn)為是從桌面點(diǎn)擊某個(gè)應(yīng)用開(kāi)始啟動(dòng),隨著不斷點(diǎn)擊深入打開(kāi)其他界面,使對(duì)應(yīng)的 Activity 入棧,在點(diǎn)擊返回時(shí)將當(dāng)前 Activity 出棧并銷(xiāo)毀,如下所示:

同時(shí),整個(gè) Task 本身也可以被移動(dòng)當(dāng)后臺(tái),比如當(dāng)用戶點(diǎn)擊 HOME 鍵時(shí),此時(shí) Task 中的所有 Activity 都會(huì)停止。Task 中的 Activity 可以同屬于一個(gè) APP,也可能屬于不同的 APP 和進(jìn)程。在 Android R (11) 以及 Android S(12) beta 的代碼中(甚至更早的代碼之前),Task 類(lèi)實(shí)際上是 ActivityStack,可以認(rèn)為?Task 就是 ActivityStack,ActivityStack 就是 Task。關(guān)于 Task 的更多介紹,可以閱讀官方的文檔:?Tasks and the back stack[1]。
resumeFocusedTasksTopActivities 中主要是判斷傳入的 targetRootTask 是否等于當(dāng)前棧頂?shù)?Task,不管是否相等,后續(xù)都是調(diào)用棧頂 Task 的?resumeTopActivityUncheckedLocked?方法。
其中對(duì) Task 進(jìn)行了一次判斷,如果是非葉子結(jié)點(diǎn),則對(duì)所有子結(jié)點(diǎn)遞歸調(diào)用本方法,遞歸結(jié)束(即到達(dá)葉子結(jié)點(diǎn))后才繼續(xù)實(shí)際流程。再次執(zhí)行了一系列的判斷,比如查找當(dāng)前棧幀中最接近棧頂且可顯示和可聚焦的 Activity (next),判斷其暫停狀態(tài)以及所屬用戶的權(quán)限等,然后進(jìn)入到 resumeTopActivityInnerLocked。
該方法中主要是尋找合適的 ActivityRecord、設(shè)置 resume 條件、準(zhǔn)備啟動(dòng)目標(biāo) Activity。最后,來(lái)到了我們的關(guān)鍵邏輯:
????@GuardedBy("mService")
????private?boolean?resumeTopActivityInnerLocked(ActivityRecord?prev,?ActivityOptions?options)?{
??????????ActivityRecord?next?=?topRunningActivity(true?/*?focusableOnly?*/);
????????//?...
??????????if?(next.attachedToProcess())?{
????????????//?Activity?已經(jīng)附加到進(jìn)程,恢復(fù)頁(yè)面并更新棧
????????}?else?{
????????????//?Whoops,?need?to?restart?this?activity!
????????????????????????mTaskSupervisor.startSpecificActivity(next,?true,?true);
????????}
????}在函數(shù)末尾處判斷當(dāng)前(棧頂) Activity 是否與已有的進(jìn)程關(guān)聯(lián),如果已經(jīng)關(guān)聯(lián),就在該進(jìn)程中恢復(fù)頁(yè)面。否則就需要 (重新) 啟動(dòng)目標(biāo) Activity。啟動(dòng)新進(jìn)程是在 startSpecificActivity 中,屬于 TaskSupervisor。這是個(gè)垃圾類(lèi),里面有各種不同功能的代碼(Google 原話),因此我們不需要對(duì)其過(guò)多關(guān)注。
void?startSpecificActivity(ActivityRecord?r,?boolean?andResume,?boolean?checkConfig)?{
????//?Is?this?activity's?application?already?running?
????final?WindowProcessController?wpc?=
????????????mService.getProcessController(r.processName,?r.info.applicationInfo.uid);
????boolean?knownToBeDead?=?false;
????if?(wpc?!=?null?&&?wpc.hasThread())?{
????????try?{
????????????realStartActivityLocked(r,?wpc,?andResume,?checkConfig);
????????????return;
????????}?catch?(RemoteException?e)?{
????????????Slog.w(TAG,?"Exception?when?starting?activity?"
????????????????????+?r.intent.getComponent().flattenToShortString(),?e);
????????}
????????//?If?a?dead?object?exception?was?thrown?--?fall?through?to
????????//?restart?the?application.
????????knownToBeDead?=?true;
????}
????r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
????final?boolean?isTop?=?andResume?&&?r.isTopRunningActivity();
????mService.startProcessAsync(r,?knownToBeDead,?isTop,?isTop???"top-activity"?:?"activity");
}startSpecificActivity 主要是判斷目標(biāo) Activity 所在的應(yīng)用是否正在運(yùn)行。如果已經(jīng)在運(yùn)行就直接啟動(dòng),否則就啟動(dòng)新進(jìn)程。下面我們分別對(duì)這兩種情況進(jìn)行分析。
進(jìn)程已存在
如果待啟動(dòng)的 Activity 所屬的 Application 已經(jīng)在運(yùn)行中,那么只需要在其對(duì)應(yīng)進(jìn)程啟動(dòng) Activity,此時(shí)所走的分支是 realStartActivityLocked。該函數(shù)的核心是創(chuàng)建事務(wù)并分發(fā)給生命周期管理器進(jìn)行處理。
//?Create?activity?launch?transaction.
final?ClientTransaction?clientTransaction?=?ClientTransaction.obtain(
????proc.getThread(),?r.appToken);
final?ActivityLifecycleItem?lifecycleItem;
if?(andResume)?{
????lifecycleItem?=?ResumeActivityItem.obtain(mService.isNextTransitionForward());
}?else?{
????lifecycleItem?=?PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
//?Schedule?transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
Transaction
事務(wù)(Transaction)是包含一系列消息的容器,這些消息最終可能會(huì)傳送到客戶端中。其中包含一組回調(diào)以及最終的生命周期狀態(tài)。setLifecycleStateRequest 用于指定客戶端的終態(tài),即事務(wù)執(zhí)行完畢后客戶端應(yīng)當(dāng)處于的最終狀態(tài),其參數(shù)類(lèi)型是 ActivityLifecycleItem,可以理解為發(fā)送給客戶端的請(qǐng)求。
這里的 mService 是 ActivityTaskManagerService,是一個(gè)主要用于管理 activity 及其容器(task、display 等)的系統(tǒng)服務(wù);getLifecycleManager 返回 ClientLifecycleManager。但這都不重要,因?yàn)樽罱K也只是執(zhí)行了?transaction.schedule()?開(kāi)始調(diào)度事務(wù),主要按照以下順序執(zhí)行:
1.客戶端調(diào)用 preExecute,觸發(fā)所有需要在真正調(diào)度事務(wù)前執(zhí)行完畢的工作;2.發(fā)送事務(wù)的 message 信息到客戶端;3.客戶端調(diào)用 TransactionExecutor.execute,執(zhí)行所有回調(diào)以及必要的生命周期事務(wù);
public?void?schedule()?throws?RemoteException?{
????mClient.scheduleTransaction(this);
}mClient 為 IApplicationThread 類(lèi)型,這是個(gè)抽象接口,同時(shí)也是遠(yuǎn)程調(diào)用接口,其 AIDL 定義在:?frameworks/base/core/java/android/app/IApplicationThread.aidl?文件中。因此,最終的調(diào)用又會(huì)回到 RPC 的實(shí)現(xiàn)端,即應(yīng)用程序所在的客戶端,實(shí)現(xiàn)類(lèi)為?ActivityThread。其中通過(guò)異步的 Handler 分發(fā)和調(diào)度事件,最終在 執(zhí)行線程(主線程)的 handleMessage 回調(diào)中執(zhí)行服務(wù)端傳過(guò)來(lái)的 Transaction。流程大致如下圖所示:

值得一提的是,TransactionExecutor 中執(zhí)行了 mTransactionHandler.handleLaunchActivity,而 mTransactionHandler 是在 TransactionExecutor 的構(gòu)造函數(shù)中傳入的,構(gòu)造正是在 ActivityThread 中:
class?ActivityThread?{
??//?...
??private?final?TransactionExecutor?mTransactionExecutor?=?new?TransactionExecutor(this);
}因此,注 1 中實(shí)際調(diào)用的是?ActivityThread?的?handleLaunchActivity。
Launch Activity
ActivityThread 中的?performLaunchActivity?是啟動(dòng) Activity 的核心實(shí)現(xiàn)。其主要偽代碼為:
private?Activity?performLaunchActivity(ActivityClientRecord?r,?Intent?customIntent)?{
????ContextImpl?appContext?=?createBaseContextForActivity(r);
??????java.lang.ClassLoader?cl?=?appContext.getClassLoader();
??????activity?=?mInstrumentation.newActivity(cl,?component.getClassName(),?r.intent);
??????Application?app?=?r.packageInfo.makeApplication(false,?mInstrumentation);
??????//?loadLabel
??????//?initialize?Activity?resources
??????//?activity.attach(appContext,?...)
??????mInstrumentation.callActivityOnCreate(activity,?...);
}長(zhǎng)話短說(shuō),主要流程為:
1.創(chuàng)建應(yīng)用上下文(Context),獲取 ClassLoader;2.創(chuàng)建 Activity 對(duì)象,實(shí)質(zhì)上是 classLoader.loadClass(name).newInstance(),這里會(huì)對(duì) Activity 類(lèi)進(jìn)行初始化,調(diào)用對(duì)象的??方法,從而執(zhí)行目標(biāo)類(lèi)里?static block?中的代碼;3.根據(jù)應(yīng)用的?AndroidManifest.xml?創(chuàng)建 Application對(duì)象,并調(diào)用其 onCreate 回調(diào);4.調(diào)用對(duì)應(yīng) Activity 的 onCreate 回調(diào);
調(diào)用時(shí)序如下圖所示:

最終,調(diào)用到開(kāi)發(fā)者熟知的生命周期函數(shù)?Activity.onCreate,開(kāi)始執(zhí)行 APP 本身的代碼。
值得一提的是上面的代碼都在 APP 的主線程中執(zhí)行,Application.onCreate?僅在應(yīng)用初次啟動(dòng)時(shí)調(diào)用一次,并且早于任意 Activity/Service/Receiver 執(zhí)行,不過(guò) ContentProvider 是個(gè)例外。
關(guān)于 Android 應(yīng)用的生命周期,可以參考:?The Activity Lifecycle[2],一個(gè)簡(jiǎn)略的流程如下圖所示:

啟動(dòng)新進(jìn)程
分析完了進(jìn)程已經(jīng)存在的情況下啟動(dòng)應(yīng)用 Activity 的流程,現(xiàn)在再翻回頭看看進(jìn)程不存在的情況。此時(shí)需要通過(guò)?mService.startProcessAsync?去啟動(dòng)進(jìn)程。
AMS
mService 也就是前面提到的?ActivityTaskManagerService(ATMS),啟動(dòng)進(jìn)程通過(guò)異步發(fā)送消息的方式發(fā)送給 AMS,再由其執(zhí)行啟動(dòng)進(jìn)程的操作。

startProcessLocked 中關(guān)鍵的偽代碼如下:
ProcessRecord?startProcessLocked(String?processName,?...)?{
??ProcessRecord?app?=?getProcessRecordLocked(processName,?info.uid);
??final?String?entryPoint?=?"android.app.ActivityThread";
??//?...
??startProcess(hostingRecord,?entryPoint,?app,?...)
}
????記住這里的 entryPoint 字符串,值為?android.app.ActivityThread,后面會(huì)用到。
ProcessRecord 中包含特定運(yùn)行中進(jìn)程的所有信息,在進(jìn)程啟動(dòng)完成后,再通過(guò) handleProcessStartedLocked 來(lái)填充動(dòng)態(tài)的進(jìn)程 ID 等內(nèi)容。
startProcess?根據(jù)入?yún)⒋_定實(shí)際的啟動(dòng)進(jìn)程方式:
private?Process.ProcessStartResult?startProcess(...)?{
??//?mount?App?data?...
??//?data?isolation?...
??if?(hostingRecord.usesWebviewZygote())?{
????????startResult?=?startWebView(entryPoint,?app.processName,?uid,?...);
??}?else?if?(hostingRecord.usesAppZygote())?{
????????final?AppZygote?appZygote?=?createAppZygoteForProcessIfNeeded(app);
????????startResult?=?appZygote.getProcess().start(entryPoint,?app.processName,?uid,?...);
??}?else?{
????????regularZygote?=?true;
????????????Process.start(entryPoint,?app.processName,?uid,?...);
??}
}可以看到新進(jìn)程都是從 zygote 衍生的,但實(shí)際上有三種不同類(lèi)型的 zygote:
1.regular zygote[3]: 即常規(guī)的 zygote32/zygote64 進(jìn)程,是所有 Android Java 應(yīng)用的父進(jìn)程;2.app zygote[4]: 應(yīng)用 zygote 進(jìn)程,與常規(guī) zygote 創(chuàng)建的應(yīng)用相比受到更多限制;3.webview zygote[5]: 輔助 zygote 進(jìn)程,用于創(chuàng)建 isolated_app 進(jìn)程來(lái)渲染不可信的 web 內(nèi)容,具有最為嚴(yán)格的安全限制;
Zygote
對(duì)于我們的分析場(chǎng)景,只需要關(guān)注常規(guī) zygote 創(chuàng)建進(jìn)程的情況,其他模式也是大同小異。根據(jù)上述代碼,創(chuàng)建進(jìn)程的請(qǐng)求最終會(huì)進(jìn)入到 Process.start,這是個(gè)靜態(tài)函數(shù),主要工作是封裝新進(jìn)程的啟動(dòng)參數(shù)(進(jìn)程名、UID、GID、appDataDir 等信息)為字符串,并通過(guò) zygoteWriter 發(fā)送給 zygote 進(jìn)程,通知 zygote 啟動(dòng)新的進(jìn)程并返回對(duì)應(yīng)的新進(jìn)程 ID,圖示如下:

上圖中的 Tunnel 是 AMS 進(jìn)程與 zygote 進(jìn)程的通信橋梁,二者實(shí)質(zhì)上通過(guò) UNIX socket 進(jìn)行通信:
//?android/internal/os/Zygote.java
/**
?*?Creates?a?managed?LocalServerSocket?object?using?a?file?descriptor
?*?created?by?an?init.rc?script.??The?init?scripts?that?specify?the
?*?sockets?name?can?be?found?in?system/core/rootdir.??The?socket?is?bound
?*?to?the?file?system?in?the?/dev/sockets/?directory,?and?the?file
?*?descriptor?is?shared?via?the?ANDROID_SOCKET_?environment
?*?variable.
?*/
static?LocalServerSocket?createManagedSocketFromInitSocket(String?socketName)?{
????int?fileDesc;
????final?String?fullSocketName?=?ANDROID_SOCKET_PREFIX?+?socketName;
????try?{
????????String?env?=?System.getenv(fullSocketName);
????????fileDesc?=?Integer.parseInt(env);
????}?catch?(RuntimeException?ex)?{
????????throw?new?RuntimeException("Socket?unset?or?invalid:?"?+?fullSocketName,?ex);
????}
????try?{
????????FileDescriptor?fd?=?new?FileDescriptor();
????????fd.setInt$(fileDesc);
????????return?new?LocalServerSocket(fd);
????}?catch?(IOException?ex)?{
????????throw?new?RuntimeException(
????????????"Error?building?socket?from?file?descriptor:?"?+?fileDesc,?ex);
????}
}socket 名稱(chēng)通過(guò)環(huán)境變量傳遞,key 為?“ANDROID_SOCKET_” + “zygote"。
ZygoteServer
前面說(shuō)了 Zygote 進(jìn)程收到 AMS 發(fā)送的數(shù)據(jù)后會(huì)啟動(dòng)進(jìn)程并將新進(jìn)程的 PID 返回,而這些流程正是在 ZygoteServer 中實(shí)現(xiàn)的:
//?frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
class?ZygoteServer?{
????/**
?????*?Runs?the?zygote?process's?select?loop.?Accepts?new?connections?as
?????*?they?happen,?and?reads?commands?from?connections?one?spawn-request's
?????*?worth?at?a?time.
?????*?@param?abiList?list?of?ABIs?supported?by?this?zygote.
?????*/
????Runnable?runSelectLoop(String?abiList)?{
???????????ArrayList?socketFDs?=?new?ArrayList<>();
??????????socketFDs.add(mZygoteSocket.getFileDescriptor());
??????
????????while?(true)?{
??????????pollFDs?=?new?StructPollfd[socketFDs.size()];
??????????pollReturnValue?=?Os.poll(pollFDs,?pollTimeoutMs);
??????????//?...
??????????while?(--pollIndex?>=?0)?{
????????????????if?((pollFDs[pollIndex].revents?&?POLLIN)?==?0)?continue;
??????????????????ZygoteConnection?connection?=?peers.get(pollIndex);
????????????????//?處理收到的命令,并且根據(jù)需要執(zhí)行?fork,注意該系統(tǒng)調(diào)用會(huì)返回兩次
?????????????????Runnable?command?=?connection.processCommand(this,?multipleForksOK);
????????????????if?(mIsForkChild)?{
????????????????????//?We're?in?the?child
??????????????}?else?{
????????????????????????????????????//?We're?in?the?server
??????????????}
????????????????//?...
??????????}
????????}
????}
} 處理和執(zhí)行 Socket 信息的流程如下圖所示:

在 fork 完成后,父進(jìn)程根據(jù)傳入的參數(shù)設(shè)置好子進(jìn)程的名稱(chēng)、UID 等屬性,再將子進(jìn)程 PID 返回給 AMS,完成新進(jìn)程的啟動(dòng)流程。當(dāng)然,其中存在一些細(xì)節(jié)的優(yōu)化,比如用 pre-fork (同時(shí)fork N個(gè)進(jìn)程,監(jiān)聽(tīng)同一個(gè)socket fd,當(dāng)收到消息的時(shí)候,只有一個(gè)進(jìn)程會(huì)被喚醒,來(lái)處理這個(gè)消息) 機(jī)制加快應(yīng)用啟動(dòng)速度,感興趣的可以自行探索。
在 ZygoteConnection fork 完成后,父進(jìn)程中的返回會(huì)執(zhí)行 handleParentProc,子進(jìn)程的返回會(huì)執(zhí)行 handleChildProc。該函數(shù)返回的是一個(gè) Runnable 對(duì)象,包含子進(jìn)程待執(zhí)行的代碼。
子進(jìn)程初始化
對(duì)于子進(jìn)程,調(diào)用鏈路為:
?handleChildProc?ZygoteInit.zygoteInit?RuntimeInit.applicationInit?RuntimeInit.findStaticMain
protected?static?Runnable?applicationInit(int?targetSdkVersion,?long[]?disabledCompatChanges,
????????String[]?argv,?ClassLoader?classLoader)?{
????VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
????VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);
????final?Arguments?args?=?new?Arguments(argv);
????//?The?end?of?of?the?RuntimeInit?event?(see?#zygoteInit).
????Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
????//?Remaining?arguments?are?passed?to?the?start?class's?static?main
????return?findStaticMain(args.startClass,?args.startArgs,?classLoader);
}最終調(diào)用的實(shí)際上是 startClass 的?static main(argv[])?方法。還記得前文中提到的 entryPoint 嗎?傳到此處的 startClass 正是 entryPoint 的值,即?android.app.ActivityThread。因此,子進(jìn)程的入口是 ActivityThread 的 main 方法,該方法的調(diào)用鏈路如下圖所示:

首先通過(guò) RPC 進(jìn)程間通信調(diào)用到 AMS 服務(wù)端,設(shè)置一些初始化狀態(tài)(如調(diào)試狀態(tài)、啟動(dòng)狀態(tài)、OOM 優(yōu)先級(jí)等)后,又通過(guò) RPC 回調(diào)到客戶端,雖然兜了一圈,但這也是為了實(shí)現(xiàn)權(quán)限分離,讓 AMS 專(zhuān)職負(fù)責(zé)管理系統(tǒng)應(yīng)用狀態(tài)。
回到客戶端后,將應(yīng)用信息封裝發(fā)送給主線程去執(zhí)行啟動(dòng)流程,這些都在 handleBindApplication 方法中實(shí)現(xiàn),摘取一些關(guān)鍵的代碼片段如下:
private?void?handleBindApplication(AppBindData?data)?{
??//?將當(dāng)前?UI?線程注冊(cè)為?JavaVM?的重要線程
????VMRuntime.registerSensitiveThread();
??//?設(shè)置調(diào)試的跟蹤棧深度
??String?property?=?SystemProperties.get("debug.allocTracker.stackDepth");
??VMDebug.setAllocTrackerStackDepth(Integer.parseInt(property));
??//?設(shè)置應(yīng)用的真正名稱(chēng)
??Process.setArgV0(data.processName);
??android.ddm.DdmHandleAppName.setAppName(data.processName,?...);
??VMRuntime.setProcessPackageName(data.appInfo.packageName);
??//?為?ART?設(shè)置應(yīng)用數(shù)據(jù)的路徑
??VMRuntime.setProcessDataDirectory(data.appInfo.dataDir);
??//?如果設(shè)置了調(diào)試模式,會(huì)等待調(diào)試器連接,同時(shí)顯示彈窗信息
??if?(data.debugMode?!=?ApplicationThreadConstants.DEBUG_OFF)?{
??????Debug.changeDebugPort(8100);
????mgr?=?ActivityManager.getService();
????mgr.showWaitingForDebugger(mAppThread,?true);
????Debug.waitForDebugger();
????mgr.showWaitingForDebugger(mAppThread,?false);
??}
??//?創(chuàng)建目標(biāo)?APP?的上下文
??ContextImpl?appContext?=?ContextImpl.createAppContext(this,?data.info);
??//?設(shè)置?HTTP?代理
??final?ConnectivityManager?cm?=?appContext.getSystemService(ConnectivityManager.class);
??Proxy.setHttpProxyConfiguration(cm.getDefaultProxy());
??//?加載?Network?Security?Config:?APP?自定義證書(shū)、SSL-Pinning?...
??NetworkSecurityConfigProvider.install(appContext);
??//?Applicaiton?初始化以及?ContentProvider?注冊(cè)
??app?=?data.info.makeApplication(data.restrictedBackupMode,?null);
??ActivityThread.updateHttpProxy(app);
??installContentProviders(app,?data.providers);
??//?啟動(dòng)應(yīng)用
??mInstrumentation.onCreate(data.instrumentationArgs);
??mInstrumentation.callApplicationOnCreate(app);
??//?預(yù)加載字體資源?...
}可以看到,如果應(yīng)用啟用了調(diào)試,那么調(diào)試器在 Application 啟動(dòng)之前初始化,而且在應(yīng)用啟動(dòng)之前還設(shè)置了系統(tǒng)的的 HTTP 代理,這也是為什么在 Android 中 native 進(jìn)程不使用系統(tǒng)代理,因?yàn)閷?duì)于代理是在 ActivityThread 即 Java 應(yīng)用的 UI 線程中進(jìn)行初始化的。
Instrumentation 類(lèi)是我們的老朋友了,在上一節(jié)進(jìn)程已存在情況下啟動(dòng) Activity 就是通過(guò)該類(lèi)最終進(jìn)入 Activity 的生命周期函數(shù)入口。如果讀者仔細(xì)看了前一節(jié),應(yīng)該還記得這么一句話:
Application.onCreate?僅在應(yīng)用初次啟動(dòng)時(shí)調(diào)用一次,并且早于任意 Activity/Service/Receiver 執(zhí)行,不過(guò) ContentProvider 是個(gè)例外。
從上面的代碼我們也能看到,ContentProvider 的注冊(cè)還在 callApplicationOnCreate 之前,這其實(shí)屬于歷史遺留問(wèn)題,因?yàn)橛袝r(shí)候 Application 的初始化過(guò)程會(huì)訪問(wèn) ContentProvider,感興趣的可以參考早期的討論(issue#36917845[6])。
所以如果我們想要自己的代碼盡早執(zhí)行,可以將其放到 ContentProvider.onCreate 方法中,比如實(shí)現(xiàn)一些野路子的加固方案,不過(guò) Android 并沒(méi)有對(duì)這個(gè)時(shí)序做應(yīng)用層的承諾就是了。
啟動(dòng) Activity
此時(shí),APP 進(jìn)程已經(jīng)啟動(dòng),但似乎 Activity 還沒(méi)開(kāi)始?其實(shí)前文中我們執(zhí)行到了 ActivityThread 的 main 函數(shù),其中最后會(huì)調(diào)用 Looper.loop() 進(jìn)入循環(huán)等待,也是在這里收到 AMS 的?BIND_APPLICATION?請(qǐng)求從而進(jìn)行子進(jìn)程初始化。除了這個(gè)請(qǐng)求,還有一個(gè)前面我們見(jiàn)過(guò)的請(qǐng)求:?EXECUTE_TRANSACTION,所以在子進(jìn)程初始化后,AMS 會(huì)進(jìn)而完成 Activity 的啟動(dòng)處理。
之后的流程就和前面進(jìn)程已存在情況的場(chǎng)景一致了,我們這里就不再分析代碼,而是通過(guò)動(dòng)態(tài)調(diào)試去驗(yàn)證。首先編寫(xiě)一個(gè)測(cè)試應(yīng)用,然后在 MainActivity 的 onCreate 方法打上斷點(diǎn),運(yùn)行之后可以得到下面的?;厮菪畔?
onCreate:13,?MainActivity?(com.evilpan.vulnapp)
performCreate:8000,?Activity?(android.app)
performCreate:7984,?Activity?(android.app)
callActivityOnCreate:1309,?Instrumentation?(android.app)
performLaunchActivity:3404,?ActivityThread?(android.app)
handleLaunchActivity:3595,?ActivityThread?(android.app)
execute:85,?LaunchActivityItem?(android.app.servertransaction)
executeCallbacks:135,?TransactionExecutor?(android.app.servertransaction)
execute:95,?TransactionExecutor?(android.app.servertransaction)
handleMessage:2066,?ActivityThread$H?(android.app)
dispatchMessage:106,?Handler?(android.os)
loop:223,?Looper?(android.os)
main:7660,?ActivityThread?(android.app)
invoke:-1,?Method?(java.lang.reflect)
run:592,?RuntimeInit$MethodAndArgsCaller?(com.android.internal.os)
main:947,?ZygoteInit?(com.android.internal.os)和我們前面的分析基本吻合。至此,應(yīng)用就完成了漫長(zhǎng)的啟動(dòng)流程。
后記
對(duì)于 Android 應(yīng)用啟動(dòng)流程,網(wǎng)上已經(jīng)有很多相關(guān)的分析[7],但自己實(shí)際看一遍代碼才真正理解實(shí)際的執(zhí)行細(xì)節(jié)。應(yīng)用啟動(dòng)看似一件簡(jiǎn)單的事,卻在操作系統(tǒng)中跨越多個(gè)線程甚至進(jìn)程,存在許多異步的操作,比如 AIDL/RCP 調(diào)用,跨線程的 Handler sendMessage/handleMessage 模式,了解這些設(shè)計(jì)模式有助于我們順利跟蹤數(shù)據(jù)流和控制流,避免在龐雜的代碼中迷失。
引用鏈接
[1]?Tasks and the back stack:?https://developer.android.com/guide/components/activities/tasks-and-back-stack[2]?The Activity Lifecycle:?https://developer.android.com/guide/components/activities/activity-lifecycle[3]?regular zygote:?https://android.googlesource.com/platform/system/sepolicy/+/master/private/zygote.te[4]?app zygote:?https://android.googlesource.com/platform/system/sepolicy/+/master/private/app_zygote.te[5]?webview zygote:?https://android.googlesource.com/platform/system/sepolicy/+/master/private/webview_zygote.te[6]?issue#36917845:?https://issuetracker.google.com/issues/36917845#comment4[7]?相關(guān)的分析:?https://blog.csdn.net/Luoshengyang/article/details/6689748
