Android 7.0 ActivityManagerService(9) 进程管理相关流程分析(3) computeOomAdjLocked

这一篇博客,我们来分析一下AMS进程管理流程中,负责计算进程oom_adj值的computeOomAdjLocked函数。

从难度上来讲,computeOomAdjLocked函数比updateOomAdjLocked函数简单,因为它的职责更明确和单一。
然而,由于Android定义的oom_adj种类庞杂,使得这个函数的分支很多,细节显得极其的繁琐。
因此从功利的角度来看,大家知道这个函数的用途和大概脉络即可。

不过对于一个框架工程师而言,阅读源码的耐心可能比写代码的能力更重要,因此我们还是耐着性子将代码看完。
“RTFSC”,毕竟大神是这么告诉我们的。

computeOomAdjLocked函数的代码很长,
因此在这篇博客中,我们还分段进行研究,然后试着进行总结。

一、computeOomAdjLocked Part-I

private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
        boolean doingAll, long now) {
    //之前的博客中提到过,updateOomAdjLocked函数每次更新oom_adj时,都会分配一个序号
    //此处就是根据序号判断是否已经处理过命令
    if (mAdjSeq == app.adjSeq) {
        // This adjustment has already been computed.
        return app.curRawAdj;
    }

    //ProcessRecord对应的ActivityThread不存在了
    //修改其中的一些变量,此时的oom_adj为CACHED_APP_MAX_ADJ,
    //其意义我们在前一篇博客中已经提到过
    if (app.thread == null) {
        app.adjSeq = mAdjSeq;
        app.curSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
        app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
        return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
    }

    //初始化一些变量
    //这些变量的具体用途,在篇博客中我们不关注
    //大家只用留意一下ProcessRecord的schedGroup、procState和oom_adj即可
    app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
    app.adjSource = null;
    app.adjTarget = null;
    app.empty = false;
    app.cached = false;

    final int activitiesSize = app.activities.size();

    //这个判断没啥意义,ProcessRecord中只有初始化时为maxAdj赋值
    //maxAdj取值为UNKNOWN_ADJ,即最大的1001
    if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
        //这部分代码就是修改app的curSchedGroup,并将oom_adj设置为maxAdj
        //实际过程中,应该是不会执行的的
        ......................
    }

    //保存当前TOP Activity的状态
    final int PROCESS_STATE_CUR_TOP = mTopProcessState;
    ......................
}

以上代码就是computeOomAdjLocked函数的第一部分。
从代码不难看出,这部分内容的主要目的是:
1、根据参数及进程的状态,决定是否需要进行后续的计算;
2、初始化一些变量。

二、computeOomAdjLocked Part-II
在第二部分,computeOomAdjLocked开始干“正事儿”了:

.................
// Determine the importance of the process, starting with most
// important to least, and assign an appropriate OOM adjustment.
// 上面的这段注释为整个computeOomAdjLocked函数“代言”

int adj;
int schedGroup;
int procState;
boolean foregroundActivities = false;
BroadcastQueue queue;

//若进程包含正在前台显示的Activity
if (app == TOP_APP) {
    // The last app on the list is the foreground app.
    adj = ProcessList.FOREGROUND_APP_ADJ;

    //单独的一种schedGroup
    schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
    app.adjType = "top-activity";

    //当前处理的是包含前台Activity的进程时,才会将该值置为true
    foregroundActivities = true;
    procState = PROCESS_STATE_CUR_TOP;
} else if (app.instrumentationClass != null) {
    //处理正在进行测试的进程

    // Don't want to kill running instrumentation.
    adj = ProcessList.FOREGROUND_APP_ADJ;
    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;

    app.adjType = "instrumentation";
    procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
} else if ((queue = isReceivingBroadcast(app)) != null) {
    //处理正在处理广播的进程

    // An app that is currently receiving a broadcast also
    // counts as being in the foreground for OOM killer purposes.
    // It's placed in a sched group based on the nature of the
    // broadcast as reflected by which queue it's active in.
    adj = ProcessList.FOREGROUND_APP_ADJ;

    //根据处理广播的Queue,决定调度策略
    schedGroup = (queue == mFgBroadcastQueue)
            ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;

    app.adjType = "broadcast";
    procState = ActivityManager.PROCESS_STATE_RECEIVER;
} else if (app.executingServices.size() > 0) {
    //处理Service正在运行的进程

    // An app that is currently executing a service callback also
    // counts as being in the foreground.
    adj = ProcessList.FOREGROUND_APP_ADJ;

    schedGroup = app.execServicesFg ?
            ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;

    procState = ActivityManager.PROCESS_STATE_SERVICE;
} else {
    //其它进程,在后续过程中再进一步处理
    // As far as we know the process is empty.  We may change our mind later.
    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.
    // 先将adj临时赋值为cachedAdj,即参数传入的UNKNOW_ADJ
    adj = cachedAdj;
    procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;

    app.cached = true;
    app.empty = true;
    app.adjType = "cch-empty";
}
..................

以上代码可以看作是computeOomAdjLocked的第二部分,从这部分代码可以看出:
1、包含前台Activity的进程、运行测试类的进程、处理广播的进程及包含正在运行服务的进程,
其oom_adj均被赋值为FOREGROUND_APP_ADJ,即从LMK的角度来看,它们的重要性是一致的。
但这些进程的procState不同,于是从AMS主动回收内存的角度来看,它们的重要性不同。

此外,这些进程的schedGroup不同。
之前的博客分析过,Process.java中提供了接口,可以调用Linux提供的接口函数设置schedGroup,使得进程具有不同的调度策略。
从获取CPU资源的能力来看,SCHED_GROUP_TOP_APP应该强于SCHED_GROUP_DEFAULT,
最后才轮到SCHED_GROUP_BACKGROUND。

2、对于其它种类的进程,这部分代码先将它们的oom_adj设置为UNKNOW_ADJ,
proc_state置为PROCESS_STATE_CACHED_EMPTY,在后续流程中再作进一步处理。

三、computeOomAdjLocked Part-III
这一部分代码主要处理包含Activity,但是Activity不在前台的进程。

注意到这些进程包括之前提到的正在处理广播、服务或测试的进程,以及oom_adj暂时为UNKNOW_ADJ的进程。
不过只有UNKNOW_ADJ对应的进程,才有可能进行实际的更新。

..................
// Examine all activities if not already foreground.
if (!foregroundActivities && activitiesSize > 0) {
    //之前分析updateOomAdjLocked的第一部分时,简单提到过rankTaskLayersIfNeeded函数
    //该函数会更新包含Activity的Task的rankLayer
    //按照显示层次从上到下,rankLayer逐渐增加,对应的最大值就是VISIBLE_APP_LAYER_MAX
    int minLayer = ProcessList.VISIBLE_APP_LAYER_MAX;

    //依次轮询进程中的Activity
    for (int j = 0; j < activitiesSize; j++) {
        final ActivityRecord r = app.activities.get(j);
        ...................
        //如果进程包含可见Activity,即该进程是个可见进程
        if (r.visible) {
            
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值