【系統之音】Activity啟動流程——史上最全最簡潔易懂版

宋者為王發表於2020-08-15

        Activity的啟動流程是一個資深Android工程師必須掌握的內容,也是高職級面試中的高頻面試知識點,無論是從事應用層開發,還是Framework開發,其重要性都無需我多言。而要真正理解它,就不可避免地要深入到原始碼了,本文將從Android8.1系統原始碼入手,來抽絲剝繭。由於Activity的啟動流程涉及到的細節非常多而且複雜,為了便於讀理解,本文將摒棄眾多的細節,而著重於關鍵流程的梳理。

       儘管簡化了很多細節,但流程還是不少,為了便於讀者閱讀和理解,筆者會先給出重要的結論和UML序列圖,讀者正確的閱讀方式也是先知道梗概,再結合UML序列圖來看原始碼,同時最好能自己再IDE上開啟原始碼,順著筆者的思路去閱讀,否者會看得暈頭轉向。

 

1、啟動Activity的若干場景

       Activity的啟動有多種途徑,比較常見的有:

    (1)點選Launcher中的快捷圖示,這種方式進入的是根Activity;

    (2)從其它應用跳轉到某個應用的activity,這種場景下啟動的可以是根Activity,也可以是其它Activity,如:從某些應用撥打電話、開啟相機、開啟瀏覽器等;

    (3)同一個應用種從某個元件中啟動Activity。

      而啟動某個Activity的時候,也可能有兩種情形:

    (1)目標Activity所在應用程式程式不存在,也就是此時該應用還沒有啟動的情形;

    (2)目標Activity所在應用程式程式存在,也就是該應用之前啟動過。

      上面這些場景,Activity的啟動流程肯定是存在一定差異的,但核心流程基本一致,都是在基本流程基礎上或增或減部分流程。從Launcher中點選快捷圖示啟動一個根Activity的場景,就比較有代表性,本文將以此情形來介紹Activity的啟動流程。

 

2、根Activity啟動流程概貌

       這裡,我先給出結論,讀者們先巨集觀看看這其中大概有哪幾步。先上圖:

       從Launcher中點選快捷圖示到啟動根Activity過程中,主要涉及到4個程式的互動:Launcher所在應用程式、ActivityManagerService(後文簡稱AMS)所在的SystemServe系統程式、Zygote系統程式、目標根Activity所在的應用程式程式(這裡請讀者注意一下不同顏色所表示的不同程式,後文會與此保持一致)。

  (1)Launcher程式請求AMS建立根Activity。我們知道,在系統啟動過程中,會啟動SystemServer程式, AMS、PackageManagerService(後文簡稱PMS)也是在這個環節中啟動的,所以AMS是執行在SystemServer程式當中的。應用的根Activity會在AndroidManifest.xml檔案中註冊,PMS解析出這些資訊,並在Launcher中對這些包名、Activity路徑及名稱等資訊進行封裝,當點選快捷圖示時,Launcher會呼叫startActivity方法去啟動該圖示所對應的根Activity。然後在Luancher程式中通過層層呼叫,直到通過Binder方式實現IPC,流程就進入到AMS中,也就是SystemServer程式中。

  (2)AMS請求建立根Activity所在的程式。AMS收到Launcher程式啟動根Activity的請求後,會先判斷根Activity所在的程式是否已經建立過了,如果沒有建立過,則會向Zygote程式請求建立該程式,我們目前討論的情形就是根Activity所在程式沒有建立過的情況。我們知道,Zygote程式在啟動的時候,會作為服務端建立一個名為“zygote”的Socket,用於監聽AMS發起的建立新應用程式請求,所以此時流程進入到Zygote程式中。

  (3)Zygote程式fork出目標程式。Zygote收到AMS的請求後,會以fork的方式建立這個新的應用程式,此過程中會例項化一個ActivityThread物件,也就是一般所說的主執行緒,執行其入口main方法。

  (4)AMS排程應用程式建立和啟動根Activity。根Activity所在的應用程式程式被建立後,AMS在SystemServer程式中也經過層層呼叫,最終又通過Binder方式實現IPC,將啟動Activity的任務交給應用程式程式中的ApplicationThread本地代理,此後,流程進入到根Activity所在的應用程式程式中。這部分流程中,SystemServer中所做的工作主要是根Actifity建立和啟動前的一些準備工作,比如當前使用者許可權等。

  (5)在應用程式中完成根Activity的建立和啟動。在這裡將建立根Activity例項、Applicaiton例項,呼叫各個生命週期方法,並將DecorView(佈局檔案中的View會新增到DecorView中)新增到Window中顯示出來。 

       上文中涉及到系統啟動流程相關知識,比如Zygote、SystemServer、AMS、PMS 的啟動以及Zygote的功能,讀者不清楚的畫,最好先閱讀這篇文章:【系統之音】Android系統啟動篇

 

3、從Launcher到AMS

       先上UML序列圖 

       前面說過,點選Luancher中的快捷圖示的時候,會通過startActivity啟動其對應的Activity,Launcher程式中的這部分流程原始碼如下:

       Launcher.java的原始碼路徑:/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

 1 //==========Launcher.java========
 2 private void startAppShortcutOrInfoActivity(View v) {
 3      ......
 4      boolean success = startActivitySafely(v, intent, item);
 5      ......
 6 }
 7 
 8 public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
 9      ......
10      startActivity(intent, optsBundle);
11      ......
12 }
13 
14 //===========Activity.java========
15 /**
16  * Launch a new activity.
17  * ......
18  */
19 @Override
20 public void startActivity(Intent intent, @Nullable Bundle options) {
21     if (options != null) {
22         startActivityForResult(intent, -1, options);
23     } else {
24         ......
25         startActivityForResult(intent, -1);
26     }
27 }
28 
29 public void startActivityForResult(...) {
30    if (mParent == null) { //表示當前根Activity還沒有建立
31             ......
32             Instrumentation.ActivityResult ar =
33                 mInstrumentation.execStartActivity(
34                     this, mMainThread.getApplicationThread(), mToken, this,
35                     intent, requestCode, options);
36             ......
37         }
38 }
39 
40 //===========Instrumentation.java==============
41 public ActivityResult execStartActivity(...){
42        ......
43        int result = ActivityManager.getService()
44                        .startActivity(whoThread, who.getBasePackageName(), intent,
45                                intent.resolveTypeIfNeeded(who.getContentResolver()),
46                                token, target != null ? target.mEmbeddedID : null,
47                                requestCode, 0, null, options); //程式碼①
48        ......
49 }

通過上述程式碼後,流程就從Launcher程式進入到AMS所在的SystemServer程式了, 這部分流程比較簡單,這裡就不做過多解釋了。這裡重點看一下程式碼①處(第43行)的ActivityManager.getService():

 1 //=========ActivityManager.java=========
 2 public static IActivityManager getService() {
 3     return IActivityManagerSingleton.get();
 4 }
 5 private static final Singleton<IActivityManager> IActivityManagerSingleton =
 6         new Singleton<IActivityManager>() {
 7             @Override
 8             protected IActivityManager create() {
 9                 final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
10                 final IActivityManager am = IActivityManager.Stub.asInterface(b);
11                 return am;
12             }
13         };
14 
15 //=================Singleton.java=========
16 /**
17  * Singleton helper class for lazily initialization.
18  * ......
19  */
20 public abstract class Singleton<T> {
21     private T mInstance;
22 
23     protected abstract T create();
24 
25     public final T get() {
26         synchronized (this) {
27             if (mInstance == null) {
28                 mInstance = create();
29             }
30             return mInstance;
31         }
32     }
33 }

ActivityManager.getService()這句程式碼實際上就是通過單例模式獲取AMS在Launcher程式中的遠端代理,類似這樣的程式碼實現在系統原始碼種還是比較常見的。

 

4、從AMS到ApplicationThread(ActivityThread)

      先上UML序列圖:

        這一部分的啟動流程呼叫非常繁瑣,可謂是“峰迴路轉”,筆者在跟進其呼叫流程時差點昏厥了,大有“山重水複疑無路”的困惑,直到看到下面程式碼:

1 final boolean realStartActivityLocked(...){
2       ......
3       app.thread.scheduleLaunchActivity(...); //程式碼②
4       ......
5 }

此時又深感“柳暗花明又一村”了。ApplicationThread是ActivityThread中的一個內部類,也是應用程式程式中的一個服務(Stub),通過Binder方式對外提供服務:

1 //=======ActivityThread.java======
2 private class ApplicationThread extends IApplicationThread.Stub {
3       ......
4       public final void scheduleLaunchActivity(...){
5             ......
6       }
7       ......
8 }

這裡我們需要重點理解下圖中的模型:

       每個應用程式都執行在一個獨立的程式中(當然也可以宣告為多個程式,這裡不做討論),不同程式之間記憶體等資源是不能直接共享的,只能通過Binder方式來和外界互動。這就好比系統像個大海,應用程式程式就像一座座孤島,而Binder就是孤島之間的橋樑或者船隻。上圖中模擬了應用程式程式與SystemServer程式的互動方式,應用程式程式持有了SystemServer程式中AMS/WMS等系統服務的遠端代理Proxy,通過這個Proxy來呼叫SystemServer程式中的系統服務;SystemServer程式中也持有了應用程式程式中的ApplicationThread的遠端代理Proxy,通過這個Proxy來呼叫應用程式程式中的方法。

       程式碼②處的app.thread就是ApplicationThread在SystemServer端的遠端代理(Proxy),正式通過這個遠端代理呼叫根Activity所在應用程式程式中的相關方法的從這裡開始,流程就進入到目標應用程式程式了。

       由於該部分又繁瑣,又沒有涉及到直接建立和啟動Activity的程式碼,所以這裡就不貼程式碼了。對於這一部分的流程,個人建議讀者沒有必要太糾結細節,知道其大概做了些什麼就夠了。

 

5、在應用程式程式中建立和啟動根Activity

       先看看ActivityThread類主要結構

       ActivityThread一般被稱作主執行緒(當然它不是真正的執行緒),它包含兩個很重要的內部類,ApplicationThread(前面已經介紹過了)和H。這個H是Handler的子類,擁有主執行緒的looper,所以其Callback的回撥函式handleMessage執行在主現在當中,所以這個H類的作用其實就是將執行緒切換到主執行緒。

       我們結合上圖來看看如下原始碼:

 1 //=======ActivityThread.java======
 2 private class ApplicationThread extends IApplicationThread.Stub {
 3       ......
 4       public final void scheduleLaunchActivity(...){
 5             ActivityClientRecord r = new ActivityClientRecord();
 6             ......
 7             r.intent = intent;
 8             ......
 9             sendMessage(H.LAUNCH_ACTIVITY, r);
10       }
11       ......
12 }
13 
14 private void sendMessage(int what, Object obj) {
15     sendMessage(what, obj, 0, 0, false);
16 }
17 
18 private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
19     ......
20     Message msg = Message.obtain();
21     msg.what = what;
22     msg.obj = obj;
23     msg.arg1 = arg1;
24     msg.arg2 = arg2;
25     ......
26     mH.sendMessage(msg);
27 }
28 
29 final H mH = new H();
30 private class H extends Handler {
31     public static final int LAUNCH_ACTIVITY = 100;
32     public void handleMessage(Message msg) {
33         switch (msg.what) {
34                 case LAUNCH_ACTIVITY: {
35                       ......
36                       handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");//程式碼③
37                       ......
38                 }
39     }
40      ......
41 }

這樣就明確了,此時的流程,又由ApplicationThread經過Handler進入到了主執行緒(ActivityThread)中了。

從程式碼③處開始,流程就由主執行緒ActivityThread來處理了,還是先上UML序列圖:

 參照該圖和如下原始碼,來看看應用程式程式是如何建立和啟動Activity的:

 1 //=======ActivityThread.java=======
 2 private void handleLaunchActivity(...){
 3      ......
 4      WindowManagerGlobal.initialize();//程式碼④
 5      ......
 6      Activity a = performLaunchActivity(r, customIntent);//程式碼⑤
 7      if (a != null) {
 8          handleResumeActivity(...);//程式碼⑫
 9      }
10      ......
11 }

程式碼④,其作用是通過單例模式獲取一個WMS在應用程式程式中的遠端代理Proxy,我們知道,後面Activity中setContentView載入的layout檔案,就需要通過WMS新增到Window中來顯示。該方法程式碼比較簡單:

 1 //========WindowManagerGlobal.java======
 2 ......
 3 private static IWindowManager sWindowManagerService;
 4 ......
 5 public static void initialize() {
 6     getWindowManagerService();
 7 }
 8 ......
 9 public static IWindowManager getWindowManagerService() {
10     synchronized (WindowManagerGlobal.class) {
11         if (sWindowManagerService == null) {
12             sWindowManagerService = IWindowManager.Stub.asInterface(
13                     ServiceManager.getService("window"));
14             ......
15         }
16         return sWindowManagerService;
17     }
18 }

進入到程式碼⑤處:

 1 //===========ActivityThread.java=======
 2 private Activity performLaunchActivity(...){
 3         ......
 4         Activity activity = null;
 5         try {
 6             java.lang.ClassLoader cl = appContext.getClassLoader();
 7             activity = mInstrumentation.newActivity(
 8                     cl, component.getClassName(), r.intent);//程式碼⑥
 9             ......
10         } catch (Exception e) {
11             ......
12         }
13         try {
14             Application app = r.packageInfo.makeApplication(false, mInstrumentation);//程式碼⑦
15               ......
16               activity.attach(...);
17               ......
18              if (r.isPersistable()) {
19                     mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); //程式碼⑩-1
20                 } else {
21                     mInstrumentation.callActivityOnCreate(activity, r.state);//程式碼⑩-2
22                 }
23               ......
24                 if (!r.activity.mFinished) {
25                     activity.performStart();//程式碼⑪
26                     ......
27                 }
28               ......
29              } catch (Exception e) {
30             ......
31         }
32         ......
33 }

程式碼⑥處,以ClassLoader的方式建立Activity例項:

 1 //================Instrumentation.java=====
 2 /**
 3  * Perform instantiation of the process's {@link Activity} object.
 4  * ......
 5  * @return The newly instantiated Activity object.
 6  */
 7 public Activity newActivity(ClassLoader cl, String className,
 8         Intent intent)
 9         throws InstantiationException, IllegalAccessException,
10         ClassNotFoundException {
11     return (Activity)cl.loadClass(className).newInstance();
12 }

從程式碼⑦處深入,該程式碼的作用在於處理Application相關的業務:

 1 //=========LoadedApk.java=========
 2 public Application makeApplication(...){
 3     if (mApplication != null) {
 4             return mApplication;
 5         }
 6      ......
 7      Application app = null;
 8      ......
 9         try {
10             java.lang.ClassLoader cl = getClassLoader();
11             ......
12             app = mActivityThread.mInstrumentation.newApplication(
13                     cl, appClass, appContext); //程式碼⑧
14             ......
15         } catch (Exception e) {
16            ......
17         }
18         mActivityThread.mAllApplications.add(app);
19         mApplication = app;
20         if (instrumentation != null) {
21             try {
22                 instrumentation.callApplicationOnCreate(app);//程式碼⑨
23             } catch (Exception e) {
24                 ......
25             }
26         }
27         ......
28 }

程式碼⑧處,也是以ClassLoader方式建立Application例項:

 1 //================Instrumentaion.java=========
 2 /**
 3  * Perform instantiation of the process's {@link Application} object.
 4  * ......
 5  * @return The newly instantiated Application object.
 6  */
 7 public Application newApplication(ClassLoader cl, String className, Context context)
 8         throws InstantiationException, IllegalAccessException,
 9         ClassNotFoundException {
10     return newApplication(cl.loadClass(className), context);
11 }
12 
13 /**
14  * Perform instantiation of the process's {@link Application} object.
15  * ......
16  * @return The newly instantiated Application object.
17  */
18 static public Application newApplication(Class<?> clazz, Context context)
19         throws InstantiationException, IllegalAccessException,
20         ClassNotFoundException {
21     Application app = (Application)clazz.newInstance();
22     app.attach(context);
23     return app;
24 }

程式碼⑨處,呼叫Application的onCreate方法,在自定義的Application中,重寫的onCreate方法開始執行:

 1 //=============LoadedApk.java========
 2 /**
 3  * Perform calling of the application's {@link Application#onCreate} method.
 4  * ......
 5  * @param app The application being created.
 6  */
 7 public void callApplicationOnCreate(Application app) {
 8     app.onCreate();
 9 }
10 
11 //=========Application.java========
12 @CallSuper
13 public void onCreate() {
14 }

程式碼⑩(程式碼⑩-1或程式碼⑩-2)中,執行Activity的onCreate方法,根Activity中的onCreate方法執行:

 1 //==============Instrumentation.java========
 2 /**
 3  * Perform calling of an activity's {@link Activity#onCreate} method.
 4  * ......
 5  */
 6 public void callActivityOnCreate(Activity activity, Bundle icicle) {
 7     prePerformCreate(activity);
 8     activity.performCreate(icicle);
 9     postPerformCreate(activity);
10 }
11 /**
12  * Perform calling of an activity's {@link Activity#onCreate} method.
13  * ......
14  */
15 public void callActivityOnCreate(Activity activity, Bundle icicle,
16         PersistableBundle persistentState) {
17     prePerformCreate(activity);
18     activity.performCreate(icicle, persistentState);
19     postPerformCreate(activity);
20 }
21 
22 //==========Activity.java========
23 final void performCreate(Bundle icicle) {
24     performCreate(icicle, null);
25 }
26 final void performCreate(Bundle icicle, PersistableBundle p
27     ......
28     if (persistentState != null) {
29         onCreate(icicle, persistentState);
30     } else {
31         onCreate(icicle);
32     }
33     ......
34 }
35 
36 public void onCreate(@Nullable Bundle savedInstanceState,
37         @Nullable PersistableBundle persistentState) {
38     onCreate(savedInstanceState);
39 }
40 
41 @MainThread
42 @CallSuper
43 protected void onCreate(@Nullable Bundle savedInstanceState) {
44     ......
45 }
程式碼⑪開始執行Activity的onStart方法,根Activity的onStart方法開始執行:
 1 //======Activity.java======
 2 final void performStart() {
 3     ......
 4     mInstrumentation.callActivityOnStart(this);
 5     ......
 6 }
 7 
 8 //=========Instrumentation.java=========
 9 /**
10  * Perform calling of an activity's {@link Activity#onStart} method.
11  * ......
12  */
13 public void callActivityOnStart(Activity activity) {
14     activity.onStart();
15 }
16 
17 //======Activity.java======
18 @CallSuper
19 protected void onStart() {
20     ......
21 }
程式碼⑫的handleResumeActivity方法用於處理resume相關的業務:
 1 //========ActivityThread.java======
 2 final void handleResumeActivity(...){
 3       ......
 4       r = performResumeActivity(token, clearHide, reason);//程式碼⑬
 5       ......
 6       //如下過程將DecorView新增到視窗中 程式碼段⑯
 7       r.window = r.activity.getWindow(); //PhoneWindow例項
 8       View decor = r.window.getDecorView(); //DecorView例項
 9       decor.setVisibility(View.INVISIBLE);
10       ViewManager wm = a.getWindowManager();
11       WindowManager.LayoutParams l = r.window.getAttributes();
12       a.mDecor = decor;
13       ......
14       ViewRootImpl impl = decor.getViewRootImpl();
15       ......
16       wm.addView(decor, l);
17       ......
18 }

深入程式碼⑬中:

 1 //======ActivityThread=======
 2 public final ActivityClientRecord performResumeActivity(...){
 3       ......
 4       r.activity.performResume();
 5       ......
 6 }
 7 
 8 //======Activity.java=====
 9 final void performResume() {
10      performRestart();//程式碼⑭
11      ......
12      mInstrumentation.callActivityOnResume(this);//程式碼⑮
13      ......
14 }

程式碼⑭用於處理reStart相關的業務,當前場景是新建立根Activity,所以不會走這個流程;如果是從其它介面回退到這個activity,就會走呼叫onRestart和onStart的流程:

 1 //===========Activity.java========
 2 final void performRestart() {
 3      ......
 4      if (mStopped) {
 5           mStopped = false;
 6           ......
 7           mInstrumentation.callActivityOnRestart(this);
 8           ......
 9           performStart();
10      }
11 }
12 
13 //============Instrumentation.java===========
14 /**
15  * Perform calling of an activity's {@link Activity#onRestart} method.
16  * ......
17  * @param activity The activity being restarted.
18  */
19 public void callActivityOnRestart(Activity activity) {
20     activity.onRestart();
21 }
22 
23 //===========Activity.java===========
24 @CallSuper
25 protected void onRestart() {
26     mCalled = true;
27 }
28 
29 final void performStart() {
30      ......
31      mInstrumentation.callActivityOnStart(this);
32      ......
33 }
34 
35 //============Instrumentation.java==========
36 /**
37  * Perform calling of an activity's {@link Activity#onStart} method.
38  *  ......
39  * @param activity The activity being started.
40  */
41 public void callActivityOnStart(Activity activity) {
42     activity.onStart();
43 }
44 //==============Activity.java============
45 @CallSuper
46 protected void onStart() {
47    ......
48 }

程式碼⑮處呼叫acitvity的onResume方法,這樣一來根Activity的onResume回撥方法就執行了:

 1 //========Instrumentation.java=========
 2 /**
 3  * Perform calling of an activity's {@link Activity#onResume} method.
 4  *  ......
 5  * @param activity The activity being resumed.
 6  */
 7 public void callActivityOnResume(Activity activity) {
 8     ......
 9     activity.onResume();
10     ......
11 }
12 
13 @CallSuper
14 protected void onResume() {
15     ......
16 }

程式碼段⑯(對應第7~16行)的作用在於將DecorView新增到Window,並完成介面的繪製流程。我們知道,根Activity在onCreate生命週期回撥方法中會通過setContentView方法載入layout佈局檔案,將其加入到DecorView中,繪製部分詳情可以閱讀【【朝花夕拾】Android自定義View篇之(一)View繪製流程】。

       這樣,應用程式程式就完成了根Activity的建立和啟動,介面也完成了顯示。從上面的UML圖和原始碼分析,可以發現這部分筆者是按照Activity的生命週期為主線來介紹的,實際上讀者完全可以結合Activity的生命週期來理解和記憶這部分的主要流程。下圖再次總結了這部分的主要流程:

 

       想必讀者應該對第4~7步的生命週期順序非常熟悉了。需要注意的是,第2和第3步可能會和我們平時的認知有些出入,實際上Activity的例項比Application的例項要更早建立。第1和第8步是關於圖形介面顯示的,也需要重點關心。

6、其它場景啟動流程

       到目前為止,從Laucher中點選一個快捷圖示來啟動根Activity的整個流程就介紹完畢了,這個場景搞清楚了,其它場景就不在話下了。比如,從Launcher中啟動一個應用程式程式已經啟動的應用的根Activity,就在上述流程基礎上少了Zytote建立應用程式程式這一步,如下圖:

 比如,應用程式內部啟動另外一個新Activity時,就只需要考慮應用程式程式和SystemSever兩個程式,如下圖:

還有從其它應用中啟動指定某另外應用中的Activity的場景和從Launcher啟動的流程類似;再次開啟一個已經啟動的Activity,就無需走create流程,而是走onRestart-onStart-onResume生命週期流程,等等,這裡就不一一列舉了。 

相關文章