一、概述
提到进程调度,可能大家首先想到的是Linux cpu调度算法,进程优先级之类概念,本文并不打算介绍这些内容,而是介绍Android framework层中承载activity/service/contentprovider/broadcastrecevier的进程是如何根据组件运行状态而动态调节进程自身的状态。进程有两个比较重要的状态值,即adj(定义在ProcessList.java
)和procState(定义在ActivityManager.java
)。
本文是根据android 6.0原生系统的算法分析,不同手机厂商都会有各自的激进策略。先来看看系统adj和procState有哪些级别。
1.1 ADJ级别
定义在ProcessList.java文件,oom_adj划分为16级,从-17到16之间取值。adj值越大,优先级越低,adj<0的进程都是系统进程。
ADJ级别 | 取值 | 解释 |
---|---|---|
UNKNOWN_ADJ | 16 | 一般指将要会缓存进程,无法获取确定值 |
CACHED_APP_MAX_ADJ | 15 | 不可见进程的adj最大值 |
CACHED_APP_MIN_ADJ | 9 | 不可见进程的adj最小值 |
SERVICE_B_AD | 8 | B List中的Service(较老的、使用可能性更小) |
PREVIOUS_APP_ADJ | 7 | 上一个App的进程(往往通过按返回键) |
HOME_APP_ADJ | 6 | Home进程 |
SERVICE_ADJ | 5 | 服务进程(Service process) |
HEAVY_WEIGHT_APP_ADJ | 4 | 后台的重量级进程,system/rootdir/init.rc文件中设置 |
BACKUP_APP_ADJ | 3 | 备份进程 |
PERCEPTIBLE_APP_ADJ | 2 | 可感知进程,比如后台音乐播放 |
VISIBLE_APP_ADJ | 1 | 可见进程(Visible process) |
FOREGROUND_APP_ADJ | 0 | 前台进程(Foreground process |
PERSISTENT_SERVICE_ADJ | -11 | 关联着系统或persistent进程 |
PERSISTENT_PROC_ADJ | -12 | 系统persistent进程,比如telephony |
SYSTEM_ADJ | -16 | 系统进程 |
NATIVE_ADJ | -17 | native进程(不被系统管理) |
lmkd会根据会根据当前系统可能内存的情况,来决定杀掉不同adj级别的进程,Android进程生命周期与ADJ。
1.2 进程state级别
定义在ActivityManager.java文件,process_state划分18类,从-1到16之间取值。
state级别 | 取值 | 解释 |
---|---|---|
PROCESS_STATE_CACHED_EMPTY | 16 | 进程处于cached状态,且为空进程 |
PROCESS_STATE_CACHED_ACTIVITY_CLIENT | 15 | 进程处于cached状态,且为另一个cached进程(内含Activity)的client进程 |
PROCESS_STATE_CACHED_ACTIVITY | 14 | 进程处于cached状态,且内含Activity |
PROCESS_STATE_LAST_ACTIVITY | 13 | 后台进程,且拥有上一次显示的Activity |
PROCESS_STATE_HOME | 12 | 后台进程,且拥有home Activity |
PROCESS_STATE_RECEIVER | 11 | 后台进程,且正在运行receiver |
PROCESS_STATE_SERVICE | 10 | 后台进程,且正在运行service |
PROCESS_STATE_HEAVY_WEIGHT | 9 | 后台进程,但无法执行restore,因此尽量避免kill该进程 |
PROCESS_STATE_BACKUP | 8 | 后台进程,正在运行backup/restore操作 |
PROCESS_STATE_IMPORTANT_BACKGROUND | 7 | 对用户很重要的进程,用户不可感知其存在 |
PROCESS_STATE_IMPORTANT_FOREGROUND | 6 | 对用户很重要的进程,用户可感知其存在 |
PROCESS_STATE_TOP_SLEEPING | 5 | 与PROCESS_STATE_TOP一样,但此时设备正处于休眠状态 |
PROCESS_STATE_FOREGROUND_SERVICE | 4 | 拥有一个前台Service |
PROCESS_STATE_BOUND_FOREGROUND_SERVICE | 3 | 拥有一个前台Service,且由系统绑定 |
PROCESS_STATE_TOP | 2 | 拥有当前用户可见的top Activity |
PROCESS_STATE_PERSISTENT_UI | 1 | persistent系统进程,并正在执行UI操作 |
PROCESS_STATE_PERSISTENT | 0 | persistent系统进程 |
PROCESS_STATE_NONEXISTENT | -1 | 不存在的进程 |
1.3 核心方法
调整进程的adj的3大护法:
updateOomAdjLocked
:更新adj,当目标进程为空,或者被杀则返回false;否则返回true;computeOomAdjLocked
:计算adj,返回计算后RawAdj值;applyOomAdjLocked
:应用adj,当需要杀掉目标进程则返回false;否则返回true。
前面提到调整adj的3大护法,最为常见的方法便是computeOomAdjLocked,这也是其他各个方法在需要更新adj时会调用的方法,该方法有3个不同参数的同名方法,定义如下:
1 2 3 4 |
无参方法:updateOomAdjLocked() 一参方法:updateOomAdjLocked(ProcessRecord app) 五参方法:updateOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP, boolean doingAll, long now) |
updateOomAdjLocked的实现过程中依次会computeOomAdjLocked
和applyOomAdjLocked
。
1.4 使用场景
到底哪些地方会需要updateOomAdjLocked呢,其实很多地方,下面列举常见场景:
- Activity的start/resume/finish;
- Service的start/bind/unbind;
- broadcast的分发/处理;
- contentprovider的发布/移除/获取;
- 进程的kill/attach等。
二、ADJ算法
ADJ算法,其核心也就是updateOomAdjLocked方法。
2.1 一参updateOomAdjLocked
[-> ActivityManagerService.java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
final boolean updateOomAdjLocked(ProcessRecord app) { //获取栈顶的Activity final ActivityRecord TOP_ACT = resumedAppLocked(); final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; final boolean wasCached = app.cached; mAdjSeq++; //确保cachedAdj>=9 final int cachedAdj = app.curRawAdj >= ProcessList.CACHED_APP_MIN_ADJ ? app.curRawAdj : ProcessList.UNKNOWN_ADJ; //执行五参updateOomAdjLocked【见小节2.2】 boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false, SystemClock.uptimeMillis()); //当app cached状态改变,或者curRawAdj=16,则执行无参数updateOomAdjLocked【见小节2.3】 if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) { updateOomAdjLocked(); } return success; } |
该方法主要功能:
- 执行
五参updateOomAdjLocked
; - 当app经过更新adj操作后,其cached状态改变(包括由cached变成非cached,或者非cached变成cached),或者curRawAdj=16,则执行
无参updateOomAdjLocked
;
2.2 五参updateOomAdjLocked
1 2 3 4 5 6 7 8 9 10 11 |
private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP, boolean doingAll, long now) { if (app.thread == null) { return false; } //【见小节2.4】 computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now); //【见小节2.5】 return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime()); } |
该方法是private方法,只提供给一参和无参的同名方法调用,系统中并没有其他地方调用。
2.3 无参updateOomAdjLocked
2.3.1 涉及的部分参数
[-> ProcessList.java]
- 空进程存活时长:
MAX_EMPTY_TIME
= 30min - (缓存+空)进程个数上限:
MAX_CACHED_APPS
= SystemProperties.getInt(“sys.fw.bg_apps_limit”,32) = 32(默认); - 空进程个数上限:
MAX_EMPTY_APPS
= computeEmptyProcessLimit(MAX_CACHED_APPS) = MAX_CACHED_APPS/2 = 16; - trim空进程个数上限:
TRIM_EMPTY_APPS
= computeTrimEmptyApps() = MAX_EMPTY_APPS/2 = 8; - trim缓存进程个数上限:
TRIM_CACHED_APPS
= computeTrimCachedApps() = MAX_CACHED_APPS-MAX_EMPTY_APPS)/3 = 5; TRIM_CRITICAL_THRESHOLD
= 3;
[-> AMS.java]
mBServiceAppThreshold
= SystemProperties.getInt(“ro.sys.fw.bservice_limit”, 5);mMinBServiceAgingTime
=SystemProperties.getInt(“ro.sys.fw.bservice_age”, 5000);mProcessLimit
= ProcessList.MAX_CACHED_APPSmProcessLimit
= emptyProcessLimit(空进程上限) + cachedProcessLimit(缓存进程上限)oldTime
= now – ProcessList.MAX_EMPTY_TIME;LRU进程队列长度
= numEmptyProcs(空进程数) + mNumCachedHiddenProcs(cached进程) + mNumNonCachedProcs(非cached进程)emptyFactor
= numEmptyProcs/3, 且大于等于1cachedFactor
= mNumCachedHiddenProcs/3, 且大于等于1
2.3.2 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |