前言
前一篇文章《重溫ActivityManagerService》重溫了AMS恢恼,記錄了AMS啟動(dòng)過(guò)程臭猜,與AMS交互的幾個(gè)重要的類和數(shù)據(jù)結(jié)構(gòu)。
分析的筆記見(jiàn):AMS源碼分析筆記
此文章主要記錄一個(gè)應(yīng)用是如何啟動(dòng)起來(lái)的敌卓。其中分析啟動(dòng)過(guò)程我將以兩種不同的啟動(dòng)方式來(lái)分析:
- 根Activity的啟動(dòng)流程(進(jìn)程沒(méi)有啟動(dòng)的狀態(tài))
- 子Activity的啟動(dòng)過(guò)程(進(jìn)程已經(jīng)啟動(dòng))
1 圖解Acitivity啟動(dòng)過(guò)程
凡事由淺入深,一口氣帶出全過(guò)程必然一臉蒙蔽。因此我先放出一張簡(jiǎn)易版的子Activity的啟動(dòng)過(guò)程圖寓娩。小伙伴們肯定可以看懂一個(gè)界面是如何啟動(dòng)起來(lái)的。但是該圖只能說(shuō)明大致流程呼渣,沒(méi)有考慮進(jìn)程還沒(méi)有啟動(dòng)的情況棘伴。
然后看看稍微詳細(xì)一些的子Activity啟動(dòng)流程圖,可以更加詳細(xì)得明白APP和AMS是如何調(diào)度的屁置。
最后看看詳細(xì)的根Activity的啟動(dòng)流程圖焊夸,可以全面看清楚一個(gè)應(yīng)用從無(wú)到啟動(dòng)完成的過(guò)程。后面章節(jié)也會(huì)詳細(xì)敘述每個(gè)步驟做了什么蓝角。
注意:根Activity的23步到24步還做了很多事件阱穗,例如AMS通過(guò)Socket請(qǐng)求Zygote fork一個(gè)子進(jìn)程等操作沒(méi)有畫入到該流程圖中,因?yàn)樵撨^(guò)程在《Android系統(tǒng)啟動(dòng)流程分析》中有分析到帅容,此處只列出了調(diào)用AMS的startProcessLocked()就啟動(dòng)了一個(gè)進(jìn)程颇象,然后調(diào)用了ActivityThread的main()方法。
小結(jié):
Launcher組件啟動(dòng)MainActivity組件的過(guò)程:
- (1)Launcher組件向AMS發(fā)送一個(gè)啟動(dòng)MAinActivity組件的進(jìn)程間通信請(qǐng)求
- (2)AMS首先將要啟動(dòng)的MAinActivity組件信息保存下來(lái)并徘,然后再向Launcher組件發(fā)送一個(gè)進(jìn)入中止?fàn)顟B(tài)的進(jìn)程間通信請(qǐng)求遣钳。
- (3)Launcher組件進(jìn)入到中止?fàn)顟B(tài)之后,就會(huì)向AMS發(fā)送一個(gè)已進(jìn)入中止?fàn)顟B(tài)的進(jìn)程間通信請(qǐng)求麦乞,以便AMS可以繼續(xù)執(zhí)行啟動(dòng)MAinActivity組件的操作蕴茴。
- (4)AMS發(fā)現(xiàn)用來(lái)運(yùn)行MAinActivity組件的應(yīng)用程序進(jìn)程不存在,因此姐直,他就會(huì)先啟動(dòng)一個(gè)新的應(yīng)用程序進(jìn)程倦淀。
- (5)新的應(yīng)用程序進(jìn)程啟動(dòng)完成之后,就會(huì)向AMS發(fā)送一個(gè)啟動(dòng)完成的進(jìn)程間通信請(qǐng)求声畏,以便AMS可以繼續(xù)執(zhí)行啟動(dòng)MAinActivity組件的操作撞叽。
- (6)AMS將第2步保存下來(lái)的MAinActivity組件的信息發(fā)送給第4步創(chuàng)建的應(yīng)用程序進(jìn)程,以便它可以將MAinActivity組件啟動(dòng)起來(lái)插龄。
Ok, let's go! 為了敘述的完整性愿棋,我們還是從啟動(dòng)根Activity開始分析,因此啟動(dòng)子Activity絕大多數(shù)步驟是沿用啟動(dòng)根Activity的流程均牢。
2.啟動(dòng)根Activity
啟動(dòng)根Activity我們以在Launcher應(yīng)用中點(diǎn)擊Icon開始分析糠雨。
2.1 在Launcher進(jìn)程中完成的操作
在Launcher進(jìn)程中完成了以下五個(gè)步驟的調(diào)用,具體實(shí)現(xiàn)的功能如下:
- 1.用戶調(diào)用launcher的startActivitySafely徘跪,設(shè)置Activity組件啟動(dòng)標(biāo)志位Intent.FLAG_ACTIVITY_NEW_TASK為1甘邀,然后調(diào)用父類的startActivity琅攘。
- 2.調(diào)用startActivityForResult(intent,int),第二個(gè)參數(shù)為-1松邪,表示不需要知道即將啟動(dòng)的Activity組件的執(zhí)行結(jié)果坞琴。
- 3.傳遞ApplicationThread給AMS,以便AMS告知Launcher可以進(jìn)入pause狀態(tài)测摔,mToken對(duì)象指向AMS中的ActivityRecord置济,每一個(gè)已經(jīng)啟動(dòng)的activity都會(huì)在AMS中記錄一個(gè)ActivityRecord,用來(lái)記錄activity組件運(yùn)行狀態(tài)锋八。
- 4.在execStartActivity中通過(guò)AMS的代理對(duì)象調(diào)用AMS的startActivity浙于。
- 5.AMS代理透?jìng)餍畔ⅰ?/li>
2.2 在ActivityManagerService中完成的操作
從6至12步驟是在AMS中完成的操作,具體實(shí)現(xiàn)的功能如下:
- 6.AMS內(nèi)部有一個(gè)activityStack挟纱,用來(lái)描述一個(gè)activity組件堆棧羞酗,在該步驟中進(jìn)一步調(diào)用mActivityStack的startActivityMayWait進(jìn)一步響應(yīng)進(jìn)程間通信請(qǐng)求。
- 7.在PMS中解析Intent的內(nèi)容紊服,以獲得要啟動(dòng)activity組件的信息檀轨。然后調(diào)用startActivityLocked繼續(xù)啟動(dòng)activity
- 8.每一個(gè)應(yīng)用程序都會(huì)使用ProcessRecord對(duì)象來(lái)描述并且保存在AMS內(nèi)部。通過(guò)傳進(jìn)來(lái)的ApplicationThread在AMS中查詢到Launcher的ProcessRecord欺嗤。從mHistory堆棧中獲得launcher組件的ActivityRecord参萄。創(chuàng)建一個(gè)Mactivity的ActivityRecord。調(diào)用startActivityUncheckedLocked啟動(dòng)目標(biāo)組件
- 9.判斷新啟動(dòng)的activity是否要在新任務(wù)中啟動(dòng)煎饼,在AMS中查詢?cè)撊蝿?wù)是否已經(jīng)存在讹挎。為MainActivity創(chuàng)建新的任務(wù),并且將該任務(wù)加入到AMS的task堆棧中吆玖。將目標(biāo)ActivityRecord保存在mHistory中筒溃,并且把MAinActivity放在棧頂,調(diào)用resumeTopActivityLocked沾乘。
- 10.從棧頂取出activity怜奖,判斷當(dāng)前activity是不是被激活的activity,如果是翅阵,并且狀態(tài)是Resumed直接退出歪玲,說(shuō)明已經(jīng)啟動(dòng)了。判斷當(dāng)前activity是否是上一次被中止的activity組件掷匠。由于當(dāng)前activity是launcher读慎,調(diào)用startPausingLocked來(lái)通知他進(jìn)入pause狀態(tài)。
- 11.向launcher發(fā)送一個(gè)中止通知槐雾,并且在AMS中發(fā)送一個(gè)中止超時(shí)消息,如果Launcher沒(méi)有在超時(shí)時(shí)間內(nèi)返回幅狮,那么就認(rèn)為L(zhǎng)auncher沒(méi)有響應(yīng)了募强。
- 12.透?jìng)鲄?shù)給ApplicationThread株灸。
2.3 在Launcher進(jìn)程中完成的操作
從13至17步驟是在Launcher中完成的操作,具體內(nèi)容如下:
13.調(diào)用ActivityThread的queueOrSendMessage擎值,這個(gè)步驟已經(jīng)在launcher進(jìn)程中慌烧。準(zhǔn)備將通知暫停的消息拋到主線程。
14.封裝一個(gè)message發(fā)送到mH主線程鸠儿。
15.處理activityThread發(fā)來(lái)的PAUSE_ACTIVITY
-
16.(1)從launcher進(jìn)程中的mActivities中取出ActivityClientRecord屹蚊。
(2)調(diào)用performUserLeavingActivity向launcher組件發(fā)送一個(gè)用戶離開事件通知,即調(diào)用成員函數(shù)onUserLeaveHint (3)調(diào)用performPauseActivity向Launcher發(fā)送中止事件通知进每,調(diào)用成員函數(shù)onPause (4)調(diào)用QueuedWork類的靜態(tài)方法waitToFinish()等待完成前面的一些數(shù)據(jù)寫入操作汹粤。為了回到Resumed狀態(tài)時(shí),能夠恢復(fù)當(dāng)前的狀態(tài)信息田晚。 (5)調(diào)用handlePauseActivity向AMS發(fā)送中止Launcher組件的進(jìn)程間通信請(qǐng)求嘱兼。
17.從AMS代理調(diào)用activityPaused。
2.4 在ActivityManagerService中完成的操作
從18至23步驟是在AMS中完成的操作贤徒,具體實(shí)現(xiàn)的功能如下:
- 18.收到launcher已經(jīng)暫停的通知之后芹壕,調(diào)用activitystack的activityPaused.
- 19.從mHistory取出launcher的ActivityRecord,從mHandler中移除暫停超時(shí)通知接奈。調(diào)用completePauseLocked踢涌。
- 20.把當(dāng)前進(jìn)入mPausingAcitivity取出,如果是空的序宦,表示當(dāng)前正在進(jìn)入中止的Activity已經(jīng)進(jìn)入了Paused狀態(tài)睁壁。檢查當(dāng)前系統(tǒng)是不是正在進(jìn)入睡眠或者關(guān)閉狀態(tài)。
- 21.取出棧頂?shù)腁ctivityRecord挨厚,MainActivity的app是空的堡僻,所以調(diào)用startSpecificActivityLocked將MainActivity的進(jìn)程啟動(dòng)起來(lái)。
- 22.通過(guò)activityRecord中的UID和進(jìn)程名字查找是否存在MAinActivity所在的進(jìn)程疫剃,如果存在則直接通知Activity啟動(dòng)钉疫,否則AMS的startProcessLocked來(lái)啟動(dòng)MAinActivity應(yīng)用進(jìn)程。如果進(jìn)程已經(jīng)起來(lái)了巢价,那就調(diào)用realStartActivityLocked
- 23.(1)通過(guò)processName和uid判斷ProcessRecord是否存在牲阁,如果不存在,調(diào)用startProcessLocked啟動(dòng)新進(jìn)程壤躲。
(2)創(chuàng)建新進(jìn)程用戶Id和用戶組Id
(3)Process.start方法啟動(dòng)一個(gè)新的應(yīng)用進(jìn)程
(4)將新創(chuàng)建的ProcessRecord保存在AMS的mPidsSelfLocked中城菊,并且發(fā)送一個(gè)啟動(dòng)計(jì)時(shí)Message,如果超時(shí)AMS認(rèn)為進(jìn)程啟動(dòng)失敗碉克,否則AMS就會(huì)通知應(yīng)用啟動(dòng)Maintivity凌唬。
2.5 在Launcher進(jìn)程中完成的操作
24步之前,AMS會(huì)調(diào)到Zygote, Zygote會(huì)fork一個(gè)進(jìn)程出來(lái)漏麦,然后調(diào)用Launcher的ActivityThread.main().
從24至25步驟是在Launcher中完成的操作客税,具體內(nèi)容如下:
- 24.此步驟已經(jīng)進(jìn)入了新進(jìn)程Main方法况褪,在Main方法中新建MainLooper,然后new一個(gè)ActivityThread更耻,并且調(diào)用attach方法测垛,最后Looper循環(huán)起來(lái)。在ActivityThread中新建一個(gè)ApplicationThread秧均,通過(guò)AMS代理調(diào)用attachApplication食侮。
- 25.新建進(jìn)程狀態(tài)透?jìng)鹘oAMS。此處將IApplicationThread傳遞給AMS目胡,AMS之后就可以通過(guò)Binder 客戶端和新起來(lái)的進(jìn)程通信了锯七。
2.6 在ActivityManagerService中完成的操作
從27至30步驟是在AMS中完成的操作,具體實(shí)現(xiàn)的功能如下:
- 27.(1)通過(guò)PID在AMS中找到新建的ProcessRecors并且初始化他們讶隐。
(2)移除應(yīng)用啟動(dòng)超時(shí)消息
(3)獲取棧頂activityRecord起胰,并且判斷棧頂?shù)腶ctivityRecord和要啟動(dòng)的是不是一致的。如果是一致的巫延,調(diào)用activityStack的realStartAcitivityLocked - 28.將ActivityRecord的app值賦成新建的APP效五,然后將activity組件存入app所描述的進(jìn)程中。然后在app描述的線程中調(diào)用scheduleLauncherActivity來(lái)通知新創(chuàng)建的進(jìn)程啟動(dòng)activityRecord所描述的組件炉峰,即MainActivity
- 29.透?jìng)鱝ctivityRecord信息
- 30.此步已經(jīng)回到了新啟動(dòng)的應(yīng)用進(jìn)程畏妖。新建一個(gè)ActivityClientRecord,將AMS傳來(lái)的參數(shù)對(duì)該ActivityClientRecord初始化疼阔,并且調(diào)用queueOrSendMessage
2.7 在Launcher進(jìn)程中完成的操作
從31至35步驟是在Launcher中完成的操作戒劫,具體內(nèi)容如下:
- 31.封裝一個(gè)message向主線程handle一個(gè)消息。
- 32.通過(guò)ActivityClientRecord的applicationInfo查詢新啟動(dòng)應(yīng)用程序的包信息婆廊。然后調(diào)用handleLaunchActivity來(lái)啟動(dòng)一個(gè)新的activity
- 33.調(diào)用performLaunchActivity將MainActivity啟動(dòng)起來(lái)迅细,并且調(diào)用HandleResumeActivity表示當(dāng)前activity已經(jīng)處于已激活狀態(tài)。
- 34.(1)獲取componentName淘邻,并且用ActivityClientRecord.packageInfo的類加載器加載MainActivity類茵典。
(2)ActivityClientRecord.packageInfo的makeApplication創(chuàng)建一個(gè)Application對(duì)象。
(3)如果上面加載的MainActivity不是空的宾舅。新建一個(gè)contextImpl并且用ActivityClientRecord來(lái)初始化他统阿。
(4)調(diào)用activity.attach來(lái)初始化activity
(5)調(diào)用mInstrumentation.callActivityOnCreate
(6)將activityClientRecord的token作為關(guān)鍵字,并且將他保存在Activity的mActivity中筹我。token是一個(gè)Binder代理扶平,指向AMS中對(duì)應(yīng)activity的ActivityRecrod - 35.onCreate被調(diào)用,加載用戶界面蔬蕊,已經(jīng)對(duì)用戶界面上的控件進(jìn)行初始化结澄。
2.8 小結(jié)
MainActivity組件作為應(yīng)用程序Activity的根activity,他啟動(dòng)起來(lái)就意味著應(yīng)用程序啟動(dòng)起來(lái)了。因此我們可以將一個(gè)根Activity的啟動(dòng)過(guò)程看做一個(gè)Android應(yīng)用程序的啟動(dòng)過(guò)程麻献。
3.啟動(dòng)子Activity
啟動(dòng)子Activity和啟動(dòng)根Activity步驟相似度非常高呼巷,只是在startActivityUncheckedLocked中判斷是否能通過(guò)AcitivityRecord獲得到IApplicationThread,如果獲取不到就說(shuō)明進(jìn)程沒(méi)有啟動(dòng)赎瑰,就去先啟進(jìn)程;如果不為空破镰,就直接啟動(dòng)子Activity餐曼。
3.1 在Launcher進(jìn)程中完成的操作
從1至5步驟是在Launcher中完成的操作,具體內(nèi)容如下:
- 1.設(shè)置intent鲜漩,調(diào)用startActivity
- 2.3.4.5.沿用根activity啟動(dòng)的流程源譬,并且目前是在原應(yīng)用進(jìn)程中執(zhí)行。
3.2 在ActivityManagerService中完成的操作
從6至12步驟是在AMS中完成的操作孕似,具體實(shí)現(xiàn)的功能如下:
- 6.7.8.沿用根activity流程踩娘。從這三步開始在AMS進(jìn)程中執(zhí)行。
- 9.判斷是否需要?jiǎng)?chuàng)建一個(gè)新的任務(wù)來(lái)啟動(dòng)子activity組件喉祭。將新建的activityRecord加入到mHistory中养渴。調(diào)用resumeTopActivityLocked
- 10.檢查要啟動(dòng)的activity是否已經(jīng)是當(dāng)前激活的activity,判斷要啟動(dòng)的activity的是否是上次中止的activity泛烙。
- 11.發(fā)送暫停通知理卑,并且開始計(jì)時(shí)
- 12.透?jìng)鲿和Mㄖ?/li>
3.3 在Launcher進(jìn)程中完成的操作
從13至17步驟是在Launcher中完成的操作,具體內(nèi)容如下:
- 13.調(diào)用queueOrSendMessage
- 14.封裝message并且發(fā)送到主線程
- 15.處理暫停事件
- 16.(1)獲得前一個(gè)組件ActivityClientRecord
(2)向前一個(gè)組件發(fā)送離開通知蔽氨,調(diào)用onUserLeaveHint
(3)調(diào)用前一個(gè)組件的中止通知onPause
(4)等待前一個(gè)組件將數(shù)據(jù)寫入磁盤 - 17.將前一個(gè)組件已經(jīng)暫停的通知告知AMS
3.4 在ActivityManagerService中完成的操作
從18至25步驟是在AMS中完成的操作藐唠,具體實(shí)現(xiàn)的功能如下:
- 18.透?jìng)饕褧和MㄖoAMS
- 19.暫停計(jì)時(shí),設(shè)置上一個(gè)activity為pause狀態(tài)
- 20.設(shè)置中止中的activity為上一個(gè)activity鹉究,說(shuō)明暫停狀態(tài)已經(jīng)結(jié)束
- 21.取出棧頂?shù)腁ctivityRecord宇立,SubActivity的app是空的,所以調(diào)用startSpecificActivityLocked將SubActivity的進(jìn)程啟動(dòng)起來(lái)自赔。
- 22.查看processRecord是否是空妈嘹,如果不是空,則調(diào)用realStartActivityLocked真正啟動(dòng)一個(gè)activity
- 23.將ActivityRecord的app值賦成新建的APP匿级,然后將activity組件存入app所描述的進(jìn)程中蟋滴。然后在app描述的線程中調(diào)用scheduleLauncherActivity來(lái)通知新創(chuàng)建的進(jìn)程啟動(dòng)activityRecord所描述的組件,即SubActivity
- 24.透?jìng)鱝ctivityRecord信息
- 25.用傳來(lái)的activityRecord初始化activityClientRecord
3.5 在Launcher進(jìn)程中完成的操作
從26至30步驟是在Launcher中完成的操作痘绎,具體實(shí)現(xiàn)的功能如下:
- 26.封裝一個(gè)message津函,向主線程發(fā)送一個(gè)message
- 27.獲取APK資源來(lái)處理啟動(dòng)activity事件
- 28.調(diào)用performLaunchActivity將MainActivity啟動(dòng)起來(lái),并且調(diào)用HandleResumeActivity表示當(dāng)前activity已經(jīng)處于已激活狀態(tài)孤页。
- 29.(1)獲取componentName尔苦,并且用ActivityClientRecord.packageInfo的類加載器加載MainActivity類。
(2)ActivityClientRecord.packageInfo的makeApplication創(chuàng)建一個(gè)Application對(duì)象。
(3)如果上面加載的MainActivity不是空的允坚。新建一個(gè)contextImpl并且用ActivityClientRecord來(lái)初始化他魂那。
(4)調(diào)用activity.attach來(lái)初始化activity
(5)調(diào)用mInstrumentation.callActivityOnCreate
(6)將activityClientRecord的token作為關(guān)鍵字,并且將他保存在Activity的mActivity中稠项。token是一個(gè)Binder代理涯雅,指向AMS中對(duì)應(yīng)activity的ActivityRecrod - 30.onCreate被調(diào)用,加載用戶界面展运,已經(jīng)對(duì)用戶界面上的控件進(jìn)行初始化活逆。
3.6 說(shuō)明
如果子activity設(shè)置了android:process屬性為另一個(gè)進(jìn)程,啟動(dòng)過(guò)程跟MainActivity啟動(dòng)一樣拗胜,只是不用再新建一個(gè)task了蔗候,因?yàn)樽觓ctivity的android:taskAffinity和MAinActivity是一樣的,MainActivity已經(jīng)新創(chuàng)建了一個(gè)task埂软,可以在同一個(gè)task中進(jìn)程锈遥。