Android adj调整 --- computeOomAdjLSP流程详解

2024-02-11 16:59

本文主要是介绍Android adj调整 --- computeOomAdjLSP流程详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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.9.1 循环计算的时候是否需要先跳过本次计算
        • 27.9.2 能力capability初始化
        • 27.9.3 低于cached activity的进程状态clientProcState约束
        • 27.9.4 如果进程设置了在低内存时托管给系统
        • 27.9.5 如果clientAdj大于当前服务的adj,则开始adj依赖关系调整
        • 27.9.6 clientProcState依赖关系调整
        • 27.9.7 service依赖关系原因的输出
      • 27.10 BIND_WAIVE_PRIORITY == true豁免优先级调整
      • 27.11 绑定客户端对象是activity的调整
    • 28. provider依赖关系调整
      • 28.1 只有当前是provider内容提供者进程才调整
      • 28.2 循环计算computeClients和判断是否需要跳过本次计算shouldSkipDueToCycle
      • 28.3 调整前客户端的clientAdj、clientProcState的记录
      • 28.4 clientAdj大于provider的adj才进行adj依赖关系调整
      • 28.5 clientProcState进程状态依赖调整
      • 28.6 客户端分组依赖关系调整
      • 28.7 输出provider调整的原因
      • 28.8 hasExternalProcessHandles的调整
    • 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. 其它相关代码
      • 38.1 获取默认的进程能力
      • 38.1 shouldSkipDueToCycle是否需要在计算依赖关系时跳过计算

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为truestate.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_EMPTYstate.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.javaint 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) != 0public 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的uidfinal 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保存成prevProcStateint prevProcState = state.getCurProcState();//将之前的能力mCurCapability保存成prevCapabilityint 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系列为setAdjSeqstate.setAdjSeq(mAdjSeq);//设置指定的mCurRawAdj(未被约束过的adj)为当前最大的adjstate.setCurRawAdj(state.getMaxAdj());//暂时初始化,先标定没有前台activitystate.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);//如果调整的是当前应用是最顶端的activityif (app == topApp) {//设置这类应用是带有界面的state.setSystemNoUi(false);//cgroup分组标记成top app(用户后面分组切换到类似*** cgroup的分组,cpuset的分组如:/dev/cpuset/top-app)state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);//adj类型标记成pers-top-activitystate.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 appstate.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 adjstate.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(有效调整),其它则返回falsereturn 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)默认设定为falseboolean foregroundActivities = false;//hasVisibleActivities(是否有可见的activity)默认设定为falseboolean hasVisibleActivities = false;

9. top顶端app的调整

//如果当前是唤醒状态(如亮屏),而且本次调整的进程是topApp(顶端的activity)

        //当前是唤醒状态(如亮屏),PROCESS_STATE_CUR_TOP才会是PROCESS_STATE_TOPif (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 appschedGroup = ProcessList.SCHED_GROUP_TOP_APP;//进程状态是"top-activity"state.setAdjType("top-activity");//拥有前台活动对象foregroundActivities = true;//拥有可见的activityhasVisibleActivities = true;//当前进程状态是PROCESS_STATE_TOPprocState = 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 appschedGroup = 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 serviceprocState = 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_BACKGROUNDschedGroup = (mTmpBroadcastQueue.contains(mService.mFgBroadcastQueue))? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;//设置adj类型为广播"broadcast"state.setAdjType("broadcast");//设置当前进程状态是PROCESS_STATE_RECEIVERprocState = 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_BACKGROUNDschedGroup = psr.shouldExecServicesFg()? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;//设置adj类型为正在运行的服务"exec-service"state.setAdjType("exec-service");//设置当前进程状态是PROCESS_STATE_SERVICEprocState = 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也是调整成0adj = ProcessList.FOREGROUND_APP_ADJ;//只是cgroup分组设置成后台SCHED_GROUP_BACKGROUNDschedGroup = ProcessList.SCHED_GROUP_BACKGROUND;//设置adj类型为顶端,而且休眠状态"top-sleeping"state.setAdjType("top-sleeping");//拥有前台活动对象foregroundActivities设置成yrue, 注意此时拥有可见的activity(hasVisibleActivities)并未设置成tureforegroundActivities = true;//进程状态设置成PROCESS_STATE_TOP_SLEEPINGprocState = 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_BACKGROUNDschedGroup = 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_EMPTYprocState = 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,代表缓存的activitystate.computeOomAdjFromActivitiesIfNecessary(mTmpComputeOomAdjWindowCallback,adj, foregroundActivities, hasVisibleActivities, procState, schedGroup,appUid, logUid, PROCESS_STATE_CUR_TOP);//将上面获取的mCachedAdj设置成当前adjadj = 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_RECENTif (procState > PROCESS_STATE_CACHED_RECENT && state.getCachedHasRecentTasks()) {//进程状态最大就是PROCESS_STATE_CACHED_RECENTprocState = 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设置成用户可感知的优先级200adj = 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级别(最前台),或者当前进程状态起码是topif (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设置成200adj = 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,还有原因reasonstate.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设置成400adj = 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的activityif (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设置成700adj = 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更新到mCurRawAdjstate.setCurRawAdj(adj);//将当前进程状态procState更新到mCurRawProcStatestate.setCurRawProcState(procState);//先默认该进程没有启动的服务,给初始化值state.setHasStartedServices(false);

25. 设置当前adj调整的系列号

        //到这里我们开始调整adj的值,设置当前进程adj调整的序列是mAdjSeqstate.setAdjSeq(mAdjSeq);

26. 调整backup备份的应用

        //获取backup的目标final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);//如果backup app就是当前调整的appif (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.//用来用来判断分组是否需要将分组设置成topboolean scheduleLikeTopApp = false;//numberOfRunningServices是查看还有多少正在运行的服务(只要startService了就会放入ProcessServiceRecord的mServices中,//stopService或者kill会从mServices移除)//而且满足其中之一才会进来:adj需要大于0的才调整,如果是0前台或者常驻进程adj是负数,或者分组是后台,或者进程状态状态大于topfor (int is = psr.numberOfRunningServices() - 1;is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND|| procState > PROCESS_STATE_TOP);is--) {//取得保存服务的对象ServiceRecordServiceRecord 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,只要进程还在都是trueif (!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 servicesif (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设置成500adj = 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这个值才是trueif (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就返回trueenabled = getPlatformCompatCache().isChangeEnabled(CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, s.appInfo);} catch (RemoteException e) {}//Android S中,如果apk是针对S做的,一般enabled都是trueif (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的adjif (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();//取得客户端的临时计算的最新进程状态值mCurRawProcStateint clientProcState = cstate.getCurRawProcState();//如果进程状态比top还小,代表是起码是常驻进程,clientIsSystem标记为truefinal 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去调整服务端的adjif ((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_SERVICEif (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 activityif (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先初始化为nullString 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"(缓存的绑定服务),代表不通过客户端来调整服务端的adjadjType = "cch-bound-services";}//忽略客户端adj,不管客户端adj的大小,将服务的adj赋值给clientAdj后,都将忽略clientAdjclientAdj = 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如果大于等于900if (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,看情况调整当前进程的adjint newAdj;//如果服务链接里面包含BIND_ABOVE_CLIENT或者BIND_IMPORTANT的时候//BIND_ABOVE_CLIENT: 代表服务的优先级需要比客户端client的高//BIND_IMPORTANT: 正常情况是就客户端是前台,服务端最多也只是visable,不过设置了这个,//adj可以到0(fg)或者-700(PERSISTENT_SERVICE)//StorageUserConnection里面bindServiceAsUser就有设置BIND_IMPORTANTif ((cr.flags&(Context.BIND_ABOVE_CLIENT|Context.BIND_IMPORTANT)) != 0) {//如果客户端的adj大于等于-700,直接将客户端的clientAdj赋值给当前进程的newAdjif (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_PERSISTENTprocState = 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设置成客户端的优先级clientAdjnewAdj = 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,赋值给当前进程的adjadj = 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设置的分组信息赋值给curSchedGroupfinal int curSchedGroup = cstate.getCurrentSchedulingGroup();//如果当前curSchedGroup(客户端分组优先级)大于schedGroup(当前进程分组优先级)if (curSchedGroup > schedGroup) {//如果设置了BIND_IMPORTANT(重要的绑定)if ((cr.flags&Context.BIND_IMPORTANT) != 0) {//则将客户端的cgroup分组优先级设置给当前进程的分组信息schedGroup = curSchedGroup;} else {//如果没有设置,则默认的分组先设置成defalutschedGroup = 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就返回trueenabled = 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=trueif (schedGroup < ProcessList.SCHED_GROUP_TOP_APP&& (cr.flags & Context.BIND_SCHEDULE_LIKE_TOP_APP) != 0&& clientIsSystem) {//将分组信息设置成top appschedGroup = ProcessList.SCHED_GROUP_TOP_APP;//标记这种app为scheduleLikeTopApp=truescheduleLikeTopApp = 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设置此次调整的来源:客户端ProcessRecordstate.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_ACTIVITYif ((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 appschedGroup = 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设置此次调整的来源:客户端ActivityServiceConnectionsHolderstate.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调整的原因是activityreportOomAdjMessageLocked(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客户端调用者的ProcessRecordProcessRecord client = conn.client;//cstate是客户端进程状态记录信息ProcessStateRecordfinal 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();//取得客户端的临时计算的最新进程状态值mCurRawProcStateint clientProcState = cstate.getCurRawProcState();//客户端的进程状态优先级低于cached activityif (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类型),初始值是nullString 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由于依赖关系最高优先级调整到0adj = 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 = falsestate.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赋值给当前进程的进程状态procStateprocState = 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_DEFAULTschedGroup = ProcessList.SCHED_GROUP_DEFAULT;}

28.7 输出provider调整的原因

                //如果adj类型不为空,那么代表根据客户端,当前进程调整过adj或者进程状态procStateif (adjType != null) {//设置adj类型state.setAdjType(adjType);//设置adj类型的代码mAdjTypeCode(和importanceReasonCode类似,就是优先级的原因)为provider正在使用中state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo.REASON_PROVIDER_IN_USE);//setAdjSource设置此次调整的来源:客户端ProcessRecordstate.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->externalProcessTokenToHandleif (cpr.hasExternalProcessHandles()) {//如果当前adj大于0前台,则设置成0if (adj > ProcessList.FOREGROUND_APP_ADJ) {//adj设置成0(FOREGROUND_APP_ADJ),这种优先级比较高//一般用在cmd、uiautomatoradj = 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 providerif (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到mCurRawProcStatestate.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;//设置分组为后台,这里是后台,不是前台和defaultschedGroup = ProcessList.SCHED_GROUP_BACKGROUND;//非cached进程state.setCached(false);//adj类型是"recent-provider"最近使用的providerstate.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) {//看一下客户端是否有activityif (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,而不是16procState = 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.javaprivate 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, 49152int high = mOomMinFreeHigh[i];//73728, 92160, 110592,129024, 147456, 184320if (is64bit) {// Increase the high min-free levels for cached processes for 64-bitif (i == 4) high = (high * 3) / 2;//221184else 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有界面时)是falseif (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复制给mCurAdjstate.setCurAdj(psr.modifyRawOomAdj(adj));//本次adj调整即将完成,将计算的能力capability复制给mCurCapabilitystate.setCurCapability(capability);//本次adj调整即将完成,将计算的分组信息schedGroup复制给mCurSchedGroupstate.setCurrentSchedulingGroup(schedGroup);//本次adj调整即将完成,将计算的进程状态procState复制给mCurProcStatestate.setCurProcState(procState);//本次adj调整即将完成,将计算的进程状态procState复制给mCurRawProcStatestate.setCurRawProcState(procState);//通过hasVisibleActivities更新mLastInvisibleTime,如果mHasVisibleActivities从true变成false,//则记录这个时候的时间,相当于当进程从可见到不可见的时间//主要用在是否允许启动前台服务里面,这个时间目前是mFgToBgFgsGraceDuration(5秒钟以内还是允许的)state.updateLastInvisibleTime(hasVisibleActivities);//更新mHasForegroundActivities是否拥有前台activitystate.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 promotedreturn 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,也即是客户端未调整完毕又进入了computeOomAdjLSPif (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;}

这篇关于Android adj调整 --- computeOomAdjLSP流程详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/700339

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Debezium 与 Apache Kafka 的集成方式步骤详解

《Debezium与ApacheKafka的集成方式步骤详解》本文详细介绍了如何将Debezium与ApacheKafka集成,包括集成概述、步骤、注意事项等,通过KafkaConnect,D... 目录一、集成概述二、集成步骤1. 准备 Kafka 环境2. 配置 Kafka Connect3. 安装 D

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

Linux流媒体服务器部署流程

《Linux流媒体服务器部署流程》文章详细介绍了流媒体服务器的部署步骤,包括更新系统、安装依赖组件、编译安装Nginx和RTMP模块、配置Nginx和FFmpeg,以及测试流媒体服务器的搭建... 目录流媒体服务器部署部署安装1.更新系统2.安装依赖组件3.解压4.编译安装(添加RTMP和openssl模块

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Spring Cloud LoadBalancer 负载均衡详解

《SpringCloudLoadBalancer负载均衡详解》本文介绍了如何在SpringCloud中使用SpringCloudLoadBalancer实现客户端负载均衡,并详细讲解了轮询策略和... 目录1. 在 idea 上运行多个服务2. 问题引入3. 负载均衡4. Spring Cloud Load

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型的操作流程

《0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeekR1模型的操作流程》DeepSeekR1模型凭借其强大的自然语言处理能力,在未来具有广阔的应用前景,有望在多个领域发... 目录0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型,3步搞定一个应