Android adj调整 --- computeOomAdjLSP流程详解
- Android adj调整 --- computeOomAdjLSP流程详解
- 1. computeOomAdjLSP的参数
- 2. 是否存在循环计算
- 3. 没有ApplicationThread的时候的调整
- 4. 对ProcessStateRecord进程状态记录的一些初始化
- 5. 设置默认是否允许冻结
- 6. 获取调整之前的一些状态
- 7. system_server或者常驻进程的调整
- 8. 调整之前的一些变量的定义
- 9. top顶端app的调整
- 10. 正在播放远端动画的调整
- 11. instrumentation的调整
- 12. 正在接受广播进程的调整
- 13. 正在运行服务进程的调整
- 14. 系统在休眠时topApp的调整
- 15. 其它app的默认状态初始化
- 16. 更新foregroundActivities和mHasVisibleActivities
- 17. 更新最近使用的activity的状态
- 18. 调整前台服务或者hasOverlayUi的进程
- 19. 调整最近活跃的前台服务进程
- 20. 调整强制提升到用户可感知的进程
- 21. 调整heavy的进程
- 21. 调整桌面应用
- 22. 调整previous上一个使用的应用
- 23. 循环计算时更新procState、adj、schedGroup
- 24. 先更新一下当前计算的值到ProcessStateRecord
- 25. 设置当前adj调整的系列号
- 26. 调整backup备份的应用
- 27. service服务自身和服务依赖关系调整
- 27.1 遍历该进程的服务numberOfRunningServices
- 27.2 根据Services自身的状态进行调整
- 27.3 获取前台服务的能力capabilityFromFGS
- 27.4 遍历每个服务里面的所有链接对象
- 27.5 取出每个服务链接对象
- 27.6 只调整自身是服务,由于客户端的链接的情况
- 27.7 computeClients循环计算时,会先计算客户端的adj
- 27.8 调整前获取客户端的clientAdj和clientProcState
- 27.9 进行没有豁免优先级情况的调整
- 27.10 BIND_WAIVE_PRIORITY == true豁免优先级调整
- 27.11 绑定客户端对象是activity的调整
- 28. provider依赖关系调整
- 29. recent-provider最近使用的provider调整
- 30. 服务相关缓存进程CACHED的调整
- 31. A、B service分布调整
- 32. 更新最新的adj到mCurRawAdj中
- 33. 如果还有未处理完的getMaxAdj进程的调整
- 34. 非唤醒状态时受限制分组SCHED_GROUP_RESTRICTED调整
- 35. 更新进程的能力capability
- 36. 更新最新的状态到ProcessStateRecord,完成本次adj调整
- 37. 本次adj调整的返回值
- 38. 其它相关代码
Android adj调整 — computeOomAdjLSP流程详解
这次就先讲OomAdjuster.java中adj调整最为关键的函数computeOomAdjLSP,这个函数几乎占了adj调整代码1/3的代码量,非常重要,建议阅读之前先看一下之前的:Android S进程的adj值
、Android adj调整时的各类进程状态
。至于OomAdjuster.java里面的其它逻辑,下次有时间再来写吧。希望对大家有帮助
下面是各个关系对应的表格(以adj为例)
1. computeOomAdjLSP的参数
注意此处上了2把锁mService(ActivityManagerService)
, ActivityManagerService的mProcLock
@GuardedBy({"mService", "mProcLock"})
private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
boolean computeClients) {
//调整adj的函数(查看这个函数之前先看一下adj各个值的意思和procState各个值的含义,具体可以参考之前的文章)
//1. app是需要调整adj的进程
//2. cachedAdj是adj调整的时候的默认值(除了一些正在使用的app都是这个默认值),默认只有一般是oldAdj或则UNKNOWN_ADJ
//3. topApp(当前最顶端activity)是从AMS的getTopApp(这个函数有点性能问题)里面拿到的(这里又是从ActivityTaskManagerService获得)
//updateTopResumedActivityIfNeeded/mRootWindowContainer.getTopDisplayFocusedRootTask/topRootTask.getResumedActivity(ActivityTaskSupervisor)
//-> updateTopApp(ActivityTaskManagerService),大概是意思是:top的task(writeWmTaskMoved/writeWmTaskToFront),而且是isTopActivityFocusable和可见shouldBeVisible
//注意顶端activity和顶端Window不是一个概念,如在桌面的时候下拉状态栏,此时顶端activity(topApp)是桌面,而focus Window是systemui
//4. doingAll在这里主要是用于调整A、B service,在updateOomAdjInnerLSP时fullUpdate或者computeClients为true时才有可能设置为true
//而A、B service调整除了doingAll这个参数,还跟cycleReEval有关系,也就是说实际有用到的地方只有fullUpdate为true是才会调整A、B services
//5. now是此次调整adj的当前时间
//6. cycleReEval只有在设置了setContainsCycle true(如正在计算computeOomAdjLSP的时候还没计算完又跑进来,
//如上面的mAdjSeq == state.getAdjSeq()或者(服务/provider的客户端有这种情况的时候)),
//在updateOomAdjInnerLSP会让cycleReEval=true(具体可以看上面的updateOomAdjInnerLSP,大概意思是循环计算依赖)
//7. computeClients是否需要计算当前进程的时候计算服务、provider提供者对端的adj
//8. 它的返回值state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
// || state.getCurCapability() != prevCapability
//当满足当前调整的mSetAdj(函数结束的时候)比prevAppAdj(刚进入这里mSetAdj)小的时候,或者mCurProcState有变小;这些都代表优先级提升
//或者mCurCapability能力不一样才返回true,其它都是false.
//这个返回值目前只在updateOomAdjInnerLSP中的循环计算adj中使用,用于判断是否需要中断循环调整adj,其它场景都未使用
//只有true才代表循环调整成功,单个进程false代表忽略,只有全部循环调整的进程都是fasle才会跳过循环调整的重试逻辑
2. 是否存在循环计算
设置该进程是循环计算setContainsCycle(true)
、将循环计算的进程进程放入mProcessesInCycle
final ProcessStateRecord state = app.mState;
//mAdjSeq在updateOomAdjInnerLSP/performUpdateOomAdjLSP有mAdjSeq++,代表是当前oom_adj调整的序列号
//如果mAdjSeq == getAdjSeq(取得的是正在处理的mAdjSeq值),代表这个进程已经参与过本次调整
if (mAdjSeq == state.getAdjSeq()) {
//getCompletedAdjSeq是已经完成的adj值
if (state.getAdjSeq() == state.getCompletedAdjSeq()) {
// This adjustment has already been computed successfully.
// 如果该进程调整过了,而且已经完成,则直接返回,同时由于是没有调整,则返回值是false
// 只有true才代表循环调整成功,单个进程false代表忽略,
// 只有全部循环调整的进程都是fasle才会跳过循环调整的重试逻辑
// 返回值只有在重复调整的时候使用,具体请查看updateOomAdjInnerLSP的使用
return false;
} else {
// The process is being computed, so there is a cycle. We cannot
// rely on this process's state.
//由于该进程之前已经计算过,而且adj还在计算值没有计算完,则设置需要adj循环调整的标记位mContainsCycle为true
state.setContainsCycle(true);
//同时将该进程放入循环计算的list里面mProcessesInCycle,后面如果需要重新计算该进程adj的时候会从此处取回
mProcessesInCycle.add(app);
// 返回值只有在重复调整的时候使用,具体请查看updateOomAdjInnerLSP的使用
return false;
}
}
3. 没有ApplicationThread的时候的调整
进程app没有ApplicationThread
(应用线程)的时候会进入
//如果app没有ApplicationThread(应用线程),那么进入这里
if (app.getThread() == null) {
//设置当前进程的adj任务的序列号为mAdjSeq,代表正在调整该进程
state.setAdjSeq(mAdjSeq);
//设置默认cgroup为backgroud
//backgroud分组原生配置了 "HighEnergySaving"(cpuctl或者schedtune),
//"ProcessCapacityLow"(cpuset), "LowIoPriority"(blkio), "TimerSlackHigh"(timerslack_ns)
state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND);
//设置当前进程状态为PROCESS_STATE_CACHED_EMPTY
state.setCurProcState(PROCESS_STATE_CACHED_EMPTY);
//设置mCurAdj为999,这是oom调整的值;
//而mSetAdj是上一次oom设置过的值(一般用的mSetAdj做为oomadj的判断, setSetAdj设置)
//applyOomAdjLSP中会调用state.setSetAdj(state.getCurAdj());
//将正在调整的mCurAdj更新到mSetAdj,同时修改ProcessList.setOomAdj(更新lmkd中的状态值)
state.setCurAdj(ProcessList.CACHED_APP_MAX_ADJ);
/*
//AndroidS\frameworks\base\services\core\java\com\android\server\am\ProcessServiceRecord.java
int modifyRawOomAdj(int adj) {
if (mHasAboveClient) {
// If this process has bound to any services with BIND_ABOVE_CLIENT,
// then we need to drop its adjustment to be lower than the service's
// in order to honor the request. We want to drop it by one adjustment
// level... but there is special meaning applied to various levels so
// we will skip some of them.
if (adj < ProcessList.FOREGROUND_APP_ADJ) {
// System process will not get dropped, ever
} else if (adj < ProcessList.VISIBLE_APP_ADJ) {
adj = ProcessList.VISIBLE_APP_ADJ;
} else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
} else if (adj < ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
} else if (adj < ProcessList.CACHED_APP_MIN_ADJ) {
adj = ProcessList.CACHED_APP_MIN_ADJ;
} else if (adj < ProcessList.CACHED_APP_MAX_ADJ) {
adj++;
}
}
return adj;
}
state.setCurRawAdj(curEmptyAdj);//mCurRawAdj是直接设置的
state.setCurAdj(psr.modifyRawOomAdj(curEmptyAdj));//类似这里就是约束过的adj在复制给mCurAdj,而且一般都是adj调整完成后设置
*/
//mCurRawAdj是未被约束过的adj,mCurAdj可能由于依赖关系被调整过
//mCurAdj当前调整的adj值,进过约束的(如mHasAboveClient进行约束,client app进程优先级会相应降低)
//mCurRawAdj当前调整的adj值,但是未经过约束
//mSetRawAdj上一次applyOomAdjLSP后设置的mCurRawAdj值
//mSetAdj上一次applyOomAdjLSP后设置的mCurAdj值
state.setCurRawAdj(ProcessList.CACHED_APP_MAX_ADJ);
//设置已经完成了mCompletedAdjSeq为mAdjSeq(代表这个adj调整任务已经完成)
state.setCompletedAdjSeq(state.getAdjSeq());
/*
public static final int PROCESS_CAPABILITY_NONE = 0;
//进程在前台的时候可以访问location
public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 0;
//进程在前台的时候可以调用camera
public static final int PROCESS_CAPABILITY_FOREGROUND_CAMERA = 1 << 1;
//进程在前台的时候可以调用电话
public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 2;
//即使是功耗优化的限制,这个进程也可以访问网络
//AndroidS\frameworks\base\core\java\android\net\NetworkPolicyManager.java的
//isProcStateAllowedWhileIdleOrPowerSaveMode有下面逻辑
//procState <= FOREGROUND_THRESHOLD_STATE || (capability & ActivityManager.PROCESS_CAPABILITY_NETWORK) != 0
public static final int PROCESS_CAPABILITY_NETWORK = 1 << 3;
*/
//由于这个进程连应用线程都没有,设置该进程没有任何能力
state.setCurCapability(PROCESS_CAPABILITY_NONE);
//同时返回false,这种场景不需要考虑重复计算adj的逻辑
return false;
}
4. 对ProcessStateRecord进程状态记录的一些初始化
/*
public static final int REASON_UNKNOWN = 0;
//这个是在provider依赖关系的时候才调用,代表进程状态改变是由于provider正在使用中导致
public static final int REASON_PROVIDER_IN_USE = 1;
//这个是在service依赖关系的时候才调用,代表进程状态改变是由于service正在使用中导致
public static final int REASON_SERVICE_IN_USE = 2;
*/
//设置adj调整的大概原因,如由于service或者provider的依赖,初始化为未知
state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN);
//设置adj调整时由于客户端clinet或者force-imp时由于什么对象导致进程状态调整
state.setAdjSource(null);
//设置adj调整的对象名字,如由于service或者provider的依赖关系,那么对端的service/provider的名字会被记录在这里
state.setAdjTarget(null);
//目前只有cch-empty && PROCESS_STATE_CACHED_EMPTY才会设置setEmptyd的mEmpty为true,代表空进程
state.setEmpty(false);
//这里设置mCached初始化值为false,用isCached取得mCached来判断是否缓存进程
state.setCached(false);
//设置mAllowStartFgsState(getAllowStartFgsState)为PROCESS_STATE_NONEXISTENT进程不存在
//这个目前只有在"top-activity"、常驻进程、"fg-service"、客户端是常驻进程而且设置了BIND_FOREGROUND_SERVICE、客户端是top才会设置
state.resetAllowStartFgsState();
5. 设置默认是否允许冻结
//cycleReEval只有在设置了setContainsCycle true(如正在计算computeOomAdjLSP的时候还没计算完又跑进来,
//如上面的mAdjSeq == state.getAdjSeq()或者(服务/provider的客户端有这种情况的时候)),
//在updateOomAdjInnerLSP会让cycleReEval=true(具体可以看上面的updateOomAdjInnerLSP,大概意思是循环计算依赖)
if (!cycleReEval) {
//如果是非循环遍历计算,则设置ProcessCachedOptimizerRecord的mShouldNotFreeze,这个用于冻结cached进程,
//在applyOomAdjLSP的updateAppFreezeStateLSP会进行进程冻结,主要有2个操作freezeBinder/setProcessFrozen
// Don't reset this flag when doing cycles re-evaluation.
app.mOptRecord.setShouldNotFreeze(false);
}
6. 获取调整之前的一些状态
//取得app的uid
final int appUid = app.info.uid;
//这个主要是存在OomAdjObserver的时候,发送消息reportOomAdjMessageLocked/onOomAdjMessage,
//如我们需要监控某个应用的adj调整情况,可以使用ActivityManagerShellCommand.java,只是调试功能而已
//adb shell cat /data/system/packages.list可以查看每个进程的uid
//使用方法:adb shell am watch-uids --oom +上面找出的应用的uid
//会输出adj调整日志Slog.d和在终端pw打印相关信息
final int logUid = mService.mCurOomAdjUid;
//获取调整adj前的mCurAdj(当前调整的adj,进过约束的),保存成prevAppAdj之前的adj状态
int prevAppAdj = state.getCurAdj();
//将之前的进程状态mCurProcState保存成prevProcState
int prevProcState = state.getCurProcState();
//将之前的能力mCurCapability保存成prevCapability
int prevCapability = state.getCurCapability();
//获取ProcessServiceRecord,这个在ActiveServices的realStartServiceLocked会调用ProcessServiceRecord的startService,
//将ServiceRecord加入ProcessServiceRecord的mServices中去,主要保存的是进程服务相关信息
final ProcessServiceRecord psr = app.mServices;
7. system_server或者常驻进程的调整
//getMaxAdj拿到的是mMaxAdj,一般只有系统system_server、常驻进程PERSISTENT或者isolated的app才会设置该值
//而小于等于前台的adj,那么就只有系统system_server、常驻进程PERSISTENT、常驻服务PERSISTENT_SERVICE才会进来
//目前除了测试用例,系统默认的setMaxAdj都是会进来这里的
if (state.getMaxAdj() <= ProcessList.FOREGROUND_APP_ADJ) {
// The max adjustment doesn't allow this app to be anything
// below foreground, so it is not worth doing work for it.
// 可以看到oom的日志一般需要打开DEBUG_OOM_ADJ_REASON或者跟上面调试的logUid一致才会输出
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making fixed: " + app);
}
//设置adj类型为fixed,类似dumpsys activity p中输出的,下面括号部分打印的就是adj类型
//PERS #46: sys F/ /PER LCMN t: 0 1239:system/1000 (fixed)
state.setAdjType("fixed");
//在app中设置当前调整的adj系列为setAdjSeq
state.setAdjSeq(mAdjSeq);
//设置指定的mCurRawAdj(未被约束过的adj)为当前最大的adj
state.setCurRawAdj(state.getMaxAdj());
//暂时初始化,先标定没有前台activity
state.setHasForegroundActivities(false);
//设置当前的cgroup调度分组为SCHED_GROUP_DEFAULT默认,
//对应cgroup分组的SCHED_SP_DEFAULT(task_profiles.json), android默认只在这个分组设置了TimerSlackNormal
//TimerSlackNormal会将/proc/(pid)/timerslack_ns设置成50000ns(0.05ms,内核中断定时器最大的超时时间,
//定时器会在定时时间到超时直接范围内执行,主要为了避免频繁中断引起的性能损耗,类似于对齐);
//于之对应的设置是TimerSlackHigh,这个android默认设置的是40000000ns=40ms,
//这个时间就很大(对于实际执行的内容会可能wait等待时间较长,导致性能问题);
//至于其它cgroup分组节点就是默认上一次行为,本次不移动节点(只操作了timerslack_ns)
//cgroup对性能也很重要,但是不是本次重点,先带过
state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
//设置该进程拥有所有能力(只有系统system_server、常驻进程PERSISTENT才会进来,所以相对安全)
state.setCurCapability(PROCESS_CAPABILITY_ALL);
//设置当前进程的状态为PROCESS_STATE_PERSISTENT,字符串转换是"PER "
state.setCurProcState(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.
//初始化设定当前系统进程没有ui界面
state.setSystemNoUi(true);
//如果调整的是当前应用是最顶端的activity
if (app == topApp) {
//设置这类应用是带有界面的
state.setSystemNoUi(false);
//cgroup分组标记成top app(用户后面分组切换到类似*** cgroup的分组,cpuset的分组如:/dev/cpuset/top-app)
state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
//adj类型标记成pers-top-activity
state.setAdjType("pers-top-activity");
//是否有top ui,目前只有systemui才会设置setHasTopUi(通过AMS设置),如下拉状态栏、灭屏幕时
} else if (state.hasTopUi()) {
// sched group/proc state adjustment is below
//设置这类应用是带有界面的
state.setSystemNoUi(false);
//设置这类应用的类型是"pers-top-ui"
state.setAdjType("pers-top-ui");
//如果是有可见的activity的话
} else if (state.getCachedHasVisibleActivities()) {
//设置这类应用是带有界面的
state.setSystemNoUi(false);
}
//只有带有界面的常驻进程才会进入这里面(如systemui会灭屏幕进入;phone进程灭屏由于isSystemNoUi是true所以不进入)
if (!state.isSystemNoUi()) {
//mWakefulness获取的是当前是否唤醒状态,如亮屏是唤醒状态则是PowerManagerInternal.WAKEFULNESS_AWAKE
//isRunningRemoteAnimation代表是否播放远端动画,如锁屏动画这个也是true
//(如在WAKEFULNESS_DOZING的状态的时候,systemui的isRunningRemoteAnimation也可能是true)
if (mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE
|| state.isRunningRemoteAnimation()) {
// screen on or animating, promote UI
//进程状态还是设置成PROCESS_STATE_PERSISTENT_UI ("PERU")
state.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
//cgroup分组标记成top app
state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
} else {
// screen off, restrict UI scheduling
//灭屏没有播放动画才进入这里,如systemui进程状态会从"PERU"切换到"BFGS"
state.setCurProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
//cgroup分组标记成限制的分组,systemui也会进入这里
state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
}
}
//设置mCurRawProcState为当前计算的mCurProcState的值,这个值一般都是用于计算client的mCurRawProcState状态
//相当于依赖调整后的状态
state.setCurRawProcState(state.getCurProcState());
//这种进程(系统system_server、常驻进程PERSISTENT)不需要调整adj,直接设置的是传入的max adj
state.setCurAdj(state.getMaxAdj());
//设置当前进程完成调整的adj为mAdjSeq,代表本次adj调整完成
state.setCompletedAdjSeq(state.getAdjSeq());
//更新mAllowStartFgsState,代表是否允许启动前台服务,进程状态需要不比PROCESS_STATE_BOUND_FOREGROUND_SERVICE优先级低
state.bumpAllowStartFgsState(state.getCurProcState());
// if curAdj is less than prevAppAdj, then this process was promoted
//如果当前的adj比上一次调整的adj小、或者当前的进程状态比上一次的优先,则返回true(有效调整),其它则返回false
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState;
}
8. 调整之前的一些变量的定义
//其它的进程先预设拥有界面,初始值
state.setSystemNoUi(false);
//如果当前唤醒状态的话,getTopProcessState返回的是PROCESS_STATE_TOP,否者是PROCESS_STATE_TOP_SLEEPING
//PROCESS_STATE_CUR_TOP定义成final,代表初始化之后就不能改了,仅当次调整有效
final int PROCESS_STATE_CUR_TOP = mService.mAtmInternal.getTopProcessState();
// Determine the importance of the process, starting with most
// important to least, and assign an appropriate OOM adjustment.
//adj是准备进行调整计算进程优先级的临时变量
int adj;
//schedGroup是准备进行调整计算进程cgrup的临时变量
int schedGroup;
//procState是准备进行调整计算进程状态的临时变量
int procState;
//cachedAdjSeq是准备进行调整计算cached adj的临时变量(旧的代码,这个在这里完全没有用到,是个bug,可以提交给google)
int cachedAdjSeq;
//capability是准备进行调整计算进程能力的临时变量
int capability = 0;
//foregroundActivities(是否有前台的activity)默认设定为false
boolean foregroundActivities = false;
//hasVisibleActivities(是否有可见的activity)默认设定为false
boolean hasVisibleActivities = false;
9. top顶端app的调整
//如果当前是唤醒状态(如亮屏),而且本次调整的进程是topApp(顶端的activity)
//当前是唤醒状态(如亮屏),PROCESS_STATE_CUR_TOP才会是PROCESS_STATE_TOP
if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp) {
// The last app on the list is the foreground app.
//设置adj是0(FOREGROUND_APP_ADJ),一般代表正在运行
adj = ProcessList.FOREGROUND_APP_ADJ;
//进程分组是top app
schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
//进程状态是"top-activity"
state.setAdjType("top-activity");
//拥有前台活动对象
foregroundActivities = true;
//拥有可见的activity
hasVisibleActivities = true;
//当前进程状态是PROCESS_STATE_TOP
procState = PROCESS_STATE_CUR_TOP;
//将是否允许启动forground service的状态设置成PROCESS_STATE_TOP
//进程状态不低于PROCESS_STATE_BOUND_FOREGROUND_SERVICE即可启动前台服务
state.bumpAllowStartFgsState(PROCESS_STATE_TOP);
//打印日志或者在终端中监控某个app的时候会进去
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
}
10. 正在播放远端动画的调整
//如果正在播放远端动画
} else if (state.isRunningRemoteAnimation()) {
//设置adj为100(VISIBLE_APP_ADJ)
adj = ProcessList.VISIBLE_APP_ADJ;
//进程分组是top app
schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
//进程状态是"running-remote-anim"
state.setAdjType("running-remote-anim");
//当前进程状态是PROCESS_STATE_TOP(设备唤醒时)/PROCESS_STATE_TOP_SLEEPING(休眠时)
procState = PROCESS_STATE_CUR_TOP;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making running remote anim: " + app);
}
11. instrumentation的调整
//如果拥有活跃的instrumentation的时候(如自动化测试,或者qq downloader也会使用类似形式活跃在后台)
} else if (app.getActiveInstrumentation() != null) {
// Don't want to kill running instrumentation.
//设置adj是0(FOREGROUND_APP_ADJ),这种类型也认为是当前运行的进程
adj = ProcessList.FOREGROUND_APP_ADJ;
//进程分组是default默认
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
//adj类型是"instrumentation");
state.setAdjType("instrumentation");
//进程状态是forground service
procState = PROCESS_STATE_FOREGROUND_SERVICE;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making instrumentation: " + app);
}
12. 正在接受广播进程的调整
//如果正在接受广播
(getCurReceiverAt)
或者广播挂起(mPendingBroadcast)
马上会接收时
//可以看到广播adj设置优先于服务adj设置
} else if (state.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) {
// 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 = 0,代表正在前台运行中的进程
adj = ProcessList.FOREGROUND_APP_ADJ;
//如果接收的是前台广播队列mFgBroadcastQueue,则分组设置成SCHED_GROUP_DEFAULT,
//否者cgroup分组设置成后台SCHED_GROUP_BACKGROUND
schedGroup = (mTmpBroadcastQueue.contains(mService.mFgBroadcastQueue))
? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
//设置adj类型为广播"broadcast"
state.setAdjType("broadcast");
//设置当前进程状态是PROCESS_STATE_RECEIVER
procState = ActivityManager.PROCESS_STATE_RECEIVER;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making broadcast: " + app);
}
13. 正在运行服务进程的调整
//如果正在运行服务bumpServiceExecutingLocked(startExecutingService加入运行服务,stopExecutingService移除)
} else if (psr.numberOfExecutingServices() > 0) {
// An app that is currently executing a service callback also
// counts as being in the foreground.
// adj = 0,代表正在前台运行中的进程
adj = ProcessList.FOREGROUND_APP_ADJ;
//如果运行的是前台服务,则分组设置成SCHED_GROUP_DEFAULT,
//否者cgroup分组设置成后台SCHED_GROUP_BACKGROUND
schedGroup = psr.shouldExecServicesFg()
? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
//设置adj类型为正在运行的服务"exec-service"
state.setAdjType("exec-service");
//设置当前进程状态是PROCESS_STATE_SERVICE
procState = PROCESS_STATE_SERVICE;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making exec-service: " + app);
}
14. 系统在休眠时topApp的调整
//如果调整的是topApp,但是在休眠的时候
} else if (app == topApp) {
//adj也是调整成0
adj = ProcessList.FOREGROUND_APP_ADJ;
//只是cgroup分组设置成后台SCHED_GROUP_BACKGROUND
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
//设置adj类型为顶端,而且休眠状态"top-sleeping"
state.setAdjType("top-sleeping");
//拥有前台活动对象foregroundActivities设置成yrue, 注意此时拥有可见的activity(hasVisibleActivities)并未设置成ture
foregroundActivities = true;
//进程状态设置成PROCESS_STATE_TOP_SLEEPING
procState = PROCESS_STATE_CUR_TOP;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top (sleeping): " + app);
}
15. 其它app的默认状态初始化
} else {
// As far as we know the process is empty. We may change our mind later.
//cgroup分组设置成后台SCHED_GROUP_BACKGROUND
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
// At this point we don't actually know the adjustment. Use the cached adj
// value that the caller wants us to.
// 其它情况,先设置成cachedAdj(oldAdj或则UNKNOWN_ADJ),
// 初始化为是空进程adj或者上一次调整的adj值,一会在进行adj调整
adj = cachedAdj;
//进程状态设置成空的缓存进程PROCESS_STATE_CACHED_EMPTY
procState = PROCESS_STATE_CACHED_EMPTY;
//如果不是循环计算,才进入里面
if (!state.containsCycle()) {
//设置成cached缓存进程
state.setCached(true);
//设置成empty空进程
state.setEmpty(true);
//adj类型是空的缓存进程"cch-empty"
state.setAdjType("cch-empty");
}
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making empty: " + app);
}
}
16. 更新foregroundActivities和mHasVisibleActivities
// Examine all activities if not already foreground.
//foregroundActivities目前只有top app才是true,除了了top它的值都是false
//只要进程有activity(getCachedHasActivities其实是hasActivities),则getCachedHasActivities返回true
//如realStartActivityLocked(ActivityTaskSupervisor)通过setProcess(ActivityRecord)/addActivityIfNeeded(WindowProcessController)
//将ActivityRecord add进入mActivities,而移除也就是从mActivities移除,
//其中的一种移除情况如:ActivityRecord在destroyImmediately(events出现wm_destroy_activity的时候)
if (!foregroundActivities && state.getCachedHasActivities()) {
//通过activity不同的状态计算其adj,
//PROCESS_STATE_CUR_TOP的值是PROCESS_STATE_TOP(设备唤醒时)/PROCESS_STATE_TOP_SLEEPING(休眠时)
//一般情况procState进程状态越小越优先,adj越小越优先,cgroup分组schedGroup一般越大越优先
//1.如visable可见的activity则会通过onVisibleActivity设置adj最低是VISIBLE_APP_ADJ(其adj通过minLayer/mLayerRank会约束到100-199)
//foregroundActivities和mHasVisibleActivities都是true,procState进程状态设置成小于等于PROCESS_STATE_CUR_TOP
//cgroup分组schedGroup设置成大于等于SCHED_GROUP_DEFAULT()
//2.pausing正在暂停的activity则会通过onPausedActivity设置adj最低是PERCEPTIBLE_APP_ADJ
//foregroundActivities = true和mHasVisibleActivities是false,procState进程状态设置成小于等于PROCESS_STATE_CUR_TOP
//cgroup分组schedGroup设置成大于等于SCHED_GROUP_DEFAULT
//3.stopping正在停止的activity则会通过onStoppingActivity设置adj最低是PERCEPTIBLE_APP_ADJ
//foregroundActivities = true和mHasVisibleActivities是false,
//如果所有activity正在STOPPING都是finishing状态(如wm_finish_activity/wm_destroy_activity),
//procState进程状态设置成小于等于PROCESS_STATE_LAST_ACTIVITY,schedGroup不变更
//4.其它状态的activity则会通过onOtherActivity,adj不更改
//foregroundActivities不变(默认foregroundActivities是false才会进来)和mHasVisibleActivities是false
//procState进程状态设置成小于等于PROCESS_STATE_CACHED_ACTIVITY,代表缓存的activity
state.computeOomAdjFromActivitiesIfNecessary(mTmpComputeOomAdjWindowCallback,
adj, foregroundActivities, hasVisibleActivities, procState, schedGroup,
appUid, logUid, PROCESS_STATE_CUR_TOP);
//将上面获取的mCachedAdj设置成当前adj
adj = state.getCachedAdj();
//将上面改变ProcessStateRecord的foregroundActivities复制给当前的foregroundActivities变量
foregroundActivities = state.getCachedForegroundActivities();
//将上面改变ProcessStateRecord的mHasVisibleActivities复制给当前的hasVisibleActivities变量
hasVisibleActivities = state.getCachedHasVisibleActivities();
//将上面的procState进程状态保存在当前的procState变量
procState = state.getCachedProcState();
//将上面的cgroup分组schedGroup状态保存在当前的schedGroup变量
schedGroup = state.getCachedSchedGroup();
}
17. 更新最近使用的activity的状态
//有activity在最近任务mRecentTasks,代表最近启动的activity,进程状态设置成小于等于PROCESS_STATE_CACHED_RECENT
if (procState > PROCESS_STATE_CACHED_RECENT && state.getCachedHasRecentTasks()) {
//进程状态最大就是PROCESS_STATE_CACHED_RECENT
procState = PROCESS_STATE_CACHED_RECENT;
//adj类型是cch-rec,缓存的最近任务
state.setAdjType("cch-rec");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to cached recent: " + app);
}
}
18. 调整前台服务或者hasOverlayUi的进程
//如果当前adj大于200(PERCEPTIBLE_APP_ADJ用户可感知的进程)
//或者当前进程状态大于PROCESS_STATE_FOREGROUND_SERVICE(前台运行的服务)
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > PROCESS_STATE_FOREGROUND_SERVICE) {
//如果其拥有前台服务(通过AMS的updateProcessForegroundLocked设置,
//目前只有updateServiceForegroundLocked(ActiveServices)才可能设置true)
// 一般前台服务带有通知
if (psr.hasForegroundServices()) {
// 将设置成200(PERCEPTIBLE_APP_ADJ)用户可感知的级别
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
// 将进程状态设置成前台服务
procState = PROCESS_STATE_FOREGROUND_SERVICE;
// 设置是否允许启动前台服务,这里是允许的(只要小于等于PROCESS_STATE_BOUND_FOREGROUND_SERVICE都是允许)
state.bumpAllowStartFgsState(PROCESS_STATE_FOREGROUND_SERVICE);
// adj类型是"fg-service"前台服务
state.setAdjType("fg-service");
// 设置成非cached的进程
state.setCached(false);
//此时设置cgroup的分组为默认
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + state.getAdjType() + ": "
+ app + " ");
}
// hasOverlayUi是true的时候(需要设置TYPE_APPLICATION_OVERLAY,有覆盖之上的界面,类似悬浮窗)
} else if (state.hasOverlayUi()) {
// adj设置成用户可感知的优先级200
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
// 将进程状态设置成重要的前台进程
procState = PROCESS_STATE_IMPORTANT_FOREGROUND;
// 设置成非cached的进程
state.setCached(false);
// adj类型是"has-overlay-ui"拥有覆盖界面的进程
state.setAdjType("has-overlay-ui");
//此时设置cgroup的分组为默认
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to overlay ui: " + app);
}
}
}
19. 调整最近活跃的前台服务进程
// If the app was recently in the foreground and moved to a foreground service status,
// allow it to get a higher rank in memory for some time, compared to other foreground
// services so that it can finish performing any persistence/processing of in-memory state.
//如果有前台服务,而且adj比50(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ最近使用的前台进程)大;
//而且是最近15s内在top级别(最前台),或者当前进程状态起码是top
if (psr.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
&& (state.getLastTopTime() + mConstants.TOP_TO_FGS_GRACE_DURATION > now
|| state.getSetProcState() <= PROCESS_STATE_TOP)) {
//将adj设定成50(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ),
//代表最近使用过的前台应用(hasForegroundServices最低是200,最近使用过的前台服务最低是50)
adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
//设置adj类型为前台服务最近活跃
state.setAdjType("fg-service-act");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app);
}
}
20. 调整强制提升到用户可感知的进程
调整通过setProcessImportant
来提升优先级的应用
// adj大于200(PERCEPTIBLE_APP_ADJ用户可感知的进程),或者进程状态大于8(PROCESS_STATE_TRANSIENT_BACKGROUND后台临时状态)
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
//如果设置了getForcingToImportant不为null(调用AMS的setProcessImportant设置),
//而且adj是用户可感知的PERCEPTIBLE_APP_ADJ,例如toasts是这种情况(NotificationManagerService中调用setProcessImportant)
//如果不想要通知又想提升优先级,setProcessImportant是个不错的选择
if (state.getForcingToImportant() != null) {
// This is currently used for toasts... they are not interactive, and
// we don't want them to cause the app to become fully foreground (and
// thus out of background check), so we yes the best background level we can.
// adj设置成200
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
// 进程状态设置成后台临时状态(PROCESS_STATE_TRANSIENT_BACKGROUND)
procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
// 设置成非cached的进程
state.setCached(false);
// adj类型是"force-imp"强制设置的重要应用
state.setAdjType("force-imp");
// adj改变的原因是ImportanceToken(pid, token, reason)对象,包括提升优先级进程的pid、传递的IBinder对象token,还有原因reason
state.setAdjSource(state.getForcingToImportant());
//此时设置cgroup的分组为默认
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to force imp: " + app);
}
}
}
21. 调整heavy的进程
//当app无法保存状态,如AndroidManifest.xml设置了"android:cantSaveState="true"",
//同时系统配置了<feature name="android.software.cant_save_state" />这个feature
//由于其无法保存状态,故尽量不要杀死, 一般只有一个,adj类型是"heavy"
if (state.getCachedIsHeavyWeight()) {
//如果adj大于400(HEAVY_WEIGHT_APP_ADJ重要app的优先级)
if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
// We don't want to kill the current heavy-weight process.
//将adj设置成400
adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
//不过将cgroup分组设置成后台的
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
// 设置成非cached的进程
state.setCached(false);
// adj类型是"heavy"(由于adj改变设置)
state.setAdjType("heavy");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to heavy: " + app);
}
}
//如果进程状态大于PROCESS_STATE_HEAVY_WEIGHT(重要应用)
if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
//将进程状态设置成PROCESS_STATE_HEAVY_WEIGHT(起码是这个进程状态级别,mHeavyWeightProcess的级别不会比这个低)
procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
// adj类型是"heavy"(由于进程状态改变设置)
state.setAdjType("heavy");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to heavy: " + app);
}
}
}
21. 调整桌面应用
//如果是桌面应用mHomeProcess
//在ActivityRecord的completeResumeLocked中会将ACTIVITY_TYPE_HOME类型的应用设置成mHomeProcess桌面应用
//(具体ACTIVITY_TYPE_HOME的设置在ActivityRecord的setActivityType)
if (state.getCachedIsHomeProcess()) {
//桌面应用的adj不能小于600(HOME_APP_ADJ)
if (adj > ProcessList.HOME_APP_ADJ) {
// This process is hosting what we currently consider to be the
// home app, so we don't want to let it go into the background.
//adj设置成600,桌面应用有点特殊,经常会返回使用,放在A、B service中间,比上一个应用稍微优先一点
adj = ProcessList.HOME_APP_ADJ;
//将cgroup分组设置成后台的
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
// 设置成非cached的进程
state.setCached(false);
// adj类型是"home"
state.setAdjType("home");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to home: " + app);
}
}
//桌面应用的进程状态不能低于PROCESS_STATE_HOME(14)
if (procState > ActivityManager.PROCESS_STATE_HOME) {
//桌面应用的进程状态设置成PROCESS_STATE_HOME(14)
procState = ActivityManager.PROCESS_STATE_HOME;
// adj类型是"home"
state.setAdjType("home");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to home: " + app);
}
}
}
22. 调整previous上一个使用的应用
//1. getCachedIsPreviousProcess: 在上一个前台进程activity stop的时候,则会将进程ActivityRecord的app(WindowProcessController)加入到mPreviousProcess,做为上一个进程
//2. getCachedHasActivities:在realStartActivityLocked()的时候将activity add进来,在detachFromProcess或者destroyImmediately()的时候移除activity,
//也就是说是否有启动过但是未destory的activity
if (state.getCachedIsPreviousProcess() && state.getCachedHasActivities()) {
//如果是上一个应用,而且activity没有销毁,那么adj最少设置成700(PREVIOUS_APP_ADJ)
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设置成700
adj = ProcessList.PREVIOUS_APP_ADJ;
//设置cgroup的分组为默认
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
// 设置成非cached的进程
state.setCached(false);
// 设置adj类型为"previous"上一个应用
state.setAdjType("previous");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app);
}
}
//进程状态最少设置成PROCESS_STATE_LAST_ACTIVITY(15)
if (procState > PROCESS_STATE_LAST_ACTIVITY) {
//进程状态设置成PROCESS_STATE_LAST_ACTIVITY(15)
procState = PROCESS_STATE_LAST_ACTIVITY;
// 设置adj类型为"previous"上一个应用
state.setAdjType("previous");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app);
}
}
}
if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
+ " reason=" + state.getAdjType());
23. 循环计算时更新procState、adj、schedGroup
循环计算时更新进程状态procState、进程优先级adj、进程分组cgroup信息schedGroup
// 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. If we're re-evaluating due to cycles, use the previously computed
// values.
//cycleReEval只有在设置了setContainsCycle true(如正在计算computeOomAdjLSP的时候还没计算完又跑进来,
//如上面的mAdjSeq == state.getAdjSeq()或者(服务/provider的客户端有这种情况的时候)),
//在updateOomAdjInnerLSP会让cycleReEval=true(具体可以看上面的updateOomAdjInnerLSP,大概意思是循环计算依赖)
//如果是循环计算的话
if (cycleReEval) {
//取之前的进程状态getCurRawProcState和上面计算出来的进程状态procState的最小值,也就是去优先级大的
procState = Math.min(procState, state.getCurRawProcState());
//取之前的进程adj(getCurRawAdj)和上面计算出来的adj的最小值,也就是去优先级大的
adj = Math.min(adj, state.getCurRawAdj());
//cgroup分组也是取小的值
schedGroup = Math.max(schedGroup, state.getCurrentSchedulingGroup());
}
24. 先更新一下当前计算的值到ProcessStateRecord
先更新一下当前计算的值到ProcessStateRecord
(进程状态信息记录)
//将当前adj更新到mCurRawAdj
state.setCurRawAdj(adj);
//将当前进程状态procState更新到mCurRawProcState
state.setCurRawProcState(procState);
//先默认该进程没有启动的服务,给初始化值
state.setHasStartedServices(false);
25. 设置当前adj调整的系列号
//到这里我们开始调整adj的值,设置当前进程adj调整的序列是mAdjSeq
state.setAdjSeq(mAdjSeq);
26. 调整backup备份的应用
//获取backup的目标
final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
//如果backup app就是当前调整的app
if (backupTarget != null && app == backupTarget.app) {
// If possible we want to avoid killing apps while they're being backed up
//那么adj最小不低于300(BACKUP_APP_ADJ)
if (adj > ProcessList.BACKUP_APP_ADJ) {
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
//那么adj设置成300(BACKUP_APP_ADJ)
adj = ProcessList.BACKUP_APP_ADJ;
//调整adj值之后,进程状态最低不低于8(TRANSIENT_BACKGROUND)
if (procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
}
//adj的类型是"backup"
state.setAdjType("backup");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to backup: " + app);
}
// 设置成非cached的进程
state.setCached(false);
}
//进程状态最低不低于9(BACKUP)
if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
//设置进程状态为9(BACKUP)
procState = ActivityManager.PROCESS_STATE_BACKUP;
//adj的类型是"backup"
state.setAdjType("backup");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to backup: " + app);
}
}
}
27. service服务自身和服务依赖关系调整
27.1 遍历该进程的服务numberOfRunningServices
//用于计算前台服务都拥有哪些能力
int capabilityFromFGS = 0; // capability from foreground service.
//用来用来判断分组是否需要将分组设置成top
boolean scheduleLikeTopApp = false;
//numberOfRunningServices是查看还有多少正在运行的服务(只要startService了就会放入ProcessServiceRecord的mServices中,
//stopService或者kill会从mServices移除)
//而且满足其中之一才会进来:adj需要大于0的才调整,如果是0前台或者常驻进程adj是负数,或者分组是后台,或者进程状态状态大于top
for (int is = psr.numberOfRunningServices() - 1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
is--) {
//取得保存服务的对象ServiceRecord
ServiceRecord s = psr.getRunningServiceAt(is);
27.2 根据Services自身的状态进行调整
/*
realStartServiceLocked:, ActiveServices (com.android.server.am) //psr.startService将ServiceRecord放入mServices
bringUpServiceLocked:, ActiveServices (com.android.server.am)
startServiceInnerLocked:, ActiveServices (com.android.server.am)//设置startRequested = true
startServiceLocked:, ActiveServices (com.android.server.am)
startService:, ActivityManagerService (com.android.server.am)
*/
//startRequested是在startServiceInnerLocked中设置,在realStartServiceLocked(会将service放入mServices)之前
if (s.startRequested) {
//设置有启动的服务
state.setHasStartedServices(true);
//没有stop的服务的进程,最低进程状态就是10(SERVICE)
if (procState > PROCESS_STATE_SERVICE) {
procState = PROCESS_STATE_SERVICE;
//adj类型是"started-services"
state.setAdjType("started-services");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise procstate to started service: " + app);
}
}
//如果不是config_keep_warming_services(目前这个是空的,也就是mKeepWarming是false)的服务,
//而且hasShownUi是true,且不是桌面
//hasShownUi只要该进程有onStartActivity的操作,就会设置成true,不管activity是否destroy,只要进程还在都是true
if (!s.mKeepWarming && state.hasShownUi() && !state.getCachedIsHomeProcess()) {
// If this process has shown some UI, let it immediately
// go to the LRU list because it may be pretty heavy with
// UI stuff. We'll tag it with a label just to help
// debug and understand what is going on.
//如果adj比500(SERVICE_ADJ)大(adj越大优先级越低),SERVICE_ADJ是A services
if (adj > ProcessList.SERVICE_ADJ) {
//则将adj类型设置成"cch-started-ui-services缓存的启动了ui的服务
state.setAdjType("cch-started-ui-services");
}
} else {
//mKeepWarming都是false,而且lastActivity服务启动或者bind时间是30分钟以内
//ServiceRecord的lastActivity代表的是上一次该服务
//startServiceInnerLocked/bindServiceLocked/realStartServiceLocked的时间
if (s.mKeepWarming
|| now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
// This service has seen some activity within
// recent memory, so we will keep its process ahead
// of the background processes.
//如果adj比500(SERVICE_ADJ)大
if (adj > ProcessList.SERVICE_ADJ) {
//则将adj设置成500
adj = ProcessList.SERVICE_ADJ;
//adj类型也是设置成"started-services"
state.setAdjType("started-services");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise adj to started service: " + app);
}
// 设置成非cached的进程
state.setCached(false);
}
}
// If we have let the service slide into the background
// state, still have some text describing what it is doing
// even though the service no longer has an impact.
//其它情况不调整adj,将adj类型设置成"cch-started-services"
if (adj > ProcessList.SERVICE_ADJ) {
state.setAdjType("cch-started-services");
}
}
}
27.3 获取前台服务的能力capabilityFromFGS
//启动的是前台服务的时候isForeground这个值才是true
if (s.isForeground) {
//foregroundServiceType一般是AndroidManifest中设置,也可以在startForeground的时候传入
//frameworks/base/core/res/res/values/attrs_manifest.xml的foregroundServiceType有各个类型定义
//例如下面前台服务的时候拥有dataSync、mediaPlayback、phoneCall、location、connectedDevice的(mediaProjection/camera/microphone)
//<service android:name="SchedulerService"
// android:foregroundServiceType="dataSync|mediaPlayback|phoneCall|location|connectedDevice">
final int fgsType = s.foregroundServiceType;
//mAllowWhileInUsePermissionInFgs用于是否允许前台服务使用一些权限
if (s.mAllowWhileInUsePermissionInFgs) {
//此时location的权限是否允许取决于foregroundServiceType是否有location权限(GPS、地图、导航)
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
boolean enabled = false;
try {
/*
boolean isEnabled(ApplicationInfo app, AndroidBuildClassifier buildClassifier) {
if (app == null) {
return defaultValue();
}
if (mEvaluatedOverrides.containsKey(app.packageName)) {
return mEvaluatedOverrides.get(app.packageName);
}
if (getDisabled()) {
return false;
}
if (getEnableSinceTargetSdk() != -1) {
// If the change is gated by a platform version newer than the one currently installed
// on the device, disregard the app's target sdk version.
//Google这里的代码也有有点奇怪,app.targetSdkVersion是app的targetSdkVersion,而platformTargetSdk是
//看注释是取最小的做为compareSdk
int compareSdk = Math.min(app.targetSdkVersion, buildClassifier.platformTargetSdk());
//但是这里不等于targetSdkVersion有赋值成targetSdkVersion,那其实是一个意思
if (compareSdk != app.targetSdkVersion) {
compareSdk = app.targetSdkVersion;
}
return compareSdk >= getEnableSinceTargetSdk();
}
return true;
}
*/
//ChangeId(136219221; name=CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID; enableSinceTargetSdk=30)
//获取camera,具体配置是读取/system/etc/compatconfig/services-platform-compat-config.xml进行初始话,这个是在30(android R)之后支持
//isChangeEnabled其实最终调用的是CompatChange的isEnabled,目前只是用apk的targetSdkVersion进行判断,主要大于30就返回true
enabled = getPlatformCompatCache().isChangeEnabled(
CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, s.appInfo);
} catch (RemoteException e) {
}
//Android S中,如果apk是针对S做的,一般enabled都是true
if (enabled) {
//判断foregroundServiceType是否有"camera"标签,有的话赋予访问camera的权限
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA : 0;
//判断foregroundServiceType是否有"microphone"标签,有的话赋予访问听筒的权限
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE : 0;
} else {
//如果是版本过低,这默认将camera、听筒的权限赋值给前台服务
capabilityFromFGS |= PROCESS_CAPABILITY_FOREGROUND_CAMERA
| PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
}
}
}
27.4 遍历每个服务里面的所有链接对象
//bindService就会往connections add相关的链接对象,key是IServiceConnection对象
//unbindService移除链接
ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections();
//遍历所有的服务,ArrayMap是按照key的hashCode/identityHashCode进行排序的,不是按照add进去的时间进行排序
//这里是从serviceConnections尾部向头部遍历(反过来其实也是一样的,可能是考虑add/remove修改数组大小的时候的健壮性才从尾部开始遍历)
//如果当前进程的adj > 0或者进程分组schedGroup是后台或者进程状态 > top,才进行调整(高优先级的不进行依赖调整,减少调整次数)
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);
27.5 取出每个服务链接对象
//取出每次链接的对象,只要(当前进程的adj > 0或者进程分组schedGroup是后台或者进程状态 > top)是非前台的都进行调整
for (int i = 0;
i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
i++) {
// XXX should compute this based on the max of
// all connected clients.
//取出每一个ConnectionRecord对象
ConnectionRecord cr = clist.get(i);
27.6 只调整自身是服务,由于客户端的链接的情况
只有服务端的adj,才会由于客户端的adj提升而得到相应的提升
这里就是服务依赖关系调整的开始
//如果服务链接的客户端是当前app,则跳过,客户端的adj不会由于服务端的adj提升而升高
//只有服务端的adj,才会由于客户端的adj提升而得到相应的提升(不然会出现客户端在使用的时候服务端由于优先级低给回收掉了)
if (cr.binding.client == app) {
// Binding to oneself is not interesting.
continue;
}
27.7 computeClients循环计算时,会先计算客户端的adj
//通过mProcessStats.mTrackingAssociations.add(this);将其放入记录ProcessState列表中
//在updateOomAdjInnerLSP的updateTrackingAssociationsLocked会去更新这些add进去的进程状态
//data/system/procstats里面有保存相关数据
boolean trackedProcState = false;
//服务链接中获取绑定的客户端进程
ProcessRecord client = cr.binding.client;
//客户端的进程状态
final ProcessStateRecord cstate = client.mState;
//computeClients是否需要计算当前进程的时候计算服务、provider提供者对端client的adj
if (computeClients) {
//调整之前先计算client的adj,将client按照当前传递计算app的重新计算一次,此处就有可能循环计算,mAdjSeq目前都是一个
computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now,
cycleReEval, true);
} else {
//如果不需要计算客户端的优先级,那么setCurRawAdj先将客户端当前调整的mCurAdj更新到mCurRawAdj中
//mCurAdj当前调整的adj值,进过约束的(如mHasAboveClient进行约束,client app进程优先级会相应降低)
//mCurRawAdj当前调整的adj值,但是未经过约束
//mSetRawAdj上一次applyOomAdjLSP后设置的mCurRawAdj值
//mSetAdj上一次applyOomAdjLSP后设置的mCurAdj值
cstate.setCurRawAdj(cstate.getCurAdj());
//mCurProcState是跑完一次computeOomAdjLSP的出的进程状态结果
//而mCurRawProcState是当前的进程状态,是在计算中的临时结果
//setCurRawProcState将上一次计算的进程状态mCurProcState赋值给mCurRawProcState(临时计算值)
cstate.setCurRawProcState(cstate.getCurProcState());
}
27.8 调整前获取客户端的clientAdj和clientProcState
获取客户端的clientAdj(客户端的adj)
和clientProcState(客户端的进程状态procState)
//取得客户端的mCurRawAdj当前调整的adj值(未经过约束)
int clientAdj = cstate.getCurRawAdj();
//取得客户端的临时计算的最新进程状态值mCurRawProcState
int clientProcState = cstate.getCurRawProcState();
//如果进程状态比top还小,代表是起码是常驻进程,clientIsSystem标记为true
final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;
//如果客户端mShouldNotFreeze是true,则服务端也被设置不允许冻结。
//(原生冻结有2个条件,一个是adj大于等于900,而且mShouldNotFreeze=false)
if (client.mOptRecord.shouldNotFreeze()) {
// Propagate the shouldNotFreeze flag down the bindings.
app.mOptRecord.setShouldNotFreeze(true);
}
27.9 进行没有豁免优先级情况的调整
//如果当前没有设置豁免绑定的优先级调整,一般没有设置
//则会进入根据客户端的adj去调整服务端的adj
if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
27.9.1 循环计算的时候是否需要先跳过本次计算
//判断是是否客户端adj没有计算完成,是否需要跳过本次依赖关系的计算,具体请看shouldSkipDueToCycle的解释
if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
continue;
}
27.9.2 能力capability初始化
//如果包含BIND_INCLUDE_CAPABILITIES,则会将客户端的能力全部赋值给服务端
if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
capability |= cstate.getCurCapability();
}
// If an app has network capability by default
// (by having procstate <= BFGS), then the apps it binds to will get
// elevated to a high enough procstate anyway to get network unless they
// request otherwise, so don't propagate the network capability by default
// in this case unless they explicitly request it.
//如果客户端有网络相关的能力
if ((cstate.getCurCapability() & PROCESS_CAPABILITY_NETWORK) != 0) {
//客户端的状态小于等于PROCESS_STATE_BOUND_FOREGROUND_SERVICE
if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
//只有设置了BIND_BYPASS_POWER_NETWORK_RESTRICTIONS(power相关限制都不会阻止服务获取网络权限)
//才会给当前进程(是服务)赋予网络相关的能力
if ((cr.flags & Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS)
!= 0) {
capability |= PROCESS_CAPABILITY_NETWORK;
}
} else {
//如果客户端优先级大于等于PROCESS_STATE_FOREGROUND_SERVICE
//则直接赋予当前进程(是服务)网络相关能力
capability |= PROCESS_CAPABILITY_NETWORK;
}
}
27.9.3 低于cached activity的进程状态clientProcState约束
//客户端的进程状态优先级低于cached activity
if (clientProcState >= 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.
//客户端的进程状态优先级低于全部归类为cached empty的进程
clientProcState = PROCESS_STATE_CACHED_EMPTY;
}
27.9.4 如果进程设置了在低内存时托管给系统
如果进程设置了在低内存时托管给系统,就可以减少很多进程依赖关系的调整,
不过目前大部分应用没有使用,而且这里规则也不是很细致
// adjType先初始化为null
String adjType = null;
// 如果服务连接记录设置了BIND_ALLOW_OOM_MANAGEMENT
//这个标记位的意思是允许系统在低内存的时候会删除这个进程,或者服务长时间运行会被杀死和重启
if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
// Similar to BIND_WAIVE_PRIORITY, keep it unfrozen.
//如果绑定服务的客户端的adj(clientAdj),小于900,则服务也不会进行冻结
if (clientAdj < ProcessList.CACHED_APP_MIN_ADJ) {
app.mOptRecord.setShouldNotFreeze(true);
}
// Not doing bind OOM management, so treat
// this guy more like a started service.
//如果当前调整的进程拥有界面(hasShownUi只要该进程有onStartActivity的操作,就会设置成true,不管activity是否destroy,只要进程还在都是true)
//而且不是桌面的情况下
if (state.hasShownUi() && !state.getCachedIsHomeProcess()) {
// If this process has shown some UI, let it immediately
// go to the LRU list because it may be pretty heavy with
// UI stuff. We'll tag it with a label just to help
// debug and understand what is going on.
//如果服务端的adj大于客户端clientAdj,则将adj类型设置成"cch-bound-ui-services"(缓存的拥有ui、被绑定的服务)
if (adj > clientAdj) {
adjType = "cch-bound-ui-services";
}
//设置cached为fasle,代表这个不是cached进程
state.setCached(false);
//将服务的adj赋值给clientAdj,注意一下这里的clientAdj只是用来调整服务端的adj,
//这里的意思是此时将不根据客户端的优先级调整服务端的优先级
//这样可以有效的避免互相依赖关系,这个功能还不错,只是目前大多数服务绑定时没有设置这个TAG
//而且目前该逻辑也相对简单,不太适合统一打开,需要更精细控制
clientAdj = adj;
//将服务的进程状态procState赋值给clientProcState ,跟上面是一个意思,调整adj时忽略客户端的进程状态
clientProcState = procState;
} else {
//针对没有界面服务,或者是桌面
//则看一下s.lastActivity(服务启动或者绑定的时候会设置该时间)
//是否上一次服务启动或者绑定的时间已经超过MAX_SERVICE_INACTIVITY(默认30分钟)
//30分钟以内的话不进入这里,还是会根据客户端的优先级来调整服务端的优先级,
//30分钟以内,相当于没有设置BIND_ALLOW_OOM_MANAGEMENT一样的逻辑
if (now >= (s.lastActivity
+ mConstants.MAX_SERVICE_INACTIVITY)) {
// This service has not seen activity within
// recent memory, so allow it to drop to the
// LRU list if there is no other reason to keep
// it around. We'll also tag it with a label just
// to help debug and undertand what is going on.
//如果是的话,当前服务端的adj小于clientAdj,也就是服务adj优先级没有客户端高
if (adj > clientAdj) {
//那么将adj类型设置成"cch-bound-services"(缓存的绑定服务),代表不通过客户端来调整服务端的adj
adjType = "cch-bound-services";
}
//忽略客户端adj,不管客户端adj的大小,将服务的adj赋值给clientAdj后,都将忽略clientAdj
clientAdj = adj;
}
}
}
27.9.5 如果clientAdj大于当前服务的adj,则开始adj依赖关系调整
//如果客户端的clientAdj小于当前服务的adj,
//那么将会根据客户端的clientAdj进行服务的优先级调整,我们认为这是依赖关系调整即可
if (adj > clientAdj) {
// If this process has recently shown UI, and
// the process that is binding to it is less
// important than being visible, then we don't
// care about the binding as much as we care
// about letting this process get into the LRU
// list to be killed and restarted if needed for
// memory.
//如果当前调整的进程拥有界面(hasShownUi只要该进程有onStartActivity的操作,就会设置成true,不管activity是否destroy,只要进程还在都是true)
//而且不是桌面的情况下,这里逻辑跟上面一样,不过多了一个clientAdj如果是大于用户可感知的200才会进来
//如果clientAdj小于等于200(优先级大于等于用户可感知级别的话),那就不会进来
if (state.hasShownUi() && !state.getCachedIsHomeProcess()
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
//注意就算是进来,也只进行了一个操作,就是当前进程的adj如果大于等于900
if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
//则将当前进程的adj类型设置成"cch-bound-ui-services"
adjType = "cch-bound-ui-services";
}
//这里少了对比上面少了state.setCached(false);clientAdj = adj;clientProcState = procState;
//isCached没有直接设置成false,isCached用的地方比较少,主要用在performUpdateOomAdjLSP
//state.setCached(false);
//这个确实没有作用了,目前已经跑完了if (adj > clientAdj)的逻辑,没有用到clientAdj的地方了,
//起码adj暂时不会由于clientAdj去调整
//clientAdj = adj;
//这个不设置是由于后面还需要用到,还会由于客户端的进程状态调整当前进程的进程状态
//clientProcState = procState;
} else {
//其它情况会根据客户端的clientAdj,看情况调整当前进程的adj
int newAdj;
//如果服务链接里面包含BIND_ABOVE_CLIENT或者BIND_IMPORTANT的时候
//BIND_ABOVE_CLIENT: 代表服务的优先级需要比客户端client的高
//BIND_IMPORTANT: 正常情况是就客户端是前台,服务端最多也只是visable,不过设置了这个,
//adj可以到0(fg)或者-700(PERSISTENT_SERVICE)
//StorageUserConnection里面bindServiceAsUser就有设置BIND_IMPORTANT
if ((cr.flags&(Context.BIND_ABOVE_CLIENT
|Context.BIND_IMPORTANT)) != 0) {
//如果客户端的adj大于等于-700,直接将客户端的clientAdj赋值给当前进程的newAdj
if (clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
newAdj = clientAdj;
} else {
//如果客户端的adj是常驻进程(-800)或者系统(-900)
// make this service persistent
// 直接赋值newAdj为PERSISTENT_SERVICE_ADJ(常驻服务)级别,
//这类进程和常驻进程有区别,不需要开机之前启动,可以动态设置和关闭
newAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
//cgroup分组设置成default,具体之前有解释
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
//进程状态设置成PROCESS_STATE_PERSISTENT
procState = ActivityManager.PROCESS_STATE_PERSISTENT;
//将关联关系记录的信息保存在AssociationState.SourceState中,主要是进程状态,当前调整的序列号和调整时间
cr.trackProcState(procState, mAdjSeq, now);
//标记已经记录过进程状态信息trackedProcState了,后面就不需要再做一次了
trackedProcState = true;
}
//如果服务链接里面包含BIND_NOT_PERCEPTIBLE(服务进程的优先级提升不会高于250)
//clientAdj优先级比200高(或等于PERCEPTIBLE_APP_ADJ),而且当前进程优先级小于250(PERCEPTIBLE_LOW_APP_ADJ)
} else if ((cr.flags & Context.BIND_NOT_PERCEPTIBLE) != 0
&& clientAdj <= ProcessList.PERCEPTIBLE_APP_ADJ
&& adj >= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
//则会设置成250(PERCEPTIBLE_LOW_APP_ADJ)
newAdj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
//如果设置了BIND_ALMOST_PERCEPTIBLE(接近是perceptible)
//而且客户端clientAdj小于200(优先级大于PERCEPTIBLE_APP_ADJ)
//而且当前进程adj大于等于225(优先级小于等于PERCEPTIBLE_MEDIUM_APP_ADJ 250)
//看逻辑貌似adj == 225的不需要将newAdj赋值成225(没用到),这里等于还有一个含义,就是进入此处的else,不进行别的else判断
} else if ((cr.flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0
&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
&& adj >= ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ) {
//newAdj设置成225(PERCEPTIBLE_MEDIUM_APP_ADJ)
newAdj = ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ;
//如果设置了BIND_NOT_VISIBLE(不要绑定成为visible 100进程)
//而且客户端clientAdj小于200(优先级大于PERCEPTIBLE_APP_ADJ)
//而且当前进程adj大于等于200(优先级小于等于PERCEPTIBLE_APP_ADJ)
} else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
&& adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
//newAdj设置成200(PERCEPTIBLE_APP_ADJ)
newAdj = ProcessList.PERCEPTIBLE_APP_ADJ;
//而且客户端clientAdj大于等于200(优先级小于等于PERCEPTIBLE_APP_ADJ)
} else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
//newAdj设置成客户端的优先级clientAdj
newAdj = clientAdj;
} else {
//假设你什么都没有设置,而且客户端clientAdj优先级大于200
//(那么客户端就是visible/fg/persistent/system的应用)
//如果应用进程adj优先级小于100(VISIBLE_APP_ADJ)
if (adj > ProcessList.VISIBLE_APP_ADJ) {
// TODO: Is this too limiting for apps bound from TOP?
//则新的adj由于依赖关系,最多设置成visiable级别(100),此处是[100, 200)
newAdj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
} else {
//如果应用进程adj优先级本来就很高,如adj小于等于100,则将当前进程adj赋值给newAdj,不做adj改变
newAdj = adj;
}
}
//只要是客户端不是cached process缓存进程
if (!cstate.isCached()) {
//那么服务端也会设置成非缓存进程
state.setCached(false);
}
//只要当前adj大于新的newAdj(新的adj优先级大于当前adj的优先级)
if (adj > newAdj) {
//将新的优先级newAdj,赋值给当前进程的adj
adj = newAdj;
//将adj保存在未经过约束的mCurRawAdj中,这里保存的是比较新的值
state.setCurRawAdj(adj);
if (DEBUG_OOM_ADJ_REASON) {
//打开DEBUG_OOM_ADJ_REASON会输出adj调整的日志,此处的nowActivityTime表示是否上一次start/bind到现在超过30分钟
boolean nowActivityTime = (now > (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY));
Slog.d(TAG, "newAdjservice: " + app + ", adj = " + adj + ", client = " + client + ", client.uid = " + client.uid
+", nowActivityTime = " + nowActivityTime + ", state.hasShownUi = " + state.hasShownUi()
+ ", clientProcState =" + clientProcState + ", cr = " + cr);
}
//将adj类型设置成服务
adjType = "service";
}
}
}
27.9.6 clientProcState依赖关系调整
//如果没有设置BIND_NOT_FOREGROUND(非前台绑定)和BIND_IMPORTANT_BACKGROUND(绑定重要后台)的时候
if ((cr.flags & (Context.BIND_NOT_FOREGROUND
| Context.BIND_IMPORTANT_BACKGROUND)) == 0) {
// This will treat important bound services identically to
// the top app, which may behave differently than generic
// foreground work.
//获取客户端cgroup设置的分组信息赋值给curSchedGroup
final int curSchedGroup = cstate.getCurrentSchedulingGroup();
//如果当前curSchedGroup(客户端分组优先级)大于schedGroup(当前进程分组优先级)
if (curSchedGroup > schedGroup) {
//如果设置了BIND_IMPORTANT(重要的绑定)
if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
//则将客户端的cgroup分组优先级设置给当前进程的分组信息
schedGroup = curSchedGroup;
} else {
//如果没有设置,则默认的分组先设置成defalut
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
//如果客户端进程状态小于top(2),也就是说客户端是常驻进程
if (clientProcState < PROCESS_STATE_TOP) {
// 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 bound state after that.
//如有拥有BIND_FOREGROUND_SERVICE(绑定前台服务,一般来自系统的绑定)
if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
//客户端的进程状态clientProcState设置成PROCESS_STATE_BOUND_FOREGROUND_SERVICE(5)(绑定了前台进程的服务)
//此处修改clientProcState不会直接修改客户端的进程状态,只是为了后面去修改服务端的进程状态使用
clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
//更新mAllowStartFgsState,最小设置成PROCESS_STATE_BOUND_FOREGROUND_SERVICE
//只要mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE则有前台服务启动的权限
state.bumpAllowStartFgsState(
PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
//其它情况,mWakefulness是唤醒状态
//而且包含BIND_FOREGROUND_SERVICE_WHILE_AWAKE(在唤醒时绑定前台服务)
} else if (mService.mWakefulness.get()
== PowerManagerInternal.WAKEFULNESS_AWAKE
&& (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
!= 0) {
//将clientProcState设置成PROCESS_STATE_BOUND_FOREGROUND_SERVICE(5)(绑定了前台进程的服务)
clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
} else {
//将clientProcState设置成PROCESS_STATE_IMPORTANT_FOREGROUND(6)(重要的前台,这个进程状态级别不能启动前台服务)
clientProcState =
PROCESS_STATE_IMPORTANT_FOREGROUND;
}
//如果clientProcState是PROCESS_STATE_TOP(2),当前顶端的Activity(非睡眠状态才会是这个级别)
} else if (clientProcState == PROCESS_STATE_TOP) {
// Go at most to BOUND_TOP, unless requested to elevate
// to client's state.
//后面用来调整当前进程的进程状态的clientProcState设置成PROCESS_STATE_BOUND_TOP(3)(绑定了前台进程)
clientProcState = PROCESS_STATE_BOUND_TOP;
//更新是否运行启动前台服务的进程状态信息mAllowStartFgsState,允许启动前台服务
state.bumpAllowStartFgsState(PROCESS_STATE_BOUND_TOP);
boolean enabled = false;
try {
//" enableAfterTargetSdk="29" id="136274596" name="PROCESS_CAPABILITY_CHANGE_ID",代表mEnableSinceTargetSdk=20
//具体配置是读取/system/etc/compatconfig/services-platform-compat-config.xml进行初始话,这个是在30(android R)之后支持
//isChangeEnabled其实最终调用的是CompatChange的isEnabled,目前只是用apk的targetSdkVersion进行判断,主要大于30就返回true
enabled = getPlatformCompatCache().isChangeEnabled(
PROCESS_CAPABILITY_CHANGE_ID, client.info);
} catch (RemoteException e) {
}
//如果sdk版本支持PROCESS_CAPABILITY_CHANGE_ID(30(android R)之后支持)
if (enabled) {
//如果包含BIND_INCLUDE_CAPABILITIES,则会将客户端的能力全部赋值给服务端
if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
// TOP process passes all capabilities to the service.
capability |= cstate.getCurCapability();
} else {
//否者不更改进程能力
// TOP process passes no capability to the service.
}
} else {
// TOP process passes all capabilities to the service.
//如果是旧版本sdk的apk,则将客户端的能力直接赋给服务端(也就是旧版本不约束)
capability |= cstate.getCurCapability();
}
}
//如果设置了BIND_NOT_FOREGROUND(非前台绑定),而且没有设置BIND_IMPORTANT_BACKGROUND(绑定重要后台)的时候
} else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
//客户端进程状态clientProcState如果优先级大于PROCESS_STATE_TRANSIENT_BACKGROUND(8)
if (clientProcState <
PROCESS_STATE_TRANSIENT_BACKGROUND) {
//将clientProcState设置成PROCESS_STATE_TRANSIENT_BACKGROUND(8)
clientProcState =
PROCESS_STATE_TRANSIENT_BACKGROUND;
}
} else {
//如果设置了BIND_IMPORTANT_BACKGROUND(绑定重要后台)的时候
//客户端进程状态小于PROCESS_STATE_IMPORTANT_BACKGROUND(7),也就是起码是IMPORTANT_FOREGROUND(6)
if (clientProcState <
PROCESS_STATE_IMPORTANT_BACKGROUND) {
//将clientProcState设置成PROCESS_STATE_IMPORTANT_BACKGROUND(7)
clientProcState =
PROCESS_STATE_IMPORTANT_BACKGROUND;
}
}
//如果cgroup分组小于top(default/resticted/background)
//而且flag包含了BIND_SCHEDULE_LIKE_TOP_APP(分组就像是top一样),如IMEs输入法在有界面的情况下
//而且客户端是系统或者常驻进程clientIsSystem=true
if (schedGroup < ProcessList.SCHED_GROUP_TOP_APP
&& (cr.flags & Context.BIND_SCHEDULE_LIKE_TOP_APP) != 0
&& clientIsSystem) {
//将分组信息设置成top app
schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
//标记这种app为scheduleLikeTopApp=true
scheduleLikeTopApp = true;
}
//如果之前没有设置过trackedProcState=true(目前只有persistent service才有设置)
if (!trackedProcState) {
//则将关联关系记录的信息保存在AssociationState.SourceState中,主要是进程状态,当前调整的序列号和调整时间
cr.trackProcState(clientProcState, mAdjSeq, now);
}
//如果当前进程状态procState大于clientProcState(就是没有(准备根据客户端调整的进程状态)clientProcState优先级高)
if (procState > clientProcState) {
//更新当前进程的进程状态procState
procState = clientProcState;
//将procState赋值给mCurRawProcState(临时计算值)
state.setCurRawProcState(procState);
//如果adj类型为空,则赋值adj类型为服务
if (adjType == null) {
adjType = "service";
}
}
//如果进程状态procState小于PROCESS_STATE_IMPORTANT_BACKGROUND(7),
//而且带有BIND_SHOWING_UI的标签
if (procState < PROCESS_STATE_IMPORTANT_BACKGROUND
&& (cr.flags & Context.BIND_SHOWING_UI) != 0) {
//而且带有BIND_SHOWING_UI的标签,则设置ProcessProfileRecord的mPendingUiClean为true
//mPendingUiClean会在更新内存等级的时候会使用,用户触发thread.scheduleTrimMemory进行应用不同级别的内存回收
app.setPendingUiClean(true);
}
27.9.7 service依赖关系原因的输出
//如果adjType不等与null,则把设置客户端setAdjSource和当前进程setAdjTarget
//如果看到只有"service"没有连接对象,其中一种情况:可能是刚进入computeOomAdjLSP调整清空了之前的对象
if (adjType != null) {
//设置adj类型
state.setAdjType(adjType);
//设置adj类型的代码mAdjTypeCode,和importanceReasonCode类似,就是优先级的原因,此处是service正在使用中
//客户端的进程在importanceReasonPid(getAdjSource),服务端的进程在importanceReasonComponent(getAdjTarget)
state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE);
//cr.binding.client(AppBindRecord)这里是ProcessRecord,setAdjSource设置此次调整的来源:客户端ProcessRecord
state.setAdjSource(cr.binding.client);
//setAdjSourceProcState设置此次调整的进程状态来源:客户端约束后的clientProcState(不高于改值)
state.setAdjSourceProcState(clientProcState);
//setAdjTarget设置调整的原因的服务组件是instanceName(服务组件的实例)
state.setAdjTarget(s.instanceName);
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
+ ": " + app + ", due to " + cr.binding.client
+ " adj=" + adj + " procState="
+ ProcessList.makeProcStateString(procState)+ ", client=" + client
+ ", cr=" + cr);
}
}
27.10 BIND_WAIVE_PRIORITY == true豁免优先级调整
} else {
// 如果设置了BIND_WAIVE_PRIORITY == true,一般没有跑,此处会豁免adj优先级的调整
// BIND_WAIVE_PRIORITY bindings are special when it comes to the
// freezer. Processes bound via WPRI are expected to be running,
// but they are not promoted in the LRU list to keep them out of
// cached. As a result, they can freeze based on oom_adj alone.
// Normally, bindToDeath would fire when a cached app would die
// in the background, but nothing will fire when a running process
// pings a frozen process. Accordingly, any cached app that is
// bound by an unfrozen app via a WPRI binding has to remain
// unfrozen.
//如果客户端是非cached进程,则当前的服务进程不能被冻结
if (clientAdj < ProcessList.CACHED_APP_MIN_ADJ) {
app.mOptRecord.setShouldNotFreeze(true);
}
}
27.11 绑定客户端对象是activity的调整
//链接记录对象cr是ConnectionRecord cr = clist.get(i);如果该链接设置了BIND_TREAT_LIKE_ACTIVITY
if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
//服务端psr则设置setTreatLikeActivity的标记位,需要像对待activity一样对待该服务进程
psr.setTreatLikeActivity(true);
}
//获取绑定客户端对象的activity(只有客户端是activity的时候才有这个对象)
final ActivityServiceConnectionsHolder a = cr.activity;
//如果ConnectionRecord设置了BIND_ADJUST_WITH_ACTIVITY:可以根据客户端activity是否可见来调整优先级
if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
//如果客户端activity不为null,而且当前服务adj大于0(FOREGROUND_APP_ADJ),
//而且客户端activity是可见的
if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ
&& a.isActivityVisible()) {
//则直接设置服务端adj为0(FOREGROUND_APP_ADJ)
adj = ProcessList.FOREGROUND_APP_ADJ;
//将adj保存在未经过约束的mCurRawAdj中
state.setCurRawAdj(adj);
//如果标签不包含BIND_NOT_FOREGROUND(非前台绑定,不允许上升到前台分组)
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
//包含重要绑定BIND_IMPORTANT(对客户端来说非常重要,需要提升到前台)
if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
//则分组cgroup直接设置成top app
schedGroup = ProcessList.SCHED_GROUP_TOP_APP_BOUND;
} else {
//否则分组cgroup设置成默认
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
//设置成非cached进程
state.setCached(false);
//adj类型为服务"service"
state.setAdjType("service");
//设置adj类型的代码mAdjTypeCode(和importanceReasonCode类似,就是优先级的原因)为service正在使用中
state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE);
//setAdjSource设置此次调整的来源:客户端ActivityServiceConnectionsHolder
state.setAdjSource(a);
//setAdjSourceProcState设置此次调整的进程状态来源:procState(这里已经是调整后的进程状态值)
state.setAdjSourceProcState(procState);
//setAdjTarget设置调整的原因的服务组件是instanceName(服务组件的实例)
state.setAdjTarget(s.instanceName);
//如果打开DEBUG_OOM_ADJ_REASON、或者设置了logUid,则会打印日志
//logUid可以通过直接介绍的adb shell am watch-uids --oom + ***来设置
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
//adj调整的原因是activity
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise to service w/activity: " + app);
}
}
}
}
}
}
到这里就结束了服务依赖调整:当前是服务进程,由于客户端进程的adj和进程状态,进行服务进程的adj和进程状态调整
28. provider依赖关系调整
provider依赖关系调整:当前是provider内容提供者进程,由于客户端进程的adj和进程状态,进行provider进程的adj和进程状态调整
28.1 只有当前是provider内容提供者进程才调整
//接下去就是当前进程的mProviders(provider对象保存信息)的调整,这里逻辑相对少一点
final ProcessProviderRecord ppr = app.mProviders;
//一样是倒叙遍历每一个ContentProviderRecord(单个provider连接信息)
//如果adj大于0(非前台进程)或者分组cgroup是后台(0)或者进程状态小于PROCESS_STATE_TOP(2)满足一个才会进来
for (int provi = ppr.numberOfProviders() - 1;
provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
provi--) {
//取出每个保存provider连接信息的ContentProviderRecord对象
//每个包含ActivityManagerService _service(AMS对象)
//ProviderInfo _info(通过PMS的resolveContentProvider获得,provider的info信息)
//ApplicationInfo ai(provider(内容提供者)的Application的信息)
//ComponentName _name(ProviderInfo构建的组件名字)
//boolean _singleton(provider是否singleton单例模式)
ContentProviderRecord cpr = ppr.getProviderAt(provi);
//每一次provider访问调用incProviderCountLocked的时候,
//都会将ContentProviderConnection add到connections里去(cpr.connections.add(conn))
//这里还是和上面一样adj大于0(非前台进程)或者分组cgroup是后台(0)或者进程状态小于PROCESS_STATE_TOP(2)有一个满足才会进来
for (int i = cpr.connections.size() - 1;
i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
i--) {
//获取ContentProviderConnection,其在ContentProviderHelper创建的时候的变量有
//provider当前provider的ContentProviderRecord
//client客户端调用者的ProcessRecord
//clientPackage调用者的包名(getContentProvider传入的callingPackage)
//mExpectedUserId(默认是调用者的UserId;如果uir的auth有制定uid则用auth的(getUserIdFromAuthority))
//createTime创建new ContentProviderConnection的时间
ContentProviderConnection conn = cpr.connections.get(i);
//client客户端调用者的ProcessRecord
ProcessRecord client = conn.client;
//cstate是客户端进程状态记录信息ProcessStateRecord
final ProcessStateRecord cstate = client.mState;
//如果客户端(查询者)就是当前app,则直接返回。我们只关注提供内容的provider端(内容提供者)
if (client == app) {
// Being our own client is not interesting.
continue;
}
28.2 循环计算computeClients和判断是否需要跳过本次计算shouldSkipDueToCycle
//computeClients是否需要计算当前进程的时候计算服务、provider提供者对端client的adj。和上面服务端计算依赖关系是一样的
if (computeClients) {
//调整之前先计算client的adj,将client按照当前传递计算app的重新计算一次,此处就有可能循环计算,mAdjSeq目前都是一个
computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true);
} else {
//如果不需要计算客户端的优先级,那么setCurRawAdj先将客户端当前调整的mCurAdj更新到mCurRawAdj中
//mCurAdj当前调整的adj值,进过约束的(如mHasAboveClient进行约束,client app进程优先级会相应降低)
//mCurRawAdj当前调整的adj值,但是未经过约束
//mSetRawAdj上一次applyOomAdjLSP后设置的mCurRawAdj值
//mSetAdj上一次applyOomAdjLSP后设置的mCurAdj值
cstate.setCurRawAdj(cstate.getCurAdj());
//mCurProcState是跑完一次computeOomAdjLSP的出的进程状态结果
//而mCurRawProcState是当前的进程状态,是在计算中的临时结果
//setCurRawProcState将上一次计算的进程状态mCurProcState赋值给mCurRawProcState(临时计算值)
cstate.setCurRawProcState(cstate.getCurProcState());
}
//判断是是否客户端adj没有计算完成,是否需要跳过本次依赖关系的计算,具体请看shouldSkipDueToCycle的解释
if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
continue;
}
28.3 调整前客户端的clientAdj、clientProcState的记录
//取得客户端的mCurRawAdj当前调整的adj值(未经过约束)
int clientAdj = cstate.getCurRawAdj();
//取得客户端的临时计算的最新进程状态值mCurRawProcState
int clientProcState = cstate.getCurRawProcState();
//客户端的进程状态优先级低于cached activity
if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty.
//客户端的进程状态优先级低于全部归类为cached empty的进程
clientProcState = PROCESS_STATE_CACHED_EMPTY;
}
//如果客户端mShouldNotFreeze是true,则服务端也被设置不允许冻结。
//(原生冻结有2个条件,一个是adj大于等于900,而且mShouldNotFreeze=false)
if (client.mOptRecord.shouldNotFreeze()) {
// Propagate the shouldNotFreeze flag down the bindings.
app.mOptRecord.setShouldNotFreeze(true);
}
28.4 clientAdj大于provider的adj才进行adj依赖关系调整
//新建adjType(adj类型),初始值是null
String adjType = null;
//如果客户端的clientAdj小于provider的adj
//开始针对provider端的进程优先级adj进行依赖调整(主要依据是客户端clientAdj的情况)
if (adj > clientAdj) {
//如果该进程有界面的,而且不是桌面,而且客户端clientAdj大于200,这类不调整adj大小,只设置adj类型
if (state.hasShownUi() && !state.getCachedIsHomeProcess()
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
//则将adj类型设置成"cch-ui-provider"(缓存的带有ui的provider)
adjType = "cch-ui-provider";
} else {
//其它情况,如当前进程没有带界面的、桌面、或者客户端clientAdj小于等于200(PERCEPTIBLE_APP_ADJ用户可感知级别)
//clientAdj如果是大于0(FOREGROUND_APP_ADJ前台adj),则直接将clientAdj赋值给provider端
//clientAdj如果是小于等于0,则provider端的adj都会设置成0(FOREGROUND_APP_ADJ)
//provider由于依赖关系最高优先级调整到0
adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
//将adj更新到mCurRawAdj中(mCurRawAdj一般是调整过程中最新的adj值)
state.setCurRawAdj(adj);
//则将adj类型设置成"provider"
adjType = "provider";
}
//只有客户端和provider都是cached的时候才设置当前进程为mCached = true,其它情况都是mCached = false
state.setCached(state.isCached() & cstate.isCached());
}
28.5 clientProcState进程状态依赖调整
//开始针对provider端的进程状态procState进行依赖调整(主要依据是客户端clientProcState的情况)
//只有进程状态clientProcState小于等于PROCESS_STATE_FOREGROUND_SERVICE(4)的时候才进来
if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) {
//只有adj类型是空的时候才进行设置
if (adjType == null) {
//只有adj类型设置成"provider"
adjType = "provider";
}
//客户端的进程状态clientProcState如果是top app(2)
if (clientProcState == PROCESS_STATE_TOP) {
//重新约束clientProcState到PROCESS_STATE_BOUND_TOP(3)
clientProcState = PROCESS_STATE_BOUND_TOP;
} else {
//重新约束clientProcState到PROCESS_STATE_BOUND_FOREGROUND_SERVICE(5),这个状态刚好是可以启动前台服务的状态
clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
}
}
//调整之前,先保存关联关系记录的信息在AssociationState.SourceState中
//主要是进程状态,当前调整的序列号和调整时间
conn.trackProcState(clientProcState, mAdjSeq, now);
//只有当前进程的进程状态procState大于约束后的客户端clientProcState的进程状态时
if (procState > clientProcState) {
//才将约束后的客户端clientProcState赋值给当前进程的进程状态procState
procState = clientProcState;
//setCurRawProcState将procState赋值给mCurRawProcState(最新的计算值,可能不是最终的值)
state.setCurRawProcState(procState);
}
28.6 客户端分组依赖关系调整
//如果客户端的分组大于当前进程的schedGroup(computeOomAdjLSP默认初始化之后最低是SCHED_GROUP_BACKGROUND(1))
//也就是客户端分组起码是SCHED_GROUP_DEFAULT(2)
if (cstate.getCurrentSchedulingGroup() > schedGroup) {
//设置当前分组schedGroup为SCHED_GROUP_DEFAULT
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
28.7 输出provider调整的原因
//如果adj类型不为空,那么代表根据客户端,当前进程调整过adj或者进程状态procState
if (adjType != null) {
//设置adj类型
state.setAdjType(adjType);
//设置adj类型的代码mAdjTypeCode(和importanceReasonCode类似,就是优先级的原因)为provider正在使用中
state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
.REASON_PROVIDER_IN_USE);
//setAdjSource设置此次调整的来源:客户端ProcessRecord
state.setAdjSource(client);
//setAdjSourceProcState设置此次调整的进程状态来源:客户端约束后的clientProcState(不高于改值)
state.setAdjSourceProcState(clientProcState);
//setAdjTarget设置调整的原因的provider组件是ComponentName name(ProviderInfo构建的组件名字)
state.setAdjTarget(cpr.name);
//打印日志由于什么原因去调整该进程的adj或者进程状态
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
+ ": " + app + ", due to " + client
+ " adj=" + adj + " procState="
+ ProcessList.makeProcStateString(procState)
+ ", target=" + cpr.name );
}
}
}
28.8 hasExternalProcessHandles的调整
// If the provider has external (non-framework) process
// dependencies, ensure that its adjustment is at least
// FOREGROUND_APP_ADJ.
//cpr.hasExternalProcessHandles为true时,adj类型是"ext-provider"
//通过调用getContentProviderExternalUnchecked/getContentProviderExternal来设置hasExternalProcessHandles
//具体流程getContentProviderExternal->getContentProviderExternalUnchecked->getContentProviderImpl(caller == null)
//->incProviderCountLocked(r == null)->addExternalProcessHandleLocked->externalProcessTokenToHandle
if (cpr.hasExternalProcessHandles()) {
//如果当前adj大于0前台,则设置成0
if (adj > ProcessList.FOREGROUND_APP_ADJ) {
//adj设置成0(FOREGROUND_APP_ADJ),这种优先级比较高
//一般用在cmd、uiautomator
adj = ProcessList.FOREGROUND_APP_ADJ;
//更新adj到mCurRawAdj中
state.setCurRawAdj(adj);
//分组设置成默认
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
//非cached进程
state.setCached(false);
//adj类型是"ext-provider"
state.setAdjType("ext-provider");
//setAdjTarget设置调整的原因的provider组件是ComponentName name(ProviderInfo构建的组件名字)
state.setAdjTarget(cpr.name);
//打印日志,调整adj的原因是由于external provider
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise adj to external provider: " + app);
}
}
//如果当前进程状态procState大于PROCESS_STATE_IMPORTANT_FOREGROUND(6)
if (procState > PROCESS_STATE_IMPORTANT_FOREGROUND) {
//则将进程状态procState设置成PROCESS_STATE_IMPORTANT_FOREGROUND(这个级别不能启动前台服务)
procState = PROCESS_STATE_IMPORTANT_FOREGROUND;
//更新进程状态procState到mCurRawProcState
state.setCurRawProcState(procState);
//打印日志,调整进程状态procState的原因是由于external provider
//(这里adj和进程状态的调整都有输出日志,看起来比上面的adjType会更清晰一点,
//如果需要修改类似日志,建议参考这里adj和procState单独输出)
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise procstate to external provider: " + app);
}
}
}
}
29. recent-provider最近使用的provider调整
//getLastProviderTime(mLastProviderTime)在removeContentProvider/decProviderCountLocked/handleProviderRemoval
//当客户端释放provider而且客户端进程状态比PROCESS_STATE_LAST_ACTIVITY(15)小,则会设置mLastProviderTime
//大概意思是provider上一次使用的时间,设置了这个时间的话provider会延迟一小会释放,
//一般只在比last activity重要的进程状态(客户端的)时设置
//CONTENT_PROVIDER_RETAIN_TIME是20s,上一次使用在20s以内会进来这里,避免低内存状态下频繁启动回收provider进程
if (ppr.getLastProviderTime() > 0
&& (ppr.getLastProviderTime() + mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) {
//如果adj大于700(PREVIOUS_APP_ADJ上一个应用)
if (adj > ProcessList.PREVIOUS_APP_ADJ) {
//则将adj设置成700(就是dumpsys meminfo里面的Previous应用)
adj = ProcessList.PREVIOUS_APP_ADJ;
//设置分组为后台,这里是后台,不是前台和default
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
//非cached进程
state.setCached(false);
//adj类型是"recent-provider"最近使用的provider
state.setAdjType("recent-provider");
//输出调整adj的原因
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise adj to recent provider: " + app);
}
}
//进程状态procState如果大于PROCESS_STATE_LAST_ACTIVITY(15)
if (procState > PROCESS_STATE_LAST_ACTIVITY) {
//则将procState设置成PROCESS_STATE_LAST_ACTIVITY(15)
procState = PROCESS_STATE_LAST_ACTIVITY;
//将adj类型设置成"recent-provider",注意只要有adj或者procState的提升都会重新设置adj类型为"recent-provider"
state.setAdjType("recent-provider");
//输出调整procstate的原因
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise procstate to recent provider: " + app);
}
}
}
30. 服务相关缓存进程CACHED的调整
//如果进程状态procState大于等于PROCESS_STATE_CACHED_EMPTY(19,这个优先级比较低)
if (procState >= PROCESS_STATE_CACHED_EMPTY) {
//看一下客户端是否有activity
if (psr.hasClientActivities()) {
// This is a cached process, but with client activities. Mark it so.
//看一下客户端是否有activity,如果有,则稍微提升一下进程状态的级别到PROCESS_STATE_CACHED_ACTIVITY_CLIENT(17)
procState = PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
//设置adj类型是"cch-client-act"
state.setAdjType("cch-client-act");
//服务端psr是ProcessServiceRecord进程的服务信息记录对象app.mServices
//如果设置了mTreatLikeActivity为true(setTreatLikeActivity设置),则就像对待activity一样对待这个进程
//adj类型设置成"cch-as-act"(as "cch-act")
} else if (psr.isTreatedLikeActivity()) {
// This is a cached process, but somebody wants us to treat it like it has
// an activity, okay!
//也是稍微提升一下进程状态的级别到PROCESS_STATE_CACHED_ACTIVITY(16)
//注意这里的优先级(值越低优先级越高)比上面17还高,但是是放在else里面,貌似不太合理,一般都是优先级高的在前面,
//不然如果同时满足hasClientActivities和isTreatedLikeActivity,那么就只能设置成17,而不是16
procState = PROCESS_STATE_CACHED_ACTIVITY;
//adj类型设置成"cch-as-act"(
state.setAdjType("cch-as-act");
}
}
31. A、B service分布调整
//如果adj是SERVICE_ADJ(500),具体可以看上面adj = ProcessList.SERVICE_ADJ;的逻辑
//只有上一次lastActivity服务启动或者bind时间是30分钟以内的才会设置成SERVICE_ADJ级别
//这段逻辑一直都没有变化,那么为啥Android O以前的版本那么多A、B services扎堆?现在S不见了
//其实不是这段逻辑有变化,而是google限制了后台进程启动服务的权限,没有启动服务的权限,那么服务就少了
//google针对后台乱象随着OS的升级逐渐砍,不够道高一尺魔高一丈,还是有很多办法绕过去的不是吗?
if (adj == ProcessList.SERVICE_ADJ) {
//在doingAll为true,而且cycleReEval循环计算为false,代表需要更新A/B services
//目前满足这个条件的只有updateOomAdjInnerLSP中fullUpdate为true的时候进来时
if (doingAll && !cycleReEval) {
//如果mNewNumAServiceProcs(A services的个数,一会下面会设置)个数大于mNumServiceProcs(上一次fullUpdate后总的服务个数)/3
//则将mServiceB设置为true,代表这个是b services
//也就是1/3的服务会被设置成B services
//从这里也可以看到其实服务的优先级还跟mLruProcesses中进程的位置index有关系,这个后面另外的文章来写吧
state.setServiceB(mNewNumAServiceProcs > (mNumServiceProcs / 3);
//mNewNumServiceProcs(fullUpdate更新所有进程中service的个数,调整完成后,会更新到mNumServiceProcs中)
mNewNumServiceProcs++;
//如果排在1/3之前的服务,也就是可能会调整成A services的进程
if (!state.isServiceB()) {
// This service isn't far enough down on the LRU list to
// normally be a B service, but if we are low on RAM and it
// is large we want to force it down since we would prefer to
// keep launcher over it.
//isLastMemoryLevelNormal获取是内存压力级别,目前用的是psi,psi不太准确,下次有时间讲到AppProfiler时再来讲
//mLastMemoryLevel只要不是(ADJ_MEM_FACTOR_NOTHING刚初始化,还没内存压力时;或者ADJ_MEM_FACTOR_NORMAL内存压力正常)
//则isLastMemoryLevelNormal返回false,代表此时有内存压力
//getLastPss获取的是AppProfiler中recordPssSampleLPf->setLastPss设置进去的mLastPss,
//android本身有一个pss收集的进程在,
//getCachedRestoreThresholdKb,如果是32bit是184320/3 = 60M, 64bit是322560/3=105M,具体逻辑在ProcessList.java中
//也就是进程的mLastPss大于60M(32bit)/105M(64bit),
//而且是有内存压力的时候会将这类服务标记成高内存用量,而且回落到B services
/*
//ProcessList.java
private final int[] mOomMinFreeLow = new int[] {
12288, 18432, 24576,
36864, 43008, 49152
};
private final int[] mOomMinFreeHigh = new int[] {
73728, 92160, 110592,
129024, 147456, 184320
};
for (int i = 0; i < mOomAdj.length; i++) {
int low = mOomMinFreeLow[i];//12288, 18432, 24576, 36864, 43008, 49152
int high = mOomMinFreeHigh[i];//73728, 92160, 110592,129024, 147456, 184320
if (is64bit) {
// Increase the high min-free levels for cached processes for 64-bit
if (i == 4) high = (high * 3) / 2;//221184
else if (i == 5) high = (high * 7) / 4;//322560
}
mOomMinFree[i] = (int)(low + ((high - low) * scale));//high,目前S上由于RAM大于1G,scale都是1
}
*/
//mLastPss值的更新,一般在亮灭屏: 如果是内存状态有变小,是5分钟更新,没有变小是20分钟更新
//其它场景如开机、更新全部的procStats(3个小时以上)时也会触发mLastPss的更新
if (!mService.mAppProfiler.isLastMemoryLevelNormal()
&& app.mProfile.getLastPss()
>= mProcessList.getCachedRestoreThresholdKb()) {
//设置该服务为高内存用量的服务,mServiceHighRam=true,isServiceHighRam提供给外部用,
//不够目前S都没有用到,Android这里也有另一个缺陷(高内存用量的进程没有单独划分出来),
//这个功能其实挺好的,不过竟然没有大批量用起来!
state.setServiceHighRam(true);
//回落到B service级别
state.setServiceB(true);
//这个注释其实没有必要注掉,可以用DEBUG_PSS、DEBUG_OOM_ADJ_REASON都是可以的
//Slog.i(TAG, "ADJ " + app + " high ram!");
} else {
//回落到B service级别
mNewNumAServiceProcs++;
//Slog.i(TAG, "ADJ " + app + " not high ram!");
}
} else {
//其它情况下(b services)都认为不是高内存的服务(这个逻辑不敢恭维,牛头不对马尾)
state.setServiceHighRam(false);
}
}
//如果是b services的话
if (state.isServiceB()) {
//则将adj设置成SERVICE_B_ADJ(800)
adj = ProcessList.SERVICE_B_ADJ;
}
}
32. 更新最新的adj到mCurRawAdj中
//更新最新的adj到mCurRawAdj中
state.setCurRawAdj(adj);
33. 如果还有未处理完的getMaxAdj进程的调整
//如果当前adj大于setMaxAdj中设置的值(除了测试用例才会进来,Android S这段代码专门为测试用例留的?)
//注意了这里是没有调用setCurRawAdj更新mCurRawAdj,故进入这里的话mCurRawAdj可能不是最新调整的状态,看起来属于一个漏洞?
if (adj > state.getMaxAdj()) {
//adj则更新成setMaxAdj中设置的值
adj = state.getMaxAdj();
//如果adj小于等于250(PERCEPTIBLE_LOW_APP_ADJ用户可感知的最低级别)
if (adj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
//则分组cgroup更新成默认分组
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
34. 非唤醒状态时受限制分组SCHED_GROUP_RESTRICTED调整
// Put bound foreground services in a special sched group for additional
// restrictions on screen off
//如果进程状态procState大于等于PROCESS_STATE_BOUND_FOREGROUND_SERVICE(5)
//而且在灭屏状态,而且scheduleLikeTopApp(设定像对待前台一样对待该app,类似IMEs有界面时)是false
if (procState >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
&& mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
&& !scheduleLikeTopApp) {
//分组cgroup状态大于SCHED_GROUP_RESTRICTED(1),那就是default、top的时候
if (schedGroup > ProcessList.SCHED_GROUP_RESTRICTED) {
//设置他们的分组状态都是SCHED_GROUP_RESTRICTED受限制分组
schedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
}
}
35. 更新进程的能力capability
// apply capability from FGS.
//如果有前台服务(ContextImpl启动前台服务或者service启动时设置服务是前台的)
if (psr.hasForegroundServices()) {
//则将当前进程的能力capability设置成前台服务的能力capabilityFromFGS(具体请查看之前的介绍)
capability |= capabilityFromFGS;
}
//通过进程的服务记录psr和进程状态procState得到默认的能力
capability |= getDefaultCapability(psr, procState);
36. 更新最新的状态到ProcessStateRecord,完成本次adj调整
// Do final modification to adj. Everything we do between here and applying
// the final setAdj must be done in this function, because we will also use
// it when computing the final cached adj later. Note that we don't need to
// worry about this for max adj above, since max adj will always be used to
// keep it out of the cached vaues.
//本次adj调整即将完成,将计算的adj复制给mCurAdj
state.setCurAdj(psr.modifyRawOomAdj(adj));
//本次adj调整即将完成,将计算的能力capability复制给mCurCapability
state.setCurCapability(capability);
//本次adj调整即将完成,将计算的分组信息schedGroup复制给mCurSchedGroup
state.setCurrentSchedulingGroup(schedGroup);
//本次adj调整即将完成,将计算的进程状态procState复制给mCurProcState
state.setCurProcState(procState);
//本次adj调整即将完成,将计算的进程状态procState复制给mCurRawProcState
state.setCurRawProcState(procState);
//通过hasVisibleActivities更新mLastInvisibleTime,如果mHasVisibleActivities从true变成false,
//则记录这个时候的时间,相当于当进程从可见到不可见的时间
//主要用在是否允许启动前台服务里面,这个时间目前是mFgToBgFgsGraceDuration(5秒钟以内还是允许的)
state.updateLastInvisibleTime(hasVisibleActivities);
//更新mHasForegroundActivities是否拥有前台activity
state.setHasForegroundActivities(foregroundActivities);
//设置mCompletedAdjSeq(当前进程完成adj调整的系列号) = mAdjSeq(当前调整的adj系列号)
state.setCompletedAdjSeq(mAdjSeq);
37. 本次adj调整的返回值
// 如果当前的adj(mCurAdj)有相对于之前优先级有提升
// 或者当前的进程状态mCurProcState有相对于之前优先级有提升
// 或者当前进程的能力mCurCapability有相对于之前有改变
// 则返回true,否则返回false
// if curAdj or curProcState improved, then this process was promoted
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
|| state.getCurCapability() != prevCapability;
}
38. 其它相关代码
38.1 获取默认的进程能力
//通过进程的服务记录psr和进程状态procState得到默认的能力
private int getDefaultCapability(ProcessServiceRecord psr, int procState) {
switch (procState) {
case PROCESS_STATE_PERSISTENT:
case PROCESS_STATE_PERSISTENT_UI:
case PROCESS_STATE_TOP:
//如果是top app或者是常驻进程的进程会有所有的能力
//包括定位、camera、电话、听筒的能力
/*
public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION
| PROCESS_CAPABILITY_FOREGROUND_CAMERA
| PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
| PROCESS_CAPABILITY_NETWORK;
*/
return PROCESS_CAPABILITY_ALL;
case PROCESS_STATE_BOUND_TOP:
//如果当前进程是service、provider,被前台(client)绑定的话,则当前进程拥有网络能力
return PROCESS_CAPABILITY_NETWORK;
case PROCESS_STATE_FOREGROUND_SERVICE:
//当前进程的进程状态是PROCESS_STATE_FOREGROUND_SERVICE(4)前台服务级别(instrumentation/hasForegroundServices)
//如果带有是前台服务(hasForegroundServices == true)
if (psr.hasForegroundServices()) {
// Capability from FGS are conditional depending on foreground service type in
// manifest file and the mAllowWhileInUsePermissionInFgs flag.
// 则拥有网络能力
return PROCESS_CAPABILITY_NETWORK;
} else {
//其它情况,如instrumentation
//还有service、provider依赖关系貌似不会直接设置PROCESS_STATE_FOREGROUND_SERVICE
//拥有camera、听筒、网络能力
/*
public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = PROCESS_CAPABILITY_FOREGROUND_CAMERA
| PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
*/
// process has no FGS, the PROCESS_STATE_FOREGROUND_SERVICE is from client.
// the implicit capability could be removed in the future, client should use
// BIND_INCLUDE_CAPABILITY flag.
return PROCESS_CAPABILITY_ALL_IMPLICIT | PROCESS_CAPABILITY_NETWORK;
}
case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
//当前进程的进程状态是PROCESS_STATE_BOUND_FOREGROUND_SERVICE(5)绑定前台服务
//则拥有网络能力
return PROCESS_CAPABILITY_NETWORK;
default:
//其它情况不赋予相关能力
return PROCESS_CAPABILITY_NONE;
}
}
38.1 shouldSkipDueToCycle是否需要在计算依赖关系时跳过计算
//app: 当前需要调整的进程
//client: 客户端的进程状态记录
//procState: 当前进程的进程状态
//adj: 当前进程的adj值
//cycleReEval: 是否处于循环计算模式,只有在updateOomAdjInnerLSP会让cycleReEval=true
//(条件是设置了setContainsCycle true,如正在计算computeOomAdjLSP的时候还没计算完又跑进来)
private boolean shouldSkipDueToCycle(ProcessRecord app, ProcessStateRecord client,
int procState, int adj, boolean cycleReEval) {
//如果客户端设置了setContainsCycle = true,也即是客户端未调整完毕又进入了computeOomAdjLSP
if (client.containsCycle()) {
// We've detected a cycle. We should retry computeOomAdjLSP later in
// case a later-checked connection from a client would raise its
// priority legitimately.
//这里计算依赖关系的时候,将当前的进程app,设置成包括循环,需要在后面重新计算
app.mState.setContainsCycle(true);
//同时将该进程放入循环计算的list里面mProcessesInCycle,后面如果需要重新计算该进程adj的时候会从此处取回
mProcessesInCycle.add(app);
// If the client has not been completely evaluated, check if it's worth
// using the partial values.
//客户端已经完成的adj调整序列号mCompletedAdjSeq,小于mAdjSeq,代表是之前的调整,本次还未更新
if (client.getCompletedAdjSeq() < mAdjSeq) {
//如果是循环计算进来此处
if (cycleReEval) {
// If the partial values are no better, skip until the next
// attempt
//如果客户端的进程状态大于当前app进程的进程状态
//而且客户端的mCurRawAdj(当前调整的未约束过的adj),大于当前进程的adj
//代表客户端的优先级比较低,需要等客户端计算完成再来,所以本次依赖关系计算先跳过
if (client.getCurRawProcState() >= procState
&& client.getCurRawAdj() >= adj) {
return true;
}
// Else use the client's partial procstate and adj to adjust the
// effect of the binding
} else {
//如果是非循环计算进来此处,由于客户端还没有计算完成,那就等客户端计算完成,先跳过
return true;
}
}
}
return false;
}