上篇鏈接:深入理解四大組件(一)Android8.0 根 Activity 的啟動過程(上)
1. ActivityThread 啟動 Activity 的過程
通過上篇知識點合冀,我們知道目前的代碼邏輯運行在應(yīng)用程序進(jìn)程中府阀。先來查看 ActivityThread 啟動 Activity 過程的時序圖掩宜,如圖所示:
接著查看 ApplicationThread 的 scheduleLaunchActivity 方法旦事,其中 ApplicationThread 是 ActivityThread 的內(nèi)部類,應(yīng)用程序進(jìn)程創(chuàng)建后會運行代表主線程的實例 ActivityThread族吻,它管理著當(dāng)前應(yīng)用程序進(jìn)程的主線程帽借。ApplicationThread 的 scheduleLaunchActivity 方法如下所示:
frameworks/base/core/java/android/app/ActivityThread.java
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
···
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
scheduleLaunchActivity 方法將啟動 Activity 的參數(shù)封裝成 ActivityClientRecord珠增,sendMessage 方法向 H 類發(fā)送類型為 LAUNCH_ACTIVITY 的消息,并將 ActivityClientRecord 傳遞過去砍艾,sendMessage 方法有多個重載方法蒂教,最終調(diào)用的 sendMessage 方法如下所示:
frameworks/base/core/java/android/app/ActivityThread.java
private void sendMessage(int what, Object obj, int arg1, int arg2, int seq) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + mH.codeToString(what) + " arg1=" + arg1 + " arg2=" + arg2 +
"seq= " + seq);
Message msg = Message.obtain();
msg.what = what;
SomeArgs args = SomeArgs.obtain();
args.arg1 = obj;
args.argi1 = arg1;
args.argi2 = arg2;
args.argi3 = seq;
msg.obj = args;
mH.sendMessage(msg);
}
這里的 mH 指的是 H,它是 ActivityThread 的內(nèi)部類并繼承自 Handler,是應(yīng)用程序進(jìn)程中主線程的消息管理類脆荷。因為 ApplicationThread 是一個 Binder悴品,它的調(diào)用邏輯運行在 Binder 線程池中,所以這里需要用 H 將代碼的邏輯切換到主線程中简烘。H 的代碼如下所示:
frameworks/base/core/java/android/app/ActivityThread.java
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
...
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj; //1
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo); //2
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY"); //3
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case RELAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
}
查看 H 的 handleMessage 方法中對 LAUNCH_ACTIVITY 的處理,在注釋 1 處將傳過來的 msg 的成員變量 obj 轉(zhuǎn)換為 ActivityClientRecord定枷。在 注釋 2 處通過 getPackageInfoNoCheck 方法獲得 LoadedApk 類型的對象并賦值給 ActivityClientRecord 的成員變量 packageInfo孤澎。應(yīng)用程序進(jìn)程要啟動 Activity 時需要將該 Activity 所屬的 APK 加載進(jìn)來,而 LoadApk 就是用來描述已加載的 APK 文件的欠窒。在注釋 3 處調(diào)用 handleLaunchActivity 方法覆旭,代碼如下所示:
frameworks/base/core/java/android/app/ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...
WindowManagerGlobal.initialize();
//啟動Activity
Activity a = performLaunchActivity(r, customIntent); //1
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
//將Activity的狀態(tài)置為Resume
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason); //2
if (!r.activity.mFinished && r.startsNotResumed) {
performPauseActivityIfNeeded(r, reason);
if (r.isPreHoneycomb()) {
r.state = oldState;
}
}
} else {
try {
//停止Activity啟動
ActivityManager.getService()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
注釋 1 處的 performLaunchActivity 方法用來啟動 Activity,注釋 2 處的代碼用來將 Activity 的狀態(tài)設(shè)置為 Resume岖妄。如果該 Activity 為 null 則會通知 AMS 停止啟動 Activity型将。下面來查看 performLaunchActivity 方法做了什么:
frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//獲取ActivityInfo類
ActivityInfo aInfo = r.activityInfo; //1
if (r.packageInfo == null) {
//獲取APK文件的描述類LoadedApk
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE); //2
}
ComponentName component = r.intent.getComponent(); //3
...
//創(chuàng)建要啟動Activity的上下文環(huán)境
ContextImpl appContext = createBaseContextForActivity(r); //4
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
//用類加載器來創(chuàng)建該Activity的實例
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent); //5
...
} catch (Exception e) {
...
}
try {
//創(chuàng)建Application
Application app = r.packageInfo.makeApplication(false, mInstrumentation); //6
...
if (activity != null) {
...
/**
* 7 初始化Activity
*/
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); //8
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
}
r.paused = true;
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
...
}
return activity;
}
注釋 1 處用來獲取 ActivityInfo,用于儲存代碼以及 AndroidManifes 設(shè)置的 Activity 和 Receiver 節(jié)點信息荐虐,比如 Activity 的 theme 和 launchMode七兜。在注釋 2 處獲取 APK 文件的描述類 LoadedApk。在注釋 3 處獲取要啟動的 Activity 的 ComponentName 類福扬,在 ComponentName 類中保存了該 Activity 的包名和類名腕铸。注釋 4 處用來創(chuàng)建要啟動 Activity 的上下文環(huán)境。注釋 5 處根據(jù) ComponentName 中儲存的 Activity 類名铛碑,用類加載器來創(chuàng)建該 Activity 的實例狠裹。注釋 6 處用來創(chuàng)建 Application,makeApplication 方法內(nèi)部會調(diào)用 Application 的 onCreate 方法汽烦。注釋 7 處調(diào)用 Activity 的 attach 方法初始化 Activity涛菠,在 attach 方法中會創(chuàng)建 Window 對象(PhoneWindow)并與 Activity 自身進(jìn)行關(guān)聯(lián)撇吞。在注釋 8 處調(diào)用 Instrumentation 的 callActivityOnCreate 方法來啟動 Activity俗冻,如下所示:
frameworks/base/core/java/android/app/Instrumentation.java
public void callActivityOnCreate(Activity activity, Bundle icicle,
PersistableBundle persistentState) {
prePerformCreate(activity);
activity.performCreate(icicle, persistentState); //1
postPerformCreate(activity);
}
注釋 1 處調(diào)用了 Activity 的 performCreate 方法,代碼如下所示:
frameworks/base/core/java/android/app/Activity.java
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
restoreHasCurrentPermissionRequest(icicle);
onCreate(icicle, persistentState);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
在 performCreate 方法中調(diào)用 Activity 的 onCreate 方法言疗,講到這里死姚,根 Activity 就啟動了,即應(yīng)用程序就啟動了碰缔。根 Activity 啟動過程就講到這里账劲,下面我們來學(xué)習(xí)根 Activity 啟動過程中涉及的進(jìn)程。
2. 根 Activity 啟動過程中涉及的進(jìn)程
根 Activity 啟動過程中會涉及 4 個進(jìn)程金抡,分別是 Zygote 進(jìn)程瀑焦、Launcher 進(jìn)程、AMS 所在的進(jìn)程(SystemServer進(jìn)程)梗肝、應(yīng)用程序進(jìn)程榛瓮。它們之間的關(guān)系如圖所示:
首先 Launcher 進(jìn)程向 AMS 請求創(chuàng)建根進(jìn)程 Activity,AMS 會判斷根 Activity 所需的應(yīng)用程序進(jìn)程是否存在并啟動巫击,如果不存在就會請求 Zygote 進(jìn)程創(chuàng)建應(yīng)用程序進(jìn)程禀晓。應(yīng)用程序進(jìn)程啟動后,AMS 會請求創(chuàng)建應(yīng)用程序進(jìn)程并啟動根 Activity坝锰。其中步驟 2 采用的是 Socket 通信粹懒,步驟 1 和步驟 4 采用的是 Binder 通信。為了更好理解顷级,下面給出這個 4 個進(jìn)程調(diào)用的時序圖凫乖,如圖所示:
總結(jié)
如果普通 Activity 啟動過程會涉及幾個進(jìn)程呢?答案是兩個愕把,AMS 所在進(jìn)程和應(yīng)用程序進(jìn)程拣凹。實際上理解了根 Activity 的啟動過程(根 Activity 的 onCreate 過程),根 Activity 和普通 Activity 其他生命周期狀態(tài)(比如 onStart恨豁、onResume 等)過程也會很輕松掌握嚣镜,這些知識點都是觸類旁通的。這兩篇的文章講解了根 Activity 的啟動過程橘蜜,下面我們對其他四大組件的啟動過程進(jìn)行學(xué)習(xí)菊匿!
學(xué)習(xí)資料主要來源于《Android進(jìn)階解密》