轉(zhuǎn)載自 https://juejin.im/post/5b0d0a0cf265da091f105858
本文闡述了用戶點(diǎn)擊啟動圖標(biāo)后,Android 系統(tǒng)是怎么啟動你的應(yīng)用程序所宰,將應(yīng)用視圖顯示在移動設(shè)備上绒尊,Android 系統(tǒng)在背后做了很多操作,本文通過重點(diǎn)介紹將一些重要信息以及他們的順序來闡述應(yīng)用的啟動過程仔粥。
首先說一下 Android 應(yīng)用程序的兩個特點(diǎn)
- 多入口婴谱,和只有一個 main 方法的應(yīng)用程序不同,Android 應(yīng)用程序有四大組件構(gòu)成 ( Activity , Service ) 躯泰,每個組件都是一個入口谭羔,所以說 Android 應(yīng)用是多入口的應(yīng)用。
- 每個 Android 應(yīng)用運(yùn)行在一個 獨(dú)立的 linux 進(jìn)程擁有自己的 dalvik vm斟冕,并且分配唯一的的用戶 ID口糕。
那么什么時候會啟動應(yīng)用的進(jìn)程呢,答案就是什么時候用到應(yīng)用程序就啟動磕蛇,這種 ‘ 懶漢模式 ‘景描。
當(dāng)用戶或者其他應(yīng)用程序用到了屬于你的應(yīng)用程序的組件十办,比如 ( Activity ,Service ) Android 就會為你的應(yīng)用程序啟動一個新的進(jìn)程(你的應(yīng)用進(jìn)程不存在當(dāng)前 Android 系統(tǒng)中時)超棺,啟動的應(yīng)用進(jìn)程會伴隨著整個 Android 系統(tǒng)向族,直到 Android 殺掉你應(yīng)用進(jìn)程(內(nèi)存不足或者被用戶清除)。
每個應(yīng)用都有獨(dú)立的進(jìn)程棠绘,默認(rèn)情況下件相,每個應(yīng)用程序都運(yùn)行在自己的進(jìn)程,并且啟動一個主線程工作氧苍。當(dāng)你的應(yīng)用程序 需要打開相冊功能就會打開系統(tǒng)的相冊應(yīng)用夜矗,因為你的應(yīng)用和相冊應(yīng)用都有自己獨(dú)立的應(yīng)用進(jìn)程,通過啟動相冊的操作让虐,在一個進(jìn)程中啟動另外一個進(jìn)程紊撕,這適用于其他應(yīng)用程序里面的每一個組件。
Android 開機(jī)過程
Android 開機(jī)的過程加載內(nèi)核和 init 進(jìn)程 然后 init 進(jìn)程又會產(chǎn)生很多守護(hù)進(jìn)程 比如 usb 進(jìn)程 debug 調(diào)試進(jìn)程 赡突,這些守護(hù)進(jìn)程一般是處理底層硬件接口对扶。
然后 init 進(jìn)程又會啟動一個 zygote 進(jìn)程 ,zygote 進(jìn)程他會創(chuàng)建一個原始 dalvik 虛擬機(jī) 然后繼承系統(tǒng)資源惭缰,和 Android 應(yīng)用程序框架浪南,然后進(jìn)入監(jiān)聽狀態(tài),隨時準(zhǔn)備復(fù)制一份漱受,當(dāng)系統(tǒng)請求 zygote 就會 fork出一份新的進(jìn)程络凿,這個進(jìn)程就有了 dalvik 虛擬機(jī)和系統(tǒng)的資源了。
然后 init 進(jìn)程還會啟動系統(tǒng)服務(wù)進(jìn)程 SystemServer昂羡,SystemServer 去創(chuàng)建系統(tǒng)服務(wù)類比如 ActivityManagerService (AMS)喷众。再去啟動 launcher 應(yīng)用(桌面啟動器)。
所以當(dāng)在桌面點(diǎn)擊 啟動 logo 就會通過 binder接口 以ipc的形式紧憾,通知 ams 會發(fā)起一個startactivity 然后通過 packagemanager.resolveIntent 來獲取 activity的信息,并且保存起來昌渤,下次就拿來用赴穗。
然后調(diào)用 geturipermissionlocked 判斷有沒有權(quán)限執(zhí)行這個操作,然后 ams 檢查 activity 在哪個應(yīng)用棧列里面膀息,然后再判斷 activity 所在的 應(yīng)用進(jìn)程是否存在般眉,如果 ams 檢測到 activity 所在進(jìn)程為空會去 通知 zygnote 去fork 一個進(jìn)程,執(zhí)行 activitythread 的 main 方法 實例化 looper 消息隊列潜支,調(diào)用 looper甸赃。loop去循環(huán)消息隊列。冗酿,然后進(jìn)程和 ams 綁定在一起埠对,下次就不會創(chuàng)建該activty了络断。
啟動應(yīng)用程序可以分為三個步驟
- 創(chuàng)建一個進(jìn)程
- 綁定應(yīng)用程序
- 啟動一個 Activity
創(chuàng)建一個進(jìn)程
ams 會通過 startprocessLocked 方法向 zygote 請求一個新的進(jìn)程,通過 socket 的方法 向 zygote 傳遞參數(shù)项玛,zygote fork了一份 調(diào)用 zygoteInit.main 方法 貌笨,然后實例化 Activitythread 對象 并返回進(jìn)程的 id。
每一個進(jìn)程都有一個主線程襟沮,主線程的有一個looper實例來處理消息隊列里面的锥惋,在遍歷里面的消息隊列時,run 方法 會調(diào)用 looper.loop 方法开伏。 activitythread 也會調(diào)用 looper.prepareLoop 和looper.loop 來啟動消息循環(huán)膀跌。詳細(xì)如圖:
進(jìn)程綁定應(yīng)用程序
這一步的作用就是將進(jìn)程綁定到應(yīng)用程序上, ams 調(diào)用 bindApplicaiton固灵,讓線程發(fā)送一個 message 給消息隊列捅伤,最后在 handler 的 handlemessage 方法調(diào)用 hanldebindapplicaiton 方法,接著調(diào)用 makeApplicaiton 怎虫,將應(yīng)用程序的類加載到內(nèi)存上暑认。如圖:
啟動一個 Activity
上面兩步為你創(chuàng)建了進(jìn)程和加載資源類到進(jìn)程的內(nèi)存里面,這一步為了 ams 調(diào)用 realstartactiivtyLocked 來啟動 activity 大审,然后調(diào)用 schedulelauncheractivity 方法 蘸际,讓 Activitythread 發(fā)送LAUNCH_ACTIVITY 的標(biāo)識,然后在 handleMessage 方法調(diào)用 handlelaunchActivity 和 performLaunchActivity 徒扶,通過 newActivity 傳入 classloader粮彤,classname 和 intent 來創(chuàng)建對應(yīng)的 activity 最后調(diào)用 oncreate 加載視圖方法 setcontentview。最后視圖顯示在手機(jī)上姜骡。 如圖:
總結(jié)
當(dāng)你啟動一個 activity 的時候 导坟,你當(dāng)前的進(jìn)程通過 binder 接口 以 ipc 的方式 startactivity 請求 AMS , AMS 判斷用戶有沒有權(quán)限請求這個actiivty 再根據(jù)應(yīng)用棧來確定新 activity 的 task 圈澈,最后請求 zygote 創(chuàng)建 dalvik 虛擬機(jī) 以及加載系統(tǒng)資源類 惫周,來創(chuàng)建新的進(jìn)程,調(diào)用新進(jìn)程的 activitythread 類的 main 方法 創(chuàng)建 looper 調(diào)用 loop 方法來遍歷消息隊列康栈。然后 zygote 返回新進(jìn)程 pid 給 AMS 递递。 AMS 綁定這個進(jìn)程到應(yīng)用上,加載類到進(jìn)程的內(nèi)存上啥么,最后調(diào)用 handlelaunchActivity 和 performlaunchactivity 啟動這個 activity登舞。最后執(zhí)行 activity 的 oncreate 方法加載視圖,執(zhí)行 onstart 方法使視圖可見悬荣。