概述
1.1 oom_adj与oom_score_adj
Android系统的设计理念正是希望应用进程能尽量长时间地存活,以提升用户体验。因此当应用推入到后台的时候进程并不会被立即杀死,而是存活一段时间,这样下次再使用则会非常快。但是如果处于后台的进程过多导致内存不足,此时就必须有选择的杀死部分进程。
到底该回收哪个进程呢?那么需要一个能管理所有进程,根据一定策略来释放进程的策略,这便有了lmk
,全称为LowMemoryKiller(低内存杀手),lmkd来决定什么时间杀掉什么进程。
系统根据进程的组件状态来决定每个进程的优先级值oom_adj,oom_adj 是 lmkd 内部定义的一个变量,其余oom_adj 存在一个映射关系,Android 7.0之前的版本,oom_score_adj= oom_adj * 1000/17; 而Android 7.0开始,oom_score_adj= oom_adj,不用再经过一次转换。
lmkd 主要是通过进程的oom_score_adj来判定进程的重要程度,其会按照oom_score_adj由大到小的顺序 杀死进程,依此类推,以回收预期的可用系统资源,从而保证系统正常运转。
1.2 ADJ 级别
ADJ级别 | 取值 | 含义 |
---|---|---|
NATIVE_ADJ | -1000 | native进程 |
SYSTEM_ADJ | -900 | 仅指system_server进程 |
PERSISTENT_PROC_ADJ | -800 | 系统persistent进程 |
PERSISTENT_SERVICE_ADJ | -700 | 关联着系统或persistent进程 |
FOREGROUND_APP_ADJ | 0 | 前台进程 |
VISIBLE_APP_ADJ | 100 | 可见进程 |
PERCEPTIBLE_APP_ADJ | 200 | 可感知进程,比如后台音乐播放 |
BACKUP_APP_ADJ | 300 | 备份进程 |
HEAVY_WEIGHT_APP_ADJ | 400 | 重量级进程 |
SERVICE_ADJ | 500 | 服务进程 |
HOME_APP_ADJ | 600 | Home进程 |
PREVIOUS_APP_ADJ | 700 | 上一个进程 |
SERVICE_B_ADJ | 800 | B List中的Service |
CACHED_APP_MIN_ADJ | 900 | 不可见进程的adj最小值 |
CACHED_APP_MAX_ADJ | 906 | 不可见进程的adj最大值 |
从Android 7.0开始,ADJ采用100、200、300;在这之前的版本ADJ采用数字1、2、3,这样的调整可以更进一步地细化进程的优先级,比如在VISIBLE_APP_ADJ(100)与PERCEPTIBLE_APP_ADJ(200)之间,可以有ADJ=101、102级别的进程。
A-Service与B-Service的划分
所有启动了服务的进程,且该服务所在的进程没有显示过UI,且该服务未执行startForeground(执行后会变为perveptible服务)动作,那该进程则为A-Service与B-Service中的一种。然后根据这类服务进程所处于Lru进程表中的位置,前1/3点服务为A-Service,其余的则为B-Service。
perceptible的标准
perceptible名为可感知的进程,但并不是说能够感知到进程就一定表示该进程属于perveptible进程,比如播放音乐的进程活着状态栏上有通知的进程,虽然能够感知到进程的存在,但是不代表进程一定时perceptible类别的进程。决定该进程是否属于perceptible进程并未进程的可感知性,而是该进程的服务是否执行了startForeground动作。
1.3 computeOomAdjLocked
第一部分
private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
boolean doingAll, long now) {
// updateOomAdjLocked函数每次更新oom_adj时,都会分配一个序号
//此处就是根据序号判断是否已经处理过命令
if (mAdjSeq == app.adjSeq) {
// This adjustment has already been computed.
return app.curRawAdj;
}
//设置empty进程adj
if (app.thread == null) {
app.adjSeq = mAdjSeq;
app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
//空进程
app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
}
//初始化一些变量
//这些变量的具体用途,我们不关注
//大家只用留意一下ProcessRecord的schedGroup、procState和oom_adj即可
app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
app.adjSource = null;
app.adjTarget = null;
app.empty = false;
app.cached = false;
final int activitiesSize = app.activities.size();
//初始化ProcessRecord maxAdjUNKNOWN_ADJ,//maxAdj取值为UNKNOWN_ADJ,即最大的1001
//但是应该是只有系统进程才有可能进入这个分支。系统进程走完这个分支就返回了
if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
//adjType 跟cpu的调度权限有关系
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
app.curRawAdj = app.maxAdj;
app.foregroundActivities = false;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
//
// System processes can do UI, and when they do we want to have
// them trim their memory after the user leaves the UI. To
// facilitate this, here we need to determine whether or not it
// is currently showing UI.
app.systemNoUi = true;
if (app == TOP_APP) {
app.systemNoUi = false;
} else if (activitiesSize > 0) {
for (int j = 0; j < activitiesSize; j++) {
final ActivityRecord r = app.activities.get(j);
if (r.visible) {
app.systemNoUi = false;
}
}
}
if (!app.systemNoUi) {
//系统进程有ui的时候
app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
}
//
return (app.curAdj=app.maxAdj);
}
app.systemNoUi = false;
//xxx
}
第一部分主要是更新了empty 进程与系统进程的curProcState。
第二部分
// Determine the importance of the process, starting with most
// important to least, and assign an appropriate OOM adjustment.
int adj;
int schedGroup;
int procState;
boolean foregroundActivities = false;
BroadcastQueue queue;
if (app == TOP_APP) {
//若进程包含正在前台显示的Activity
adj = ProcessList.FOREGROUND_APP_ADJ;
//
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "top-activity";
foregroundActivities = true;
procState = ActivityManager.PROCESS_STATE_TOP;
} else if (app.instrumentationClass != null) {
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "instrumentation";
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
} else if ((queue = isReceivingBroadcast(app)) != null) {
// An app that is currently receiving a broadcast also
// counts as being in the foreground for OOM killer purposes.
// It's placed in a sched group based on the nature of the
// broadcast as reflected by which queue it's active in.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = (queue == mFgBroadcastQueue)
? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.adjType = "broadcast";
procState = ActivityManager.PROCESS_STATE_RECEIVER;
} else if (app.executingServices.size() > 0) {
// An app that is currently executing a service callback also
// counts as being in the foreground.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = app.execServicesFg ?
Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.adjType = "exec-service";
procState = ActivityManager.PROCESS_STATE_SERVICE;
//Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
} else {
// As far as we know the process is empty. We may change our mind later.
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
// At this point we don't actually know the adjustment. Use the cached adj
// value that the caller wants us to.
//这一句很重要,除了上面几种情形,先设置adj为cacheAdj,也即是UNKNOWN_ADJ
adj = cachedAdj;
//表明此时进程处于后台
procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
app.cached = true;
app.empty = true;
app.adjType = "cch-empty";
}
上述几个分支除了最后的else 分支其余的adj都是FOREGROUND_APP_ADJ,但是schedGroup与procState 不同,也就是cpu资源调度是不一样的。
当进程正在显示或者正在测试或者正在执行Service 或者正在执行Receiver的时候此时设置adj 为FOREGROUND_APP_ADJ。FOREGROUND_APP_ADJ 实际是0,比他小的都是adj一般表示的都是系统进程,因此FOREGROUND_APP_ADJ 可以看成是普通用户可以使用的最高的adj,用于这个adj的进程内存几乎不会被回收。
最后的else 分支是将先将adj 设置为cachedAdj,此处cachedAdj 为UNKNOWN_ADJ,实际就是在后面再根据情况决定adj的值为多少。如果computeOomAdjLocked 执行完了,这个进程的adj 还是UNKNOWN_ADJ,此时会在updateOomAdjLocked 方法中将adj 设置为ProcessList.CACHED_APP_MIN_ADJ到ProcessList.CACHED_APP_MAX_ADJ之间的某一个值。详情参见上一篇文章。
第三部分
//第三部分处理包含Activity的进程时
// //依次轮询进程中的Activity,app的adj会由
if (!foregroundActivities && activitiesSize > 0) {
for (int j = 0; j < activitiesSize; j++) {
final ActivityRecord r = app.activities.get(j);
if (r.app != app) {
continue;
}
//如果进程包含可见Activity,即该进程是个可见进程,
if (r.visible) {
//更新状态,原因是在for循环里面可能先走了后面的分支,然后再进入了本分支
//这样最终进程的adj就由最重要的activity的状态决定了。
if (adj > ProcessList.VISIBLE_APP_ADJ) {
//adj大于VISIBLE_APP_ADJ时,才更新对应的adj
//之前提到的正在处理广播、服务或测试的进程(也就是第一部分),adj为FOREGROUND,是小于VISIBLE_APP_ADJ
//因此不会在此更新,
adj = ProcessList.VISIBLE_APP_ADJ;
app.adjType = "visible";
}
if (procState > ActivityManager.PROCESS_STATE_TOP) {
procState = ActivityManager.PROCESS_STATE_TOP;
}
//正在处理广播、服务或测试的进程,如果它们的调度策略为BACKGROUND
//但又包含了可见Activity时,调度策略变更为DEFAULT
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
app.empty = false;
foregroundActivities = true;
//注意break了
//发现可见Activity时,直接可以结束循环
break;
} else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
//如果进程包含处于PAUSING或PAUSED状态的Activity时
//将其oom_adj调整为“用户可察觉”的的等级,这个等级还是很高的
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "pausing";
}
if (procState > ActivityManager.PROCESS_STATE_TOP) {
procState = ActivityManager.PROCESS_STATE_TOP;
}
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
app.empty = false;
foregroundActivities = true;
//注意并不会break
} else if (r.state == ActivityState.STOPPING) {
//包含处于Stopping状态Activity的进程,其oom_adj也被置为PERCEPTIBLE_APP_ADJ
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "stopping";
}
if (!r.finishing) {
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
}
}
app.cached = false;
app.empty = false;
foregroundActivities = true;
} else {
//只是含有cached-activity的进程,仅调整procState
if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
app.adjType = "cch-act";
}
}
}
}
这一部分主要是遍历进程当中的所有页面,每一个页面都有一个adj,而最终进程的adj 选取其中最小的值。例如一个进程有一个可见页面有一个正在执行onPause 的页面,那么进程的adj 是ProcessList.VISIBLE_APP_ADJ,再比例进程有一个正在执行onPause的页面以及一个正在执行onStop 的页面,此时进程的adj 是ProcessList.PERCEPTIBLE_APP_ADJ。
如果没有可见页面,也不是正在执行onPause 以及onStop 的页面,就是已经处于后台的将进程,,此时adj 为cacheAdj。 参见第二部的else 分支。
第四部分
//第四部分主要用于处理一些特殊的进程。
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
//进程包含前台服务或被强制在前台运行时
//oom_adj被调整为PERCEPTIBLE_APP_ADJ,只是procState略有不同
if (app.foregroundServices) {
// 当前进程包含前台服务
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
app.cached = false;
app.adjType = "fg-service";
schedGroup = Process.THREAD_GROUP_DEFAULT;
} else if (app.forcingToForeground != null) {
//例如当前进程正在弹出一个Toast。(是否可以使用定时Toast来保活)
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
app.cached = false;
app.adjType = "force-fg";
app.adjSource = app.forcingToForeground;
schedGroup = Process.THREAD_GROUP_DEFAULT;
}
}
///AMS的HeavyWeight进程单独处理
if (app == mHeavyWeightProcess) {
if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
// We don't want to kill the current heavy-weight process.
adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.cached = false;
app.adjType = "heavy";
}
if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
}
}
//home进程特殊处理
if (app == mHomeProcess) {
if (adj > ProcessList.HOME_APP_ADJ) {
adj = ProcessList.HOME_APP_ADJ;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.cached = false;
app.adjType = "home";
}
if (procState > ActivityManager.PROCESS_STATE_HOME) {
procState = ActivityManager.PROCESS_STATE_HOME;
}
}
//前台进程之前的一个进程,也就是上次显示的进程
if (app == mPreviousProcess && app.activities.size() > 0) {
if (adj > ProcessList.PREVIOUS_APP_ADJ) {
// This was the previous process that showed UI to the user.
// We want to try to keep it around more aggressively, to give
// a good experience around switching between two apps.
adj = ProcessList.PREVIOUS_APP_ADJ;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.cached = false;
app.adjType = "previous";
}
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
}
}
if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
+ " reason=" + app.adjType);
// By default, we use the computed adjustment. It may be changed if
// there are applications dependent on our services or providers, but
// this gives us a baseline and makes sure we don't get into an
// infinite recursion.
app.adjSeq = mAdjSeq;
app.curRawAdj = adj;
app.hasStartedServices = false;
//处理正在进行backup工作的进程
if (mBackupTarget != null && app == mBackupTarget.app) {
// If possible we want to avoid killing apps while they're being backed up
if (adj > ProcessList.BACKUP_APP_ADJ) {
if (DEBUG_BACKUP) Slog.v(TAG, "oom BACKUP_APP_ADJ for " + app);
adj = ProcessList.BACKUP_APP_ADJ;
if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
}
app.adjType = "backup";
app.cached = false;
}
if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
procState = ActivityManager.PROCESS_STATE_BACKUP;
}
}
这里以及前面三个部分在处理adj的时候都会先判断一下adj的大小,例如本部分的第一行
adj > ProcessList.PERCEPTIBLE_APP_ADJ。这里这句代码的主要作用是过滤掉前面已经设置了adj的进程。
因为computeOomAdjLocked 里面设置adj 是按照由小到大的顺序处理的,因此在前面部分被设置了某个非UNKNOWN_ADJ的值一般后续比较adj大于某个值的条件都不在处理。
这一部分主要处理了一些特殊的进程,如执行前台Service 的进程,桌面进程,前一次显示的进程等等。
第五部分
boolean mayBeTop = false;
for (int is = app.services.size()-1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
|| procState > ActivityManager.PROCESS_STATE_TOP);
is--) {
ServiceRecord s = app.services.valueAt(is);
//通过startService启动过Service
if (s.startRequested) {
app.hasStartedServices = true;
if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
procState = ActivityManager.PROCESS_STATE_SERVICE;
}
//app之前启动过Activity
if (app.hasShownUi && app != mHomeProcess) {
if (adj > ProcessList.SERVICE_ADJ) {
app.adjType = "cch-started-ui-services";
}
} else {
//MAX_SERVICE_INACTIVITY为activity启动service后,系统最多保留Service的时间。
//没有启动过Activity,并且30分钟之内活跃过的服务进程
if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
if (adj > ProcessList.SERVICE_ADJ) {
//虽然处于后台,相当于提高了adj的级别,
//app.hasShownUi && app != mHomeProcess 这个分支内部内有提高adj级别
//说明一个纯粹的服务进程的优先级是高于既有ui又有服务的进程的
adj = ProcessList.SERVICE_ADJ;
app.adjType = "started-services";
app.cached = false;
}
}
//处理Service存在超时的情况,可见超时时也不会调整oom_adj
if (adj > ProcessList.SERVICE_ADJ) {
app.adjType = "cch-started-services";
}
}
}
//bindService 启动的Service。
for (int conni = s.connections.size()-1;
conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
|| procState > ActivityManager.PROCESS_STATE_TOP);
conni--) {
ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
//多次调用bind多次调用bindService 绑定同一个Service,每次绑定的
//参数可能不一样。
for (int i = 0;
i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
|| procState > ActivityManager.PROCESS_STATE_TOP);
i++) {
// XXX should compute this based on the max of
// all connected clients.
ConnectionRecord cr = clist.get(i);
if (cr.binding.client == app) {
// Binding to ourself is not interesting.
continue;
}
//bingService时添加了BIND_WAIVE_PRIORITY这个flag。
if ((cr.flags& Context.BIND_WAIVE_PRIORITY) == 0) {
// client 是调用bindService 的进程,也就是客户端。
ProcessRecord client = cr.binding.client;
//计算出客户端进程的oom_adj
//由此可看出Android oom_adj的计算多么麻烦
int clientAdj = computeOomAdjLocked(client, cachedAdj,
TOP_APP, doingAll, now);
int clientProcState = client.curProcState;
if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty. The specific cached state
// doesn't propagate except under certain conditions.
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
}
String adjType = null;
//BIND_ALLOW_OOM_MANAGEMENT置为1时,先按照通常的处理方式,调整服务端进程的adjType
if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
if (app.hasShownUi && app != mHomeProcess) {
if (adj > clientAdj) {
adjType = "cch-bound-ui-services";
}
app.cached = false;
//当前进程展示过ui, 会将clientAdj修改为当前进程的adj,
clientAdj = adj;
clientProcState = procState;
} else {
if (now >= (s.lastActivity
+ ActiveServices.MAX_SERVICE_INACTIVITY)) {
if (adj > clientAdj) {
adjType = "cch-bound-services";
}
//服务已经好长时间没有执行过了,那么同样 会将clientAdj修改为当前进程的adj
clientAdj = adj;
}
//若是距离服务上次活跃时间还没有超过30min,那么adj 放到后面修改
}
}
//当前进程优先级低于客户端
//adj>clientAdj 表明client此时可能是正在显示或是可见的页面,而当前进程是后台进程
if (adj > clientAdj) {
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adjType = "cch-bound-ui-services";
} else {
//这里主要是处理client 的adj 大于当前进程adj的情形。
//例如进程A 绑定了另一个进程B 内的一个Service。
//此时可能A进程为当前正在显示的进程而B 是一个后台进程。
//此时可以适当提高一个进程B的adj。
//例如B本来是CACHED_APP_MAX_ADJ但由于A 是可见进程,
//此时B 的adj 也会是可见进程。
//bindService 同时添加了BIND_ABOVE_CLIENT与BIND_IMPORTANT
if ((cr.flags&(Context.BIND_ABOVE_CLIENT
|Context.BIND_IMPORTANT)) != 0) {
//adj 最小取值是PERSISTENT_SERVICE_ADJ。
adj = clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ
? clientAdj : ProcessList.PERSISTENT_SERVICE_ADJ;
} else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
&& adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
//BIND_NOT_VISIBLE表示不将服务端当作visible进程看待
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
} else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
//例如客户端是PERCEPTIBLE_APP_ADJ,这里一般也是提升
//adj 的级别
adj = clientAdj;
} else {
if (adj > ProcessList.VISIBLE_APP_ADJ) {
adj = ProcessList.VISIBLE_APP_ADJ;
}
}
if (!client.cached) {
app.cached = false;
}
adjType = "service";
}
}
// adj <=clientAdj,例如客户端是后台进程,当前进程为正在显示的进程。
//
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
//BIND_NOT_FOREGROUND表示系统将阻止驻留该服务的进程具有前台优先级
if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
schedGroup = Process.THREAD_GROUP_DEFAULT;
}
if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
// Special handling of clients who are in the top state.
// We *may* want to consider this process to be in the
// top state as well, but only if there is not another
// reason for it to be running. Being on the top is a
// special state, meaning you are specifically running
// for the current top app. If the process is already
// running in the background for some other reason, it
// is more important to continue considering it to be
// in the background state.
mayBeTop = true;
//降低clientProcState
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
} else {
// Special handling for above-top states (persistent
// processes). These should not bring the current process
// into the top state, since they are not on top. Instead
// give them the best state after that.
//也是降低clientProcState
clientProcState =
ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
}
}
} else {
if (clientProcState <
ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
clientProcState =
ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
}
}
if (procState > clientProcState) {
procState = clientProcState;
}
if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
&& (cr.flags&Context.BIND_SHOWING_UI) != 0) {
app.pendingUiClean = true;
}
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.name;
}
}
//看成是activity
if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
app.treatLikeActivity = true;
}
// 根据当前进程activity来调整adj和schedGroup
final ActivityRecord a = cr.activity;
//a 非空表示Service 是从页面a 启动。
//&Context.BIND_ADJUST_WITH_ACTIVITY是指当从Activity绑定到该进程时,
// 允许目标服务进程根据该activity的可见性来提升优先级
if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
(a.visible || a.state == ActivityState.RESUMED
|| a.state == ActivityState.PAUSING)) {
//提高服务进程的优先级
adj = ProcessList.FOREGROUND_APP_ADJ;
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
schedGroup = Process.THREAD_GROUP_DEFAULT;
}
app.cached = false;
app.adjType = "service";
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE;
app.adjSource = a;
app.adjSourceProcState = procState;
app.adjTarget = s.name;
}
}
}
}
}
这里主要是处理进程内运行了Service的情况,根据Service的启动情形有分为两种情况。
通过startService启动:
这里Service 所在进程没有启动父ui 并且服务在30分钟活跃过,那么adj 为ProcessList.SERVICE_ADJ,其余的情形的adj 依然是在前面设置的PROCESS_STATE_CACHED_ACTIVITY。换句话说一个Service 在一定时间不在运行之后就会无效。
通过bindService 启动:
这里主要是根据bindService 提供的Flag 来适当的提高Service 进程的adj,使得服务进程的内存没有那么容易被回收。具体Flag 的意义大家可以查询相关资料。
假设一个进程既有activity 又有Service 那么该进程的adj 取何值?
该Service 是starService 且没有被bindService绑定过,同时进程内没有ContentProvider。
由上图可以看到当一个服务进程展示过ui的情况下会修改adjType,但是没有给adj 赋值,此时adj 依然是前面设置的UNKNOW_ADJ。
updateOomAdjLocked
updateOomAdjLocked 通过computeOomAdjLocked 修改进程的adj 之后会判断进程的adj是否大于等于UNKNOWN_ADJ, 一个有ui的Service 进程的adj 是UNKNOWN_ADJ,正好满足条件
之后进程app 的adj 会被设置为CACHED_APP_MIN_ADJ到CACHED_APP_MAX_ADJ 之间的某一个值。
一般启动了服务的进程往往是希望服务在后台能够执行某些任务,这样看是不希望这些服务因为进程被杀而过早的被终止的。正确的做法是,对于期望较长时间留在后台的服务,应该将服务运行在单独的进程里,即是UI进程与Servie进程分离,这样期望长时间留在后台的Serivce会获得较小的Adj值,而占有大量内存的UI进程则会分类为Cached(后台)进程,能够在需要的时候更快地被回收。
第六部分
省略,这一部分主要是根据ContentProivder 来设置adj,逻辑类似Service。
第七部分
//第七部分
if (mayBeTop && procState > ActivityManager.PROCESS_STATE_TOP) {
// A client of one of our services or providers is in the top state. We
// *may* want to be in the top state, but not if we are already running in
// the background for some other reason. For the decision here, we are going
// to pick out a few specific states that we want to remain in when a client
// is top (states that tend to be longer-term) and otherwise allow it to go
// to the top state.
switch (procState) {
case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
case ActivityManager.PROCESS_STATE_SERVICE:
// These all are longer-term states, so pull them up to the top
// of the background states, but not all the way to the top state.
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
break;
default:
// Otherwise, top is a better choice, so take it.
procState = ActivityManager.PROCESS_STATE_TOP;
break;
}
}
//
if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
if (app.hasClientActivities) {
// This is a cached process, but with client activities. Mark it so.
procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
app.adjType = "cch-client-act";
} else if (app.treatLikeActivity) {
// This is a cached process, but somebody wants us to treat it like it has
// an activity, okay!
// 将Service 看成是activity .
procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
app.adjType = "cch-as-act";
}
}
// 对Service进程做一些特殊处理
if (adj == ProcessList.SERVICE_ADJ) {
if (doingAll) {
//每次updateOomAdj时,将mNewNumAServiceProcs置为0
//然后LRU list中,从后往前数,前1/3的service进程就是AService
//其余的就是bService
//mNumServiceProcs为上一次update时,service进程的数量
//mNewNumAServiceProcs 表示当前处理的第几个Service
app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
mNewNumServiceProcs++;
//Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);
if (!app.serviceb) {
// 如果不是bService,但内存回收等级过高,也被视为bService
if (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 {
app.serviceHighRam = false;
}
}
if (app.serviceb) {
//LRU中后1/3的Service,都是AService
adj = ProcessList.SERVICE_B_ADJ;
}
}
//计算完毕
app.curRawAdj = adj;
//if基本没有用,maxAdj已经是最大的UNKNOW_ADJ
if (adj > app.maxAdj) {
adj = app.maxAdj;
if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
schedGroup = Process.THREAD_GROUP_DEFAULT;
}
}
//最后做一些记录和调整
app.curAdj = app.modifyRawOomAdj(adj);
app.curSchedGroup = schedGroup;
app.curProcState = procState;
app.foregroundActivities = foregroundActivities;
return app.curRawAdj;
这一部分主要是根据前面计算修改一些进程的proState以及根据服务在进程列表的位置修改adj。
所有的进程保存在一个列表里面,从后往前数,前1/3的service进程就是AService