本屆課程主要講解了 startActivity 啟動過程源碼分析扼鞋,引用的源碼版本是 android-28申鱼。
假設(shè) ActivityA 跳轉(zhuǎn)到另一個App中的 ActivityB,過程如下圖所示:
整個 startActivity 的流程分為 3 大部分云头,也涉及 3 個進程之間的交互:
- ActivityA --> ActivityManagerService(簡稱 AMS)
- ActivityManagerService --> ApplicationThread
- ApplicationThread --> Activity
ActivityA --> ActivityManagerService 階段
這一過程并不復(fù)雜捐友,用一張圖表示具體過程如下:
Activity 的 startActivity
這里最終調(diào)用了 startActivityForResult 方法,傳入的 -1 表示不需要獲取 startActivity 的結(jié)果溃槐。
Activity 的 startActivityForResult
startActivityForResult 也很簡單匣砖,調(diào)用 Instrumentation.execStartActivity 方法。剩下的交給 Instrumentation 類去處理昏滴。
解釋說明:
- Instrumentation 類主要用來監(jiān)控應(yīng)用程序與系統(tǒng)交互猴鲫。
- 藍(lán)框中的 mMainThread 是 ActivityThread 類型尺棋,ActivityThread 可以理解為一個進程键俱,在這就是 A 所在的進程。
- 通過 mMainThread 獲取一個 ApplicationThread 的引用料饥,這個引用就是用來實現(xiàn)進程間通信的姻几,具體來說就是 AMS 所在系統(tǒng)進程通知應(yīng)用程序進程進行的一系列操作匣缘。
Instrumentation 的 execStartActivity
這里獲取了AMS,然后調(diào)用了startActivity方法鲜棠。實際上這里就是通過 AIDL 來調(diào)用 AMS 的 startActivity 方法,至此培慌,startActivity 的工作重心成功地從進程 A 轉(zhuǎn)移到了系統(tǒng)進程 AMS 中豁陆。
ActivityManagerService --> ApplicationThread
接下來就看下在 AMS 中是如何一步一步執(zhí)行到 B 進程的。
注:剛才在看 Instrumentation 的時候吵护,講過一個 ApplicationThread 類盒音,這個類是負(fù)責(zé)進程間通信的,這里 AMS 最終其實就是調(diào)用了 B 進程中的一個 ApplicationThread 引用馅而,從而間接地通知 B 進程進行相應(yīng)操作祥诽。
相比于 startActivity-->AMS,AMS-->ApplicationThread 流程看起來復(fù)雜好多了瓮恭,實際上這里面就干了 2 件事:
- 綜合處理 launchMode 和 Intent 中的 Flag 標(biāo)志位雄坪,并根據(jù)處理結(jié)果生成一個目標(biāo) Activity B 的對象(ActivityRecord)。
- 判斷是否需要為目標(biāo) Activity B 創(chuàng)建一個新的進程(ProcessRecord)屯蹦、新的任務(wù)棧(TaskRecord)维哈。
AMS 的 startActivity
經(jīng)過多個方法的調(diào)用绳姨,最終通過 obtainStarter 方法獲取了 ActivityStarter 類型的對象,然后調(diào)用其 execute 方法阔挠。在 execute 方法中飘庄,會再次調(diào)用其內(nèi)部的 startActivityMayWait 方法。
ActivityStarter 的 startActivityMayWait
ActivityStarter 這個類看名字就知道它專門負(fù)責(zé)一個 Activity 的啟動操作购撼。它的主要作用包括解析 Intent跪削、創(chuàng)建 ActivityRecord、如果有可能還要創(chuàng)建 TaskRecord迂求。startActivityMayWait 方法的部分實現(xiàn)如下:
這里的mSupervisor主要是負(fù)責(zé) Activity 所處棧的管理類碾盐。
在上圖中的 resolveIntent 中實際上是調(diào)用系統(tǒng) PackageManagerService 來獲取最佳 Activity。有時候我們通過隱式 Intent 啟動 Activity 時锁摔,系統(tǒng)中可能存在多個 Activity 可以處理 Intent廓旬,此時會彈出一個選擇框讓用戶選擇具體需要打開哪一個 Activity 界面,就是此處的邏輯處理結(jié)果谐腰。
在 startActivityMayWait 方法中調(diào)用了一個重載的 startActivity 方法孕豹,而最終會調(diào)用的 ActivityStarter 中的 startActivityUnchecked 方法來獲取啟動 Activity 的結(jié)果。
ActivityStarter 的 startActivityUnchecked
- 圖中 1 處計算啟動 Activity 的 Flag 值励背。
- 注釋 2 處處理 Task 和 Activity 的進棧操作。
- 注釋 3 處啟動棧中頂部的 Activity叶眉。
computeLaunchingTaskFlags 方法具體如下:
這個方法的主要作用是計算啟動 Activity 的 Flag芹枷,不同的 Flag 決定了啟動 Activity 最終會被放置到哪一個 Task 集合中衅疙。
- 圖中 1 處 mInTask 是 TaskRecord 類型,此處為 null鸳慈,代表 Activity 要加入的棧不存在,因此需要判斷是否需要新建 Task走芋。
- 圖中 2 處的 mSourceRecord 的類型 ActivityRecord 類型,它是用來描述“初始 Activity”翁逞,什么是“初始 Activity”呢肋杖?比如 ActivityA 啟動了ActivityB,ActivityA 就是初始 Activity挖函。當(dāng)我們使用 Context 或者 Application 啟動 Activity 時,此 SourceRecord 為 null。
- 圖中 3 處表示初始 Activity 如果是在 SingleInstance 棧中的 Activity浅萧,這種需要添加 NEW_TASK 的標(biāo)識。因為 SingleInstance 棧只能允許保存一個 Activity吩案。
- 圖中 4 處表示如果 Launch Mode 設(shè)置了 singleTask 或 singleInstance,則也要創(chuàng)建一個新棧徘郭。
ActivityStackSupervisor 的 startActivityLocked
方法中會調(diào)用 insertTaskAtTop 方法嘗試將 Task 和 Activity 入棧丧肴。如果 Activity 是以 newTask 的模式啟動或者 TASK 堆棧中不存在該 Task id残揉,則 Task 會重新入棧芋浮,并且放在棧的頂部抱环。需要注意的是:Task 先入棧纸巷,之后才是 Activity 入棧镇草,它們是包含關(guān)系瘤旨。
這里一下子涌出了好幾個概念 Stack、Task存哲、Activity,其實它們都是在 AMS 內(nèi)部維護的數(shù)據(jù)結(jié)構(gòu)祟偷,可以用一張圖來描述它們之間的關(guān)系。
如:這次課程是 ActivityA 跳轉(zhuǎn)到另一個App中的 ActivityB杭棵,所以如果ActivityB所在的App沒有啟動。這里會先在AMS中的 ActivityStackSupervisor 中創(chuàng)建 ActivityStack,并且通過創(chuàng)建的 ActivityStack 來管理 TaskRecord先舷。Task會入棧,然后Activity入棧蒋川,不同啟動模式所放入的棧的方式也是不一樣的。如果是 singleTask 或 singleInstance 啟動模式缸浦,則會另外創(chuàng)建TaskRecord夕冲,并添加到 ActivityStack 進行管理裂逐。
ActivityStack 的 resumeFocusedStackTopActivityLocked
經(jīng)過一系列調(diào)用,最終代碼又回到了 ActivityStackSupervisor 中的 startSpecificActivityLocked 方法弥姻。
ActivityStackSupervisor 的 startSpecificActivityLocked
解釋說明:
- 圖中 1 處根據(jù)進程名稱和 Application 的 uid 來判斷目標(biāo)進程是否已經(jīng)創(chuàng)建掺涛,如果沒有則代表進程未創(chuàng)建庭敦。
- 圖中 2 處調(diào)用 AMS 創(chuàng)建 Activity 所在進程薪缆。創(chuàng)建進程也就進而創(chuàng)建了ActivityThread對象,AMS 最終也就是調(diào)用了 B 進程中的這個 ApplicationThread 引用拣帽。
不管是目標(biāo)進程已經(jīng)存在還是新建目標(biāo)進程,最終都會調(diào)用圖中紅線標(biāo)記的 realStartActivityLocked 方法來執(zhí)行啟動 Activity 的操作澜沟。
ActivityStackSupervisor 的 realStartActivityLocked
這個方法在 android-27 和 android-28 版本的區(qū)別很大,從 android-28 開始 Activity 的啟動交給了事務(wù)(Transaction)來完成茫虽。
- 圖中 1 處創(chuàng)建 Activity 啟動事務(wù)既们,并傳入 app.thread 參數(shù)濒析,它是 ApplicationThread 類型啥纸。在上文 startActivity 階段已經(jīng)提過 ApplicationThread 是為了實現(xiàn)進程間通信的,是 ActivityThread 的一個內(nèi)部類斯棒。
- 圖中 2 處執(zhí)行 Activity 啟動事務(wù)。
Activity 啟動事務(wù)的執(zhí)行是由 ClientLifecycleManager 來完成的荣暮,具體代碼如下:
可以看出實際上是調(diào)用了啟動事務(wù) ClientTransaction 的 schedule 方法,而這個 transaction 實際上是在創(chuàng)建 ClientTransaction 時傳入的 app.thread 對象护赊,也就是 ApplicationThread。如下所示:
解釋說明:
- 這里傳入的 app.thread 會賦值給 ClientTransaction 的成員變量 mClient骏啰,ClientTransaction 會調(diào)用 mClient.scheduleTransaction(this) 來執(zhí)行事務(wù)。
- 這個 app.thread 是 ActivityThread 的內(nèi)部類 ApplicationThread判耕,所以事務(wù)最終是調(diào)用 app.thread 的 scheduleTransaction 執(zhí)行。
到這為止 startActivity 操作就成功地從 AMS 轉(zhuǎn)移到了另一個進程 B 中的ApplicationThread中渺贤,剩下的就是 AMS 通過進程間通信機制通知 ApplicationThread 執(zhí)行 ActivityB 的生命周期方法。而這里的app.thread也是在startSpecificActivityLocked中創(chuàng)建進程時所創(chuàng)建的志鞍。
ApplicationThread -> Activity
在 ClientLifecycleManager 中會調(diào)用 ClientTransaction的schedule() 方法
而 mClient 是一個 IApplicationThread 接口類型方仿,具體實現(xiàn)是 ActivityThread 的內(nèi)部類 ApplicationThread。因此后續(xù)執(zhí)行 Activity 生命周期的過程都是由 ApplicationThread 指導(dǎo)完成的仙蚜,scheduleTransaction 方法如下:
可以看出,這里還是調(diào)用了ActivityThread 的 scheduleTransaction 方法委粉。但是這個方法實際上是在 ActivityThread 的父類 ClientTransactionHandler 中實現(xiàn),具體如下:
調(diào)用 sendMessage 方法汁汗,向 Handler 中發(fā)送了一個 EXECUTE_TRANSACTION 的消息,并且 Message 中的 obj 就是啟動 Activity 的事務(wù)對象知牌。而這個 Handler 的具體實現(xiàn)是 ActivityThread 中的 mH 對象。具體如下:
最終調(diào)用了事務(wù)的 execute 方法角寸,execute 方法如下:
在 executeCallback 方法中忿墅,會遍歷事務(wù)中的 callback 并執(zhí)行 execute 方法
在創(chuàng)建 ClientTransaction 時,通過 addCallback 方法傳入了 Callback 參數(shù)疚脐,從圖中可以看出其實是一個 LauncherActivityItem 類型的對象。
LaunchActivityItem 的 execute()
終于到了跟 Activity 生命周期相關(guān)的方法了橄杨,圖中 client 是 ClientTransationHandler 類型,實際實現(xiàn)類就是 ActivityThread式矫。因此最終方法又回到了 ActivityThread。
ActivityThread 的 handleLaunchActivity
這是一個比較重要的方法采转,Activity 的生命周期方法就是在這個方法中有序執(zhí)行瞬痘,具體如下:
解釋說明:
- 圖中 1 處初始化 Activity 的 WindowManager故慈,每一個 Activity 都會對應(yīng)一個“窗口”框全,下一節(jié)會詳細(xì)講解。
- 圖中 2 處調(diào)用 performLaunchActivity 創(chuàng)建并顯示 Activity津辩。
- 圖中 3 處通過反射創(chuàng)建目標(biāo) Activity 對象。
- 圖中 4 處調(diào)用 attach 方法建立 Activity 與 Context 之間的聯(lián)系喘沿,創(chuàng)建 PhoneWindow 對象,并與 Activity 進行關(guān)聯(lián)操作蚜印,下節(jié)會詳細(xì)講解。
- 圖中 5 處通過 Instrumentation 最終調(diào)用 Activity 的 onCreate 方法窄赋。
至此,目標(biāo) Activity 已經(jīng)被成功創(chuàng)建并執(zhí)行生命周期方法寝凌。