前面介紹了Linux OS中進程管理(包括調度和OOM控制)方面的API,但AMS是如何利用它們的呢?這就涉及AMS中的進程管理規則了。這里簡單介紹相關規則。
Android將應用進程分為五大類,分別為Forground類、Visible類、Service類、Background類及Empty類。這五大類的劃分各有規則。
1. 進程分類
(1) Forground類
該類中的進程重要性最高,屬于該類的進程包括下面幾種情況:
- 含一個前端Activity(即onResume函數被調用過了,或者說當前正在顯示的那個Activity)。
- 含一個Service,并且該Service和一個前端Activity綁定(例如Music應用包括一個前端界面和一個播放Service,當我們一邊聽歌一邊操作Music界面時,該Service即和一個前端Activity綁定)。
- 含一個調用了startForground的Service,或者該進程的Service正在調用其生命周期的函數(onCreate、onStart或onDestroy)。
- 最后一種情況是,該進程中有BroadcastReceiver實例正在執行onReceive函數。
(2) Visible類
屬于Visible類的進程中沒有處于前端的組件,但是用戶仍然能看到它們,例如位于一個對話框后的Activity界面。目前該類進程包括兩種:
- 該進程包含一個僅onPause被調用的Activity(即它還在前臺,只不過部分界面被遮住)。
- 或者包含一個Service,并且該Service和一個Visible(或Forground)的Activity綁定(從字面意義上看,這種情況不太好和Forground進程中第二種情況區分)。
(3) Service類、Background類及Empty類
這三類進程都沒有可見的部分,具體情況如下。
- Service進程:該類進程包含一個Service。此Service通過startService啟動,并且不屬于前面兩類進程。這種進程一般在后臺默默地干活,例如前面介紹的MediaScannerService。
- Background進程:該類進程包含當前不可見的Activity(即它們的onStop被調用過)。系統保存這些進程到一個LRU(最近最少使用)列表。當系統需要回收內存時,該列表中那些最近最少使用的進程將被殺死。
- Empty進程:這類進程中不包含任何組件。為什么會出現這種不包括任何組件的進程呢?其實很簡單,假設該進程僅創建了一個Activity,它完成工作后主動調用finish函數銷毀(destroy)自己,之后該進程就會成為Empty進程。系統保留Empty進程的原因是當又重新需要它們時(例如用戶在別的進程中通過startActivity啟動了它們),可以省去fork進程、創建Android運行環境等一系列漫長而艱苦的工作。
通過以上介紹可發現,當某個進程和前端顯示有關系時,其重要性相對要高,這或許是體現Google重視用戶體驗的一個很直接的證據吧。
* * * * *
**建議**:讀者可閱讀SDK/docs/guide/topics/fundamentals/processes-and-threads.html以獲取更為詳細的信息。
* * * * *
2. Process類API介紹
我們先來介紹Android平臺中進程調度和OOM控制的API,它們統一被封裝在Process.java中,其相關代碼如下:
**Process.java**
~~~
//設置線程的調度優先級,Linux kernel并不區分線程和進程,二者對應同一個數據結構Task
public static final native void setThreadPriority(inttid, int priority)
throws IllegalArgumentException, SecurityException;
/*
設置線程的Group,實際上就是設置線程的調度策略,目前Android定義了三種Group。
由于缺乏相關資料,加之筆者感覺對應的注釋也只可意會不可言傳,故此處直接照搬了英文
注釋,敬請讀者諒解。
THREAD_GROUP_DEFAULT:Default thread group - gets a 'normal'share of the CPU
THREAD_GROUP_BG_NONINTERACTIVE:Background non-interactive thread group.
Allthreads in this group are scheduled with a reduced share of the CPU
THREAD_GROUP_FG_BOOST:Foreground 'boost' thread group - Allthreads in
this group are scheduled with an increasedshare of the CPU.
目前代碼中還沒有地方使用THREAD_GROUP_FG_BOOST這種Group
*/
public static final native void setThreadGroup(inttid, int group)
throws IllegalArgumentException, SecurityException;
//設置進程的調度策略,包括該進程的所有線程
public static final native voidsetProcessGroup(int pid, int group)
throws IllegalArgumentException, SecurityException;
//設置線程的調度優先級
public static final native voidsetThreadPriority(int priority)
throws IllegalArgumentException, SecurityException;
//調整進程的oom_adj值
public static final native boolean setOomAdj(intpid, int amt);
~~~
Process類還為不同調度優先級定義一些非常直觀的名字以避免在代碼中直接使用整型,例如為最低的調度優先級19定義了整型變量THREAD_PRIORITY_LOWEST。除此之外,Process還提供了fork子進程等相關的函數。
* * * * *
**注意**:Process.java中的大多數函數是由JNI層實現的,其中Android在調度策略設置這一功能上還有一些特殊的地方,感興趣的讀者不妨閱讀system/core/libcutils/sched_policy.c文件。
* * * * *
3. 關于ProcessList類和ProcessRecord類的介紹
(1) ProcessList類的介紹
ProcessList類有兩個主要功能:
- 定義一些成員變量,這些成員變量描述了不同狀態下進程的oom_adj值。
- 在Android 4.0之后,LMK的配置參數由ProcessList綜合考慮手機總內存大小和屏幕尺寸后再行設置(在Android 2.3中,LMK的配置參數在init.rc中由init進程設置,并且沒有考慮屏幕尺寸的影響)。讀者可自行閱讀其updateOomLevels函數,此處不再贅述。
本節主要關注ProcessList對oom_adj的定義。雖然前面介紹時將Android進程分為五大類,但是在實際代碼中的劃分更為細致,考慮得更為周全。
**ProcessList.java**
~~~
class ProcessList {
//當一個進程連續發生Crash的間隔小于60秒時,系統認為它是為Bad進程
staticfinal int MIN_CRASH_INTERVAL = 60*1000;
//下面定義各種狀態下進程的oom_adj
//不可見進程的oom_adj,最大15,最小為7。殺死這些進程一般不會帶來用戶能夠察覺的影響
staticfinal int HIDDEN_APP_MAX_ADJ = 15;
staticint HIDDEN_APP_MIN_ADJ = 7;
/*
位于B List中Service所在進程的oom_adj。什么樣的Service會在BList中呢?其中的
解釋只能用原文來表達” these are the old anddecrepit services that aren't as
shiny andinteresting as the ones in the A list“
*/
staticfinal int SERVICE_B_ADJ = 8;
/*
前一個進程的oom_adj,例如從A進程的Activity跳轉到位于B進程的Activity,
B進程是當前進程,而A進程就是previous進程了。因為從當前進程A退回B進程是一個很簡單
卻很頻繁的操作(例如按back鍵退回上一個Activity),所以previous進程的oom_adj
需要單獨控制。這里不能簡單按照五大類來劃分previous進程,還需要綜合考慮
*/
staticfinal int PREVIOUS_APP_ADJ = 7;
//Home進程的oom_adj為6,用戶經常和Home進程交互,故它的oom_adj也需要單獨控制
staticfinal int HOME_APP_ADJ = 6;
//Service類中進程的oom_adj為5
staticfinal int SERVICE_ADJ = 5;
//正在執行backup操作的進程,其oom_adj為4
staticfinal int BACKUP_APP_ADJ = 4;
//heavyweight的概念前面曽提到過,該類進程的oom_adj為3
staticfinal int HEAVY_WEIGHT_APP_ADJ = 3;
//Perceptible進程指那些當前并不在前端顯示而用戶能感覺到它在運行的進程,例如正在
//后臺播放音樂的Music
staticfinal int PERCEPTIBLE_APP_ADJ = 2;
//Visible類進程,oom_adj為1
staticfinal int VISIBLE_APP_ADJ = 1;
//Forground類進程,oom_adj為0
staticfinal int FOREGROUND_APP_ADJ = 0;
//persistent類進程(即退出后,系統需要重新啟動的重要進程),其oom_adj為-12
staticfinal int PERSISTENT_PROC_ADJ = -12;
//核心服務所在進程,oom_adj為-12
staticfinal int CORE_SERVER_ADJ = -12;
//系統進程,其oom_adj為-16
staticfinal int SYSTEM_ADJ = -16;
//內存頁大小定義為4KB
staticfinal int PAGE_SIZE = 4*1024;
//系統中能容納的不可見進程數最少為2,最多為15。在Android 4.0系統中,可通過設置程序來
//調整
staticfinal int MIN_HIDDEN_APPS = 2;
staticfinal int MAX_HIDDEN_APPS = 15;
//下面兩個參數用于調整進程的LRU權重。注意,它們的注釋和具體代碼中的用法不能統一起來
staticfinal long CONTENT_APP_IDLE_OFFSET = 15*1000;
staticfinal long EMPTY_APP_IDLE_OFFSET = 120*1000;
//LMK設置了6個oom_adj閾值
privatefinal int[] mOomAdj = new int[] {
FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, EMPTY_APP_ADJ
};
//用于內存較低機器(例如小于512MB)中LMK的內存閾值配置
privatefinal long[] mOomMinFreeLow = new long[] {
8192, 12288, 16384,
24576, 28672, 32768
};
//用于較高內存機器(例如大于1GB)的LMK內存閾值配置
privatefinal long[] mOomMinFreeHigh = new long[] {
32768, 40960, 49152,
57344, 65536, 81920
};
~~~
從以上代碼中定義的各種ADJ值可知,AMS中的進程管理規則遠比想象得要復雜(讀者以后見識到具體的代碼,更會有這樣的體會)。
* * * * *
**說明**:在ProcessList中定義的大部分變量在Android 2.3代碼中定義于ActivityManagerService.java中,但這段代碼的開發者僅把代碼復制了過來,其中的注釋并未隨著系統升級而更新。
* * * * *
(2) ProcessRecord中相關成員變量的介紹
ProcessRecord定義了較多成員變量用于進程管理。筆者不打算深究其中的細節。這里僅把其中的主要變量及一些注釋列舉出來。下文會分析到它們的作用。
**ProcessRecord.java**
~~~
//用于LRU列表控制
long lastActivityTime; // For managing the LRU list
long lruWeight; // Weight for ordering in LRU list
//和oom_adj有關
int maxAdj; // Maximum OOM adjustment for thisprocess
int hiddenAdj; // If hidden, this is the adjustment touse
int curRawAdj; // Current OOM unlimited adjustment forthis process
int setRawAdj; // Last set OOM unlimited adjustment forthis process
int curAdj; // Current OOM adjustment for thisprocess
int setAdj; // Last set OOM adjustment for thisprocess
//和調度優先級有關
int curSchedGroup; // Currently desired scheduling class
int setSchedGroup; // Last set to background scheduling class
//回收內存級別,見后文解釋
int trimMemoryLevel; // Last selected memorytrimming level
//判斷該進程的狀態,主要和其中運行的Activity,Service有關
boolean keeping; // Actively running code sodon't kill due to that?
boolean setIsForeground; // Running foreground UI when last set?
boolean foregroundServices; // Running anyservices that are foreground?
boolean foregroundActivities; // Running anyactivities that are foreground?
boolean systemNoUi; // This is a system process, but notcurrently showing UI.
boolean hasShownUi; // Has UI been shown in this process since itwas started?
boolean pendingUiClean; // Want to clean up resources from showingUI?
boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so wantto be lower
//是否處于系統BadProcess列表
boolean bad; // True if disabled in the badprocess list
//描述該進程因為是否有太多后臺組件而被殺死
boolean killedBackground; // True when proc has been killed due to toomany bg
String waitingToKill; // Process is waiting to be killed whenin the bg; reason
//序號,每次調節進程優先級或者LRU列表位置時,這些序號都會遞增
int adjSeq; // Sequence id for identifyingoom_adj assignment cycles
int lruSeq; // Sequence id for identifyingLRU update cycles
~~~
上面注釋中提到了LRU(最近最少使用)一詞,它和AMS另外一個用于管理應用進程ProcessRecord的數據結構有關。
* * * * *
**提示**:進程管理和調度一向比較復雜,從ProcessRecord定義的這些變量中可見一斑。需要提醒讀者的是,對這部分功能的相關說明非常少,代碼讀起來會感覺比較晦澀。
* * * * *
- 前言
- 第1章 搭建Android源碼工作環境
- 1.1 Android系統架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.2.3 利用Eclipse調試system_process
- 1.3 本章小結
- 第2章 深入理解Java Binder和MessageQueue
- 2.1 概述
- 2.2 Java層中的Binder架構分析
- 2.2.1 Binder架構總覽
- 2.2.2 初始化Java層Binder框架
- 2.2.3 addService實例分析
- 2.2.4 Java層Binder架構總結
- 2.3 心系兩界的MessageQueue
- 2.3.1 MessageQueue的創建
- 2.3.2 提取消息
- 2.3.3 nativePollOnce函數分析
- 2.3.4 MessageQueue總結
- 2.4 本章小結
- 第3章 深入理解SystemServer
- 3.1 概述
- 3.2 SystemServer分析
- 3.2.1 main函數分析
- 3.2.2 Service群英會
- 3.3 EntropyService分析
- 3.4 DropBoxManagerService分析
- 3.4.1 DBMS構造函數分析
- 3.4.2 dropbox日志文件的添加
- 3.4.3 DBMS和settings數據庫
- 3.5 DiskStatsService和DeviceStorageMonitorService分析
- 3.5.1 DiskStatsService分析
- 3.5.2 DeviceStorageManagerService分析
- 3.6 SamplingProfilerService分析
- 3.6.1 SamplingProfilerService構造函數分析
- 3.6.2 SamplingProfilerIntegration分析
- 3.7 ClipboardService分析
- 3.7.1 復制數據到剪貼板
- 3.7.2 從剪切板粘貼數據
- 3.7.3 CBS中的權限管理
- 3.8 本章小結
- 第4章 深入理解PackageManagerService
- 4.1 概述
- 4.2 初識PackageManagerService
- 4.3 PKMS的main函數分析
- 4.3.1 構造函數分析之前期準備工作
- 4.3.2 構造函數分析之掃描Package
- 4.3.3 構造函數分析之掃尾工作
- 4.3.4 PKMS構造函數總結
- 4.4 APK Installation分析
- 4.4.1 adb install分析
- 4.4.2 pm分析
- 4.4.3 installPackageWithVerification函數分析
- 4.4.4 APK 安裝流程總結
- 4.4.5 Verification介紹
- 4.5 queryIntentActivities分析
- 4.5.1 Intent及IntentFilter介紹
- 4.5.2 Activity信息的管理
- 4.5.3 Intent 匹配查詢分析
- 4.5.4 queryIntentActivities總結
- 4.6 installd及UserManager介紹
- 4.6.1 installd介紹
- 4.6.2 UserManager介紹
- 4.7 本章學習指導
- 4.8 本章小結
- 第5章 深入理解PowerManagerService
- 5.1 概述
- 5.2 初識PowerManagerService
- 5.2.1 PMS構造函數分析
- 5.2.2 init分析
- 5.2.3 systemReady分析
- 5.2.4 BootComplete處理
- 5.2.5 初識PowerManagerService總結
- 5.3 PMS WakeLock分析
- 5.3.1 WakeLock客戶端分析
- 5.3.2 PMS acquireWakeLock分析
- 5.3.3 Power類及LightService類介紹
- 5.3.4 WakeLock總結
- 5.4 userActivity及Power按鍵處理分析
- 5.4.1 userActivity分析
- 5.4.2 Power按鍵處理分析
- 5.5 BatteryService及BatteryStatsService分析
- 5.5.1 BatteryService分析
- 5.5.2 BatteryStatsService分析
- 5.5.3 BatteryService及BatteryStatsService總結
- 5.6 本章學習指導
- 5.7 本章小結
- 第6章 深入理解ActivityManagerService
- 6.1 概述
- 6.2 初識ActivityManagerService
- 6.2.1 ActivityManagerService的main函數分析
- 6.2.2 AMS的 setSystemProcess分析
- 6.2.3 AMS的 installSystemProviders函數分析
- 6.2.4 AMS的 systemReady分析
- 6.2.5 初識ActivityManagerService總結
- 6.3 startActivity分析
- 6.3.1 從am說起
- 6.3.2 AMS的startActivityAndWait函數分析
- 6.3.3 startActivityLocked分析
- 6.4 Broadcast和BroadcastReceiver分析
- 6.4.1 registerReceiver流程分析
- 6.4.2 sendBroadcast流程分析
- 6.4.3 BROADCAST_INTENT_MSG消息處理函數
- 6.4.4 應用進程處理廣播分析
- 6.4.5 廣播處理總結
- 6.5 startService之按圖索驥
- 6.5.1 Service知識介紹
- 6.5.2 startService流程圖
- 6.6 AMS中的進程管理
- 6.6.1 Linux進程管理介紹
- 6.6.2 關于Android中的進程管理的介紹
- 6.6.3 AMS進程管理函數分析
- 6.6.4 AMS進程管理總結
- 6.7 App的 Crash處理
- 6.7.1 應用進程的Crash處理
- 6.7.2 AMS的handleApplicationCrash分析
- 6.7.3 AppDeathRecipient binderDied分析
- 6.7.4 App的Crash處理總結
- 6.8 本章學習指導
- 6.9 本章小結
- 第7章 深入理解ContentProvider
- 7.1 概述
- 7.2 MediaProvider的啟動及創建
- 7.2.1 Context的getContentResolver函數分析
- 7.2.2 MediaStore.Image.Media的query函數分析
- 7.2.3 MediaProvider的啟動及創建總結
- 7.3 SQLite創建數據庫分析
- 7.3.1 SQLite及SQLiteDatabase家族
- 7.3.2 MediaProvider創建數據庫分析
- 7.3.3 SQLiteDatabase創建數據庫的分析總結
- 7.4 Cursor 的query函數的實現分析
- 7.4.1 提取query關鍵點
- 7.4.2 MediaProvider 的query分析
- 7.4.3 query關鍵點分析
- 7.4.4 Cursor query實現分析總結
- 7.5 Cursor close函數實現分析
- 7.5.1 客戶端close的分析
- 7.5.2 服務端close的分析
- 7.5.3 finalize函數分析
- 7.5.4 Cursor close函數總結
- 7.6 ContentResolver openAssetFileDescriptor函數分析
- 7.6.1 openAssetFileDescriptor之客戶端調用分析
- 7.6.2 ContentProvider的 openTypedAssetFile函數分析
- 7.6.3 跨進程傳遞文件描述符的探討
- 7.6.4 openAssetFileDescriptor函數分析總結
- 7.7 本章學習指導
- 7.8 本章小結
- 第8章 深入理解ContentService和AccountManagerService
- 8.1 概述
- 8.2 數據更新通知機制分析
- 8.2.1 初識ContentService
- 8.2.2 ContentResovler 的registerContentObserver分析
- 8.2.3 ContentResolver的 notifyChange分析
- 8.2.4 數據更新通知機制總結和深入探討
- 8.3 AccountManagerService分析
- 8.3.1 初識AccountManagerService
- 8.3.2 AccountManager addAccount分析
- 8.3.3 AccountManagerService的分析總結
- 8.4 數據同步管理SyncManager分析
- 8.4.1 初識SyncManager
- 8.4.2 ContentResolver 的requestSync分析
- 8.4.3 數據同步管理SyncManager分析總結
- 8.5 本章學習指導
- 8.6 本章小結