重溫ActivityManagerService--應(yīng)用啟動流程分析

前言

前一篇文章《重溫ActivityManagerService》重溫了AMS,記錄了AMS啟動過程,與AMS交互的幾個重要的類和數(shù)據(jù)結(jié)構(gòu)。

分析的筆記見:AMS源碼分析筆記

此文章主要記錄一個應(yīng)用是如何啟動起來的。其中分析啟動過程我將以兩種不同的啟動方式來分析:

  • 根Activity的啟動流程(進程沒有啟動的狀態(tài))
  • 子Activity的啟動過程(進程已經(jīng)啟動)

1 圖解Acitivity啟動過程

凡事由淺入深,一口氣帶出全過程必然一臉蒙蔽。因此我先放出一張簡易版的子Activity的啟動過程圖。小伙伴們肯定可以看懂一個界面是如何啟動起來的。但是該圖只能說明大致流程,沒有考慮進程還沒有啟動的情況。

啟動子Activity流程圖.png

然后看看稍微詳細一些的子Activity啟動流程圖,可以更加詳細得明白APP和AMS是如何調(diào)度的。

子Activity組件啟動過程.png

最后看看詳細的根Activity的啟動流程圖,可以全面看清楚一個應(yīng)用從無到啟動完成的過程。后面章節(jié)也會詳細敘述每個步驟做了什么。

根Activity組件啟動過程.png

注意:根Activity的23步到24步還做了很多事件,例如AMS通過Socket請求Zygote fork一個子進程等操作沒有畫入到該流程圖中,因為該過程在《Android系統(tǒng)啟動流程分析》中有分析到,此處只列出了調(diào)用AMS的startProcessLocked()就啟動了一個進程,然后調(diào)用了ActivityThread的main()方法。

小結(jié):

Launcher組件啟動MainActivity組件的過程:

  • (1)Launcher組件向AMS發(fā)送一個啟動MAinActivity組件的進程間通信請求
  • (2)AMS首先將要啟動的MAinActivity組件信息保存下來,然后再向Launcher組件發(fā)送一個進入中止狀態(tài)的進程間通信請求。
  • (3)Launcher組件進入到中止狀態(tài)之后,就會向AMS發(fā)送一個已進入中止狀態(tài)的進程間通信請求,以便AMS可以繼續(xù)執(zhí)行啟動MAinActivity組件的操作。
  • (4)AMS發(fā)現(xiàn)用來運行MAinActivity組件的應(yīng)用程序進程不存在,因此,他就會先啟動一個新的應(yīng)用程序進程。
  • (5)新的應(yīng)用程序進程啟動完成之后,就會向AMS發(fā)送一個啟動完成的進程間通信請求,以便AMS可以繼續(xù)執(zhí)行啟動MAinActivity組件的操作。
  • (6)AMS將第2步保存下來的MAinActivity組件的信息發(fā)送給第4步創(chuàng)建的應(yīng)用程序進程,以便它可以將MAinActivity組件啟動起來。

Ok, let's go! 為了敘述的完整性,我們還是從啟動根Activity開始分析,因此啟動子Activity絕大多數(shù)步驟是沿用啟動根Activity的流程。

2.啟動根Activity

啟動根Activity我們以在Launcher應(yīng)用中點擊Icon開始分析。

2.1 在Launcher進程中完成的操作
Launcher_startActivity.png

在Launcher進程中完成了以下五個步驟的調(diào)用,具體實現(xiàn)的功能如下:

  • 1.用戶調(diào)用launcher的startActivitySafely,設(shè)置Activity組件啟動標志位Intent.FLAG_ACTIVITY_NEW_TASK為1,然后調(diào)用父類的startActivity。
  • 2.調(diào)用startActivityForResult(intent,int),第二個參數(shù)為-1,表示不需要知道即將啟動的Activity組件的執(zhí)行結(jié)果。
  • 3.傳遞ApplicationThread給AMS,以便AMS告知Launcher可以進入pause狀態(tài),mToken對象指向AMS中的ActivityRecord,每一個已經(jīng)啟動的activity都會在AMS中記錄一個ActivityRecord,用來記錄activity組件運行狀態(tài)。
  • 4.在execStartActivity中通過AMS的代理對象調(diào)用AMS的startActivity。
  • 5.AMS代理透傳信息。
2.2 在ActivityManagerService中完成的操作
AMS_pause.png

從6至12步驟是在AMS中完成的操作,具體實現(xiàn)的功能如下:

  • 6.AMS內(nèi)部有一個activityStack,用來描述一個activity組件堆棧,在該步驟中進一步調(diào)用mActivityStack的startActivityMayWait進一步響應(yīng)進程間通信請求。
  • 7.在PMS中解析Intent的內(nèi)容,以獲得要啟動activity組件的信息。然后調(diào)用startActivityLocked繼續(xù)啟動activity
  • 8.每一個應(yīng)用程序都會使用ProcessRecord對象來描述并且保存在AMS內(nèi)部。通過傳進來的ApplicationThread在AMS中查詢到Launcher的ProcessRecord。從mHistory堆棧中獲得launcher組件的ActivityRecord。創(chuàng)建一個Mactivity的ActivityRecord。調(diào)用startActivityUncheckedLocked啟動目標組件
  • 9.判斷新啟動的activity是否要在新任務(wù)中啟動,在AMS中查詢該任務(wù)是否已經(jīng)存在。為MainActivity創(chuàng)建新的任務(wù),并且將該任務(wù)加入到AMS的task堆棧中。將目標ActivityRecord保存在mHistory中,并且把MAinActivity放在棧頂,調(diào)用resumeTopActivityLocked。
  • 10.從棧頂取出activity,判斷當前activity是不是被激活的activity,如果是,并且狀態(tài)是Resumed直接退出,說明已經(jīng)啟動了。判斷當前activity是否是上一次被中止的activity組件。由于當前activity是launcher,調(diào)用startPausingLocked來通知他進入pause狀態(tài)。
  • 11.向launcher發(fā)送一個中止通知,并且在AMS中發(fā)送一個中止超時消息,如果Launcher沒有在超時時間內(nèi)返回,那么就認為Launcher沒有響應(yīng)了。
  • 12.透傳參數(shù)給ApplicationThread。
2.3 在Launcher進程中完成的操作
launcher_pause.png

從13至17步驟是在Launcher中完成的操作,具體內(nèi)容如下:

  • 13.調(diào)用ActivityThread的queueOrSendMessage,這個步驟已經(jīng)在launcher進程中。準備將通知暫停的消息拋到主線程。

  • 14.封裝一個message發(fā)送到mH主線程。

  • 15.處理activityThread發(fā)來的PAUSE_ACTIVITY

  • 16.(1)從launcher進程中的mActivities中取出ActivityClientRecord。

      (2)調(diào)用performUserLeavingActivity向launcher組件發(fā)送一個用戶離開事件通知,即調(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)時,能夠恢復(fù)當前的狀態(tài)信息。
      (5)調(diào)用handlePauseActivity向AMS發(fā)送中止Launcher組件的進程間通信請求。
    
  • 17.從AMS代理調(diào)用activityPaused。

2.4 在ActivityManagerService中完成的操作
AMS_startproc.png

從18至23步驟是在AMS中完成的操作,具體實現(xiàn)的功能如下:

  • 18.收到launcher已經(jīng)暫停的通知之后,調(diào)用activitystack的activityPaused.
  • 19.從mHistory取出launcher的ActivityRecord,從mHandler中移除暫停超時通知。調(diào)用completePauseLocked。
  • 20.把當前進入mPausingAcitivity取出,如果是空的,表示當前正在進入中止的Activity已經(jīng)進入了Paused狀態(tài)。檢查當前系統(tǒng)是不是正在進入睡眠或者關(guān)閉狀態(tài)。
  • 21.取出棧頂?shù)腁ctivityRecord,MainActivity的app是空的,所以調(diào)用startSpecificActivityLocked將MainActivity的進程啟動起來。
  • 22.通過activityRecord中的UID和進程名字查找是否存在MAinActivity所在的進程,如果存在則直接通知Activity啟動,否則AMS的startProcessLocked來啟動MAinActivity應(yīng)用進程。如果進程已經(jīng)起來了,那就調(diào)用realStartActivityLocked
  • 23.(1)通過processName和uid判斷ProcessRecord是否存在,如果不存在,調(diào)用startProcessLocked啟動新進程。
    (2)創(chuàng)建新進程用戶Id和用戶組Id
    (3)Process.start方法啟動一個新的應(yīng)用進程
    (4)將新創(chuàng)建的ProcessRecord保存在AMS的mPidsSelfLocked中,并且發(fā)送一個啟動計時Message,如果超時AMS認為進程啟動失敗,否則AMS就會通知應(yīng)用啟動Maintivity。
2.5 在Launcher進程中完成的操作
launcher_attach.png

24步之前,AMS會調(diào)到Zygote, Zygote會fork一個進程出來,然后調(diào)用Launcher的ActivityThread.main().

從24至25步驟是在Launcher中完成的操作,具體內(nèi)容如下:

  • 24.此步驟已經(jīng)進入了新進程Main方法,在Main方法中新建MainLooper,然后new一個ActivityThread,并且調(diào)用attach方法,最后Looper循環(huán)起來。在ActivityThread中新建一個ApplicationThread,通過AMS代理調(diào)用attachApplication。
  • 25.新建進程狀態(tài)透傳給AMS。此處將IApplicationThread傳遞給AMS,AMS之后就可以通過Binder 客戶端和新起來的進程通信了。
2.6 在ActivityManagerService中完成的操作
AMS_launch_activity.png

從27至30步驟是在AMS中完成的操作,具體實現(xiàn)的功能如下:

  • 27.(1)通過PID在AMS中找到新建的ProcessRecors并且初始化他們。
    (2)移除應(yīng)用啟動超時消息
    (3)獲取棧頂activityRecord,并且判斷棧頂?shù)腶ctivityRecord和要啟動的是不是一致的。如果是一致的,調(diào)用activityStack的realStartAcitivityLocked
  • 28.將ActivityRecord的app值賦成新建的APP,然后將activity組件存入app所描述的進程中。然后在app描述的線程中調(diào)用scheduleLauncherActivity來通知新創(chuàng)建的進程啟動activityRecord所描述的組件,即MainActivity
  • 29.透傳activityRecord信息
  • 30.此步已經(jīng)回到了新啟動的應(yīng)用進程。新建一個ActivityClientRecord,將AMS傳來的參數(shù)對該ActivityClientRecord初始化,并且調(diào)用queueOrSendMessage
2.7 在Launcher進程中完成的操作
launcher_handle_create.png

從31至35步驟是在Launcher中完成的操作,具體內(nèi)容如下:

  • 31.封裝一個message向主線程handle一個消息。
  • 32.通過ActivityClientRecord的applicationInfo查詢新啟動應(yīng)用程序的包信息。然后調(diào)用handleLaunchActivity來啟動一個新的activity
  • 33.調(diào)用performLaunchActivity將MainActivity啟動起來,并且調(diào)用HandleResumeActivity表示當前activity已經(jīng)處于已激活狀態(tài)。
  • 34.(1)獲取componentName,并且用ActivityClientRecord.packageInfo的類加載器加載MainActivity類。
    (2)ActivityClientRecord.packageInfo的makeApplication創(chuàng)建一個Application對象。
    (3)如果上面加載的MainActivity不是空的。新建一個contextImpl并且用ActivityClientRecord來初始化他。
    (4)調(diào)用activity.attach來初始化activity
    (5)調(diào)用mInstrumentation.callActivityOnCreate
    (6)將activityClientRecord的token作為關(guān)鍵字,并且將他保存在Activity的mActivity中。token是一個Binder代理,指向AMS中對應(yīng)activity的ActivityRecrod
  • 35.onCreate被調(diào)用,加載用戶界面,已經(jīng)對用戶界面上的控件進行初始化。
2.8 小結(jié)

MainActivity組件作為應(yīng)用程序Activity的根activity,他啟動起來就意味著應(yīng)用程序啟動起來了。因此我們可以將一個根Activity的啟動過程看做一個Android應(yīng)用程序的啟動過程。

3.啟動子Activity

啟動子Activity和啟動根Activity步驟相似度非常高,只是在startActivityUncheckedLocked中判斷是否能通過AcitivityRecord獲得到IApplicationThread,如果獲取不到就說明進程沒有啟動,就去先啟進程;如果不為空,就直接啟動子Activity。

3.1 在Launcher進程中完成的操作
launcher_sub_startactivity.png

從1至5步驟是在Launcher中完成的操作,具體內(nèi)容如下:

  • 1.設(shè)置intent,調(diào)用startActivity
  • 2.3.4.5.沿用根activity啟動的流程,并且目前是在原應(yīng)用進程中執(zhí)行。
3.2 在ActivityManagerService中完成的操作
AMS_sub_pause.png

從6至12步驟是在AMS中完成的操作,具體實現(xiàn)的功能如下:

  • 6.7.8.沿用根activity流程。從這三步開始在AMS進程中執(zhí)行。
  • 9.判斷是否需要創(chuàng)建一個新的任務(wù)來啟動子activity組件。將新建的activityRecord加入到mHistory中。調(diào)用resumeTopActivityLocked
  • 10.檢查要啟動的activity是否已經(jīng)是當前激活的activity,判斷要啟動的activity的是否是上次中止的activity。
  • 11.發(fā)送暫停通知,并且開始計時
  • 12.透傳暫停通知
3.3 在Launcher進程中完成的操作
launcher_sub_pause.png

從13至17步驟是在Launcher中完成的操作,具體內(nèi)容如下:

  • 13.調(diào)用queueOrSendMessage
  • 14.封裝message并且發(fā)送到主線程
  • 15.處理暫停事件
  • 16.(1)獲得前一個組件ActivityClientRecord
    (2)向前一個組件發(fā)送離開通知,調(diào)用onUserLeaveHint
    (3)調(diào)用前一個組件的中止通知onPause
    (4)等待前一個組件將數(shù)據(jù)寫入磁盤
  • 17.將前一個組件已經(jīng)暫停的通知告知AMS
3.4 在ActivityManagerService中完成的操作
AMS_sub_launch_activity.png

從18至25步驟是在AMS中完成的操作,具體實現(xiàn)的功能如下:

  • 18.透傳已暫停通知給AMS
  • 19.暫停計時,設(shè)置上一個activity為pause狀態(tài)
  • 20.設(shè)置中止中的activity為上一個activity,說明暫停狀態(tài)已經(jīng)結(jié)束
  • 21.取出棧頂?shù)腁ctivityRecord,SubActivity的app是空的,所以調(diào)用startSpecificActivityLocked將SubActivity的進程啟動起來。
  • 22.查看processRecord是否是空,如果不是空,則調(diào)用realStartActivityLocked真正啟動一個activity
  • 23.將ActivityRecord的app值賦成新建的APP,然后將activity組件存入app所描述的進程中。然后在app描述的線程中調(diào)用scheduleLauncherActivity來通知新創(chuàng)建的進程啟動activityRecord所描述的組件,即SubActivity
  • 24.透傳activityRecord信息
  • 25.用傳來的activityRecord初始化activityClientRecord
3.5 在Launcher進程中完成的操作
launcher_sub_handle_create.png

從26至30步驟是在Launcher中完成的操作,具體實現(xiàn)的功能如下:

  • 26.封裝一個message,向主線程發(fā)送一個message
  • 27.獲取APK資源來處理啟動activity事件
  • 28.調(diào)用performLaunchActivity將MainActivity啟動起來,并且調(diào)用HandleResumeActivity表示當前activity已經(jīng)處于已激活狀態(tài)。
  • 29.(1)獲取componentName,并且用ActivityClientRecord.packageInfo的類加載器加載MainActivity類。
    (2)ActivityClientRecord.packageInfo的makeApplication創(chuàng)建一個Application對象。
    (3)如果上面加載的MainActivity不是空的。新建一個contextImpl并且用ActivityClientRecord來初始化他。
    (4)調(diào)用activity.attach來初始化activity
    (5)調(diào)用mInstrumentation.callActivityOnCreate
    (6)將activityClientRecord的token作為關(guān)鍵字,并且將他保存在Activity的mActivity中。token是一個Binder代理,指向AMS中對應(yīng)activity的ActivityRecrod
  • 30.onCreate被調(diào)用,加載用戶界面,已經(jīng)對用戶界面上的控件進行初始化。
3.6 說明

如果子activity設(shè)置了android:process屬性為另一個進程,啟動過程跟MainActivity啟動一樣,只是不用再新建一個task了,因為子activity的android:taskAffinity和MAinActivity是一樣的,MainActivity已經(jīng)新創(chuàng)建了一個task,可以在同一個task中進程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Zygote是什么?有什么作用? Android系統(tǒng)底層基于Linux Kernel, 當Kernel啟動過程會創(chuàng)...
    Mr槑閱讀 2,903評論 4 18
  • 1 前言 網(wǎng)上看過很多Activity啟動過程的源碼解析,很多文章會貼上一大段代碼,然后從startActivit...
    天才木木閱讀 2,490評論 2 9
  • Android Activity的啟動過程過程分析 前言 在了解Activity的啟動的過程的時候,我們需要先了解...
    真的有照片閱讀 1,346評論 0 6
  • 以在桌面點擊一個App圖標冷啟動為例,Activity的啟動大致可以總結(jié)為如下流程: 一個應(yīng)用對應(yīng)一個進程或多個進...
    Luckflower閱讀 652評論 0 0
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭,有人歡樂有人憂愁,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,814評論 28 54

友情鏈接更多精彩內(nèi)容