Android Activity啟動流程原始碼分析

chengleiCoder發表於2019-02-28

最近大致分析了一把 Activity 啟動的流程,趁著今晚剛?完精神狀態好,把之前記錄的寫成文章。

開門見山,我們直接點進去看 Activity 的 startActivity , 最終,我們都會走到 startActivityForResult 這個方法,我們可以發現關鍵的程式碼:

Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);
複製程式碼

我們會發現 Activity 啟動其實都經過了一箇中轉站叫做 Instrumentation, 檢視InstrumentationexecStartActivity 方法:

/// 刪除了我們不關心的部分
try {
	intent.migrateExtraStreamToClipData();
	intent.prepareToLeaveProcess(who);
	int result = ActivityManager.getService().startActivity(whoThread, who.getBasePackageName(), intent,
                     intent.resolveTypeIfNeeded(who.getContentResolver()),token, target != null ? target.mEmbeddedID : null,requestCode, 0, null, options);
	checkStartActivityResult(result, intent);
	} catch (RemoteException e) {
		throw new RuntimeException("Failure from system", e);
	}
複製程式碼

我們會發現這裡通過 ActivityManager.getService 在進行通訊,進去檢視,我們發現這個 service 其實是一個 IActivityManager.aidl, 說明這裡我們進行了一次 Android 的 IPC。

全域性搜尋 extends IActivityManager 我們可以發現進行通訊的就是 ActivityManagerService , 檢視 startActivity 最終可以走到 ActivityStartstartActivityMayWait 方法。我們抽取它的關鍵程式碼:

Android Activity啟動流程原始碼分析

這部分我們可以看到根據 intent 解析除了需要的資訊,並根據資訊去獲取了跳轉 Activity 的系統許可權。

Android Activity啟動流程原始碼分析

這一部分程式碼,則對 intent 進行了處理和判斷,我們基本可以省略這部分非關鍵邏輯

最終我們會走到 startActivityLocked 方法,並走到 startActivity

Android Activity啟動流程原始碼分析

這裡我們會看到很多對於不同的 ActivityManager 的 狀態進行邏輯判斷和處理,這裡不影響我們的關鍵流程,我們可以繼續往下分析, 分析 doPendingActivityLaunchesLocked 方法

startActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null,
                        null, null /*outRecords*/);
複製程式碼

最終還是會走到另一個過載的 startActivity :

mService.mWindowManager.deferSurfaceLayout();
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
複製程式碼

檢視 startActivityUnchecked : 這裡程式碼邏輯比較長,我們檢視 ActivityStackSupervisor.resumeFocusedStackTopActivityLocked 方法

Android Activity啟動流程原始碼分析

繼續檢視 resumeTopActivityUncheckedLocked 方法, 跟蹤到 resumeTopActivityInnerLocked 方法:

Android Activity啟動流程原始碼分析

這邊我們檢視需要 restart 這個 Activity 的簡單情況,會呼叫 ActivityStackSupervisorstartSpecificActivityLocked 方法

Android Activity啟動流程原始碼分析

這裡我們找到了邏輯的關鍵:如果 app的執行緒和程式都存在,我們會執行 realStartActivityLocked 方法。否則,會繼續進行 IPC 通知 ActivityManagerService 去執行 startProcessLocked

這裡我們差不多能猜到啟動邏輯:

  1. 如果啟動的是我們自己 app 程式的 Activity, 那麼直接去啟動就好了
  2. 如果我們啟動的 Activity 所在的程式不存在,例如:我們把微信 kill 了,然後跳轉微信分享的 Activity,或者我們點選launch 的微信圖示,那麼,我麼就會走建立新程式的邏輯

那麼我們分別來跟蹤這2種情況:

啟動自己的Activity

Android Activity啟動流程原始碼分析

我們可以找到這段程式碼的關鍵邏輯,我們先分析下 app.thread 是什麼。跟蹤進去會發現是一個 IApplicationThread, 可以發現這裡又是一個 aidl, 最後我們可以找到 ApplicationThread

private class ApplicationThread extends IApplicationThread.Stub
複製程式碼

這是 ActivityThread 的一個靜態內部類,ActivtyThread和啟動Activity 相關,那麼這個類就應該是和 Application 啟動相關。

Android Activity啟動流程原始碼分析

我們會發現最後其實發了一個message 到訊息佇列中,找到 H 這個 handler 的 handleMessage 方法

case LAUNCH_ACTIVITY: {
	final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
	r.packageInfo = getPackageInfoNoCheck(
	r.activityInfo.applicationInfo, r.compatInfo);
	handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
} break;
複製程式碼

檢視 handleLaunchActivity 方法

Activity a = performLaunchActivity(r, customIntent);
複製程式碼

performLaunchActivity方法中可以看到

java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
複製程式碼

這裡,我們發現這裡通過 Insteumentation new 了一個 Activity

Android Activity啟動流程原始碼分析

Android Activity啟動流程原始碼分析

通過以上程式碼,我們還可以發現 new 出 Activity 後的幾個步驟

  1. attach Activity, 目測會有初始化 window 的流程
  2. 設定 theme
  3. Activity 的 onCreate 流程
  4. Activity 如果已經銷燬,會去執行 onRestoreInstance ,我們可以在這裡做資料恢復的操作
  5. Activity 在 onCreate 完成後的一些操作

到這裡,我們的 Activity 就啟動成功了

啟動新的程式

下面來分析我們的第二種情況,我們可以跟蹤到 ActivityManagerService 的 `startProcessLocked 方法, 這個方法最終會走到自己的過載方法:

Android Activity啟動流程原始碼分析

如果我們啟動的是一個 webview service, 則會走到 startWebView ,這裡我們不考慮,所以我們分析的是 Process.start 這種初始化一個普通程式的情況。

這個方法最後呼叫了 ZygoteProcessstart 方法

Android Activity啟動流程原始碼分析

這裡我們也可以大致分析出來,這裡就是在通過 socket 通訊請求 Zygote 程式 fork 一個子程式,作為新的 APP 程式,具體流程本篇文章暫時不做深究。

最終我們會啟動 ActivityThreadmain 方法,繼續走到 attach 方法

這裡我們能看到啟動主執行緒的 Looper, 建立系統 Context 等工作,最終我們走到 ApplicationThreadbindApplication , 程式碼這裡就不貼了,這裡負責了 Application 在初始化的時候的各種工作。包括 LoadedAPKmakeApplication 過程。

if (normalMode) {
	try {
		if (mStackSupervisor.attachApplicationLocked(app)) {
			didSomething = true;
		}
	} catch (Exception e) {
		Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
		badApp = true;
	}
}
複製程式碼

這裡會發現,正常模式下,我們走到了 ActivityStackSupervisorattachApplicationLocked 方法,後面就又會和第一部分介紹的一樣,走到 realStartActivityLocked 方法,去建立並執行 Activity 的生命週期。

總結

到這裡,Activity 的啟動流程就大致梳理出來了。基本就是,Instrumentation 負責 Activity 的建立和中轉, ActivityStackSupervisor 負責 Activity的 棧管理。Activity 都通過了 ActviityServerManager 來進行管理。

大概的關係如下圖所示:

Android Activity啟動流程原始碼分析

後續

這裡我只是對Activity的啟動流程做了一個簡單的梳理。我們會發現每個模組和細節都有幾百幾百行的程式碼。非常的複雜。下面的內容有興趣大家也可以細細探究。

  • 存在的 Activity 是怎麼管理的,怎麼走 onResume 去恢復的
  • Activity 不同的 launch mode是怎麼處理的
  • zygote fork 新的app程式的細節
  • LoadedApk 是怎麼載入 apk 的內容的
  • Activity 初始化完成後,內部是 window 又是怎麼初始化並且渲染上 UI 內容的

相關文章