本文主要講述了App的啟動流程、Application的生命周期以及進程的回收機制。 ...
本文主要講述了App的啟動流程、Application的生命周期以及進程的回收機制。
在絕大多數情況下,每一個Android應用都在自己的Linux進程中運行。當需要運行某些代碼時,進程就會被創建。進程將保持運行直到不再需要,當其他應用有需要的時候,系統會釋放該進程的記憶體。
一個不常見但很基礎的Android特性是,一個應用進程的生命周期並不是由應用本身直接控制的。它是由系統根據正在運行的程式,對用戶的重要程度以及所占用的記憶體,綜合去管理的。
1. App啟動流程
此處討論的是第一次啟動App。在講解App啟動流程的時候,有兩點需要知曉:
- 每一個App都運行在一個獨立空間里,也可以稱之為沙盒,這意味著它是在獨立的線程中,擁有自己的虛擬機實例,被分配一個唯一的用戶ID。
- App由很多不同組建組成,這些組件還可以調用其他App的組建,並沒有一個單獨的類似於main函數的入口。
總體來說,App啟動分為三個步驟,創建進程、綁定Application以及啟動Activity。當用戶點擊Android桌面一個App圖標,啟動一個應用的時候,整個流程如下所示:
點擊事件通過Binder IPC機制最終被轉換成startActivity(intent),而App相關信息的解析以及處理則在安裝的時候就已經完畢。當startActivity的時候,ActivityManagerService(AMS)的操作如下:
- 第一步是intent解析。通過PackageManager的resolveIntent()方法,收集目標intent對象的信息。
- 第二步是許可權檢查。通過grantUriPermissionLocked()方法,檢查用戶是否有足夠的許可權去調用intent的目標組件。
- 第三步是創建新的任務。如果用戶有足夠的許可權,ActivityManagerService就會檢查目標Activity是否需要被載入在新的任務中。這個任務是根據Intent Flag來進行創建的。
最後檢測進程記錄表(ProgressRecord)是否存在。如果不存在,則需要通過ActivityManagerService來創建新的進程。
1.1 進程創建
ActivityManagerService通過調用startProcessLocked()方法來創建一個新的進程,這個方法會通過socket連接發送參數到Zygote進程。Zygote創建ActivityThread對象並返回新創建進程的pid。ActivityThread通過依次調用Looper.prepareLoop()和Looper.loop()方法開啟消息迴圈。
1.2 綁定Application
當進程創建完畢後,需要將其與Application綁定起來。ActivityThread通過發送BIND_APPLICATION消息執行綁定,會執行makeApplication()方法將App的類載入進記憶體。
1.3 啟動Activity
經過前面兩步,系統擁有了與application相關聯的進程,應用中相關的類被載入到進程的記憶體區域。在新創建或者已經存在的進程中啟動Activity的步驟是一樣的。ActivityThread通過發送LAUNCH_ACTIVITY消息進行啟動操作。
大致梳理一下上面的過程,當用戶點擊應用圖標的時候,系統會去檢測進程是否存在,如果不存在,則通過Zygote創建進程,創建完進程後,則需要將進程與App進行綁定,將App的資源載入到記憶體中,當載入完畢,各種條件準備就緒,接下來就是啟動Activity了,如此,App的界面就展示出來了。
2. Application生命周期
此處討論的是Application類,而非應用生命周期。Application的作用,用官方文檔的話說。
Base class for maintaining global application state.
它的作用是維護全局的應用狀態的基類。Application類是應用中最先被初始化的類,先於Activity等組件。它的生命周期與Activity有幾分相似,都經歷了創建銷毀過程,只不過它是一個線性的過程,不存在一些恢復過程。
2.1 onCreate
Called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.
當應用啟動的時候調用,除了content providers之外,早於其他任何組件的創建。
2.2 onLowMemory
This is called when the overall system is running low on memory, and actively running processes should trim their memory usage.
當整個系統記憶體不足的時候,活躍的進程需要減少它們的記憶體使用的時候,回調會被調用。系統調用此回調過後,會產生一次GC操作。
2.3 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.
在正式環境的真實設備上,不會被調用。由於系統結束進程採用的是kill的方法,因此不會產生相關的回調。
2.4 onTrimMemory
Called when the operating system has determined that it is a good time for a process to trim unneeded memory from its process.
當系統檢測到應用可以回收不需要的記憶體時,會產生此回調。例如應用處於後臺,系統記憶體不足的時候。
3. 回收機制
當系統出現低記憶體狀況的時候,會根據不同進程的優先順序進行記憶體回收。系統根據進程的狀態,將進程分為四個等級。
3.1 Foreground Process
前臺進程是優先順序最高的進程,用戶當前操作交互的必須是前臺進程。當一個進程包含以下條件的時候,可以認為是前臺進程。
- 用戶正在交互的,處在屏幕最上層的Activity(onResume被調用過後)。
- 包含一個正在運行的BroadcastReceiver(onReceive正在執行)。
- 包含一個正在運行它的回調(onCreate、onStart、onDestroy)的service。
在一般狀況下,殺死前臺進程需要用戶交互。當被系統殺死的時候,說明此時系統連該進程所需要的記憶體都無法滿足,是最後才被殺死的。
3.2 Visible Process
可見進程是當前用戶關心但是殺掉它會顯著的影響用戶體驗的進程。當包含如下情況時,該進程可以被當做可見進程。
- 包含一個對用戶可見但不在前臺(onPause被調用過後)的Activity。
- 包含一個通過startForeground啟動,正在運行的作為前臺service的進程。
- 包含一些用戶可感知的特定需求的service,例如動態壁紙、輸入服務等。
可見進程一般不會被銷毀,除非是為了保證所有前臺進程的運行,而不得不殺死可見進程。
3.3 Service Process
服務進程是包含用startService所創建service的進程。這類進程對用戶不是直接可見,但是用戶會關心的,例如後臺上傳服務等等。所以系統會儘量維持它們的運行,除非系統記憶體不足以維持前臺進程和可見進程的運行需要。
當service運行了很長的時間,例如超過30分鐘,系統就會對其降級,以使該進程會被更容易的回收。
3.4 Cached Process
緩存進程是當前不被需要的進程,因此系統可以在任何需要記憶體的時候,釋放掉它們的記憶體。
這類進程通常包含一個或多個當前不可見(onStop被調用)的Activity實例。當系統殺掉這類進程的時候,不會影響用戶的體驗。
3.5 不一致的地方
關於進程優先順序,一般網上給出的前三種跟此處所列一致,不同之處是最後兩種為後臺進程以及空進程,而谷歌文檔上,直接被歸到緩存進程了。這個本身沒有什麼衝突,本質是一樣的,谷歌根據進程對用戶的重要程度劃分的優先順序,記住這個大方向就沒啥問題了。
3.6 管理
關於進程的管理,首先需要知道Low Memory Killer(LMK)這個概念。它是基於Linux的Out of Memory Mechanism(OOM機制)改進而來的。LMK是一個內核層組件,是一個進程殺手。它的主要作用是在系統低記憶體狀態時,釋放掉那些不太重要進程的記憶體,讓系統更加流暢。OOM只有當系統記憶體不足的時候才會啟動檢查,而LMK則不僅是在應用程式分配記憶體發現記憶體不足時啟動檢查,它也會定時地進行檢查。
每一個進程根據其重要性,都包含一個oom_adj值,oom_adj的大小和進程的類型以及進程被調度的次序有關,AMS會去動態的更新oom_adj。當系統處在低記憶體狀態時,LMK會根據oom_adj值大小,去殺死相關的進程。oom_adj值得範圍是-17~15,一個進程的oom_adj值越高,它被殺死的概率就越大。
整個過程就是AMS更新oom_adj值,LMK去挑選並殺死進程。
4. 問題
ActivityManagerService的主要功能包括哪些?
可以看到,在安裝App以及啟動App的過程中,都有AMS的大量參與,它的主要功能包括以下幾部分:
- 統一調度各應用程式的Activity
- 記憶體管理
- 進程管理
App的安裝過程是怎樣的?
Apk其實就是一個壓縮包,系統安裝App的過程,其實就是資源的解析、拷貝以及驗證等過程。
PackageManagerService會將App中的Manifest信息解析出來,並持久化,當用戶點擊桌面icon的時候,系統就會知道該啟動哪個組件。
PMS安裝App,最後底層調用的也是adb命令來執行的。
大致來說,整個流程是,解析apk文件,執行安裝過程,最後更新UI。
onLowMemory與onTrimMemory區別?
onLowMemory與onTrimMemory都是可以進行記憶體回收操作的地方,兩者不同之處有以下幾點:
- 兩者API level不同,onLowMemory在API level 1就被添加了,而onTrimMemory是在API level 14中被添加的。當然,對於現在最低版本都是從十幾開始支持的,完全可以直接使用onTrimMemory。
- 兩者的觸發時機不同,onLowMemory是在系統出現低記憶體狀況時被觸發,而onTrimMemory則是在置於後臺而記憶體不足時被觸發。
對於API 14以上的條件下,onTrimMemory在TRIM_MEMORY_COMPLETE
級別跟onLowMemory可以等同。
5. 參考
- Processes and Application Lifecycle
- Android Application Launch
- Android Application Launch Part 2
- Application
- Android application and activity life cycle - Tutorial
- Android系統APP安裝流程解析
- android內核剖析學習筆記:AMS(ActivityManagerService)內部原理和工作機制
- Android源碼解析之(十二)-->系統啟動並解析Manifest的流程
- Android源碼解析之(十三)-->apk安裝流程
- How Android manages background processes?
- Android Low Memory Killer
- Android low memory killer 機制
- How to Tweak Android Low Memory Killer to Your Needs