本文主要講述了App的啟動(dòng)流程、Application的生命周期以及進(jìn)程的回收機(jī)制。
在絕大多數(shù)情況下,每一個(gè)Android應(yīng)用都在自己的Linux進(jìn)程中運(yùn)行。當(dāng)需要運(yùn)行某些代碼時(shí),進(jìn)程就會(huì)被創(chuàng)建。進(jìn)程將保持運(yùn)行直到不再需要,當(dāng)其他應(yīng)用有需要的時(shí)候,系統(tǒng)會(huì)釋放該進(jìn)程的內(nèi)存。
一個(gè)不常見但很基礎(chǔ)的Android特性是,一個(gè)應(yīng)用進(jìn)程的生命周期并不是由應(yīng)用本身直接控制的。它是由系統(tǒng)根據(jù)正在運(yùn)行的程序,對用戶的重要程度以及所占用的內(nèi)存,綜合去管理的。
App啟動(dòng)流程
此處討論的是第一次啟動(dòng)App。在講解App啟動(dòng)流程的時(shí)候,有兩點(diǎn)需要知曉:
- 每一個(gè)App都運(yùn)行在一個(gè)獨(dú)立空間里,也可以稱之為沙盒,這意味著它是在獨(dú)立的線程中,擁有自己的虛擬機(jī)實(shí)例,被分配一個(gè)唯一的用戶ID。
- App由很多不同組建組成,這些組件還可以調(diào)用其他App的組建,并沒有一個(gè)單獨(dú)的類似于main函數(shù)的入口。
總體來說,App啟動(dòng)分為三個(gè)步驟,創(chuàng)建進(jìn)程、綁定Application以及啟動(dòng)Activity。當(dāng)用戶點(diǎn)擊Android桌面一個(gè)App圖標(biāo),啟動(dòng)一個(gè)應(yīng)用的時(shí)候,整個(gè)流程如下所示:

點(diǎn)擊事件通過Binder IPC機(jī)制最終被轉(zhuǎn)換成startActivity(intent),而App相關(guān)信息的解析以及處理則在安裝的時(shí)候就已經(jīng)完畢。當(dāng)startActivity的時(shí)候,ActivityManagerService(AMS)的操作如下:
- 第一步是intent解析。通過PackageManager的resolveIntent()方法,收集目標(biāo)intent對象的信息。
- 第二步是權(quán)限檢查。通過grantUriPermissionLocked()方法,檢查用戶是否有足夠的權(quán)限去調(diào)用intent的目標(biāo)組件。
- 第三步是創(chuàng)建新的任務(wù)。如果用戶有足夠的權(quán)限,ActivityManagerService就會(huì)檢查目標(biāo)Activity是否需要被加載在新的任務(wù)中。這個(gè)任務(wù)是根據(jù)Intent Flag來進(jìn)行創(chuàng)建的。
最后檢測進(jìn)程記錄表(ProgressRecord)是否存在。如果不存在,則需要通過ActivityManagerService來創(chuàng)建新的進(jìn)程。
進(jìn)程創(chuàng)建
ActivityManagerService通過調(diào)用startProcessLocked()方法來創(chuàng)建一個(gè)新的進(jìn)程,這個(gè)方法會(huì)通過socket連接發(fā)送參數(shù)到Zygote進(jìn)程。Zygote創(chuàng)建ActivityThread對象并返回新創(chuàng)建進(jìn)程的pid。ActivityThread通過依次調(diào)用Looper.prepareLoop()和Looper.loop()方法開啟消息循環(huán)。
綁定Application
當(dāng)進(jìn)程創(chuàng)建完畢后,需要將其與Application綁定起來。ActivityThread通過發(fā)送BIND_APPLICATION消息執(zhí)行綁定,會(huì)執(zhí)行makeApplication()方法來講App的類加載進(jìn)內(nèi)存。
啟動(dòng)Activity
經(jīng)過前面兩步,系統(tǒng)擁有了與application相關(guān)聯(lián)的進(jìn)程,應(yīng)用中相關(guān)的類被加載到進(jìn)程的內(nèi)存區(qū)域。在新創(chuàng)建或者已經(jīng)存在的進(jìn)程中啟動(dòng)Activity的步驟是一樣的。ActivityThread通過發(fā)送LAUNCH_ACTIVITY消息進(jìn)行啟動(dòng)操作。
大致梳理一下上面的過程,當(dāng)用戶點(diǎn)擊應(yīng)用圖標(biāo)的時(shí)候,系統(tǒng)會(huì)去檢測進(jìn)程是否存在,如果不存在,則通過Zygote創(chuàng)建進(jìn)程,創(chuàng)建完進(jìn)程后,則需要將進(jìn)程與App進(jìn)行綁定,將App的資源加載到內(nèi)存中,當(dāng)加載完畢,各種條件準(zhǔn)備就緒,接下來就是啟動(dòng)Activity了,如此,App的界面就展示出來了。
Application生命周期
此處討論的是Application類,而非應(yīng)用生命周期。Application的作用,用官方文檔的話說。
Base class for maintaining global application state.
它的作用是維護(hù)全局的應(yīng)用狀態(tài)的基類。Application類是應(yīng)用中最先被初始化的類,先于Activity等組件。它的生命周期與Activity有幾分相似,都經(jīng)歷了創(chuàng)建銷毀過程,只不過它是一個(gè)線性的過程,不存在一些恢復(fù)過程。
onCreate
Called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.
當(dāng)應(yīng)用啟動(dòng)的時(shí)候調(diào)用,除了content providers之外,早于其他任何組件的創(chuàng)建。
onLowMemory
This is called when the overall system is running low on memory, and actively running processes should trim their memory usage.
當(dāng)整個(gè)系統(tǒng)內(nèi)存不足的時(shí)候,活躍的進(jìn)程需要減少它們的內(nèi)存使用的時(shí)候,回調(diào)會(huì)被調(diào)用。系統(tǒng)調(diào)用此回調(diào)過后,會(huì)產(chǎn)生一次GC操作。
onTerminate
This method is for use in emulated process environments.It will never be called on a production Android device, where processes are removed by simply killing them; no user code (including this callback) is executed when doing so.
在正式環(huán)境的真實(shí)設(shè)備上,不會(huì)被調(diào)用。由于系統(tǒng)結(jié)束進(jìn)程采用的是kill的方法,因此不會(huì)產(chǎn)生相關(guān)的回調(diào)。
onTrimMemory
Called when the operating system has determined that it is a good time for a process to trim unneeded memory from its process.
當(dāng)系統(tǒng)檢測到應(yīng)用可以回收不需要的內(nèi)存時(shí),會(huì)產(chǎn)生此回調(diào)。例如應(yīng)用處于后臺(tái),系統(tǒng)內(nèi)存不足的時(shí)候。
回收機(jī)制
當(dāng)系統(tǒng)出現(xiàn)低內(nèi)存狀況的時(shí)候,會(huì)根據(jù)不同進(jìn)程的優(yōu)先級(jí)進(jìn)行內(nèi)存回收。系統(tǒng)根據(jù)進(jìn)程的狀態(tài),將進(jìn)程分為四個(gè)等級(jí)。
Foreground Process
前臺(tái)進(jìn)程是優(yōu)先級(jí)最高的進(jìn)程,用戶當(dāng)前操作交互的必須是前臺(tái)進(jìn)程。當(dāng)一個(gè)進(jìn)程包含以下條件的時(shí)候,可以認(rèn)為是前臺(tái)進(jìn)程。
- 用戶正在交互的,處在屏幕最上層的Activity(onResume被調(diào)用過后)。
- 包含一個(gè)正在運(yùn)行的BroadcastReceiver(onReceive正在執(zhí)行)。
- 包含一個(gè)正在運(yùn)行它的回調(diào)(onCreate、onStart、onDestroy)的service。
在一般狀況下,殺死前臺(tái)進(jìn)程需要用戶交互。當(dāng)被系統(tǒng)殺死的時(shí)候,說明此時(shí)系統(tǒng)連該進(jìn)程所需要的內(nèi)存都無法滿足,是最后才被殺死的。
Visible Process
可見進(jìn)程是當(dāng)前用戶關(guān)心但是殺掉它會(huì)顯著的影響用戶體驗(yàn)的進(jìn)程。當(dāng)包含如下情況時(shí),該進(jìn)程可以被當(dāng)做可見進(jìn)程。
- 包含一個(gè)對用戶可見但不在前臺(tái)(onPause被調(diào)用過后)的Activity。
- 包含一個(gè)通過startForeground啟動(dòng),正在運(yùn)行的作為前臺(tái)service的進(jìn)程。
- 包含一些用戶可感知的特定需求的service,例如動(dòng)態(tài)壁紙、輸入服務(wù)等。
可見進(jìn)程一般不會(huì)被銷毀,除非是為了保證所有前臺(tái)進(jìn)程的運(yùn)行,而不得不殺死可見進(jìn)程。
Service Process
服務(wù)進(jìn)程是包含用startService所創(chuàng)建service的進(jìn)程。這類進(jìn)程對用戶不是直接可見,但是用戶會(huì)關(guān)心的,例如后臺(tái)上傳服務(wù)等等。所以系統(tǒng)會(huì)盡量維持它們的運(yùn)行,除非系統(tǒng)內(nèi)存不足以維持前臺(tái)進(jìn)程和可見進(jìn)程的運(yùn)行需要。
當(dāng)service運(yùn)行了很長的時(shí)間,例如超過30分鐘,系統(tǒng)就會(huì)對其降級(jí),以使該進(jìn)程會(huì)被更容易的回收。
Cached Process
緩存進(jìn)程是當(dāng)前不被需要的進(jìn)程,因此系統(tǒng)可以在任何需要內(nèi)存的時(shí)候,釋放掉它們的內(nèi)存。
這類進(jìn)程通常包含一個(gè)或多個(gè)當(dāng)前不可見(onStop被調(diào)用)的Activity實(shí)例。當(dāng)系統(tǒng)殺掉這類進(jìn)程的時(shí)候,不會(huì)影響用戶的體驗(yàn)。
不一致的地方
關(guān)于進(jìn)程優(yōu)先級(jí),一般網(wǎng)上給出的前三種跟此處所列一致,不同之處是最后兩種為后臺(tái)進(jìn)程以及空進(jìn)程,而谷歌文檔上,直接被歸到緩存進(jìn)程了。這個(gè)本身沒有什么沖突,本質(zhì)是一樣的,谷歌根據(jù)進(jìn)程對用戶的重要程度劃分的優(yōu)先級(jí),記住這個(gè)大方向就沒啥問題了。
管理
關(guān)于進(jìn)程的管理,首先需要知道Low Memory Killer(LMK)這個(gè)概念。它是基于Linux的Out of Memory Mechanism(OOM機(jī)制)改進(jìn)而來的。LMK是一個(gè)內(nèi)核層組件,是一個(gè)進(jìn)程殺手。它的主要作用是在系統(tǒng)低內(nèi)存狀態(tài)時(shí),釋放掉那些不太重要進(jìn)程的內(nèi)存,讓系統(tǒng)更加流暢。
每一個(gè)進(jìn)程根據(jù)其重要性,都包含一個(gè)oom_adj值,AMS會(huì)去動(dòng)態(tài)的更新oom_adj這個(gè)值。當(dāng)系統(tǒng)處在低內(nèi)存狀態(tài)時(shí),LMK會(huì)根據(jù)oom_adj這個(gè)值,去殺死相關(guān)的進(jìn)程。oom_adj值得范圍是-17~15,一個(gè)進(jìn)程的oom_adj值越高,它被殺死的概率就越大。
整個(gè)過程就是AMS更新oom_adj值,LMK去挑選并殺死進(jìn)程。
問題
ActivityManagerService的主要功能包括哪些?
可以看到,在安裝App以及啟動(dòng)App的過程中,都有AMS的大量參與,它的主要功能包括以下幾部分:
- 統(tǒng)一調(diào)度各應(yīng)用程序的Activity
- 內(nèi)存管理
- 進(jìn)程管理
App的安裝過程是怎樣的?
Apk其實(shí)就是一個(gè)壓縮包,系統(tǒng)安裝App的過程,其實(shí)就是資源的解析、拷貝以及驗(yàn)證等過程。
PackageManagerService會(huì)將App中的Manifest信息解析出來,并持久化,當(dāng)用戶點(diǎn)擊桌面icon的時(shí)候,系統(tǒng)就會(huì)知道該啟動(dòng)哪個(gè)組件。
PMS安裝App,最后底層調(diào)用的也是adb命令來執(zhí)行的。
大致來說,整個(gè)流程是,解析apk文件,執(zhí)行安裝過程,最后更新UI。
onLowMemory與onTrimMemory區(qū)別?
onLowMemory與onTrimMemory都是可以進(jìn)行內(nèi)存回收操作的地方,兩者不同之處有以下幾點(diǎn):
- 兩者API level不同,onLowMemory在API level 1就被添加了,而onTrimMemory是在API level 14中被添加的。當(dāng)然,對于現(xiàn)在最低版本都是從十幾開始支持的,完全可以直接使用onTrimMemory。
- 兩者的觸發(fā)時(shí)機(jī)不同,onLowMemory是在系統(tǒng)出現(xiàn)低內(nèi)存狀況時(shí)被觸發(fā),而onTrimMemory則是在置于后臺(tái)而內(nèi)存不足時(shí)被觸發(fā)。
對于API 14以上的條件下,onTrimMemory在TRIM_MEMORY_COMPLETE級(jí)別跟onLowMemory可以等同。
參考
- Processes and Application Lifecycle
- Android Application Launch
- Android Application Launch Part 2
- Application
- Android application and activity life cycle - Tutorial
- Android系統(tǒng)APP安裝流程解析
- android內(nèi)核剖析學(xué)習(xí)筆記:AMS(ActivityManagerService)內(nèi)部原理和工作機(jī)制
- Android源碼解析之(十二)-->系統(tǒng)啟動(dòng)并解析Manifest的流程
- Android源碼解析之(十三)-->apk安裝流程
- How Android manages background processes?
- Android Low Memory Killer
- Android low memory killer 機(jī)制
- How to Tweak Android Low Memory Killer to Your Needs