Kotlin進階-10-Activity的啓動流程

目錄

1、介紹

2、Launcher 請求 AMS 過程

3、 AMS 到 ApplicationThread的調用過程

4、ActivityThread 啓動 Activity 的過程

5、根 Activity 啓動過程中涉及的進程


1、介紹

Activity的啓動過程分爲兩種,一種是根Activity的啓動過程,另一種是普通Activity的啓動過程。根Activity指的是應用程序啓動的第一個Activity,因此根Activity的啓動過程一般情況下也可以理解爲應用程序的啓動過程。普通Activity指的是除應用程序啓動的第一個Activity之外的其他Activity。

根Activity的啓動過程比較複雜,因此這裏分爲 3 個部分來講,分別是 :

1、Launcher 請求 AMS 過程

2、AMS 到 ApplicationThread 的調用過程

3、ActivityThread 啓動 Activity

2、Launcher 請求 AMS 過程

在Android系統中,Launcher的重要作用有兩點:
(1)作爲Android系統的啓動器,用來啓動應用程序。
(2)作爲Android系統的桌面,用於顯示和管理應用程序的快捷圖標或者其他桌面組件。

當 Luancher 啓動後會將已安裝應用程序的快捷圖標顯示到桌面上,這些應用程序的快捷圖標就是啓動根Activity的入口,當我們點擊某個應用程序的快捷圖標時,就會通過 Launcher 請求 AMS 來啓動該應用程序。Launcher 請求 AMS 的時序圖如圖所示:

1、當我們點擊應用程序的快捷圖標時,就會調用 Launcher 的 startActivitySafely 方法,如下所示:

該類在該包內:packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

2、在紅色框內處將 Flag 設置爲 Intent.FLAG_ACTIVITY_NEW_TASK ,這樣根 Activity 會在新的任務棧中啓動;

在藍色框處會調用 startActivity() 方法,這個 startActivity() 方法在 Activity 中實現,如下所示:

frameworks/base/core/java/android/app/Activity.java

3、在 startActivity 方法中調用 startActivityForResult 方法,它的第二個參數爲 -1,表示 Launcher 不需要知道 Activity 啓動的結果,startActivityForResult 方法的代碼如下所示:

frameworks/base/core/java/android/app/Activity.java

4、上面的 mParent 是 Activity 類型的,表示當前 Activity 的父類。因爲目前根 Activity 還沒有創建出來,因此,mParent == null 成立。

接着調用 InstrumentationexecStartActivity() 方法,Instrumentation 主要用來監控應用程序和系統的交互,execStartActivity() 方法的代碼如下所示:

frameworks/base/core/java/android/app/Instrumentation.java

5、首先調用 ActivityManager 的 getService() 方法來獲取 AMS 的代理對象,按着調用它的 startActivity 方法。

這裏與 Android 8.0 之前代碼的邏輯有些不同,Android 8.0 之前是通過 ActivityManagerNative 的 getDefault 來獲取 AMS 的代理對象的,現在這個邏輯封裝到了 ActivityManager 中而不是 ActivityManagerNative 中。

首先我們來查看 ActivityManager 的 getService 方法做了什麼:

frameworks/base/core/java/android/app/ActivityManager.java

6、getService() 方法調用了 IActivityManagerSingleton 的 get() 方法,我們接着往下看,IActivityManagerSingleton 是一個 Singleton 類。

在紅框中第一行處得到名爲 "activity" 的 Service 引用,也就是 IBinder 類型的 AMS 的引用。

接着在紅框中第二行處將它轉換成 IActivityManager 類型的對象,這段代碼採用的是 AIDL,IActivityManager.java 類是由 AIDL 工具在編譯時自動生成的,IActivityManager.aidl 的文件路徑爲 frameworks/base/core/java/android/app/IActivityManager.aidl

要實現進程間通信,服務器端也就是 AMS 只需要繼承 IActivityManager.Stub 類並實現相應的方法就可以了。

注意 Android 8.0 之前並沒有採用 AIDL,而是採用了類似 AIDL 的形式,用 AMS 的代理對象 ActivityManagerProxy 來與 AMS 進行進程間通信,Android 8.0 去除了 ActivityManagerNative 的內部類 ActivityManagerProxy,代替它的是 IActivityManager,它是 AMS 在本地的代理。

回到 Instrumentation 類的 execStartActivity 方法中,從上面得知 execStartActivity 方法最終調用的是 AMS 的 startActivity 方法。

3、 AMS 到 ApplicationThread的調用過程

Luancher 請求 AMS 後,代碼邏輯已進入 AMS 中,接着是 AMS 到 ApplicationThread 的調用流程,時序圖如果所示:

7、AMS中的startActivity()方法如下所示:

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

8、在 AMS 的 startActivity() 方法中返回了 startActivityAsUser() 方法,可以發現 startActivityAsUser() 方法比 startActivity() 方法多了一個參數 UserHandle.getCallingUserId(),這個方法會獲得調用者的 UserId,AMS 根據這個 UserId 來確定調用者的權限

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

9、在黃色框處判斷調用者進程是否被隔離,如果被隔離則拋出 SecurityException 異常,

在綠色框 處檢查調用者是否有權限,如果沒有權限也會拋出 SecurityException 異常。

最後通過 mActivityStartController.obtainStarter()獲取到了ActivityStarter對象,並執行了它的execute()方法。

frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

10、在上面execute()方法中會通過mRequest.mayWait字段來判斷最後執行startActivityMayWait()或者startActivity().(這一步是在Android9.0添加的)

mRequest.mayWait字段的值,在ActivityManagerService中調用execute()的前,就調用了setMayWait()方法賦值爲了true。

最後調用了 startActivityMayWait() 方法,startActivityMayWait ()方法的參數要比 startActivityAsUser() 多幾個,需要注意的是倒數第三個參數類型爲 TaskRecord,代表啓動的 Activity 所在的棧。

startActivityMayWait() 方法的代碼如下所示:

11、ActivityStarter 是 Android 7.0 中新加入的類,它是加載 Activity 的控制類,會收集所有的邏輯來決定如何將 Intent 和 Flags 轉換爲 Activity,並將 Activity 和 Task 以及 Stack 相關聯。

ActivityStarter 的 startActivityMayWait() 方法調用了 startActivity()方法,如下所示:

frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

12、在上面代碼中我們看到會對啓動原因 reason進行判斷,判斷啓動的理由不爲空,如果爲空則拋出 IllegalArgumentException 異常。緊接着又調用了 startActivity 方法,如下所示:

frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

13、ActivityStarter 的 startActivity 方法邏輯比較多,這裏列出部分我們需要關心的代碼。

在藍色框 處判斷 IApplicationThread 類型的 caller 是否爲 null,這個 caller 是方法調用一路傳過來的,指向的是 Launcher 所在的應用程序的 ApplicationThread 對象;

在綠色框 處調用 AMS 的 getRecordForAppLocked 方法得到的是代表 Launcher 進程的 callerApp 對象,它是 ProcessRecord 類型的,ProcessRecord 用於描述一個應用程序進程。

同樣地,ActivityRecord 用於描述一個 Activity,用來記錄一個 Activity 的所有信息。接下來創建 ActivityRecord,用於描述將要啓動的 Activity,並在紅色框處將創建的 ActivityRecord 賦值給 ActivityRecord [] 類型的 outActivity,

這個 outActivity 會作爲最底部 的 startActivity 方法的參數傳遞下去。

frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

14、startActivity 方法緊接着調用了 startActivityUnchecked() 方法:

frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

15、startActivityUnchecked 方法主要處理與棧管理相關的邏輯。

根據上文中 startActivitySafely 方法我們得知,啓動根 Activity 時會將 Intent 的 Flag 設置爲 FLAG_ACTIVITY_NEW_TASK,這樣藍色框 處的條件判斷就會滿足;

接着執行綠色框處的 setTaskFromReuseOrCreateNewTask 方法,其內部會創建一個新的 TaskRecord,用來描述一個 Activity 任務棧,也就是說 setTaskFromReuseOrCreateNewTask 方法內部會創建一個新的 Activity 任務棧。

在黃色框處會調用 ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked 方法,如下所示:

frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

16、在紅色框第一行 處調用 ActivityStack 的 topRunningActivityLocked 方法獲取要啓動的 Activity 所在棧的棧頂的不是處於停止狀態的 ActivityRecord。

在紅色框第二行處,如果 ActivityRecord 不爲 null,或者要啓動的 Activity 的狀態不是 RESUMED 狀態,就會調用紅色框第三行  處的 ActivityStack 的 resumeTopActivityUncheckedLocked 方法。

對於即將啓動的 Activity,紅色框第二行 處的條件判斷是肯定滿足的,我們來查看 ActivityStack 的resumeTopActivityUncheckedLocked 方法,如下所示:

frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

17、緊接着查看紅色框處 ActivityStack 的 resumeTopActivityInnerLocked 方法:

frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

18、resumeTopActivityInnerLocked 方法代碼非常多,我們只需要關注調用了 ActivityStackSupervisor 的 startSpecificActivityLocked 方法,代碼如下所示。

frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

19、在黃色框處獲取即將啓動的 Activity 所在的應用程序進程;

在綠色框 處判斷要啓動的 Activity 所在的應用程序進程如果已經運行的話;

就會調用紅色框 處的 realStartActivityLocked 方法,這個方法的第二個參數是代表要啓動的 Activity 所在的應用程序進程 ProcessRecord。

frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

20、這裏的 app.thread 指的是 IApplicationThread,它的實現是 ActivityThread 的內部類 ApplicationThread,其中 ApplicationThread 繼承了 IApplicationThread.Stub。

app 指的是傳入的要啓動的 Activity 所在的應用程序進程,因此,這段代碼指的就是要在目標應用程序進程啓動 Activity。當前代碼邏輯運行在 AMS 所在的進程(SystemServer 進程)中,通過 ApplicationThread 來與應用程序進程進行 Binder 通信,換句話說,ApplicationThread 是 AMS 所在進程(SystemServer 進程)和應用程序進程的通信橋樑,如圖所示:

4、ActivityThread 啓動 Activity 的過程

通過上面的講解,我們知道目前的代碼邏輯已經運行在應用程序進程中。先來查看 ActivityThread 啓動 Activity 過程的時序圖,如圖所示:

21、接着查看 ApplicationThread 的 scheduleLaunchActivity 方法,其中 ApplicationThread 是 ActivityThread 的內部類,應用程序進程創建後會運行代表主線程的實例 ActivityThread,它管理着當前應用程序進程的主線程。

ApplicationThread 的 scheduleLaunchActivity 方法如下所示:

frameworks/base/core/java/android/app/ActivityThread.java

22、scheduleLaunchActivity 方法將啓動 Activity 的參數封裝成 ActivityClientRecord,sendMessage 方法向 H 類發送類型爲 LAUNCH_ACTIVITY 的消息,並將 ActivityClientRecord 傳遞過去,sendMessage 方法有多個重載方法,最終調用的 sendMessage 方法如下所示:

frameworks/base/core/java/android/app/ActivityThread.java

23、這裏的 mH 指的是 H,它是 ActivityThread 的內部類並繼承自 Handler,是應用程序進程中主線程的消息管理類。

因爲 ApplicationThread 是一個 Binder,它的調用邏輯運行在 Binder 線程池中,所以這裏需要用 H 將代碼的邏輯切換到主線程中。

H 的代碼如下所示:

frameworks/base/core/java/android/app/ActivityThread.java

24、查看 H 的 handleMessage 方法中對 LAUNCH_ACTIVITY 的處理;

在註釋 1 處將傳過來的 msg 的成員變量 obj 轉換爲 ActivityClientRecord;

在 註釋 2 處通過 getPackageInfoNoCheck 方法獲得 LoadedApk 類型的對象並賦值給 ActivityClientRecord 的成員變量 packageInfo。應用程序進程要啓動 Activity 時需要將該 Activity 所屬的 APK 加載進來,而 LoadApk 就是用來描述已加載的 APK 文件的。

在註釋 3 處調用 handleLaunchActivity 方法,代碼如下所示:

frameworks/base/core/java/android/app/ActivityThread.java

25、註釋 1 處的 performLaunchActivity 方法用來啓動 Activity;

註釋 2 處的代碼用來將 Activity 的狀態設置爲 Resume。

如果該 Activity 爲 null 則會通知 AMS 停止啓動 Activity。

下面來查看 performLaunchActivity 方法做了什麼:

frameworks/base/core/java/android/app/ActivityThread.java

26、註釋 1 處用來獲取 ActivityInfo,用於儲存代碼以及 AndroidManifes 設置的 Activity 和 Receiver 節點信息,比如 Activity 的 theme 和 launchMode。

在註釋 2 處獲取 APK 文件的描述類 LoadedApk。

在註釋 3 處獲取要啓動的 Activity 的 ComponentName 類,在 ComponentName 類中保存了該 Activity 的包名和類名。

在註釋 4 處用來創建要啓動 Activity 的上下文環境。

在註釋 5 處根據 ComponentName 中儲存的 Activity 類名,用類加載器來創建該 Activity 的實例。

在註釋 6 處用來創建 Application,makeApplication 方法內部會調用 Application 的 onCreate 方法。

在註釋 7 處調用 Activity 的 attach 方法初始化 Activity,在 attach 方法中會創建 Window 對象(PhoneWindow)並與 Activity 自身進行關聯。

在註釋 8 處調用 Instrumentation 的 callActivityOnCreate 方法來啓動 Activity,如下所示:

frameworks/base/core/java/android/app/Instrumentation.java

27、註釋 1 處調用了 Activity 的 performCreate 方法,代碼如下所示:

frameworks/base/core/java/android/app/Activity.java

28、在 performCreate 方法中調用 Activity 的 onCreate 方法,講到這裏,根 Activity 就啓動了,即應用程序就啓動了。根 Activity 啓動過程就講到這裏,下面我們來學習根 Activity 啓動過程中涉及的進程。

5、根 Activity 啓動過程中涉及的進程

根 Activity 啓動過程中會涉及 4 個進程,分別是 Zygote 進程、Launcher 進程、AMS 所在的進程(SystemServer進程)、應用程序進程。它們之間的關係如圖所示:

首先 Launcher 進程向 AMS 請求創建根進程 Activity,AMS 會判斷根 Activity 所需的應用程序進程是否存在並啓動,如果不存在就會請求 Zygote 進程創建應用程序進程。

應用程序進程啓動後,AMS 會請求創建應用程序進程並啓動根 Activity。

其中步驟 2 採用的是 Socket 通信,步驟 1 和步驟 4 採用的是 Binder 通信。

爲了更好理解,下面給出這個 4 個進程調用的時序圖,如圖所示:

 

 

 

                                                                                 學習資料主要來源於《Android進階解密》 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章