码迷,mamicode.com
首页 > 移动开发 > 详细

Android 7.0 ActivityManagerService(8) 进程管理相关流程分析(2)

时间:2017-01-07 18:32:41      阅读:647      评论:0      收藏:0      [点我收藏+]

标签:ssr   slot   and   rds   可见   idc   源码   call   管理   

前一篇博客进程管理相关流程分析(1)里,
我们介绍了AMS中updateLruProcessLocked函数相关的流程。

updateLruProcessLocked只是按照进程中运行的组件,粗略地定义了不同进程的优先级。
实际上,Android根据进程的oom_adj进行了更加细致的进程分类,
而AMS中的updateOomAdjLocked函数,就是用于更新进程的oom_adj值。

本篇博客中,我们来看看AMS中updateOomAdjLocked相关的流程。

一、ProcessList.java中的oom_adj
进程在不同场景下的oom_adj值,定义于ProcessList.java中。
考虑到updateOomAdjLocked函数极其的复杂,我们有必要先了解一下不同oom_adj的含义。

final class ProcessList {
    ..............
    // OOM adjustments for processes in various states:

    // Uninitialized value for any major or minor adj fields
    // 未初始化时,定义为-10000
    static final int INVALID_ADJ = -10000;
    ..............

    // Adjustment used in certain places where we don‘t know it yet.
    // (Generally this is something that is going to be cached, but we
    // don‘t know the exact value in the cached range to assign yet.)
    // 如注释所述,过渡态的值
    static final int UNKNOWN_ADJ = 1001;

    // This is a process only hosting activities that are not visible,
    // so it can be killed without any disruption.
    // 从注释来看,这里应该是仅持有Activity的background进程对应的值,最小为900,最大为906
    // 实际上empty进程和background进程均会使用这些值
    static final int CACHED_APP_MAX_ADJ = 906;
    static final int CACHED_APP_MIN_ADJ = 900;

    // The B list of SERVICE_ADJ -- these are the old and decrepit
    // services that aren‘t as shiny and interesting as the ones in the A list.
    // 这里应该是对应持有老旧服务的background进程
    static final int SERVICE_B_ADJ = 800;

    // This is the process of the previous application that the user was in.
    // This process is kept above other things, because it is very common to
    // switch back to the previous app.
    // 当前页面对应进程的前一个进程
    // 例如,从A进程的Activity跳转到B进程的Activity
    // 此时B进程就是当前进程,A进程就是previous进程
    // 由于用户可能在A、B Activity之间切换,因此为previous进程赋予一个单独的oom_adj
    // 本质上来说,这仍是background进程
    static final int PREVIOUS_APP_ADJ = 700;

    // This is a process holding the home application -- we want to try
    // avoiding killing it, even if it would normally be in the background,
    // because the user interacts with it so much.
    // 用户经常会和home进程交互,因此单独为home进程赋予一个oom_adj
    // 一般情况下,home进程也可以归属到background进程
    static final int HOME_APP_ADJ = 600;

    // This is a process holding an application service -- killing it will not
    // have much of an impact as far as the user is concerned.
    // service进程
    static final int SERVICE_ADJ = 500;

    // This is a process with a heavy-weight application.  It is in the
    // background, but we want to try to avoid killing it.  Value set in
    // system/rootdir/init.rc on startup.
    // 对于heavy_weight进程,虽是后台进程,但重要性甚至大于service进程
    // 应该是该类型的进程,重新启动的成本太高了,因此尽量避免杀掉吧
    // 这是所谓的“尾大不掉”吧

    // 需要指出的是,这里的注释太老旧了,Android N里的路径已经是system/core/rootdir/init.rc
    // 同时,没有看到与heavy_weight相关的配置,个人觉得注释的意思是:
    // 可以按照需要自己配置吧,类似于init进程的写法:
    // # Set init and its forked children‘s oom_adj.
    // write /proc/1/oom_score_adj -1000
    static final int HEAVY_WEIGHT_APP_ADJ = 400;

    // This is a process currently hosting a backup operation.  Killing it
    // is not entirely fatal but is generally a bad idea.
    // 正在执行backup的进程
    // 与heavy_weight进程一样,android已经不完全按照进程的组件来划分重要性了
    // 还考虑了进程当前正在执行的操作
    static final int BACKUP_APP_ADJ = 300;

    // This is a process only hosting components that are perceptible to the
    // user, and we really want to avoid killing them, but they are not
    // immediately visible. An example is background music playback.
    // “perceptible”的意思是:可察觉到
    // 从这里来看,其实这种进程已经属于visible进程的范畴了,毕竟用户可以察觉到这种进程的存在
    // 不过这种进程属于不包含visible activity,但包含绑定了Activity的service
    static final int PERCEPTIBLE_APP_ADJ = 200;

    // This is a process only hosting activities that are visible to the
    // user, so we‘d prefer they don‘t disappear.
    // visible进程, 侧重于包含visible activity
    static final int VISIBLE_APP_ADJ = 100;
    static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;

    // This is the process running the current foreground app.  We‘d really
    // rather not kill it!
    // foreground进程
    static final int FOREGROUND_APP_ADJ = 0;

    // This is a process that the system or a persistent process has bound to,
    // and indicated it is important.
    // 系统进程或常驻进程绑定的service所在的进程
    static final int PERSISTENT_SERVICE_ADJ = -700;

    // This is a system persistent process, such as telephony.  Definitely
    // don‘t want to kill it, but doing so is not completely fatal.
    // 常驻进程
    static final int PERSISTENT_PROC_ADJ = -800;

    // The system process runs at the default adjustment.
    // 系统进程
    static final int SYSTEM_ADJ = -900;

    // Special code for native processes that are not being managed by the system (so
    // don‘t have an oom adj assigned by the system).
    // 框架层无法约束的native进程
    static final int NATIVE_ADJ = -1000;
    ..............
    // The minimum number of cached apps we want to be able to keep around,
    // without empty apps being able to push them out of memory.
    // 从注释来看,min_cached_apps不包含empty进程的数量
    static final int MIN_CACHED_APPS = 2;

    // The maximum number of cached processes we will keep around before killing them.
    // NOTE: this constant is *only* a control to not let us go too crazy with
    // keeping around processes on devices with large amounts of RAM.  For devices that
    // are tighter on RAM, the out of memory killer is responsible for killing background
    // processes as RAM is needed, and we should *never* be relying on this limit to
    // kill them.  Also note that this limit only applies to cached background processes;
    // we have no limit on the number of service, visible, foreground, or other such
    // processes and the number of those processes does not count against the cached
    // process limit.
    // 这里的注释需要看一看,这里应该指系统可保留的所有后台和empty进程最大值
    // MAX_CACHED_APPS不限制service, visible, foreground, or other such processes的数量
    // 仅仅作为参考值,系统并不会真的保留这么多后台进程,毕竟LMK将按需看kill them
    static final int MAX_CACHED_APPS = 32;
    ..............
    // The maximum number of empty app processes we will let sit around.
    //最多保留16个empty进程
    private static final int MAX_EMPTY_APPS = computeEmptyProcessLimit(MAX_CACHED_APPS);

    // The number of empty apps at which we don‘t consider it necessary to do
    // memory trimming.
    // Android依靠LMK杀死进程来释放内存
    // 当empty进程数少于这个门限(8)时,说明LMK已经杀死了一部分empty进程
    // 于是AMS主动释放一些应用的内存
    static final int TRIM_EMPTY_APPS = MAX_EMPTY_APPS/2;

    // The number of cached at which we don‘t consider it necessary to do
    // memory trimming.
    // 与TRIM_EMPTY_APPS的用途类似
    // 当后台进程少于该门限(5)时,AMS主动释放一些应用的内存
    static final int TRIM_CACHED_APPS = (MAX_CACHED_APPS-MAX_EMPTY_APPS)/3;
    ...................
    //以下是之前博客提到过的,LMK预定义的阈值,这里区分了高内存和低内存的机器
    //例如对于低内存机器而言,当内存小于12288KB时,就要kill掉oom_adj大于FOREGROUND_APP_ADJ的进程
    //对于高内存的机器而言,当内存小于73728时,才kill掉oom_adj大于FOREGROUND_APP_ADJ的进程

    // These are the various interesting memory levels that we will give to
    // the OOM killer.  Note that the OOM killer only supports 6 slots, so we
    // can‘t give it a different value for every possible kind of process.
    private final int[] mOomAdj = new int[] {
            FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
            BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ
    };
    // These are the low-end OOM level limits.  This is appropriate for an
    // HVGA or smaller phone with less than 512MB.  Values are in KB.
    private final int[] mOomMinFreeLow = new int[] {
            12288, 18432, 24576,
            36864, 43008, 49152
    };
    // These are the high-end OOM level limits.  This is appropriate for a
    // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.
    private final int[] mOomMinFreeHigh = new int[] {
            73728, 92160, 110592,
            129024, 147456, 184320
    };
}

ProcessList.java中定义的oom_adj值较多,由此可见Android对于进程的管理考虑的很细,这也意味着对应的工作流程会很复杂。
除去oom_adj的定义外,ProcessList.java中还定义了一些门限值,决定系统在合适的时候,主动进行一些内存回收工作,后文分析具体代码流程时将会遇到。根据自己分析源码的感受,个人觉得对这些变量有一些了解,是理解具体流程的必要条件。

这里按照Android对进程的分类,粗略划分一下不同oom_adj对应的场景,以便后文的分析:
技术分享
这里唯一要注意的是:CACHED_APP_MIN_ADJ和CACHED_APP_MAX_ADJ的分配,
跨越了后台进程和Empty进程的范畴。

Android并不是kill掉所有Empty进程后,才kill后台进程。
它是将CACHED_APP_MIN_ADJ和CACHED_APP_MAX_ADJ之间的范围,分成多个slot。
然后在每个slot中,分别分配一定量的后台进程和Empty进程。
在单独的slot中,会先kill掉empty进程,后kill掉后台进程。
只有当一个slot中的进程kill完毕后,才会kill掉下一个slot中的进程。
我们将从后面的代码中,得到对应的分析依据,这里先有个印象即可。

二、AMS中的updateOomAdjLocked
AMS中有几个重载的updateOomAdjLocked函数,我们从比较通用的一个入手进行分析。
该updateOomAdjLocked函数较长,分段进行分析。

1 updateOomAdjLocked Part-I

final void updateOomAdjLocked() {
    //正常情况下,resumedAppLocked返回当前正处于前台的Activity,即AMS维护的mResumedActivity
    //如果没有mResumedActivity,则返回前台Task中的mPausingActivity或最顶端的Activity
    final ActivityRecord TOP_ACT = resumedAppLocked();

    //得到当前前台Activity对应进程信息
    final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
    ..................
    //得到LRU表中,统计进程的数量
    final int N = mLruProcesses.size();
    ..................
    // Reset state in all uid records.
    // UidRecord用于记录某个用户组中的进程运行状态
    // 该对象可以记录用户组中的进程数量,但只记录最重要进程的状态,
    // 即优先级最高进程的状态决定了用户组的状态
    for (int i=mActiveUids.size()-1; i>=0; i--) {
        final UidRecord uidRec = mActiveUids.valueAt(i);
        ............
        //重置
        uidRec.reset();
    }

    //更新Task的mLayerRank变量
    //Task中无可见Activity时,mLayerRank为-1
    //Task有可见Activity时,按显示的先后,mLayerRank逐渐增加
    mStackSupervisor.rankTaskLayersIfNeeded();

    //每次调节oom_adj时,都会有唯一的序号
    mAdjSeq++;
    mNewNumServiceProcs = 0;
    mNewNumAServiceProcs = 0;

    final int emptyProcessLimit;
    final int cachedProcessLimit;

    //mProcessLimit中记录的是:
    //系统允许保留的后台进程和empty进程的总和
    if (mProcessLimit <= 0) {
        emptyProcessLimit = cachedProcessLimit = 0;
    } else if (mProcessLimit == 1) {
        //居然优先保证的是empty进程数量
        emptyProcessLimit = 1;
        cachedProcessLimit = 0;
    } else {
        //emptyProcess和cachedProcess的数量,各占mProcessLimit的一半
        emptyProcessLimit = ProcessList.computeEmptyProcessLimit(mProcessLimit);
        cachedProcessLimit = mProcessLimit - emptyProcessLimit;
    }

    // Let‘s determine how many processes we have running vs.
    // how many slots we have for background processes; we may want
    // to put multiple processes in a slot of there are enough of
    // them.
    // numSlots等于3
    // 后台进程和empty进程对应的oom_adj,可取的值一共有6个
    // 这里划分出3个slot, 后台进程和empty进程将被分配到这3个slot中
    // 2代表的是不同slot的oom_adj差异
    int numSlots = (ProcessList.CACHED_APP_MAX_ADJ
            - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2;

    //计算出当前的empty进程数量
    //N为LRU表中维护的总进程数量
    //mNumNonCachedProcs表示非cached/empty进程的数量
    //mNumCachedHiddenProcs表示cachedHidden进程的数量 (就是后台进程的数量)
    int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;

    if (numEmptyProcs > cachedProcessLimit) {
        // If there are more empty processes than our limit on cached
        // processes, then use the cached process limit for the factor.
        // This ensures that the really old empty processes get pushed
        // down to the bottom, so if we are running low on memory we will
        // have a better chance at keeping around more cached processes
        // instead of a gazillion empty processes.
        // 超过门限,则修改
        // 这里有点奇怪,为什么不用emptyProcessLimit来比较和修改?
        numEmptyProcs = cachedProcessLimit;
    }

    //计算出每个slot中,可容纳empty进程的数量
    int emptyFactor = numEmptyProcs/numSlots;
    if (emptyFactor < 1) emptyFactor = 1;

    //计算出每个slot中,可容纳后台进程的数量
    int cachedFactor = (mNumCachedHiddenProcs > 0 ? mNumCachedHiddenProcs : 1)/numSlots;
    if (cachedFactor < 1) cachedFactor = 1;

    //从上面的分配可以看出,Android并不是先kill完所有empty进程,才去kill后台进程的
    //这二者之间按比例分布在不同的slot中
    //每kill一个优先级对应的slot时,都会kill一部分empty进程和后台进程
    .........................
    //在本次处理前,重置变量
    mNumNonCachedProcs = 0;
    mNumCachedHiddenProcs = 0;
    .....................
}

updateOomAdjLocked函数的第一部分,并没有什么具体的逻辑,主要是初始化一些变量,为后续的oom_adj调整做好准备。
个人觉得大致了解即可,不用太深究每一个变量的含义。

2 updateOomAdjLocked Part-II
这一部分将计算和更新每个进程的oom_adj值。

..................
// First update the OOM adjustment for each of the
// application processes based on their current state.


//empty进程相对而言,oom_adj的值还是要大于后台进程
int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextCachedAdj = curCachedAdj+1;
int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextEmptyAdj = curEmptyAdj+2;

for (int i=N-1; i>=0; i--) {
    //从后往前,依次取出LRU中进程对应的ProcessRecord
    ProcessRecord app = mLruProcesses.get(i);
    if (!app.killedByAm && app.thread != null) {
        app.procStateChanged = false;

        //计算并更新进程的curProcState,并得到初步的oom_adj值
        computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);

        // If we haven‘t yet assigned the final cached adj
        // to the process, do that now.
        // computeOomAdjLocked没能完成oom_adj的计算时,
        // 进一步调整oom_adj值 (从代码来看,computeOomAdjLocked应该是无法计算后台进程和empty进程)
        if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {

            //根据进程的状态调整oom_adj
            switch (app.curProcState) {

                //包含Activity的后台进程,或其客户端进程
                case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
                case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
                    // This process is a cached process holding activities...
                    // assign it the next cached value for that type, and then
                    // step that cached level.
                    app.curRawAdj = curCachedAdj;

                    //当前进程以BIND_ABOVE_CLIENT绑定一个Service时,modifyRawOomAdj才会生效
                    //结果是进一步增加oom_adj
                    app.curAdj = app.modifyRawOomAdj(curCachedAdj);
                    ................
                    //调整curCachedAdj和nextCachedAdj
                    if (curCachedAdj != nextCachedAdj) {
                        stepCached++;

                        //可以看出,每个slot分配的进程数超过对应门限时
                        //才会增加curCachedAdj和nextCachedAdj,即向下个slot分配进程
                        if (stepCached >= cachedFactor) {
                            stepCached = 0;
                            curCachedAdj = nextCachedAdj;
                            nextCachedAdj += 2;
                            if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
                                nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
                            }
                        }
                    }
                    break;
                default:
                    // For everything else, assign next empty cached process
                    // level and bump that up.  Note that this means that
                    // long-running services that have dropped down to the
                    // cached level will be treated as empty (since their process
                    // state is still as a service), which is what we want.
                    // 如果后台进程不含有Activity等,将被视为empty进程(参考注释)

                    //与上面的代码一样,修改oom_adj
                    //同样按照slot来分配empty进程的oom_adj
                    app.curRawAdj = curEmptyAdj;
                    app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
                    ..............
                    if (curEmptyAdj != nextEmptyAdj) {
                        stepEmpty++;
                        if (stepEmpty >= emptyFactor) {
                            stepEmpty = 0;
                            curEmptyAdj = nextEmptyAdj;
                            nextEmptyAdj += 2;
                            if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
                                nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
                            }
                         }
                    }
                    break;
            }
        }

        //更新进程对应的信息
        applyOomAdjLocked(app, true, now, nowElapsed);

        // Count the number of process types.
        // 更新不同类型进程的数量
        switch (app.curProcState) {
            case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
            case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
                //更新后台进程的数量(包含Activity的进程,或其客户端)
                mNumCachedHiddenProcs++;
                numCached++;
                if (numCached > cachedProcessLimit) {
                    //超过门限时,直接kill掉
                    app.kill("cached #" + numCached, true);
                }
                break;
            case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
                //更新empty进程的数量

                //超过trim门限,同时empty进程存活时间大于30min时,被kill掉
                if (numEmpty > ProcessList.TRIM_EMPTY_APPS
                        && app.lastActivityTime < oldTime) {
                    app.kill("empty for "
                            + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
                            / 1000) + "s", true);
                } else {
                    numEmpty++;
                    //empty进程的数量超过门限后,kill掉
                    if (numEmpty > emptyProcessLimit) {
                        app.kill("empty #" + numEmpty, true);
                    }
                }
                break;
            default:
                //更新其它进程的数量
                mNumNonCachedProcs++;
                break;
        }

        //独立进程中没有服务时,直接kill掉
        if (app.isolated && app.services.size() <= 0) {
            // If this is an isolated process, and there are no
            // services running in it, then the process is no longer
            // needed.  We agressively kill these because we can by
            // definition not re-use the same process again, and it is
            // good to avoid having whatever code was running in them
            // left sitting around after no longer needed.
            app.kill("isolated not needed", true);
        } else {
            // Keeping this process, update its uid.
            final UidRecord uidRec = app.uidRecord;
            //初始时,reset过,值为PROCESS_STATE_CACHED_EMPTY
            //这个值越小,说明uid含有的进程越重要,最小值为PROCESS_STATE_PERSISTENT
            if (uidRec != null && uidRec.curProcState > app.curProcState) {
                uidRec.curProcState = app.curProcState;
            }
        }

        //home本身就是个后台进程,若当前进程状态大于home
        //则该进程是个不重要的后台进程,或empty进程
        if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
                && !app.killedByAm) {
            numTrimming++;
        }
    }
}
................

updateOomAdjLocked第二部分没有让我们失望,可谓是“杀伐果断”。
从上面的代码我们可以看出:
1、该部分代码,将逆序处理LRU中的每一个进程。
我们可以看到,当某类进程的数量超过门限时,将被kill掉。
由于是逆序处理LRU中的进程,因此不重要的进程(使用较少、较老)将先被kill掉。

2、利用computeOomAdjLocked函数,计算每个进程的oom_adj。
从代码来看,对于cached process而言,computeOomAdjLocked可能无法计算出其oom_adj,
因此这类进程被单独处理。
computeOomAdjLocked函数较长,需要单独用一篇博客介绍。

3、上面的代码证明了我们之前的分析:
后台进程和empty进程,在CACHED_APP_MIN_ADJ和CACHED_APP_MAX_ADJ混合分布。
这段区间被划分为不同的slot,前一个slot中的位置分配完毕后,才会分配后一个slot。
由于后一个slot的oom_adj比较大,将被优先kill掉,再次和LRU的定义结合起来了。

4、调用applyOomAdjLocked函数,更新进程相关的信息。

5、对于“隔离”的进程,Android的处理比较严格。
若其中没有运行服务,则直接kill掉。
此外,一个用户组的重要性,由其中最重要的进程决定。
这也符合我们的常识。

6、最后,该部分代码统计了重要性小于home的后台进程数量。
后面的代码将使用该变量。

这一部分代码的流程基本如下图所示:
技术分享

3 updateOomAdjLocked Part-III
从之前的代码,我们知道了updateOomAdjLocked的第二部分负责更新进程的oom_adj值,
这些值最终将决定进程何时被LMK kill掉。
同时,第二部分还会在进程数量超过门限等情况下,主动kill掉一些进程。

与第二部分不同的是,在updateOomAdjLocked的第三部分主要是在不kill进程的前提下,
尽可能地主动回收进程的一些内存。

..........
//computeOomAdjLocked函数中,更新了mNewNumServiceProcs的值
//将其保存到mNumServiceProcs中
mNumServiceProcs = mNewNumServiceProcs;

// 以下代码用于计算内存回收等级
// Now determine the memory trimming level of background processes.
// Unfortunately we need to start at the back of the list to do this
// properly.  We only do this if the number of background apps we
// are managing to keep around is less than half the maximum we desire;
// if we are keeping a good number around, we‘ll let them use whatever
// memory they want.
// 得到当前后台进程和empty进程的数量
final int numCachedAndEmpty = numCached + numEmpty;

// memFactor将用于保存内存回收等级
int memFactor;

//后台进程数量小于5,并且empty进程数量小于8时
if (numCached <= ProcessList.TRIM_CACHED_APPS
        && numEmpty <= ProcessList.TRIM_EMPTY_APPS) {

    //总数小于3时,内存回收等级为critical
    if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
        memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;

    //总数小于5时,内存回收等级为low
    } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
        memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;

    //否则内存回收等级为moderate
    } else {
        memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
    }
} else {
    //后台和empty进程足够时,内存回收等级为normal
    memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
}

//从上面的代码,我们可以看出当前后台进程和empty进程数量越少时,内存的回收等级越高
//个人觉得这么设计的原因是:
//在内存足够的情况下,即当后台进程和empty进程的数量没有超过规定门限时,
//系统不会主动去kill掉后台进程和empty进程。
//当LMK察觉到内存不够用时,才会去主动kill掉进程(优先kill掉后台进程和empty进程)
//因此,当系统检查到empty和后台进程数量较少时,就推断出内存不够了

// We always allow the memory level to go up (better).  We only allow it to go
// down if we are in a state where that is allowed, *and* the total number of processes
// has gone down since last time.
..........
//根据条件判断,是否需要修改memFactor (见注释)
//一般情况下,内存回收等级变高时(即允许尽可能多地回收),不允许主动降低它
//但mAllowLowerMemLevel为false,或进程数量变多时,可以降低
if (memFactor > mLastMemoryLevel) {
    if (!mAllowLowerMemLevel || mLruProcesses.size() >= mLastNumProcesses) {
        memFactor = mLastMemoryLevel;
        ...........
    }
}
..........
//保存变量
mLastMemoryLevel = memFactor;
mLastNumProcesses = mLruProcesses.size();

//memFactor保存到mProcessStats中,与之前不等时,返回true
//即内存回收等级与之前不一致时,返回true
boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleepingLocked(), now);

//记录ProcessStats状态
final int trackerMemFactor = mProcessStats.getMemFactorLocked();

//内存状态不等于normal,表示所有进程都要进行内存回收工作
if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
    if (mLowRamStartTime == 0) {
        mLowRamStartTime = now;
    }
    int step = 0;

    //根据内存回收等级,得到对应的fgTrimLevel (即前台进程的内存回收等级)
    //ComponentCallbacks2中定义的回收等级,值越大,越是会尽可能的回收
    int fgTrimLevel;
    switch (memFactor) {
        case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
            fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
            break;
        case ProcessStats.ADJ_MEM_FACTOR_LOW:
            fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
            break;
        default:
            fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
            break;
    }

    //前面已经分析过,numTimming中记录的是重要性低于home的后台进程数量
    int factor = numTrimming/3;

    //决定factor的值
    //与之前划分slot的思想相似,factor代表每个slot可以分配进程的数量
    int minFactor = 2;
    if (mHomeProcess != null) minFactor++;
    if (mPreviousProcess != null) minFactor++;
    if (factor < minFactor) factor = minFactor;

    //初始level为TRIM_MEMORY_COMPLETE (回收的最高等级)
    int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;

    //开始逆序处理LRU中的每一个进程
    // 对应重要性大于home的进程而言,重要性越高,内存回收等级越低
    // 对于重要性小于home的进程,排在LRU表越靠后,即越重要回收等级越高
    // 这么安排的理由有两个:1、此时越不重要的进程,其中运行的组件越少,能够回收的内存不多,不需要高回收等级
    // 2、越不重要的进程越有可能被LMK kill掉,没必要以高等级回收内存
    for (int i=N-1; i>=0; i--) {
        ProcessRecord app = mLruProcesses.get(i);

        //更新进程信息
        if (allChanged || app.procStateChanged) {
            setProcessTrackerStateLocked(app, trackerMemFactor, now);
            app.procStateChanged = false;
        }

        //处理重要性小于home的进程
        if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
                && !app.killedByAm) {
            if (app.trimMemoryLevel < curLevel && app.thread != null) {
                try {
                    .............
                    //回调ApplicationThread的scheduleTrimMemory函数,回收内存
                    //
                    app.thread.scheduleTrimMemory(curLevel);
                } catch (RemoteException e) {
                }
                ........
            }
            app.trimMemoryLevel = curLevel;

            //更新trimMemoryLevel,LRU中越有排在前面,trimMemroyLevel越低
            step++;
            //一个slot分配满,开始下一个slot
            if (step >= factor) {
                step = 0;
                switch (curLevel) {
                    case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
                        curLevel = ComponentCallbacks2.TRIM_MEMORY_MODERATE;
                        break;
                    case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
                        curLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
                        break;
                    }
                }
            }
        //处理Heavy weight进程
        } else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
            //Heavy weight进程的trimLevel小于background时,才会以background回收
            if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
                    && app.thread != null) {
                try {
                    ...............
                    app.thread.scheduleTrimMemory(
                            ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
                } catch (RemoteException e) {
                }
            }
            //更新
            app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
        } else {
            //重要性低于等于IMPROTTANT Background的,以TRIM_MEMORY_UI_HIDDEN等级回收
            if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
                    || app.systemNoUi) && app.pendingUiClean) {
                // If this application is now in the background and it
                // had done UI, then give it the special trim level to
                // have it free UI resources.
                final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
                if (app.trimMemoryLevel < level && app.thread != null) {
                    try {
                        ............
                        app.thread.scheduleTrimMemory(level);
                    } catch (RemoteException e) {
                    }
                }
                app.pendingUiClean = false;
            }

            //之前的回收等级不够时,以新的回收等级回收内存
            if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
                try {
                    .............
                    app.thread.scheduleTrimMemory(fgTrimLevel);
                } catch (RemoteException e) {
                }
            }
            app.trimMemoryLevel = fgTrimLevel;
        }
    }
//else处理内存回收等级为normal的情况
} else {
    if (mLowRamStartTime != 0) {
        mLowRamTimeSinceLastIdle += now - mLowRamStartTime;
        mLowRamStartTime = 0;
    }

    for (int i=N-1; i>=0; i--) {
        ProcessRecord app = mLruProcesses.get(i);

        //更新状态
        if (allChanged || app.procStateChanged) {
            setProcessTrackerStateLocked(app, trackerMemFactor, now);
            app.procStateChanged = false;
        }

        //normal时,只处理重要性低于低于等于import background的进程
        if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
                || app.systemNoUi) && app.pendingUiClean) {
            //之前的回收等级小于UI_HIDDEN时,才进一步回收
            if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
                    && app.thread != null) {
                try {
                    ............
                    //且回收等级最多为TRIM_MEMORY_UI_HIDDEN
                     app.thread.scheduleTrimMemory(
                             ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
                } catch (RemoteException e) {
                }
            }
            app.pendingUiClean = false;
        }
        app.trimMemoryLevel = 0;
    }
}
..........

从updateOomAdjLocked第三部分的代码可以看出,这部分的主要工作,就是在不杀死进程的前提下,
通过回调进程的接口回收一些内存。

不同的进程回收内存的等级不一样。
对于重要性大于home的进程而言,重要性越大,内存的回收等级越低;
对于重要性小于home的进程而言,重要性越大,内存的回收等级越高。

这部分代码的流程基本如下图所示:
技术分享
大图链接

在这一部分的最后,我们看看进程ApplicationThread中的scheduleTrimMemory接口:

public void scheduleTrimMemory(int level) {
    //发送消息,触发ActivityThread处理
    sendMessage(H.TRIM_MEMORY, null, level);
}

ActivityThread中,处理TRIM_MEMORY消息的函数为handleTrimMemory:

final void handleTrimMemory(int level) {
    ................
    //collectComponentCallbacks将获取进程中运行的所有Application、Activity、Service和Provider
    ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);

    final int N = callbacks.size();
    for (int i = 0; i < N; i++) {
        //调用组件的onTrimMemory接口
        //这些组件均实现ComponentCallbacks2接口
        //然后,实际上大多数组件可能只是空实现而已
        callbacks.get(i).onTrimMemory(level);
    }

    //调用WindowManager的接口
    WindowManagerGlobal.getInstance().trimMemory(level);
}

从上面的代码可以看出,updateOomAdjLocked第三部分工作,
最终依赖于组件自身的实现,考虑到大多数组件可能并没有实际实现onTrimMemory的功能,
因此updateOomAdjLocked函数的第三部分工作可能没有任何实际效果。

4 updateOomAdjLocked Part-IV
updateOomAdjLocked第四部分主要进行一些扫尾工作。

.............
//对应开发者选项,其中有一个选项用于控制是否销毁后台Activity
if (mAlwaysFinishActivities) {
    // Need to do this on its own message because the stack may not
    // be in a consistent state at this point.
    mStackSupervisor.scheduleDestroyAllActivities(null, "always-finish");
}
..............
// Update from any uid changes.
for (int i=mActiveUids.size()-1; i>=0; i--) {
    final UidRecord uidRec = mActiveUids.valueAt(i);
    int uidChange = UidRecord.CHANGE_PROCSTATE;
    //如果一个用户组的状态发生变化,取决于最重要进程的状态变化
    if (uidRec.setProcState != uidRec.curProcState) {
        //进行一些记录和更新
        ...........
    }
}
.............

从上面的代码可以看出,updateOomAdjLocked的最后一部分主要就是进行一些信息的记录和更新。

三、总结
至此,updateOomAdjLocked函数分析完毕,
从代码可以看出updateOomAdjLocked函数的重点集中在第二部分和第三部分。

其中,第二部分主要用于计算不同进程的oom_adj,并在恰当的时候主动kill掉一些进程;
第三部分将计算出不同进程的内存回收等级,然后回调进程的接口,进行一些内存回收工作。

然而通过上文的分析,我们知道第三部分的工作依赖于进程中的组件主动实现ComponentCallbacks2接口中的功能,
因此基本上很难取得实际的效果。
系统最终的内存管理,还是依赖于oom_adj的配置,以及LMK的工作。

Android 7.0 ActivityManagerService(8) 进程管理相关流程分析(2)

标签:ssr   slot   and   rds   可见   idc   源码   call   管理   

原文地址:http://blog.csdn.net/gaugamela/article/details/53927724

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!