網上看過不少Activity啓動過程的源碼解析,不少文章會貼上一大段代碼,而後從startActivity()
函數開始深究整個源碼的調用棧。我的感受這類文章代碼細節太多,反而容易迷失在源碼調用之中,從而忽略了Activity啓動過程的本質。因此本文就簡單地定性地對Activity啓動過程進行描述,不會貼上大篇幅的源碼,同時梳理一下相關的經典問題。也是對之前的所學作一個複習總結。html
Activity啓動過程當中,通常會牽涉到應用啓動的流程。應用啓動又分爲冷啓動和熱啓動。前端
通常來講,冷啓動包括瞭如下內容:java
Looper.loop()
。ActivityThread#attach(false)
方法進行 Binder 通訊,通知system_server進程執行 ActivityManagerService#attachApplication(mAppThread)
方法,用於初始化Application和Activity。 在system_server進程中,ActivityManagerService#attachApplication(mAppThread)
裏依次初始化了Application和Activity,分別有2個關鍵函數: - thread#bindApplication()
方法通知主線程Handler 建立 Application 對象、綁定 Context 、執行 Application#onCreate() 生命週期 - mStackSupervisor#attachApplicationLocked()
方法中調用 ActivityThread#ApplicationThread#scheduleLaunchActivity()
方法,進而經過主線程Handler消息通知建立 Activity 對象,而後再調用 mInstrumentation#callActivityOnCreate()
執行 Activity#onCreate() 生命週期至此,應用啓動流程完成。linux
其中一、二、3的源碼流程能夠參考Android Application 啓動流程分析及其源碼調用探究,但代碼細節不是本篇重點。android
下面說說上述流程中的幾個關鍵角色,以及其做用:git
這裏稍微說下Android系統下的進程機制,每一個應用運行時都是:github
衆所周知,Android是基於Linux系統的,在Linux中全部的進程都是由init進程直接或者是間接fork出來的。fork進程每每比建立進程效率更高。在Android中,全部的應用的進程都是由zygote進程fork出來的。編程
提到zygote進程,就不得不介紹下Android開機流程:瀏覽器
Android手機開機Linux內核啓動後,會加載system/core/init/init.rc文件,啓動init進程。這個進程是Android系統特有的初始化程序,簡單介紹下它的工做:安全
在系統啓動後init進程會fork Zygote進程,Zygote做爲孵化器進程,它的main函數會建立好本身的環境準備孵化子進程,並開始等待孵化請求:
Zygote進程首先會fork本身孵化出SystemServer進程,它的main函數主要負責:
當系統裏面的zygote進程運行以後,後續啓動APP,就至關於開啓一個新的進程。而Android爲了實現資源共用和更快的啓動速度,子進程都是經過zygote進程fork出來的。因此說,除了init進程fork出來的第一個進程zygote,其餘應用進程都是zygote的子進程,也不難理解爲什麼這個孵化器進程的英文名叫zygote(受精卵),由於全部的應用進程都是由它孵化誕生。
SystemServer是由zygote進程fork出來的第一個進程,SystemServer和Zygote是Android Framework最重要的2個進程。 系統裏面重要的服務都是在這個進程裏面開啓的,好比ActivityManagerService、PackageManagerService、WindowManagerService。
應用啓動流程基本是圍繞着ActivityManagerService和ActivityThread展開。
平時咱們所熟知的前端(Web\Android\iOS)經過網絡與服務器通訊是客戶端-服務端模式的體現,而在Android Framework中,四大組件的建立、生命週期也是經過這樣的模式進行通訊:
Android開發者都應該知道,經過包名和Activity類名就能夠打開一個APP。實際上,項目裏的業務代碼startActivity()方法並非直接建立進程、拉起APP的。而是經過一系列的調用,把請求傳遞給SystemServer的AMS。AMS收到來自客戶端的請求後,再通知zygote進程來fork一個新進程,來開啓咱們的目標App的。 這就像是在瀏覽器裏打開一個網頁,瀏覽器把url和參數發送到服務器,而後仍是服務器處理請求,並返回相應的html並展現在瀏覽器上。
這個過程涉及到3個進程:App進程、AMS(SystemServer進程)、zygote進程。
在Android系統中,任何一個Activity的啓動都是由AMS和App進程(主要是ActivityThread)相互配合來完成的。AMS服務統一調度系統中全部進程的Activity啓動,而每一個Activity的啓動過程則由其所屬的進程具體來完成。
咱們知道AMS與ActivityThread的交互主要是經過進程間通訊 (IPC) 。跨進程通訊的機制就是將方法調用及其數據分解至操做系統可識別的程度,並將其從本地進程和地址空間傳輸至遠程進程和地址空間,而後在遠程進程中從新組裝並執行該調用。 Android 提供了執行這些 IPC 事務的方案——Binder機制,所以咱們只需關心接口定義和實現 RPC 編程接口。
而App進程與SystemServer進程也是經過Binder機制進行進程間通訊,Android爲此設計了兩個Binder接口:
對於一個Binder接口,在客戶端和服務端各有一個實現:Proxy和Native,它們之間的通訊主要是經過transact和onTransact觸發。通常從命名上能夠區分:xxxNative是在本進程內的Binder代理類,xxxProxy是在對方進程的Binder代理類。
多說一句,這些Binder都由ServiceManager統一管理:
- ServiceManager管理全部的Android系統服務,有人把ServiceManager比喻成Binder機制中的DNS服務器,client端應用若是要使用系統服務,調用getSystemService接口,ServiceManager就會經過字符串形式的Binder名稱找到並返回對應的服務的Binder對象。
- 它是一個系統服務進程,在native層啓動,它在system/core/rootdir/init.rc腳本中描述並由init進程啓動。
- ServiceManager啓動後,會經過循環等待來處理Client進程的通訊請求。
App進程與SystemServer進程的Binder接口以下圖:
AMS是一個系統服務,在SystemServer進程啓動後完成初始化。在應用啓動流程中,充當着服務端的角色。 App中Activity的生命週期由AMS管理,它決定着何時該調用onCreate、onResume這些生命週期函數,把Activity放在哪一個棧裏,上下文之間的關係是怎樣的等等。
好比:
和服務端的AMS相對應,ActivityThread在應用啓動的Client/Server模式中,是做爲客戶端那一邊的具體實現。它並非一個線程,但它包含了一個應用進程的主線程運做的所有機制:
咱們已經知道應用進程建立之後,App進程的ActivityThread與SystemServer進程的AMS經過Binder進行通訊。 在文章前面【2 應用啓動流程】提到,在ActivityThread的main方法中,調用 ActivityThread#attach(false)
方法進行 Binder 通訊,通知system_server進程執行 ActivityManagerService#attachApplication(mAppThread)
方法,用於初始化Application和Activity。
能夠結合源碼流程,稍微總結一下這個通訊過程。
在ActivityThread建立的時候,會將本身的ApplicationThread綁定到AMS中:
ActivityThread.main()
└── ActivityThread.attach()
└── IActivityManager.attachApplication(mAppThread)
└── Binder.transact()
複製代碼
應用進程做爲客戶端,經過IAcitivtyManager接口發起了跨進程調用,跨進程傳遞的參數mAppThread就是IApplicationThread的實例,執行流程從應用進程進入到系統進程:
ActivityManagerService.onTransact()
└── ActivityManagerService.attachApplication(IApplicationThread thread)
複製代碼
AMS做爲IActivityManager接口的服務端實現,會響應客戶端的請求,最終AMS.attachApplication()函數會被執行,該函數接收跨進程傳遞過來的IApplicationThread實例,將存在系統進程維護的ProcessRecord中。 具體細節能夠看AMS的源碼,咱們只須要知道AMS中維護了全部進程運行時的信息(ProcessRecord),一旦發生了應用進程的綁定請求,ProcessRecord.thread就被賦值成應用進程的IApplicationThread實例,這樣一來,在AMS中就能經過該IApplicationThread實例發起嚮應用進程的調用。
在AMS.attachApplication()的過程當中,會有一些信息要傳遞給應用進程,以便應用進程的初始化,系統進程會發起以下函數調用:
ActivityManagerService.attachApplication()
└── ActivityManagerService.attachApplicationLocked()
└── IApplicationThread.bindApplication(processName, appInfo ...)
└── Binder.transact()
複製代碼
此時,AMS會反轉角色,即系統進程做爲客戶端,經過IApplicationThread接口嚮應用進程發起調用。
應用進程響應請求的調用關係以下所示:
ApplicationThread.onTransact()
└── ApplicationThread.bindApplication()
└── ActivityThread.H.handleMessage(BIND_APPLICATION)
└── ActivityThread.handleBindApplication()
└── Application.onCreate()
複製代碼
ApplicationThread做爲IApplicationThread接口的服務端實現,運行在應用進程中,而後ApplicationThread.bindApplication()會被執行,完成一些簡單的數據封裝(AppBindData)後,經過Handler拋出BIND_APPLICATION消息。這一拋,就拋到了主線程上,ActivityThread.handleBindApplication()會被執行,終於建立了Application 對象,而後調用 Application#attach(context) 來綁定 Context,並調用Application.onCreate()函數。歷經應用進程和系統進程之間的一個來回,總算是建立了一個應用程序。
Android源碼裏有較統一的函數命名方式,在AMS中與Activity管理相關不少函數都會帶有Locked後綴,表示這些函數的調用都須要多線程同步操做(synchronized),它們會讀/寫一些多線程共享的數據
前面提到在system_server進程中,ActivityManagerService#attachApplication(mAppThread)
裏依次初始化了Application和Activity,其中的mStackSupervisor#attachApplicationLocked(ProcessRecord)
裏進行了Activity的初始化。
private IBinder mToken;
,IBinder類型表示這個屬性是一個遠程對象的引用,Token持有了一個ActivityRecord實例的弱引用。在建立一個ActivityRecord的時候,就會建立了一個Token類型的對象。在啓動一個新的Activity時,AMS會將ActivityRecord的Token傳遞給應用進程,調用關係以下所示:
ActivityStackSupervisor.realStartActivityLocked(ActivityRecord, ...) └── IApplicationThread.scheduleLaunchActivity(...token, ...) // 將ActivityRecord的Token跨進程傳遞給應用進程 └── Binder.transact() 複製代碼
ActivityStackSupervisor.realStartActivityLocked()表示要啓動一個Activity實例,ActivityRecord做爲參數。從ActivityRecord中提取出Token對象,做爲跨進程調用的參數,經過IApplicationThread.scheduleLaunchActivity()傳遞到應用進程。
在應用進程這一側,會收到啓動Activity的跨進程調用,觸發如下函數的調用:
ApplicationThread.onTransact() └── ApplicationThread.scheduleLaunchActivity(...token, ...) // token將被封裝進ActivityClientRecord這個數據結構中 └── ActivityThread.H.handleMessage() └── ActivityThread.handleLaunchActivity(LAUNCH_ACTIVITY) └── ActivityThread.performLaunchActivity(ActivityClientRecord, ...) // 從ActivityRecord取出token └── Activity.attch(...token, ...) 複製代碼
標準的Binder服務端處理流程,收到AMS傳遞過來的Token對象,進行一下數據封裝(ActivityClientRecord),而後經過Handler拋出一個LAUNCH_ACTIVITY消息。這個消息顯然也是拋到了應用進程的主線程去執行,因此ActivityThread.performLaunchActivity()函數會在主線程上執行,該函數從封裝的數據結構ActivityClientRecord中取出Token對象,調用Activity.attach()函數,將其綁定到Activity上,如此一來,就創建應用進程的Activity與系統進程中ActivityRecord的關聯。
系統進程維護的是ActivityRecord,應用進程維護的是Activity,二者之間的映射關係就是利用Token來維繫的。應用進程的Activity在建立的時候,就被賦予了一個Token,拿着這個Token才能完成後續與系統進程的通訊。在發生Activity切換時,應用進程會將上一個Activity的Token(AMS.startActivity()的輸入參數resultTo)傳遞給系統進程,系統進程會根據這個Token找到ActivityRecord,對其完成調度後,再通知應用進程:Activity狀態發生了變化。
每一個Activity都持有Instrumentation對象的一個引用,可是整個應用程序進程只會存在一個Instrumentation對象。 Instrumentation能夠理解爲應用進程的管家,ActivityThread要建立或暫停某個Activity時,都須要經過Instrumentation來進行具體的操做。
Instrumentation這個類就是完成對Application和Activity初始化和生命週期的工具類。
前面提到,App和AMS是經過Binder傳遞信息的,ActivityThread接受AMS的命令,而後就是經過Instrumentation真正地建立Activity以及調用Activity的生命週期函數。 好比ApplicationThread接受AMS命令建立Acitivity,最後執行到ActivityThread,經過Instrumentation建立Activity並調用onCreate()生命週期。
// ActivityThread.performLaunchActivity() └── mInstrumentation.newActivity(appContext.getClassLoader(), component.getClassName(), activityClientRecord.intent) └── return (Activity)cl.loadClass(className).newInstance() └── mInstrumentation.callActivityOnCreate(activity, r.state) └── activity.performCreate() └── activity.onCreate(Bundle) 複製代碼
前面知道應用啓動以及Activity啓動是一個跨進程通訊的過程,這是由於: 每一個應用都是一個獨立的進程,Activity的生命週期原本就會在不一樣進程之間互相影響,因此須要一個系統進程對全部Activity進行統一管理。 在一個應用程序安裝時,系統會解析出APK中全部Activity的信息,當顯示APK中的用戶界面時,就須要調度Activity的生命週期函數了。 系統進程(SystemServer)中維護了全部Activity的狀態,管理中樞就是ActivityManagerService。
在應用進程這邊,Activity的生命週期都是發生在本進程的主線程裏,由ActivityThread調用Instrumentation完成。 而在系統進程(SystemServer)這頭,則是由AMS維護ActivityRecord等數據結構來進行調度。 Activity管理的數據結構包括: ActivityRecord TaskRecord ActivityStack ActivityDisplay ActivityStackSupervisor ProcessRecord 這些數據結構都屬於JAVA實體類,它們的構建和銷燬都在系統進程中完成。
它們之間的聯繫能夠參考下圖:
圖中的方框能夠理解爲一個包含關係:譬如一個TaskRecord中包含多個ActivityRecord; 圖中的鏈接線能夠理解爲等價關係,譬如同一個ActivityRecord會被TaskRecord和ProcessRecord引用,二者是從不一樣維度來管理ActivityRecord。
前面知道應用進程與AMS經過Binder進行了跨進程通訊,那麼Binder到底是如何運做的:
下面簡單說說Binder機制 在Android中的具體實現:
Server進程 建立 一個 Binder 對象,並向 ServiceManager 註冊服務。
Client進程 須要使用 Server進程的服務時,須 經過Binder驅動 向 ServiceManager進程 獲取相應的Service信息。ServiceManager會返回Server進程的Binder代理對象