標籤:sys .com 訊息迴圈 ant 分配 建立 ssr 連結 第一個
原文:https://www.jianshu.com/p/a5532ecc8377
作者曾經在高通的Android效能組工作,主要工作是最佳化Android Application的啟動時間。
- APP基礎理論
要想最佳化App啟動時間, 第一步就是瞭解App啟動進程的工作原理. 有幾個基礎理論:
Android Application與其他移動平台有兩個重大不同點:
- 每個Android App都在一個獨立空間裡,意味著其運行在一個單獨的進程中,擁有自己的VM,
被系統分配一個唯一的user ID
- Android APP由很多不同的組件組成,這些組件還可以啟動其他APP的組件,因此,android APP
並沒有一個類似程式入口的main()方法
Android application組件包括:
Activity:前台介面,直接面向User,提供UI和操作
Service:背景工作
Broadcast Receivers:廣播接受者
Context Providers:資料提供者
Android進程和Linux進程一樣,預設情況下,每個apk運行在自己的Linux進程中,另外,預設一個進程裡面只有一個線程=主線程。
這個主線程中有一個Looper執行個體,通過調用Looper.loop()從Message隊列裡面取出Message來做相應的處理
那麼,這個進程何時啟動合適啟動的呢?
簡單來說,進程在其需要的時候被啟動,任意時候,當使用者或者其他組件調取你的apk中的任意組件時,如果你的apk此時沒有運行,
系統會為其建立一個信心的進程並啟動。通常,這個進程會持續運行直到被系統殺死。關鍵是:進程時在被需要的時候才建立的。
舉個例子,如果你點擊email中的超連結, 會在瀏覽器裡面開啟一個網頁. Email App和瀏覽器App是兩個不同的App, 運行在不同的進程中.
這次點擊事件促使Android系統去建立了一個新的進程來執行個體化瀏覽器的組件.
首先, 讓我們快速看下Android啟動流程. 與眾多基於Linux核心的系統類別似, 啟動系統時, bootloader啟動核心和init進程. init進程分裂出更多名為"daemons(守護進程)"的底層的Linux進程, 諸如android debug deamon, USB deamon等. 這些守護進程處理底層硬體相關的介面. 隨後, init進程會啟動一個非常有意思的進程---"Zygote". 顧名思義, 這是一個Android平台的非常基礎的進程. 這個進程初始化了第一個VM, 並且預先載入了framework和眾多App所需要的通用資源. 然後它開啟一個Socket介面來監聽請求, 根據請求孵化出新的VM來管理新的App進程. 一旦收到新的請求, Zygote會基於自身積極式載入的VM來孵化出一個新的VM建立一個新的進程. 啟動Zygote之後, init進程會啟動runtime進程. Zygote會孵化出一個超級管理進程---System Server. SystemServer會啟動所有系統核心服務, 例如Activity Manager Service, 硬體相關的Service等. 到此, 系統準備好啟動它的第一個App進程---Home進程了. |
- 啟動APP流程
使用者點擊Home上的一個APP表徵圖,啟動一個應用時:
Click事件會調用startActivity(Intent), 會通過Binder IPC機制, 最終調用到ActivityManagerService. 該Service會執行如下操作:
- 第一步通過PackageManager的resolveIntent()收集這個intent對象的指向資訊.指向資訊被儲存在一個intent對象中
- 下面重要的一步是通過grantURIPermissionLocked()方法來驗證是否有足夠的權利去調用該intent對象指向Activity。
- 如果有許可權,ActivityManagerService會檢查並在新的task中啟動目標activity
- 現在,是時候檢查這個進程的ProcessRecord是否存在了。如果ProcessRecord是null,ActivityManagerService會建立新的進程來執行個體化目標activity
2.1建立進程
ActivityManagerService調用startProcessLocked()方法來建立新的進程, 該方法會通過前面講到的socket通道傳遞參數給Zygote進程. Zygote孵化自身,
並調用ZygoteInit.main()方法來執行個體化ActivityThread對象並最終返回新進程的pid.
ActivityThread隨後依次調用Looper.prepareLoop()和Looper.loop()來開啟訊息迴圈.
流程圖如下:
- 綁定Application
接下來要做的就是將進程和指定的Application綁定起來. 這個是通過上節的ActivityThread對象中調用bindApplication()方法完成的.
該方法發送一個BIND_APPLICATION的訊息到訊息佇列中, 最終通過handleBindApplication()方法處理該訊息. 然後調用makeApplication()方法
來載入App的classes到記憶體中.
流程圖如下:
- 啟動activity
經過前兩個步驟之後, 系統已經擁有了該application的進程. 後面的調用順序就是普通的從一個已經存在的進程中啟動一個新進程的activity了.
實際調用方法是realStartActivity(), 它會調用application線程對象中的sheduleLaunchActivity()發送一個LAUNCH_ACTIVITY訊息到
訊息佇列中, 通過 handleLaunchActivity()來處理該訊息.
假設點擊的是一個視頻瀏覽的App, 其流程如下:
Android 啟動流程分析