Android OomAdj
Android系统的设计理念正是希望应用进程能尽量长时间地存活,以提升用户体验。应用首次打开比较慢,这个过程有进程创建以及Application等信息的初始化,所以应用在启动之后,即便退到后台并非立刻杀死,而是存活一段时间,这样下次再使用则会非常快(cached进程和empty进程)。对于APP同样希望自身尽可能存活更长的时间。物极必反,系统处于低内存的状态下,手机性能会有所下降;系统继续放任所有
Android系统的设计理念正是希望应用进程能尽量长时间地存活,以提升用户体验。应用首次打开比较慢,这个过程有进程创建以及Application等信息的初始化,所以应用在启动之后,即便退到后台并非立刻杀死,而是存活一段时间,这样下次再使用则会非常快(cached进程和empty进程)。对于APP同样希望自身尽可能存活更长的时间。物极必反,系统处于低内存的状态下,手机性能会有所下降;系统继续放任所有进程一直存活,系统内存很快就会枯竭而亡,那么需要合理地进程回收机制。
谈到优先级,可能有些人会想到Linux进程本身有nice值,这个能决定CPU资源调度的优先级;而本文介绍Android系统中的ADJ,主要决定在什么场景下什么类型的进程可能会被杀,影响的是进程存活时间。ADJ与nice值两者定位不同,不过也有一定的联系,优先级很高的进程,往往也是用户不希望被杀的进程,是具有有一定正相关性。
因此就需要一些机制来衡量每一个进程的优先级和重要性,ADJ和proc_state就是两个很重要的衡量标准。系统根据进程的组件状态来决定每个进程的优先级值ADJ,系统根据一定策略先杀优先级最低的进程,然后逐步杀优先级更低的进程,依此类推,以回收预期的可用系统资源,从而保证系统正常运转。
AMS的OomAdj(Oom:out of memory,内存紧张)更新机制就是在Android系统中根据每个进程所处的实时状态用一个合适的ADJ值衡量其重要性,这个ADJ值会随之运行状态发生改变;实际上,OomAdj的更新不止是对进程ADJ的更新,伴随着会计算和更新的,还会有进程级别ProcState,scheduleGroup以及adjType等值,他们都能描述进程所处状态和重要性。
进程优先级(ADJ)
进程优先级(ADJ)定义在ProcessList.java文件,Oom_Adj划分为20个级,从-1000到1001之间取值
从Android 7.0开始,ADJ采用100、200、300;在这之前的版本ADJ采用数字1、2、3,这样的调整可以更进一步地细化进程的优先级,比如在VISIBLE_APP_ADJ(100)与PERCEPTIBLE_APP_ADJ(200)之间,可以有ADJ=101、102级别的进程。
ADJ级别 | adjString | 取值 | 解释 |
---|---|---|---|
UNKNOWN_ADJ | 1001 | 一般指将要会缓存进程,无法获取确定值 | |
CACHED_APP_MAX_ADJ | 999 | 不可见进程的adj最大值 | |
CACHED_APP_LMK_FIRST_ADJ | 950 | lowmem 查杀的最小等级 | |
CACHED_APP_MIN_ADJ | cch | 900 | 不可见进程的adj最小值 |
SERVICE_B_ADJ | svcb | 800 | B List中的Service(运行时间较长、使用可能性更小) |
PREVIOUS_APP_ADJ | prev | 700 | 上一个App的进程(上一个stopActivity的进程/20s内刚被使用的provider进程) |
HOME_APP_ADJ | home | 600 | Home进程 |
SERVICE_ADJ | svc | 500 | 服务进程(Service process) |
HEAVY_WEIGHT_APP_ADJ | hvy | 400 | 后台的重量级进程 |
BACKUP_APP_ADJ | bkup | 300 | 备份进程 |
PERCEPTIBLE_LOW_APP_ADJ | prcl | 250 | 由系统(或其他应用程序)绑定的进程,它比服务更重要,但不易察觉(clientAdj<200通过BIND_NOT_PERCEPTIBLE bind) |
PERCEPTIBLE_APP_ADJ | prcp | 200 | 可感知进程,比如后台音乐播放 (前台服务/display an overlay UI/currently used for toasts/clientAdj<200通过BIND_NOT_VISIBLE bind) |
VISIBLE_APP_ADJ(VISIBLE_APP_LAYER_MAX200-100-1) | vis | 100 | 可见进程(Visible process) ,一般是100+当前可见的layer数:activity不在前台,但是确实可见的或者正在运行远程动画 |
PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ | 50 | 应用有前台服务,从前台切换到前台service,且在15s内到过前台 | |
FOREGROUND_APP_ADJ | fg | 0 | 前台进程(Foreground process):应用本身就是在前台或者正在接收处理广播isReceivingBroadcastLocked或者服务执行过程中 |
PERSISTENT_SERVICE_ADJ | psvc | -700 | 关联着系统或persistent进程(由startIsolatedProcess()方式启动的进程,或者是由system_server或者persistent进程所绑定的服务进程) |
PERSISTENT_PROC_ADJ | pers | -800 | 系统persistent进程,比如telephony(一般不会被杀,即使被杀或crash,立即重启) |
SYSTEM_ADJ | sys | -900 | 系统进程(system_server进程) |
NATIVE_ADJ | ntv | -1000 | native进程(由init进程fork出的进程,并不受system管控) |
进程刚启动时ADJ等于INVALID_ADJ,当执行完attachApplication(),该该进程的curAdj和setAdj不相等,则会触发执行setOomAdj()将该进程的节点/proc/pid/oom_score_adj写入oomadj值
当系统剩余空闲内存低于某阈值(比如147MB),则从ADJ大于或等于相应阈值(比如900)的进程中,选择ADJ值最大的进程,如果存在多个ADJ相同的进程,则选择内存最大的进程
在updateOomLevels()过程,会根据手机屏幕尺寸或内存大小来调整scale,默认大多数手机内存都大于700MB,则scale等于1
进程state级别(ProcState)
定义在ActivityManager.java文件,process_state划分22类,从0到21之间取值。
state级别 | procStateString | 取值 | 解释 |
---|---|---|---|
PROCESS_STATE_NONEXISTENT | NONE | 20 | 进程不存在 |
PROCESS_STATE_CACHED_EMPTY | CEM | 19 | 进程处于cached状态,且为空进程 |
PROCESS_STATE_CACHED_RECENT | CRE | 18 | 带有recentTasks的cache进程(有activity在最近任务列表) |
PROCESS_STATE_CACHED_ACTIVITY_CLIENT | CACC | 17 | 进程处于cached状态,且为另一个cached进程(内含Activity)的client进程 |
PROCESS_STATE_CACHED_ACTIVITY | CAC | 16 | 进程处于cached状态,且内含Activity |
PROCESS_STATE_LAST_ACTIVITY | LAST | 15 | 后台进程,且拥有上一次显示的Activity |
PROCESS_STATE_HOME | HOME | 14 | 后台进程,且拥有home Activity |
PROCESS_STATE_HEAVY_WEIGHT | HVY | 13 | 后台进程,但无法执行restore,因此尽量避免kill该进程 |
PROCESS_STATE_TOP_SLEEPING | TPSL | 12 | 与PROCESS_STATE_TOP一样,但此时设备正处于休眠状态 |
PROCESS_STATE_RECEIVER | RCVR | 11 | 后台进程,且正在运行receiver |
PROCESS_STATE_SERVICE | SVC | 10 | 后台进程,且正在运行service |
PROCESS_STATE_BACKUP | BKUP | 9 | 后台进程,正在运行backup/restore操作 |
PROCESS_STATE_TRANSIENT_BACKGROUND | TRNB | 8 | 后台进程 |
PROCESS_STATE_IMPORTANT_BACKGROUND | IMPB | 7 | 对用户很重要的进程,用户不可感知其存在 |
PROCESS_STATE_IMPORTANT_FOREGROUND | IMPF | 6 | 对用户很重要的进程,用户可感知其存在 |
PROCESS_STATE_BOUND_FOREGROUND_SERVICE | BFGS | 5 | 通过系统绑定拥有一个前台Service, |
PROCESS_STATE_FOREGROUND_SERVICE | FGS | 4 | 拥有一个前台Service |
PROCESS_STATE_BOUND_TOP | BTOP | 3 | 绑定到top应用的进程 |
PROCESS_STATE_TOP | TOP | 2 | 拥有当前用户可见的top Activity |
PROCESS_STATE_PERSISTENT_UI | PERU | 1 | persistent系统进程,并正在执行UI操作 |
PROCESS_STATE_PERSISTENT | PER | 0 | persistent系统进程 |
PROCESS_STATE_UNKNOWN | -1 | UNKNOWN进程 |
schedGroup解释
schedGroup | 值 | 含义 |
---|---|---|
SCHED_GROUP_BACKGROUND | 0 | 后台进程组 |
SCHED_GROUP_RESTRICTED | 1 | |
SCHED_GROUP_DEFAULT | 2 | 前台进程组 |
SCHED_GROUP_TOP_APP | 3 | TOP进程组 |
SCHED_GROUP_TOP_APP_BOUND | 4 | TOP进程组 |
adjType
Method | adjType | adj | procState |
---|---|---|---|
hasOverlayUi | has-overlay-ui | ProcessList.PERCEPTIBLE_APP_ADJ = 200 | PROCESS_STATE_IMPORTANT_FOREGROUND = 7 |
hasForegroundServices() && 15s内从前台切到前台服务 | fg-service-act | ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50 | |
forcingToImportant != null | force-imp | ProcessList.PERCEPTIBLE_APP_ADJ = 200 | PROCESS_STATE_TRANSIENT_BACKGROUND = 9 |
mService.mAtmInternal.isHeavyWeightProcess(app.getWindowProcessController() | heavy | ProcessList.HEAVY_WEIGHT_APP_ADJ = 400 | PROCESS_STATE_HEAVY_WEIGHT = 14 |
wpc.isHomeProcess() | home | ProcessList.HOME_APP_ADJ = 600 | PROCESS_STATE_HOME = 15 |
wpc.isPreviousProcess() && app.hasActivities() | previous | PREVIOUS_APP_ADJ = 700 | PROCESS_STATE_LAST_ACTIVITY = 16 |
mService.mBackupTargets.get(app.userId) == app | backup | BACKUP_APP_ADJ = 300 | PROCESS_STATE_TRANSIENT_BACKGROUND = 9 |
process的services中某个service的startRequested 为true | started-services | SERVICE_ADJ = 500 | PROCESS_STATE_SERVICE = 11 |
app.hasShownUi && !wpc.isHomeProcess() | cch-started-ui-services | 同上 |
在ULMK(user lowmemorykiller:用户空间低内存杀手)机制当中,就会经常使用到进程优先级(ADJ);AMS通过四大组件的运行状态更新这些组件相关联的进程的OomAdj(包括adj,proc_state,schedule_group以及adjtype等值),AMS在计算好每一个进程的ADJ之后,会调用setOomAdjLocked方法,将每个进程对应的adj传送到native层的ULMK当中,ULMK维护着一个管理系统中所有进程及其adj信息的双向链表数组,这个双向链表数组的每一个元素都是一个双向链表,一个数组元素中的双向链表里面的元素,都是adj相同的进程;ULMK在系统低内存的时候,就会根据进程优先级去查杀一些显得不这么重要的进程,回收这些进程的内存空间,达到回收内存的目的,防止内存过低影响系统运行。
因此,在framework层中AMS更新进程OomAdj的过程,其实就是根据系统运行场景,将系统中所有的进程都分配一个优先级值,根据优先级的大小彰显每一个进程的重要性,实际上就是排队的过程;然后更新到ULMK中,根据ADJ的值对这些进程进行排序分类;但内存不足时直接根据进程优先级对不重要的进程进行查杀,回收内存。
函数 | 说明 |
---|---|
updateOomAdjLocked | 当Android四大组件状态改变时会调用updateOomAdjLocked()来同步更新相应进程的ADJ优先级。当同一个进程有多个决定其优先级的组件状态时,取优先级最高的ADJ作为最终的ADJ。当目标进程为空或者被杀则返回false;否则返回true; |
computeOomAdjLocked | 计算adj,返回计算后RawAdj值 |
applyOomAdjLocked | 将计算后的adj写入lmkd,当需要杀掉目标进程则返回false;否则返回true。 |
updateOomAdjLocked
在OomAdjuster.java中,不仅仅有一/二/三参三个具体实现方法,还新增了一个五参方法,这个方法也是这几个方法中最重要的一个方法
五参方法是一个private方法,仅供二/三参进行调用
一/二/三/五参方法的实现很多都是彼此依靠的,相互调用;下图是他们之间彼此的调用关系:
- 一参方法:更新整个LRU list(所有由AMS启动的进程都会保存到这里边)中全部进程的OomAdj
- 二参方法:更新一个进程机及其reachable进程
- 三参方法:也是一个对特定进程和其关联进程进行OomAdj更新的方法,具体的实现逻辑可以参考上图
- 五参方法:private方法,供二参三参方法调用;主要是调用ComputeOomAdjLocked方法和ApplyOomAdjLocked方法,对指定的进程进行OomAdj计算和应用
- 一参
主要是用来更新AMS中整个LRU列表的所有进程的OomAdj(adj,ProcState,adjType,scheduleGroup等值),并且在这个过程中会对cached进程和empty进程进行处理
updateOomAdjLocked(一参)
|-> updateOomAdjLockedInner()
|->updateAndTrimProcessLocked()
|->updateLowMemStateLocked
/**
* Update OomAdj for all processes in LRU list
*/
@GuardedBy("mService")
void updateOomAdjLocked(String oomAdjReason) {
// 前台的app(若无app 处于前台则是TASK栈栈顶的应用)
final ProcessRecord topApp = mService.getTopAppLocked();
//一参方法实际调用updateOomAdjLockedInner方法
updateOomAdjLockedInner(oomAdjReason, topApp , null, null, true, true);
}
/** 更新整个lru list或者传入的processes的ADJ和proc_state
* Update OomAdj for all processes within the given list (could be partial), or the whole LRU
* list if the given list is null; when it's partial update, each process's client proc won't
* get evaluated recursively here.
*/
@GuardedBy("mService")
private void updateOomAdjLockedInner(String oomAdjReason, final ProcessRecord topApp,
ArrayList<ProcessRecord> processes, ActiveUids uids, boolean potentialCycles,
boolean startProfiling) {
// true
if (startProfiling) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);
mService.mOomAdjProfiler.oomAdjStarted();
}
final long now = SystemClock.uptimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
final long oldTime = now - ProcessList.MAX_EMPTY_TIME;//30 min
final boolean fullUpdate = processes == null;
ActiveUids activeUids = uids;
// 执行partial或者全部,这里是mLruProcesses
ArrayList<ProcessRecord> activeProcesses = fullUpdate ? mProcessList.mLruProcesses
: processes;
final int numProc = activeProcesses.size();
//初始化uids列表
if (activeUids == null) {
//mActiveUids:跟踪所有正在运行进程的uid
final int numUids = mActiveUids.size();
activeUids = mTmpUidRecords;
activeUids.clear();
for (int i = 0; i < numUids; i++) {
//通过mActiveUids更新activeUids
UidRecord r = mActiveUids.valueAt(i);
activeUids.put(r.uid, r);
}
}
// 重置用户组中所有进程的状态.
for (int i = activeUids.size() - 1; i >= 0; i--) {
final UidRecord uidRec = activeUids.valueAt(i);
uidRec.reset();
}
...
//用于标识oom_adj分配周期的id
mAdjSeq++;
if (fullUpdate) {
mNewNumServiceProcs = 0;
mNewNumAServiceProcs = 0;
}
boolean retryCycles = false;
boolean computeClients = fullUpdate || potentialCycles;
// need to reset cycle state before calling computeOomAdjLocked because of service conns
for (int i = numProc - 1; i >= 0; i--) {
ProcessRecord app = activeProcesses.get(i);
//所有的reachable都为false
app.mReachable = false;
// No need to compute again it has been evaluated in previous iteration
if (app.adjSeq != mAdjSeq) {
app.containsCycle = false;
//设为empty进程
app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);
//adj设为UNKNOWN_ADJ
app.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
app.setCapability = PROCESS_CAPABILITY_NONE;
app.resetCachedInfo();
}
}
for (int i = numProc - 1; i >= 0; i--) {
ProcessRecord app = activeProcesses.get(i);
if (!app.killedByAm && app.thread != null) {
app.procStateChanged = false;
computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, topApp, fullUpdate, now, false,
computeClients); // It won't enter cycle if not computing clients.
// if any app encountered a cycle, we need to perform an additional loop later
retryCycles |= app.containsCycle;
// 保持completedAdjSeq最新
app.completedAdjSeq = mAdjSeq;
}
}
//将cache进程和empty进程均匀分散到slot中去
assignCachedAdjIfNecessary(mProcessList.mLruProcesses);
if (computeClients) { // There won't be cycles if we didn't compute clients above.
...
}
// 非cached进程
mNumNonCachedProcs = 0;
// cached进程
mNumCachedHiddenProcs = 0;
//杀掉超过限额的empty进程和cached进程,这个函数很重要
boolean allChanged = updateAndTrimProcessLocked(now, nowElapsed, oldTime, activeUids);
mNumServiceProcs = mNewNumServiceProcs;
...
}
updateAndTrimProcessLocked含有较多的app.kill()方法,是AMS除了lmkd之外的一个杀进程机制
/**
*本方法主要是遍历LRU列表,分别统计cached,empty和trim进程的个数,
* 并且对超出限定值的cache和empty进程进行查杀,回收内存
* cached和empty进程查杀规则:
* 1、cached进程数大于cachedProcessLimit(16),查杀当前进程
* 2、empty进程数大于emptyProcessLimit(16),查杀当前进程
* 3、empty进程数大于 CUR_TRIM_EMPTY_PROCESSES(8),并且三十分钟内该进程没有活跃,杀掉
* 4、如果进程为isolate进程且当前没有运行服务,杀掉
* */
private boolean updateAndTrimProcessLocked(final long now, final long nowElapsed,
final long oldTime, final ActiveUids activeUids) {
ArrayList<ProcessRecord> lruList = mProcessList.mLruProcesses;
final int numLru = lruList.size();
final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;//16
final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES
- emptyProcessLimit;//16
int lastCachedGroup = 0;
int lastCachedGroupUid = 0;
int numCached = 0;
int numCachedExtraGroup = 0;
int numEmpty = 0;
int numTrimming = 0;
ProcessRecord selectedAppRecord = null;
long serviceLastActivity = 0;
int numBServices = 0;//B_service 进程数量
//反向遍历LRU
for (int i = numLru - 1; i >= 0; i--) {
ProcessRecord app = lruList.get(i);
if (!app.killedByAm && app.thread != null) {
// 我们不需要为没有计算的进程应用更新
if (app.completedAdjSeq == mAdjSeq) {
applyOomAdjLocked(app, true, now, nowElapsed);
}
// 统计进程类型数量
switch (app.getCurProcState()) {
case PROCESS_STATE_CACHED_ACTIVITY://cache_activity + cached_activity_client
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
mNumCachedHiddenProcs++;//统计cached进程个数,全局
numCached++;
if (app.connectionGroup != 0) {
if (lastCachedGroupUid == app.info.uid
&& lastCachedGroup == app.connectionGroup) {//与上一个进程是同一个进程组的,不计数
numCachedExtraGroup++;//额外计数
} else {
lastCachedGroupUid = app.info.uid;
lastCachedGroup = app.connectionGroup;
}
} else {
lastCachedGroupUid = lastCachedGroup = 0;
}
//除掉额外计数的cached进程,仍超出限制值,杀掉
if ((numCached - numCachedExtraGroup) > cachedProcessLimit) {
app.kill("cached #" + numCached,
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_TOO_MANY_CACHED,
true);
}
break;
case PROCESS_STATE_CACHED_EMPTY://empty进程
//empty进程数量大于 CUR_TRIM_EMPTY_PROCESSES(=8)并且activity上一次活跃超过了30min,杀掉
if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
&& app.lastActivityTime < oldTime) {
app.kill("empty for "
+ ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
/ 1000) + "s",
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_TRIM_EMPTY,
true);
} else {
numEmpty++;
//empty进程数大于16,直接杀
if (numEmpty > emptyProcessLimit) {
app.kill("empty #" + numEmpty,
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_TOO_MANY_EMPTY,
true);
}
}
break;
default:
mNumNonCachedProcs++;
break;
}
if (app.isolated && app.numberOfRunningServices() <= 0
&& app.isolatedEntryPoint == null) {
// 如果这是一个isolated的进程,其中没有运行服务,并
// 且它不是具有自定义入口点的特殊进程,那么该进程就不再需要。
// 我们强烈地杀死这些代码,因为我们可以根据定义不再重复使用相同的过程,
// 并且避免在不再需要的情况下让代码中的任何代码在它们中运行是好的。
app.kill("isolated not needed", ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_ISOLATED_NOT_NEEDED, true);
} else {
//更新uidRec.setCurProcState,uidRec.foregroundServices和uidRec.curCapability
updateAppUidRecLocked(app);
}
if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedByAm) {
//trimming进程, 比PROCESS_STATE_HOME不重要的进程
numTrimming++;
}
}
//B_SERVICE进程级别
if (mEnableBServicePropagation && app.serviceb
&& (app.curAdj == ProcessList.SERVICE_B_ADJ)) {
numBServices++;//计数 B_service
//遍历该进程正在运行的服务
for (int s = app.numberOfRunningServices() - 1; s >= 0; s--) {
ServiceRecord sr = app.getRunningServiceAt(s);
//当前时间和上一次activity运行该服务的时间差,lastActivity在创建services时候更新
//mMinBServiceAgingTime = 5000 ms,B_service的最小老化时间阈值
if (SystemClock.uptimeMillis() - sr.lastActivity
< mMinBServiceAgingTime) {
...
continue;
}
//更新距上一次运行service时间最久的app
// 当进程为一个B_service,在B_service进程数超出阈值(5个)时,
// 如果该进程相关联的service中,有最久未被调用的service,则将该进程设置为SelectedAppRecord,
// 将其adj设置为800,lmkd中存储的为900
if (serviceLastActivity == 0) {
serviceLastActivity = sr.lastActivity;
selectedAppRecord = app;
} else if (sr.lastActivity < serviceLastActivity) {
serviceLastActivity = sr.lastActivity;
selectedAppRecord = app;
}
}
}
}
//当BServices个数超过上限(mBServiceAppThreshold=5),
//且mAllowLowerMemLevel为true,即为低内存lmkd杀过进程
if ((numBServices > mBServiceAppThreshold) && (true == mService.mAllowLowerMemLevel)
&& (selectedAppRecord != null)) {
//setOomAdj()方法将更新后的adj写入到native层的lmkd
ProcessList.setOomAdj(selectedAppRecord.pid, selectedAppRecord.info.uid,
ProcessList.CACHED_APP_MAX_ADJ);
//将最久没运行过的appRecord的adj设为最高值
selectedAppRecord.setAdj = selectedAppRecord.curAdj;
if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + selectedAppRecord.processName
+ " app.pid = " + selectedAppRecord.pid + " is moved to higher adj");
}
mProcessList.incrementProcStateSeqAndNotifyAppsLocked(activeUids);
//本方法根据cached和empty进程的数量,确定 memFactor;根据memFactor是否为NORMAL等级分别进行处理
return mService.updateLowMemStateLocked(numCached, numEmpty, numTrimming);
}
/**
*本方法根据cached和empty进程的数量,确定 memFactor;根据memFactor是否为NORMAL等级分别进行处理
* 1、非NORMAL:将memFactor转换为trim level等级,根据当前进程的进程级别分等级处理,确定最新的trim level
* 2、NORMAL:对于重要性比IMPORTANT_BACKGROUND小或没有运行UI的system进程,关闭其从showing UI回收内存的权利,并且将trimlevel提升到不低于UI_HIDDEN
*/
final boolean updateLowMemStateLocked(int numCached, int numEmpty, int numTrimming) {
final int N = mProcessList.getLruSizeLocked();//lru大小
final long now = SystemClock.uptimeMillis();
//内存因子,值越大,级别越高,内存资源越紧张
int memFactor;
if (mLowMemDetector != null && mLowMemDetector.isAvailable()) {
//获取memfactor,此函数根据PSI event返回对应的内存因子级别,通过监听/proc/pressure/memory实现
// waitforPressure方法是一个jni调用
memFactor = mLowMemDetector.getMemFactor();
} else {
// R上不在使用
// 根据cache进程和empty进程的个数得出memfactor,memfactor越大,内存压力越大
if (numCached <= mConstants.CUR_TRIM_CACHED_PROCESSES//32/6=5
&& numEmpty <= mConstants.CUR_TRIM_EMPTY_PROCESSES) {//8
final int numCachedAndEmpty = numCached + numEmpty;
if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {//3
memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
} else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {//5
memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
} else {
memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
}
} else {
memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
}
}
// We always allow the memory level to go up (better). We only allow it to go
// down if we are in a state where that is allowed, *and* the total number of processes
// has gone down since last time.
if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "oom: memFactor=" + memFactor
+ " last=" + mLastMemoryLevel + " allowLow=" + mAllowLowerMemLevel
+ " numProcs=" + mProcessList.getLruSizeLocked() + " last=" + mLastNumProcesses);
//现在的等级比之前还高,说明内存紧张,不主动降低等级
if (memFactor > mLastMemoryLevel) {
//当不允许LowerMemLevel或者LRU进程数有增加时,可以降低等级
if (!mAllowLowerMemLevel || mProcessList.getLruSizeLocked() >= mLastNumProcesses) {
memFactor = mLastMemoryLevel;
if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "Keeping last mem factor!");
}
}
//内存因子更新了
if (memFactor != mLastMemoryLevel) {
EventLogTags.writeAmMemFactor(memFactor, mLastMemoryLevel);
FrameworkStatsLog.write(FrameworkStatsLog.MEMORY_FACTOR_STATE_CHANGED, memFactor);
}
//更新最近一次memorylevel的等级
mLastMemoryLevel = memFactor;
mLastNumProcesses = mProcessList.getLruSizeLocked();
//将内存等级保存到processstats中,如果与之前不等(更新了),返回true
boolean allChanged = mProcessStats.setMemFactorLocked(
memFactor, mAtmInternal != null ? !mAtmInternal.isSleeping() : true, now);
//更新后获取factor
final int trackerMemFactor = mProcessStats.getMemFactorLocked();
//下面为两个大判断,memFactor 为NORMAL和不为NORMAL两种情况
//memFactor 不等于NORMAL时的处理
if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
if (mLowRamStartTime == 0) {
//进入lowRam状态,记录进入的时间点
mLowRamStartTime = now;
}
int step = 0;
int fgTrimLevel;
//将内存因子memFactor转换为ComponentCallbacks2中定义的变量名,
//就是从memFactor等级转换到 TrimMemlevel
//TrimMemlevel 值越大越容易被回收
switch (memFactor) {
case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
break;
case ProcessStats.ADJ_MEM_FACTOR_LOW:
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
break;
default:
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
break;
}
//factor为每个槽可以容纳的进程数
// 三个LowRam状态各自放多少Trimming进程
int factor = numTrimming/3;
int minFactor = 2;
if (mAtmInternal.getHomeProcess() != null) minFactor++;
if (mAtmInternal.getPreviousProcess() != null) minFactor++;
if (factor < minFactor) factor = minFactor;
//80,最高等级,内存压力最大
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
// 对于重要性大于home的进程而言,重要性越高,内存回收等级越低
// 对于重要性小于home的进程,排在LRU列表越靠后,即越重要回收等级越高
// 这么安排的理由有两个:
// 1、此时越不重要的进程,其中运行的组件越少,能够回收的内存不多,不需要高回收等级
// 2、越不重要的进程越有可能被LMK kill掉,没必要以高等级回收内存
//反向遍历LRU链表
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
setProcessTrackerStateLocked(app, trackerMemFactor, now);
app.procStateChanged = false;
}
//process_state大于等于HOME进程,没HOME这么重要的进程
if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedByAm) {
if (app.trimMemoryLevel < curLevel && app.thread != null) {
try {
//加大内存回收
app.thread.scheduleTrimMemory(curLevel);
} catch (RemoteException e) {
}
}
//调整 trimMemoryLevel 到 curlevel
app.trimMemoryLevel = curLevel;
step++;
//当前factor满了,下一个factor
if (step >= factor) {
step = 0;
switch (curLevel) {
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
curLevel = ComponentCallbacks2.TRIM_MEMORY_MODERATE;
break;
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
curLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
break;
}
}
} else if (app.getCurProcState() == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
&& !app.killedByAm) {//重量级后台进程
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
&& app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Trimming memory of heavy-weight " + app.processName
+ " to " + ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
//level提到TRIM_MEMORY_BACKGROUND
app.thread.scheduleTrimMemory(
ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
} catch (RemoteException e) {
}
}
app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
} else {//其他进程级别
//级别大于等于重要的后台进程
if ((app.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
|| app.systemNoUi) && app.hasPendingUiClean()) {
// If this application is now in the background and it
// had done UI, then give it the special trim level to
// have it free UI resources.
final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
if (app.trimMemoryLevel < level && app.thread != null) {
try {
//回收
app.thread.scheduleTrimMemory(level);
} catch (RemoteException e) {
}
}
app.setPendingUiClean(false);
}
if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
try {
//关掉showingUI回收
app.thread.scheduleTrimMemory(fgTrimLevel);
} catch (RemoteException e) {
}
}
app.trimMemoryLevel = fgTrimLevel;
}
}
} else { //memFactor == NORMAL时的处理
if (mLowRamStartTime != 0) {
//统计总的LowRam持续时间
mLowRamTimeSinceLastIdle += now - mLowRamStartTime;
//NORMAL状态取消LowRam状态和计时
mLowRamStartTime = 0;
}
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
setProcessTrackerStateLocked(app, trackerMemFactor, now);
app.procStateChanged = false;
}
//当前内存factor是NORMAL,根据当前进程state和trimmemorylevel,
// 关掉showingUI回收(只处理比PROCESS_STATE_IMPORTANT_BACKGROUND不重要的进程)
//PROCESS_STATE_IMPORTANT_BACKGROUND重要的后台进程
// systemNoUi:系统进程但是没有正在显示的UI;hasPendingUiClean:是否想从showingUI回收内存
if ((app.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
|| app.systemNoUi) && app.hasPendingUiClean()) {
//内存等级小于TRIM_MEMORY_UI_HIDDEN
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
&& app.thread != null) {
try {
//调整TrimMemoryLevel到TRIM_MEMORY_UI_HIDDEN
app.thread.scheduleTrimMemory(
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
} catch (RemoteException e) {
}
}
//清理showingUI:false
app.setPendingUiClean(false);
}
app.trimMemoryLevel = 0;
}
}
return allChanged;
}
- 五参
该方法是private方法,只提供给二参和三参调用,该方法只是更新某一个特定的进程以及其关联的进程,主要是调用ComputeOomAdjLocked方法和applyOomAdjLocked方法
private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
ProcessRecord TOP_APP, boolean doingAll, long now) {
...
//重置缓存info
app.resetCachedInfo();
//获取进程所在用户组的整体状态:overall state of process's uid
//UidRecord用于记录某个用户组中的进程运行状态
UidRecord uidRec = app.uidRecord;
if (uidRec != null) {
//重置用户组
uidRec.reset();
}
//计算一次OomAdj,最后一个参数为true,把client进程也算了
computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false, true);
//应用adj
boolean success = applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
//以下为UidRecord的一些更新
if (uidRec != null) {
final ArraySet<ProcessRecord> procRecords = app.uidRecord.procRecords;
//遍历uidRecord的所有processRecord
for (int i = procRecords.size() - 1; i >= 0; i--) {
final ProcessRecord pr = procRecords.valueAt(i);
//还存在
if (!pr.killedByAm && pr.thread != null) {
//孤立进程 && 没有运行的service
if (pr.isolated && pr.numberOfRunningServices() <= 0
&& pr.isolatedEntryPoint == null) {
// No op.
} else {
//更新pr在UidRecord的信息
updateAppUidRecLocked(pr);
}
}
}
if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT
&& (uidRec.setProcState != uidRec.getCurProcState()
|| uidRec.setCapability != uidRec.curCapability
|| uidRec.setWhitelist != uidRec.curWhitelist)) {
ActiveUids uids = mTmpUidRecords;
uids.clear();
uids.put(uidRec.uid, uidRec);
updateUidsLocked(uids, now);
mProcessList.incrementProcStateSeqAndNotifyAppsLocked(uids);
}
}
return success;
}
- 二参
1、调用五参方法更新自己的OomAdj
2、找出当前进程的所有reachable进程(service和provider相关的进程)
3、调用一参方法中的主要实现方法:updateOomAdjLockedInner()方法,传入整理好的reachable进程的列表,使用updateOomAdjLockedInner的更新部分列表OomAdj的功能更新reachable进程列表的OomAdj
boolean updateOomAdjLocked(ProcessRecord app, String oomAdjReason) {
...
//从AMS获取TopApp
final ProcessRecord topApp = mService.getTopAppLocked();
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);
mService.mOomAdjProfiler.oomAdjStarted();
//updateOomAdjLocked调用次数
mAdjSeq++;
// 第一步首先更新自己
//是否处于cached状态
final boolean wasCached = app.isCached();
//当前unlimit 的adj
final int oldAdj = app.getCurRawAdj();
//确定cachedAdj
final int cachedAdj = oldAdj >= ProcessList.CACHED_APP_MIN_ADJ
? oldAdj : ProcessList.UNKNOWN_ADJ;
final boolean wasBackground = ActivityManager.isProcStateBackground(app.setProcState);
app.containsCycle = false;
app.procStateChanged = false;
//重置cache信息,值重置
app.resetCachedInfo();
//调用五参更新adj,app的adj
boolean success = updateOomAdjLocked(app, cachedAdj, topApp, false,
SystemClock.uptimeMillis());
//是cache进程并且background状态未变,五参更新没成功(进程被杀了)
if (!success || (wasCached == app.isCached() && oldAdj != ProcessList.INVALID_ADJ
&& wasBackground == ActivityManager.isProcStateBackground(app.setProcState))) {
// Okay, it's unchanged, it won't impact any service it binds to, we're done here.
if (DEBUG_OOM_ADJ) {
Slog.i(TAG_OOM_ADJ, "No oomadj changes for " + app);
}
mService.mOomAdjProfiler.oomAdjEnded();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return success;//此时返回的是不成功
}
//第二步:找到所有的reachable进程, 更新reachable进程
ArrayList<ProcessRecord> processes = mTmpProcessList;
ActiveUids uids = mTmpUidRecords;
//mTmpQueue:大小是两倍的 CUR_MAX_CACHED_PROCESSES = 32
ArrayDeque<ProcessRecord> queue = mTmpQueue;
processes.clear();
uids.clear();
queue.clear();
// Track if any of them reachables could include a cycle
boolean containsCycle = false;
// Scan downstreams of the process record
app.mReachable = true;
//循环遍历reachable的进程,其实就是遍历有关联的service和provider
//第一个for循环执行的是app,此时queue为空,第一个for循环将app的所有相关联service和provider都加入到queue中
//之后的for循环就是遍历queue,即遍历reachable进程
//poll:检索并移除队列的头部
for (ProcessRecord pr = app; pr != null; pr = queue.poll()) {
if (pr != app) {
//将reachable进程加入到processes
processes.add(pr);
}
if (pr.uidRecord != null) {
uids.put(pr.uidRecord.uid, pr.uidRecord);
}
// 有连接相关的进程
for (int i = pr.connections.size() - 1; i >= 0; i--) {
ConnectionRecord cr = pr.connections.valueAt(i);
ProcessRecord service = (cr.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
? cr.binding.service.isolatedProc : cr.binding.service.app;
if (service == null || service == pr) {
continue;
}
containsCycle |= service.mReachable;
if (service.mReachable) {
continue;
}
// BIND_WAIVE_PRIORITY: 不会影响服务的进程优先级,像通用的应用进程一样将服务放在一个LRU表中
if ((cr.flags & (Context.BIND_WAIVE_PRIORITY
| Context.BIND_TREAT_LIKE_ACTIVITY
| Context.BIND_ADJUST_WITH_ACTIVITY))
== Context.BIND_WAIVE_PRIORITY) {
continue;
}
//加入队列尾部
queue.offer(service);
//该服务是reachable的
service.mReachable = true;
}
for (int i = pr.conProviders.size() - 1; i >= 0; i--) {
ContentProviderConnection cpc = pr.conProviders.get(i);
ProcessRecord provider = cpc.provider.proc;
if (provider == null || provider == pr || (containsCycle |= provider.mReachable)) {
continue;
}
containsCycle |= provider.mReachable;
if (provider.mReachable) {
continue;
}
queue.offer(provider);
provider.mReachable = true;
}
}
// Reset the flag
app.mReachable = false;
int size = processes.size();
if (size > 0) {
// Reverse the process list, since the updateOomAdjLockedInner scans from the end of it.
for (int l = 0, r = size - 1; l < r; l++, r--) {
ProcessRecord t = processes.get(l);
processes.set(l, processes.get(r));
processes.set(r, t);
}
mAdjSeq--;
//更新传入的进程列表,updateOomAdjLockedInner()能根据传入的参数确定更新部分或全部的list
updateOomAdjLockedInner(oomAdjReason, topApp, processes, uids, containsCycle, false);
} else if (app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ) {
// In case the app goes from non-cached to cached but it doesn't have other reachable
// processes, its adj could be still unknown as of now, assign one.
processes.add(app);
assignCachedAdjIfNecessary(processes);
applyOomAdjLocked(app, false, SystemClock.uptimeMillis(),
SystemClock.elapsedRealtime());
}
//统计系统进入计算OomAdj的起始和结束时间,最后计算出OomAdj的运行时间
//mOomAdjProfiler 这个类应该是用来统计所有OomAdj信息的,在AMS中有定义实例
mService.mOomAdjProfiler.oomAdjEnded();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return true;
}
assignCachedAdjIfNecessary
/*
*该函数是将lru list中的cache的进程按照一定的跨距逐个分配到[CACHED_APP_MIN_ADJ,CACHED_APP_MAX_ADJ]区间中
*根据proc_state为empty和其他cached,对其进行分配
*/
private void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
final int numLru = lruList.size();
//第一步:根据各应用进程的当前状态更新对应的优先级
int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
// CACHED_APP_IMPORTANCE_LEVELS=5,ProcessList中的静态变量
int nextCachedAdj = curCachedAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);
int curCachedImpAdj = 0;
int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
int nextEmptyAdj = curEmptyAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);
final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;//16
final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES//32 - 16
- emptyProcessLimit; //emptyProcessLimit == 16
//计算出槽的数量,再将cache进程和empty进程分别平均分配到这些槽中(slots)
//CACHED_APP_MIN_ADJ == 900,CACHED_APP_MAX_ADJ == 999,在min和max之间交错分配cached和empty进程
//mNumNonCachedProcs是除cached进程外的进程数,mNumCachedHiddenProcs是cached进程个数
int numEmptyProcs = numLru - mNumNonCachedProcs - mNumCachedHiddenProcs;
if (numEmptyProcs > cachedProcessLimit) {//空进程数大于cache进程阈值
//确保低内存杀进程的时候以杀empty为主,尽可能保留cache
numEmptyProcs = cachedProcessLimit;
}
//cachedFactor和emptyFactor分别表示每个slot中包括的进程个数
int cachedFactor = (mNumCachedHiddenProcs > 0 ? (mNumCachedHiddenProcs + mNumSlots - 1) : 1)
/ mNumSlots;
if (cachedFactor < 1) cachedFactor = 1;
int emptyFactor = (numEmptyProcs + mNumSlots - 1) / mNumSlots;
if (emptyFactor < 1) emptyFactor = 1;
int stepCached = -1;
int stepEmpty = -1;
int lastCachedGroup = 0;
int lastCachedGroupImportance = 0;
int lastCachedGroupUid = 0;
//遍历lru列表,为每一个app进程更新cache状态
for (int i = numLru - 1; i >= 0; i--) {
ProcessRecord app = lruList.get(i);
// If we haven't yet assigned the final cached adj
// to the process, do that now.
if (!app.killedByAm && app.thread != null && app.curAdj
>= ProcessList.UNKNOWN_ADJ) {
switch (app.getCurProcState()) {
//三种非emptycache进程
case PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
case ActivityManager.PROCESS_STATE_CACHED_RECENT:
// Figure out the next cached level, taking into account groups.
boolean inGroup = false;
if (app.connectionGroup != 0) {
if (lastCachedGroupUid == app.uid
&& lastCachedGroup == app.connectionGroup) {
// This is in the same group as the last process, just tweak
// adjustment by importance.
if (app.connectionImportance > lastCachedGroupImportance) {
lastCachedGroupImportance = app.connectionImportance;
if (curCachedAdj < nextCachedAdj
&& curCachedAdj < ProcessList.CACHED_APP_MAX_ADJ) {
curCachedImpAdj++;
}
}
inGroup = true;
} else {
lastCachedGroupUid = app.uid;
lastCachedGroup = app.connectionGroup;
lastCachedGroupImportance = app.connectionImportance;
}
}
if (!inGroup && curCachedAdj != nextCachedAdj) {
stepCached++;
curCachedImpAdj = 0;
//当前slot数大于factor,分配下一个slot,更新cur和next的cachedadj
if (stepCached >= cachedFactor) {
stepCached = 0;
curCachedAdj = nextCachedAdj;
nextCachedAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
}
}
}
// This process is a cached process holding activities...
// assign it the next cached value for that type, and then
// step that cached level.
app.setCurRawAdj(curCachedAdj + curCachedImpAdj);
app.curAdj = app.modifyRawOomAdj(curCachedAdj + curCachedImpAdj);
if (DEBUG_LRU) {
Slog.d(TAG_LRU, "Assigning activity LRU #" + i
+ " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj
+ " curCachedImpAdj=" + curCachedImpAdj + ")");
}
break;
default:
//empty进程
// Figure out the next cached level.
if (curEmptyAdj != nextEmptyAdj) {
stepEmpty++;
if (stepEmpty >= emptyFactor) {
stepEmpty = 0;
curEmptyAdj = nextEmptyAdj;
nextEmptyAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
}
}
}
app.setCurRawAdj(curEmptyAdj);
app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
if (DEBUG_LRU) {
Slog.d(TAG_LRU, "Assigning empty LRU #" + i
+ " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj
+ ")");
}
break;
}
}
}
}
AMS将所有cache和empty按照一定的机制均分到[900,999]区间中;在这个区间中,每一个分配给cache/empty进程的adj值都被称为一个槽点(slot),实际上是将LRU列表中的所有cache进程按照一定的跨距均分到这些槽点中;
在这个机制里面,cache进程的adj分配起点为900,而empty进程的分配起点为905,两者都是以跨距为10进行均匀分配的;这样就能够将empty进程和cache进程分开,彼此间隔相同的距离。当内存不足时,lmkd进程就会从adj最大值开始,逐步往下查杀进程,不会出现集体被杀或者都不被杀导致内存占用过高的问题。
ComputeOomAdjLocked
调用该方法时传入需要更新进程的ProcessRecord描述符、是否连带计算相关联的客户端进程等参数,进而计算出该进程甚至是其关联客户端进程的最新优先级、进程级别以及调度组等信息。
private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
boolean computeClients) {
//updateOomAdjLocked函数每次更新oom_adj时,都会分配一个序号,记录在mAdjSeq中
//此处就是根据序号判断是否已经处理过命令
if (mAdjSeq == app.adjSeq) {
//已经处理过命令
if (app.adjSeq == app.completedAdjSeq) {
// This adjustment has already been computed successfully.
return false;
} else {
...
}
}
//进程的thread不存在,则初始化后返回
if (app.thread == null) {
...
return false;
}
...
final int appUid = app.info.uid;
final int logUid = mService.mCurOomAdjUid;
int prevAppAdj = app.curAdj;
int prevProcState = app.getCurProcState();
int prevCapability = app.curCapability;
//最大Adj值设置在 0 以下,(maxAdj初始化都是1001)都是重要的系统进程
//FOREGROUND_APP_ADJ = 0
if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
//adjtype 是用于区分同一个adj值下的不同应用场景
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
app.setCurRawAdj(app.maxAdj);
app.setHasForegroundActivities(false);
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
app.curCapability = PROCESS_CAPABILITY_ALL;
app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);
//systemNoUi:没有显示UI的系统进程
//默认系统进程没有显示UI
app.systemNoUi = true;
//确定该系统进程是否正在显示UI,false表示正在显示UI
//根据各种场景设定adj,adjType,scheduleGroup等
if (app == topApp) {
app.systemNoUi = false;
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
app.adjType = "pers-top-activity";
} else if (app.hasTopUi()) {
// sched group/proc state adjustment is below
app.systemNoUi = false;//正在显示UI
app.adjType = "pers-top-ui";
} else if (app.getCachedHasVisibleActivities()) {
app.systemNoUi = false;
}
//系统进程正在显示UI,调整proc_state
if (!app.systemNoUi) {
//功耗的:device 醒着
if (mService.mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
// 亮屏,提升 proc_state 至 PERSISTENT_UI
app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
} else {
// screen off, restrict UI scheduling
//通过系统绑定带有一个前台service
app.setCurProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
}
}
//设置当前 unlimit proc_state
app.setCurRawProcState(app.getCurProcState());
//adj提到最大,重要性下降
app.curAdj = app.maxAdj;
app.completedAdjSeq = app.adjSeq;
// true表示重要性提高了
return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
}
app.systemNoUi = false;
// PROC_STATE_TOP:进程拥有用户可见的top activity
final int PROCESS_STATE_CUR_TOP = mService.mAtmInternal.getTopProcessState();
...
boolean foregroundActivities = false;
//根据不同场景设置前台进程的adjType,并且更新adj、schedGroup和procState
//【这一部分主要是处理前台进程相关的】
topApp为传入的参数
if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp) {
// //进程为top app,先设置一组默认数值,后续再细化
//前台进程的级别
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
app.adjType = "top-activity";
foregroundActivities = true;
procState = PROCESS_STATE_CUR_TOP;
...
} else if (app.runningRemoteAnimation) { //正在运行远程动画
adj = ProcessList.VISIBLE_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
app.adjType = "running-remote-anim";
procState = PROCESS_STATE_CUR_TOP;
} else if (app.getActiveInstrumentation() != null) { //与测试相关的一种场景
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.adjType = "instrumentation";
procState = PROCESS_STATE_FOREGROUND_SERVICE;
} else if (app.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) {//cache是否在接收广播
//在OOM中,接收广播等同于前台进程
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = (mTmpBroadcastQueue.contains(mService.mFgBroadcastQueue))
? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
app.adjType = "broadcast";
//后台进程正在运行receiver
procState = ActivityManager.PROCESS_STATE_RECEIVER;
} else if (app.executingServices.size() > 0) { //正在运行service调用,也看作前台进程
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = app.execServicesFg ?
ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
app.adjType = "exec-service";
procState = PROCESS_STATE_SERVICE;//后台进程,正在运行service
} else if (app == topApp) {//topApp
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.adjType = "top-sleeping";
foregroundActivities = true;
procState = PROCESS_STATE_CUR_TOP;
} else {//空进程
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
adj = cachedAdj;
procState = PROCESS_STATE_CACHED_EMPTY;
if (!app.containsCycle) {
app.setCached(true);
app.empty = true;
app.adjType = "cch-empty";
}
}
//全局变量 foregroundActivities 记录是否已经是前台进程
// 如果不是前台,且存在cache activity,则需要继续确定adj,重置adj为cache
//只有 app == topapp时foregroundActivities才=true
if (!foregroundActivities && app.getCachedHasActivities()) {
//mTmpComputeOomAdjWindowCallback计算adj时的window回调
// computeOomAdjFromActivitiesIfNecessary判断是否执行过
// 如果未执行过,则调用callback.initialize把adj/prostate存储
// 然后判断是否visible(adj=VISIBLE_APP_ADJ)、paused/stop(adj=PERCEPTIBLE_APP_ADJ)、
// other(procState=PROCESS_STATE_CACHED_ACTIVITY)
// 然后把adj/prostate赋值给app.mCachedAdj/app.mCachedProcState
// 如果执行过,则上一次计算出来的值
app.computeOomAdjFromActivitiesIfNecessary(mTmpComputeOomAdjWindowCallback,
adj, foregroundActivities, procState, schedGroup, appUid, logUid,
PROCESS_STATE_CUR_TOP);
// 如果进入cache的应用,这里adj会为1001,procstate为PROCESS_STATE_CACHED_ACTIVITY
adj = app.mCachedAdj;
foregroundActivities = app.mCachedForegroundActivities;
procState = app.mCachedProcState;
schedGroup = app.mCachedSchedGroup;
}
//带有recentTasks的cache;如果adj过大,回拉
if (procState > PROCESS_STATE_CACHED_RECENT && app.getCachedHasRecentTasks()) {
procState = PROCESS_STATE_CACHED_RECENT;
app.adjType = "cch-rec";
}
//重要性低于可感知进程且级别高于带前台service的处理
//对于adj大于可感知进程,级别大于带service的前台进程,分带service和Overlay UI分别处理,adj都是perceptible,但是级别不同
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > PROCESS_STATE_FOREGROUND_SERVICE) {
if (app.hasForegroundServices()) { //带前台service
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = PROCESS_STATE_FOREGROUND_SERVICE;
app.adjType = "fg-service";
app.setCached(false);
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
} else if (app.hasOverlayUi()) {//Overlay UI
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = PROCESS_STATE_IMPORTANT_FOREGROUND;
app.setCached(false);
app.adjType = "has-overlay-ui";
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
//从前台进程切换到带前台service,允许保持15s的更高级别adj,保证其可以完成一些剩余操作
if (app.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
&& (app.lastTopTime + mConstants.TOP_TO_FGS_GRACE_DURATION > now
|| app.setProcState <= PROCESS_STATE_TOP)) {
adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
app.adjType = "fg-service-act";
}
//adj大于可感知进程,级别大于后台进程
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
if (app.forcingToImportant != null) {//使进程变更重要的标志
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
//级别降到PROCESS_STATE_TRANSIENT_BACKGROUND
procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
app.setCached(false);
app.adjType = "force-imp";
app.adjSource = app.forcingToImportant;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
//重量级后台进程,把adj和proc_state都拉回到heavy weight的水平
if (app.getCachedIsHeavyWeight()) {
...
}
//HOME进程,同上面一样
if (app.getCachedIsHomeProcess()) {
if (adj > ProcessList.HOME_APP_ADJ) {
adj = ProcessList.HOME_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.setCached(false);
app.adjType = "home";
}
if (procState > ActivityManager.PROCESS_STATE_HOME) {
procState = ActivityManager.PROCESS_STATE_HOME;
app.adjType = "home";
}
}
if (app.getCachedIsPreviousProcess() && app.getCachedHasActivities()) {
//上一个App的进程且有activity,或者20s内刚被使用的provider进程,则设置为800
if (adj > ProcessList.PREVIOUS_APP_ADJ) {
adj = ProcessList.PREVIOUS_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.setCached(false);
app.adjType = "previous";
}
if (procState > PROCESS_STATE_LAST_ACTIVITY) {
procState = PROCESS_STATE_LAST_ACTIVITY;
app.adjType = "previous";
}
}
//当进程有关联的service或者provider,还需要根据service和provider继续更新adj
if (cycleReEval) {
procState = Math.min(procState, app.getCurRawProcState());
adj = Math.min(adj, app.getCurRawAdj());
schedGroup = Math.max(schedGroup, app.getCurrentSchedulingGroup());
}
//前面根据不同场景更新了adj,schedGroup,proc_state等,先暂时更新到processRecord app的参数里面
app.setCurRawAdj(adj);
app.setCurRawProcState(procState);
app.hasStartedServices = false;
app.adjSeq = mAdjSeq;
//处理service中的备份进程
final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
if (backupTarget != null && app == backupTarget.app) {
...
}
int capabilityFromFGS = 0; // capability from foreground service.
/**************以下为service连接相关的处理逻辑***************/
//遍历adj > 前台进程的进程中正在运行的service,根据这些service进一步更新当前app的adj等值
for (int is = app.numberOfRunningServices() - 1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
is--) {
ServiceRecord s = app.getRunningServiceAt(is);
if (s.startRequested) {
// 如果服务启动,则处理procState最低为PROCESS_STATE_SERVICE
app.hasStartedServices = true;
if (procState > PROCESS_STATE_SERVICE) {
procState = PROCESS_STATE_SERVICE;
app.adjType = "started-services";
...
}
//有显示的UI并且不是home,则标记cch-started-ui-services
if (app.hasShownUi && !app.getCachedIsHomeProcess()) {
if (adj > ProcessList.SERVICE_ADJ) {
app.adjType = "cch-started-ui-services";
}
} else {
// 如果上一次调用service的时间间隔超过30 min,则设置adj为SERVICE_ADJ(500)
if (now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
if (adj > ProcessList.SERVICE_ADJ) {
adj = ProcessList.SERVICE_ADJ;
app.adjType = "started-services";
...
app.setCached(false);
}
}
if (adj > ProcessList.SERVICE_ADJ) {
app.adjType = "cch-started-services";
}
}
} // end startRequested
//service运行在前台,主要更新capabilityFromFGS
if (s.isForeground) {
// 处理curCapability
}
//该服务还被其他客户端连接时,遍历所有连接该service的客户端,对该服务进行adj计算
ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections();
for (int conni = serviceConnections.size() - 1;
conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
conni--) {
// 获取这个服务链接的客户端进程
ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni);
for (int i = 0;
i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
i++) {
ConnectionRecord cr = clist.get(i);
// 连接到自己,不处理
if (cr.binding.client == app) {
continue;
}
boolean trackedProcState = false;
// 获取客户端的ProcessRecord
ProcessRecord client = cr.binding.client;
//传入的参数,是否计算客户端的adj, 如果更新所有进程,则为true
if (computeClients) {
computeOomAdjLocked(client, cachedAdj, topApp, doingAll, now,
cycleReEval, true);
} else {
client.setCurRawAdj(client.setAdj);
client.setCurRawProcState(client.setProcState);
}
int clientAdj = client.getCurRawAdj();
int clientProcState = client.getCurRawProcState();
// 假如不包含BIND_WAIVE_PRIORITY状态,即没有假如特殊标记不影响服务进程优先级
if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
...
// 如果客户端进程是cache,则认为是empty进程
if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
clientProcState = PROCESS_STATE_CACHED_EMPTY;
}
String adjType = null;
// BIND_ALLOW_OOM_MANAGEMENT代表保持服务受默认的服务管理器管理,当内存不足时候,会销毁服务
if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
// 将adj赋值为clientAdj
}
//假如服务进程的优先级小于客户端进程,则提升优先级
if (adj > clientAdj) {
// 如果当前进程有activity,但是与他关联的进程大于可感知状态200
if (app.hasShownUi && !app.getCachedIsHomeProcess() && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
adjType = "cch-bound-ui-services";
}
} else {
int newAdj;
// BIND_ABOVE_CLIENT表明service比连接他的客户端更重要,则客户端进程adj赋值给当前进程
// BIND_IMPORTANT 标识服务对客户端是非常重要的
if ((cr.flags&(Context.BIND_ABOVE_CLIENT
|Context.BIND_IMPORTANT)) != 0) {
// clientAdj 一般是大于PERSISTENT_SERVICE_ADJ的,所以直接采用客户端adj
if (clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
newAdj = clientAdj;
} else {
// persistent进程
...
}
} else if ((cr.flags & Context.BIND_NOT_PERCEPTIBLE) != 0
&& clientAdj <= ProcessList.PERCEPTIBLE_APP_ADJ
&& adj >= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
// 不是可感知服务,但是adj优先级大于等于可感知,则设置newadj为250
newAdj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
} else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
&& adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
// 假如绑定服务状态BIND_NOT_VISIBLE,则设置200
newAdj = ProcessList.PERCEPTIBLE_APP_ADJ;
} else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
newAdj = clientAdj;
} else {
// 假如clientadj<PERCEPTIBLE_APP_ADJ,则设置为VISIBLE_APP_ADJ
if (adj > ProcessList.VISIBLE_APP_ADJ) {
// TODO: Is this too limiting for apps bound from TOP?
newAdj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
} else {
newAdj = adj;
}
}
if (!client.isCached()) {
app.setCached(false);
}
if (adj > newAdj) {
adj = newAdj;
app.setCurRawAdj(adj);
adjType = "service";
}
}
}
// 根据后台情况,处理clientProcState,然后赋值给当前ProcessRecord的adjSourceProcState
if ((cr.flags & (Context.BIND_NOT_FOREGROUND | Context.BIND_IMPORTANT_BACKGROUND)) == 0) {
...
} else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
if (clientProcState < PROCESS_STATE_TRANSIENT_BACKGROUND) {
clientProcState = PROCESS_STATE_TRANSIENT_BACKGROUND;
}
} else {
if (clientProcState < PROCESS_STATE_IMPORTANT_BACKGROUND) {
clientProcState = PROCESS_STATE_IMPORTANT_BACKGROUND;
}
}// end BIND_NOT_FOREGROUND
...
if (procState > clientProcState) {
procState = clientProcState;
app.setCurRawProcState(procState);
if (adjType == null) {
adjType = "service";
}
}
...
if (adjType != null) {
app.adjType = adjType;
app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_SERVICE_IN_USE;
app.adjSource = cr.binding.client;
app.adjSourceProcState = clientProcState;
app.adjTarget = s.instanceName;
}
...
}// end BIND_WAIVE_PRIORITY
...
// 假如客户端进程的activity可见,则提升当前ProcessRecord的adj为FOREGROUND_APP_ADJ
final ActivityServiceConnectionsHolder a = cr.activity;
if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ
&& a.isActivityVisible()) {
...
}
}
}// end for ConnectionRecord
} // end for serviceConnections
} // end service
/**************provider相关的处理*****************/
//根据provider客户端的状态确定当前app的 adj,scheduleGroup 和 ProcState
//遍历与当前进程相关的所有provider
for (int provi = app.pubProviders.size() - 1;
provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
provi--) {
ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
for (int i = cpr.connections.size() - 1;
i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
i--) {
...
// //provider有非framework层的进程依赖,保证其adj不高于前台进程
if (cpr.hasExternalProcessHandles()) {
...
}
//当一个进程20s前带有contentProvider,不会把他降到LRU list,避免provider进程陷入低内存状态
if (app.lastProviderTime > 0 &&
(app.lastProviderTime + mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) {
if (adj > ProcessList.PREVIOUS_APP_ADJ) {
adj = ProcessList.PREVIOUS_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.setCached(false);
app.adjType = "recent-provider";
}
if (procState > PROCESS_STATE_LAST_ACTIVITY) {
procState = PROCESS_STATE_LAST_ACTIVITY;
app.adjType = "recent-provider";
}
}
//对cache进程进一步细分
if (procState >= PROCESS_STATE_CACHED_EMPTY) {//级别大于等于empty进程
...
}
//由adj判断是服务进程
if (adj == ProcessList.SERVICE_ADJ) {
//doingAll:传入的参数,只有五参的updateOomAdjLocked有这个参数,传入的一般是false
if (doingAll && !cycleReEval) {
//当A类Service个数 > service/3时,则加入到B类Service
app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
mNewNumServiceProcs++;
if (!app.serviceb) {//不在service b list中
//当对于低RAM设备,则把该service直接放入B类Service
if (mService.mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
&& app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {
app.serviceHighRam = true;
app.serviceb = true;
//Slog.i(TAG, "ADJ " + app + " high ram!");
} else {
mNewNumAServiceProcs++;
//Slog.i(TAG, "ADJ " + app + " not high ram!");
}
} else {//在service b中
app.serviceHighRam = false;
}
}
if (app.serviceb) {
adj = ProcessList.SERVICE_B_ADJ;
}
}
app.setCurRawAdj(adj);
...
//最终更新adj,scheduleGroup和ProcState
app.setCurProcState(procState);
app.setCurRawProcState(procState);
app.setHasForegroundActivities(foregroundActivities);
app.completedAdjSeq = mAdjSeq;
//重要性提升了,返回true,否则返回false
return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState
|| app.curCapability != prevCapability ;
}
bind类型
bind类型 | 说明 |
---|---|
BIND_WAIVE_PRIORITY | 不会影响服务的进程优先级,像通用的应用进程一样将服务放在一个LRU表中 |
BIND_TREAT_LIKE_ACTIVITY | 将binding 视为持有一个activity,unbinding视为activity在后台,这个通常用在输入法进程,以便更快捷的切换键盘。 |
BIND_ALLOW_OOM_MANAGEMENT | 保持服务受默认的服务管理器管理,当内存不足时候,会销毁服务 |
BIND_ABOVE_CLIENT | 设置服务的进程优先级高于客户端的优先级,只有当需要服务晚于客户端被销毁这种情况才这样设置 |
BIND_IMPORTANT | 标识服务对客户端是非常重要的,会将服务提升至前台进程优先级,通常情况下,即时客户端是前台优先级,服务最多也只能被提升至可见进程优先级, |
BIND_NOT_FOREGROUND | 不会将被绑定的服务提升到前台优先级,但是这个服务也至少会和客户端在内存中优先级是相同的 |
BIND_SCHEDULE_LIKE_TOP_APP | 此标志仅用于系统调整IME(以及与top应用程序紧密配合的任何进程外用户可见组件)的调度策略。所以托管此类服务的UI能够拥有top app一样的调度策略。仅限于系统调用,否则会抛出安全异常 |
BIND_ADJUST_WITH_ACTIVITY | Service的优先级将相对于其绑定的Activity,Activity到前台,则Service优先级相对提升,Activity到后台,则Servcie优先级相对降低。 |
BIND_AUTO_CREATE | 绑定服务时候,如果服务尚未创建,服务会自动创建| |
ApplyOomAdjLocked
该方法为实际衔接native层ULMK机制的一个点,在这个方法中会调用ProcessList.setOomAdj()方法,将计算好的OomAdj通过socket的方式传送到Native层中的LMKD守护进程中,再由LMKD将这些Adj参数值更新到其管理的LRU双向链表数组中
并且将对应进程的Adj更新写入到进程对应的Proc文件系统的相应文件中。
private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
long nowElapsed) {
boolean success = true;
//setAdj:上一次设置的adj
//curAdj:当前adj
//setRawAdj:上一次设置的unlimit adj
//curRawAdj:当前unlimit adj
// 在BOOT阶段开启app的compaction
// useCompaction()返回是否使能app compact;
// mBooted:当系统启动完成时设为tru
if (mCachedAppOptimizer.useCompaction() && mService.mBooted) {
//当前跟上次的adj不一致,有变化
if (app.curAdj != app.setAdj) {
//当app从perceptible变为home/previous,执行一次小的内存压缩
if (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ &&
(app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||
app.curAdj == ProcessList.HOME_APP_ADJ)) {
mCachedAppOptimizer.compactAppSome(app);//低等级的内存压缩
} else if ((app.setAdj < ProcessList.CACHED_APP_MIN_ADJ
|| app.setAdj > ProcessList.CACHED_APP_MAX_ADJ)
&& app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ
&& app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) {
//变为cache了,加大压缩力度
mCachedAppOptimizer.compactAppFull(app);
}
} else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE //非唤醒状态
&& app.setAdj < ProcessList.FOREGROUND_APP_ADJ//上一次重要性比前台进程高
&& mCachedAppOptimizer.shouldCompactPersistent(app, now)) {
// 非唤醒状态且上一次重要性比前台进程高
//且app上一次压缩时间已超过10分钟或者上一次没压缩都返回true
//persistent的内存压缩
mCachedAppOptimizer.compactAppPersistent(app);
} else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
&& app.getCurProcState()
== ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
&& mCachedAppOptimizer.shouldCompactBFGS(app, now)) {
//非唤醒状态且当前进程级别为绑定一个前台 service的进程
//且app上一次压缩时间已超过10分钟或者上一次没压缩都返回true
//app执行一次内存压缩
mCachedAppOptimizer.compactAppBfgs(app);
}
}
//adj当前和上次不一致,变化了
if (app.curAdj != app.setAdj) {
...
//此处将更新好的adj发送给lmkd守护进程,也是只有变化了才应用
//setOomAdj将更新的adj通过socket发送给native层的lmkd守护进程,更新其维护的adj双向链表
//发包的时候会触发epoll的监听函数,自动进行解包,将更新的adj写入到proc文件系统中
ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
app.setAdj = app.curAdj;
app.verifiedAdj = ProcessList.INVALID_ADJ;
}
...
final int curSchedGroup = app.getCurrentSchedulingGroup();
if (app.setSchedGroup != curSchedGroup) {
int oldSchedGroup = app.setSchedGroup;
app.setSchedGroup = curSchedGroup;
...
//情况为: waitingToKill:proc在后台时等待被杀
if (app.waitingToKill != null && app.curReceivers.isEmpty()
&& app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
//杀进程,并设置applyOomAdjLocked过程失败
app.kill(app.waitingToKill, ApplicationExitInfo.REASON_USER_REQUESTED,
ApplicationExitInfo.SUBREASON_UNKNOWN, true);
success = false;
} else {
int processGroup;
switch (curSchedGroup) {
case ProcessList.SCHED_GROUP_BACKGROUND:
processGroup = THREAD_GROUP_BACKGROUND;
break;
case ProcessList.SCHED_GROUP_TOP_APP:
case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
processGroup = THREAD_GROUP_TOP_APP;
break;
case ProcessList.SCHED_GROUP_RESTRICTED:
processGroup = THREAD_GROUP_RESTRICTED;
break;
default:
processGroup = THREAD_GROUP_DEFAULT;
break;
}
// 异步设置进程组信息
mProcessGroupHandler.sendMessage(mProcessGroupHandler.obtainMessage(
0 /* unused */, app.pid, processGroup, app));
try {
// 当前在前台
if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
// 第一次切换到前台,因为mUseFifoUiScheduling默认为false,则什么也不做
if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
app.getWindowProcessController().onTopProcChanged();
if (mService.mUseFifoUiScheduling) {
// 切换UI管道到SCHED_FIFO,
app.savedPriority = Process.getThreadPriority(app.pid);
mService.scheduleAsFifoPriority(app.pid, /* suppressLogs */true);
if (app.renderThreadTid != 0) {
mService.scheduleAsFifoPriority(app.renderThreadTid,/* suppressLogs */true);
...
}
} else {
//如果已经在前台了,则boost前台应用的UI线程和Runder线程的优先级为TOP_APP_PRIORITY_BOOST(-10)
setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST);
if (app.renderThreadTid != 0) {
...
setThreadPriority(app.renderThreadTid, TOP_APP_PRIORITY_BOOST);
...
}
}
}
// 如果切换到后台,则设置主线程优先级为0,render线程为THREAD_PRIORITY_DISPLAY(-4)
} else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
app.getWindowProcessController().onTopProcChanged();
if (mService.mUseFifoUiScheduling) {
...
// Reset UI pipeline to SCHED_OTHER
setThreadScheduler(app.pid, SCHED_OTHER, 0);
setThreadPriority(app.pid, app.savedPriority);
if (app.renderThreadTid != 0) {
setThreadScheduler(app.renderThreadTid, SCHED_OTHER, 0);
}
...
} else {
// Reset priority for top app UI and render threads
setThreadPriority(app.pid, 0);
}
if (app.renderThreadTid != 0) {
setThreadPriority(app.renderThreadTid, THREAD_PRIORITY_DISPLAY);
}
}
} catch (Exception e) {
...
}
}
}
...
//更新app的冻结状态
updateAppFreezeStateLocked(app);
...
//设置进程状态
app.thread.setProcessState(app.getReportedProcState());
...
// 执行pss统计操作,以及计算下一次pss时间
if (app.setProcState == PROCESS_STATE_NONEXISTENT
|| ProcessList.procStatesDifferForMem(app.getCurProcState(), app.setProcState)) {
...
//当setProcState = 20或者curProcState与setProcState值对应的内存类型不同时,则计算pss下次时间(参数true),大概一般在10分钟左右
app.lastStateTime = now;
app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
app.procStateMemTracker, mService.mTestPssMode,
mService.mAtmInternal.isSleeping(), now);
} else {
// 当前时间超过pss下次时间,则请求统计pss,并计算pss下次时间(参数false)
// 最大不超过PSS_MAX_INTERVAL(1h)
if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
&& now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
mService.mTestPssMode)))) {
if (mService.requestPssLocked(app, app.setProcState)) {
app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
app.procStateMemTracker, mService.mTestPssMode,
mService.mAtmInternal.isSleeping(), now);
}
}
...
}
// 更新应用使用度UsageStats
if (app.setProcState != app.getCurProcState()) {
..
maybeUpdateUsageStatsLocked(app, nowElapsed);
..
}
return success;
}
进程优先级
进程可划分为普通进程和实时进程,那么优先级与nice值的关系图:
优先级值越小表示进程优先级越高,3个进程优先级的概念:
静态优先级: 不会时间而改变,内核也不会修改,只能通过系统调用改变nice值的方法区修改。优先级映射公式: static_prio = MAX_RT_PRIO + nice + 20,其中MAX_RT_PRIO = 100,那么取值区间为[100, 139];对应普通进程;
实时优先级:只对实时进程有意义,取值区间为[0, MAX_RT_PRIO -1],其中MAX_RT_PRIO = 100,那么取值区间为[0, 99];对应实时进程;
动态优先级: 调度程序通过增加或减少进程静态优先级的值,来达到奖励IO消耗型或惩罚cpu消耗型的进程,调整后的进程称为动态优先级。区间范围[0, MX_PRIO-1],其中MX_PRIO = 140,那么取值区间为[0,139];
nice∈[-20, 19],可通过adb直接修改某个进程的nice值: renice prio pid
Framework调度策略
- 进程优先级级别:
Process.setThreadPriority(int tid, int priority)- 组优先级
setProcessGroup(int pid, int group)
setThreadGroup(int tid, int group)- 调度器类别
setThreadScheduler(int tid, int policy, int priority)
进程优先级 | nice值 | 解释 |
---|---|---|
THREAD_PRIORITY_LOWEST | 19 | 最低优先级 |
THREAD_PRIORITY_BACKGROUND | 10 | 后台 |
THREAD_PRIORITY_LESS_FAVORABLE | 1 | 比默认略低 |
THREAD_PRIORITY_DEFAULT | 0 | 默认 |
THREAD_PRIORITY_MORE_FAVORABLE | -1 | 比默认略高 |
THREAD_PRIORITY_FOREGROUND | -2 | 前台 |
THREAD_PRIORITY_DISPLAY | -4 | 显示相关 |
THREAD_PRIORITY_URGENT_DISPLAY | -8 | 显示(更为重要),input事件 |
TOP_APP_PRIORITY_BOOST | -10 | 前台进程的主线程和Render线程boost优先级 |
THREAD_PRIORITY_AUDIO | -16 | 音频相关 |
THREAD_PRIORITY_URGENT_AUDIO | -19 | 音频(更为重要) |
组优先级 | 取值 | 解释 |
---|---|---|
THREAD_GROUP_DEFAULT | -1 | 仅用于setProcessGroup,将优先级<=10的进程提升到-2 |
THREAD_GROUP_BG_NONINTERACTIVE | 0 | CPU分时的时长缩短 |
THREAD_GROUP_FOREGROUND | 1 | CPU分时的时长正常 |
THREAD_GROUP_SYSTEM | 2 | 系统线程组 |
THREAD_GROUP_AUDIO_APP | 3 | 应用程序音频 |
THREAD_GROUP_AUDIO_SYS | 4 | 系统程序音频 |
调度器 | 名称 | 解释 |
---|---|---|
SCHED_OTHER | 默认 | 标准round-robin分时共享策略 |
SCHED_BATCH | 批处理调度 | 针对具有batch风格(批处理)进程的调度策略 |
SCHED_IDLE | 空闲调度 | 针对优先级非常低的适合在后台运行的进程 |
SCHED_FIFO | 先进先出 | 实时调度策略 |
SCHED_RR | 循环调度 | 实时调度策略 |
updateLruProcessLocked
AMS中有一个LRU列表mProcessList经过AMS启动的每一个进程,都会加入到LRU列表中进行管理,这个LRU列表并不是随意排序或者说按加入的时间顺序进行排布的,而是有一定的逻辑进行计算,而后根据每个进程的实时动态状态进行改变的。
mProcessList这个LRU列表的定义其实最终在ProcessList.java中,AMS中定义了一个processList的实体,并且在整个系统中只有一个这样的LRU列表专门用于管理AMS启动的所有进程。
AMS中有一个成员变量 mLruProcesses,所有通过ams启动的java进程都会记录在里面,按照进程的使用时间以及进程种类,按照重要性由低到高排序,即越重要在 arraylist 中的index越大kill的时候也是先 kill index 小的进程, 总体来说index从小到大放置3类的进程:其他进程、含有service组件的进程、和activity有关的进程(包含 activity 或 client 包含 activity )
调用 updateLruProcessLocked 更新LRU列表的地方:
- ASM 启动一个进程的时候
- 绑定/解绑服务:bindserviceLocked
- start/kill service的时候
- remove connection的时候
- update processInfo的时候
- 处理boardCastor receive的时候
- setSystemProcess的时候
- getContentProvider和addApp(AMS启动新进程的方法)的时候
LRU列表更新的逻辑如下:
- 首先LRU列表被分为三段,这三段分别放置带activity的进程,带service的进程以及其他以外的进程,使用两个标志mLruProcessServiceStart和mLruProcessActivityStart间隔开;其中,mLruProcessServiceStart表示带service的那一段进程的开始,如图所示,mLruProcessActivityStart表示带activity的那一段进程的开始,如图所示;这样区分是为了让LRU列表尾部的进程变得更重要,而头部就没这么重要;所以LRU列表中的进程重要性是从头到位逐步递增的。
- 在对一个进程进行逻辑计算adj值时,会对其所处的当前状态进行分析,判断其是否带有一些提升自身重要性的一些组件(带有activity,service或者provider等等),将其对应的分到三段进程中的某一段;
- 当进程被分到其对应的那一段进程的时候,其插入点默认都是那一段的尾部开始插入的;比如,当一个进程A,带有service时,他就被分到hasService这一段进程列表中,如果他本身就已经在LRU列表中(即不是新启动的进程),需要将其先从LRU列表删除,再将其插入到hasService这一段LRU列表的尾部,即mLruProcessActivityStart的前一个位置;如果他是新启动的进程,即原先不在LRU列表中,则直接找到对应的地方插入即可,而不必删除原先的进程
- 值得注意的是,mLruProcessServiceStart和mLruProcessActivityStart这两个标志是用于间隔开other,hasService和hasActivity列表的,所以任何一个对LRU列表进行的操作都要及时更新这两个标志位的位置(这两个标志位其实就相当于两个指针,用于插入一个新的进程时使用)
- AMS在更新所有的进程的adj的时候,都会调用updateLruProcessLocked 方法对LRU列表进行更新,实时更新每一个进程在LRU列表的位置,每一个进程一旦其状态有所改变(前后台切换,service切换等),其在LRU列表中的位置都将会被修改到合适的位置。
- 在对进程进行插入的时候,为什么要从尾部进行插入???之前说过,LRU列表中,进程的重要性都是从头到尾逐步增加的;也即是说这三段列表中,尾部的进程都是最重要的,头部的是没有这么重要的。当一个进程的状态被更新,其在LRU列表中的位置被更新,代表该进程最近的状态有被修改过,也就是说这个进程最近是有活跃过的;这样,每一次更新进程在LRU列表中的位置,都表示被更新的进程是最新的(最近活跃的),这样子逐步更新之后,那些老的进程,不活跃的,其状态没有改变,那么他在LRU列表中的位置就会逐步被沉淀到列表尾部,进一步变老,其重要性就越来越显得不这么重要了。就这样,经过逐步的迭代更新,最终LRU列表维护的进程都是越靠近尾部越重要的。
更多推荐
所有评论(0)