android 内存管理之adj 《三》

概述

1.1 oom_adj与oom_score_adj

Android系统的设计理念正是希望应用进程能尽量长时间地存活,以提升用户体验。因此当应用推入到后台的时候进程并不会被立即杀死,而是存活一段时间,这样下次再使用则会非常快。但是如果处于后台的进程过多导致内存不足,此时就必须有选择的杀死部分进程。

到底该回收哪个进程呢?那么需要一个能管理所有进程,根据一定策略来释放进程的策略,这便有了lmk,全称为LowMemoryKiller(低内存杀手),lmkd来决定什么时间杀掉什么进程。

系统根据进程的组件状态来决定每个进程的优先级值oom_adj,oom_adj 是 lmkd 内部定义的一个变量,其余oom_adj 存在一个映射关系,Android 7.0之前的版本,oom_score_adj= oom_adj * 1000/17; 而Android 7.0开始,oom_score_adj= oom_adj,不用再经过一次转换。

lmkd 主要是通过进程的oom_score_adj来判定进程的重要程度,其会按照oom_score_adj由大到小的顺序 杀死进程,依此类推,以回收预期的可用系统资源,从而保证系统正常运转。

1.2  ADJ 级别

ADJ级别取值含义
NATIVE_ADJ-1000native进程
SYSTEM_ADJ-900仅指system_server进程
PERSISTENT_PROC_ADJ-800系统persistent进程
PERSISTENT_SERVICE_ADJ-700关联着系统或persistent进程
FOREGROUND_APP_ADJ0前台进程
VISIBLE_APP_ADJ100可见进程
PERCEPTIBLE_APP_ADJ200可感知进程,比如后台音乐播放
BACKUP_APP_ADJ300备份进程
HEAVY_WEIGHT_APP_ADJ400重量级进程
SERVICE_ADJ500服务进程
HOME_APP_ADJ600Home进程
PREVIOUS_APP_ADJ700上一个进程
SERVICE_B_ADJ800B List中的Service
CACHED_APP_MIN_ADJ900不可见进程的adj最小值
CACHED_APP_MAX_ADJ906不可见进程的adj最大值

从Android 7.0开始,ADJ采用100、200、300;在这之前的版本ADJ采用数字1、2、3,这样的调整可以更进一步地细化进程的优先级,比如在VISIBLE_APP_ADJ(100)与PERCEPTIBLE_APP_ADJ(200)之间,可以有ADJ=101、102级别的进程。

A-Service与B-Service的划分

        所有启动了服务的进程,且该服务所在的进程没有显示过UI,且该服务未执行startForeground(执行后会变为perveptible服务)动作,那该进程则为A-Service与B-Service中的一种。然后根据这类服务进程所处于Lru进程表中的位置,前1/3点服务为A-Service,其余的则为B-Service。

perceptible的标准

        perceptible名为可感知的进程,但并不是说能够感知到进程就一定表示该进程属于perveptible进程,比如播放音乐的进程活着状态栏上有通知的进程,虽然能够感知到进程的存在,但是不代表进程一定时perceptible类别的进程。决定该进程是否属于perceptible进程并未进程的可感知性,而是该进程的服务是否执行了startForeground动作。 

1.3  computeOomAdjLocked

第一部分

 private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
                                          boolean doingAll, long now) {
//        updateOomAdjLocked函数每次更新oom_adj时,都会分配一个序号
        //此处就是根据序号判断是否已经处理过命令
        if (mAdjSeq == app.adjSeq) {
            // This adjustment has already been computed.
            return app.curRawAdj;
        }
        //设置empty进程adj
        if (app.thread == null) {
            app.adjSeq = mAdjSeq;
            app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
            //空进程
            app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
            return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
        }

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

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

     
        //初始化ProcessRecord maxAdjUNKNOWN_ADJ,//maxAdj取值为UNKNOWN_ADJ,即最大的1001
        //但是应该是只有系统进程才有可能进入这个分支。系统进程走完这个分支就返回了
        if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
            //adjType 跟cpu的调度权限有关系
            app.adjType = "fixed";
            app.adjSeq = mAdjSeq;
            app.curRawAdj = app.maxAdj;
            app.foregroundActivities = false;
            app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
            app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
            //
            // System processes can do UI, and when they do we want to have
            // them trim their memory after the user leaves the UI.  To
            // facilitate this, here we need to determine whether or not it
            // is currently showing UI.
            app.systemNoUi = true;
            if (app == TOP_APP) {
                app.systemNoUi = false;
            } else if (activitiesSize > 0) {
                for (int j = 0; j < activitiesSize; j++) {
                    final ActivityRecord r = app.activities.get(j);
                    if (r.visible) {
                        app.systemNoUi = false;
                    }
                }
            }
            if (!app.systemNoUi) {
                //系统进程有ui的时候
                app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
            }
            //
            return (app.curAdj=app.maxAdj);
        }

        app.systemNoUi = false;
     //xxx
}

第一部分主要是更新了empty 进程与系统进程的curProcState。

第二部分

        // Determine the importance of the process, starting with most
        // important to least, and assign an appropriate OOM adjustment.
        int adj;
        int schedGroup;
        int procState;
        boolean foregroundActivities = false;
        BroadcastQueue queue;
        if (app == TOP_APP) {
            //若进程包含正在前台显示的Activity
            adj = ProcessList.FOREGROUND_APP_ADJ;
            //
            schedGroup = Process.THREAD_GROUP_DEFAULT;
            app.adjType = "top-activity";
            foregroundActivities = true;
            procState = ActivityManager.PROCESS_STATE_TOP;
        } else if (app.instrumentationClass != null) {
            // Don't want to kill running instrumentation.
            adj = ProcessList.FOREGROUND_APP_ADJ;
            schedGroup = Process.THREAD_GROUP_DEFAULT;
            app.adjType = "instrumentation";
            procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
        } else if ((queue = isReceivingBroadcast(app)) != null) {
            // An app that is currently receiving a broadcast also
            // counts as being in the foreground for OOM killer purposes.
            // It's placed in a sched group based on the nature of the
            // broadcast as reflected by which queue it's active in.
            adj = ProcessList.FOREGROUND_APP_ADJ;
            schedGroup = (queue == mFgBroadcastQueue)
                    ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
            app.adjType = "broadcast";
            procState = ActivityManager.PROCESS_STATE_RECEIVER;
        } else if (app.executingServices.size() > 0) {
            // An app that is currently executing a service callback also
            // counts as being in the foreground.
            adj = ProcessList.FOREGROUND_APP_ADJ;
            schedGroup = app.execServicesFg ?
                    Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
            app.adjType = "exec-service";
            procState = ActivityManager.PROCESS_STATE_SERVICE;
            //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
        } else {
            // As far as we know the process is empty.  We may change our mind later.
            schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
            // At this point we don't actually know the adjustment.  Use the cached adj
            // value that the caller wants us to.
            //这一句很重要,除了上面几种情形,先设置adj为cacheAdj,也即是UNKNOWN_ADJ
            adj = cachedAdj;
            //表明此时进程处于后台
            procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
            app.cached = true;
            app.empty = true;
            app.adjType = "cch-empty";
        }
上述几个分支除了最后的else 分支其余的adj都是FOREGROUND_APP_ADJ,但是schedGroup与procState 不同,也就是cpu资源调度是不一样的。

当进程正在显示或者正在测试或者正在执行Service 或者正在执行Receiver的时候此时设置adj 为FOREGROUND_APP_ADJ。FOREGROUND_APP_ADJ 实际是0,比他小的都是adj一般表示的都是系统进程,因此FOREGROUND_APP_ADJ 可以看成是普通用户可以使用的最高的adj,用于这个adj的进程内存几乎不会被回收。

最后的else 分支是将先将adj 设置为cachedAdj,此处cachedAdj 为UNKNOWN_ADJ,实际就是在后面再根据情况决定adj的值为多少。如果computeOomAdjLocked 执行完了,这个进程的adj 还是UNKNOWN_ADJ,此时会在updateOomAdjLocked 方法中将adj 设置为ProcessList.CACHED_APP_MIN_ADJ到ProcessList.CACHED_APP_MAX_ADJ之间的某一个值。详情参见上一篇文章。

第三部分

        //第三部分处理包含Activity的进程时
        // //依次轮询进程中的Activity,app的adj会由
        if (!foregroundActivities && activitiesSize > 0) {
            for (int j = 0; j < activitiesSize; j++) {
                final ActivityRecord r = app.activities.get(j);
                if (r.app != app) {
                    continue;
                }
                //如果进程包含可见Activity,即该进程是个可见进程,
                if (r.visible) {
                    //更新状态,原因是在for循环里面可能先走了后面的分支,然后再进入了本分支
                    //这样最终进程的adj就由最重要的activity的状态决定了。
                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
                        //adj大于VISIBLE_APP_ADJ时,才更新对应的adj
                        //之前提到的正在处理广播、服务或测试的进程(也就是第一部分),adj为FOREGROUND,是小于VISIBLE_APP_ADJ
                        //因此不会在此更新,
                        adj = ProcessList.VISIBLE_APP_ADJ;
                        app.adjType = "visible";
                    }
                    if (procState > ActivityManager.PROCESS_STATE_TOP) {
                        procState = ActivityManager.PROCESS_STATE_TOP;
                    }
                    //正在处理广播、服务或测试的进程,如果它们的调度策略为BACKGROUND
                    //但又包含了可见Activity时,调度策略变更为DEFAULT
                    schedGroup = Process.THREAD_GROUP_DEFAULT;
                    app.cached = false;
                    app.empty = false;
                    foregroundActivities = true;
                    //注意break了
                    //发现可见Activity时,直接可以结束循环
                    break;
                } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
                    //如果进程包含处于PAUSING或PAUSED状态的Activity时
                    //将其oom_adj调整为“用户可察觉”的的等级,这个等级还是很高的
                    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                        adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                        app.adjType = "pausing";
                    }
                    if (procState > ActivityManager.PROCESS_STATE_TOP) {
                        procState = ActivityManager.PROCESS_STATE_TOP;
                    }
                    schedGroup = Process.THREAD_GROUP_DEFAULT;
                    app.cached = false;
                    app.empty = false;
                    foregroundActivities = true;
                    //注意并不会break
                } else if (r.state == ActivityState.STOPPING) {
                    //包含处于Stopping状态Activity的进程,其oom_adj也被置为PERCEPTIBLE_APP_ADJ
                    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                        adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                        app.adjType = "stopping";
                    }
                    if (!r.finishing) {
                        if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
                            procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
                        }
                    }
                    app.cached = false;
                    app.empty = false;
                    foregroundActivities = true;
                } else {
                    //只是含有cached-activity的进程,仅调整procState
                    if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
                        procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
                        app.adjType = "cch-act";
                    }
                }
            }
        }

这一部分主要是遍历进程当中的所有页面,每一个页面都有一个adj,而最终进程的adj 选取其中最小的值。例如一个进程有一个可见页面有一个正在执行onPause 的页面,那么进程的adj 是ProcessList.VISIBLE_APP_ADJ,再比例进程有一个正在执行onPause的页面以及一个正在执行onStop 的页面,此时进程的adj 是ProcessList.PERCEPTIBLE_APP_ADJ。

如果没有可见页面,也不是正在执行onPause 以及onStop 的页面,就是已经处于后台的将进程,,此时adj 为cacheAdj。  参见第二部的else 分支。

第四部分

        //第四部分主要用于处理一些特殊的进程。
        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
            //进程包含前台服务或被强制在前台运行时
            //oom_adj被调整为PERCEPTIBLE_APP_ADJ,只是procState略有不同
            if (app.foregroundServices) {
                // 当前进程包含前台服务
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
                app.cached = false;
                app.adjType = "fg-service";
                schedGroup = Process.THREAD_GROUP_DEFAULT;
            } else if (app.forcingToForeground != null) {
                //例如当前进程正在弹出一个Toast。(是否可以使用定时Toast来保活)
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
                app.cached = false;
                app.adjType = "force-fg";
                app.adjSource = app.forcingToForeground;
                schedGroup = Process.THREAD_GROUP_DEFAULT;
            }
        }
        ///AMS的HeavyWeight进程单独处理
        if (app == mHeavyWeightProcess) {
     
            if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                // We don't want to kill the current heavy-weight process.
                adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
                app.cached = false;
                app.adjType = "heavy";
            }
            if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
                procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
            }
        }

        //home进程特殊处理
        if (app == mHomeProcess) {
            if (adj > ProcessList.HOME_APP_ADJ) {
                adj = ProcessList.HOME_APP_ADJ;
                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
                app.cached = false;
                app.adjType = "home";
            }
            if (procState > ActivityManager.PROCESS_STATE_HOME) {
                procState = ActivityManager.PROCESS_STATE_HOME;
            }
        }
        //前台进程之前的一个进程,也就是上次显示的进程
        if (app == mPreviousProcess && app.activities.size() > 0) {
            if (adj > ProcessList.PREVIOUS_APP_ADJ) {
                // This was the previous process that showed UI to the user.
                // We want to try to keep it around more aggressively, to give
                // a good experience around switching between two apps.
                adj = ProcessList.PREVIOUS_APP_ADJ;
                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
                app.cached = false;
                app.adjType = "previous";
            }
            if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
                procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
            }
        }

        if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
                + " reason=" + app.adjType);

        // By default, we use the computed adjustment.  It may be changed if
        // there are applications dependent on our services or providers, but
        // this gives us a baseline and makes sure we don't get into an
        // infinite recursion.
        app.adjSeq = mAdjSeq;
        app.curRawAdj = adj;
        app.hasStartedServices = false;
        //处理正在进行backup工作的进程
        if (mBackupTarget != null && app == mBackupTarget.app) {
            // If possible we want to avoid killing apps while they're being backed up
            if (adj > ProcessList.BACKUP_APP_ADJ) {
                if (DEBUG_BACKUP) Slog.v(TAG, "oom BACKUP_APP_ADJ for " + app);
                adj = ProcessList.BACKUP_APP_ADJ;
                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
                    procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
                }
                app.adjType = "backup";
                app.cached = false;
            }
            if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
                procState = ActivityManager.PROCESS_STATE_BACKUP;
            }
        }

这里以及前面三个部分在处理adj的时候都会先判断一下adj的大小,例如本部分的第一行

adj > ProcessList.PERCEPTIBLE_APP_ADJ。这里这句代码的主要作用是过滤掉前面已经设置了adj的进程。

因为computeOomAdjLocked 里面设置adj 是按照由小到大的顺序处理的,因此在前面部分被设置了某个非UNKNOWN_ADJ的值一般后续比较adj大于某个值的条件都不在处理。

这一部分主要处理了一些特殊的进程,如执行前台Service 的进程,桌面进程,前一次显示的进程等等。

第五部分

    boolean mayBeTop = false;
        for (int is = app.services.size()-1;
             is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                     || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
                     || procState > ActivityManager.PROCESS_STATE_TOP);
             is--) {
            ServiceRecord s = app.services.valueAt(is);
            //通过startService启动过Service
            if (s.startRequested) {
                app.hasStartedServices = true;
                if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
                    procState = ActivityManager.PROCESS_STATE_SERVICE;
                }
                //app之前启动过Activity
                if (app.hasShownUi && app != mHomeProcess) {
                    if (adj > ProcessList.SERVICE_ADJ) {
                        app.adjType = "cch-started-ui-services";
                    }
                } else {
                    //MAX_SERVICE_INACTIVITY为activity启动service后,系统最多保留Service的时间。
                    //没有启动过Activity,并且30分钟之内活跃过的服务进程
                    if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
                        if (adj > ProcessList.SERVICE_ADJ) {
                            //虽然处于后台,相当于提高了adj的级别,
                            //app.hasShownUi && app != mHomeProcess 这个分支内部内有提高adj级别
                            //说明一个纯粹的服务进程的优先级是高于既有ui又有服务的进程的
                            adj = ProcessList.SERVICE_ADJ;
                            app.adjType = "started-services";
                            app.cached = false;
                        }
                    }
                    //处理Service存在超时的情况,可见超时时也不会调整oom_adj
                    if (adj > ProcessList.SERVICE_ADJ) {
                        app.adjType = "cch-started-services";
                    }
                }
            }

           //bindService 启动的Service。
            for (int conni = s.connections.size()-1;
                 conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                         || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
                         || procState > ActivityManager.PROCESS_STATE_TOP);
                 conni--) {
                ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
                //多次调用bind多次调用bindService 绑定同一个Service,每次绑定的
                //参数可能不一样。

                          for (int i = 0;
                     i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
                             || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
                             || procState > ActivityManager.PROCESS_STATE_TOP);
                     i++) {
                    // XXX should compute this based on the max of
                    // all connected clients.
                    ConnectionRecord cr = clist.get(i);
                    if (cr.binding.client == app) {
                        // Binding to ourself is not interesting.
                        continue;
                    }

                    //bingService时添加了BIND_WAIVE_PRIORITY这个flag。
                    if ((cr.flags& Context.BIND_WAIVE_PRIORITY) == 0) {
                        // client 是调用bindService 的进程,也就是客户端。
                        ProcessRecord client = cr.binding.client;
                        //计算出客户端进程的oom_adj
                        //由此可看出Android oom_adj的计算多么麻烦
                        int clientAdj = computeOomAdjLocked(client, cachedAdj,
                                TOP_APP, doingAll, now);
                        int clientProcState = client.curProcState;
                        if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
                            // If the other app is cached for any reason, for purposes here
                            // we are going to consider it empty.  The specific cached state
                            // doesn't propagate except under certain conditions.
                            clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
                        }
                        String adjType = null;
                        //BIND_ALLOW_OOM_MANAGEMENT置为1时,先按照通常的处理方式,调整服务端进程的adjType
                        if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {

                            if (app.hasShownUi && app != mHomeProcess) {

                                if (adj > clientAdj) {
                                    adjType = "cch-bound-ui-services";
                                }
                                app.cached = false;
                                //当前进程展示过ui, 会将clientAdj修改为当前进程的adj,
                                clientAdj = adj;
                                clientProcState = procState;
                            } else {
                                if (now >= (s.lastActivity
                                        + ActiveServices.MAX_SERVICE_INACTIVITY)) {
                                    if (adj > clientAdj) {
                                        adjType = "cch-bound-services";
                                    }
                                    //服务已经好长时间没有执行过了,那么同样 会将clientAdj修改为当前进程的adj
                                    clientAdj = adj;
                                }
                                //若是距离服务上次活跃时间还没有超过30min,那么adj 放到后面修改
                            }
                        }
                        //当前进程优先级低于客户端
                        //adj>clientAdj 表明client此时可能是正在显示或是可见的页面,而当前进程是后台进程
                        if (adj > clientAdj) {
                            if (app.hasShownUi && app != mHomeProcess
                                    && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                adjType = "cch-bound-ui-services";
                            } else {
                                //这里主要是处理client 的adj 大于当前进程adj的情形。
                                //例如进程A 绑定了另一个进程B 内的一个Service。
                                //此时可能A进程为当前正在显示的进程而B 是一个后台进程。
                                //此时可以适当提高一个进程B的adj。
                                //例如B本来是CACHED_APP_MAX_ADJ但由于A 是可见进程,
                                //此时B 的adj 也会是可见进程。

                                //bindService 同时添加了BIND_ABOVE_CLIENT与BIND_IMPORTANT
                                if ((cr.flags&(Context.BIND_ABOVE_CLIENT
                                        |Context.BIND_IMPORTANT)) != 0) {
                                    //adj 最小取值是PERSISTENT_SERVICE_ADJ。
                                    adj = clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ
                                            ? clientAdj : ProcessList.PERSISTENT_SERVICE_ADJ;
                                } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
                                        && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
                                        && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                     //BIND_NOT_VISIBLE表示不将服务端当作visible进程看待
                                    adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                                } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
                                    //例如客户端是PERCEPTIBLE_APP_ADJ,这里一般也是提升
                                    //adj 的级别
                                    adj = clientAdj;
                                } else {
                                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
                                        adj = ProcessList.VISIBLE_APP_ADJ;
                                    }
                                }
                                if (!client.cached) {
                                    app.cached = false;
                                }
                                adjType = "service";
                            }
                        }
                        // adj <=clientAdj,例如客户端是后台进程,当前进程为正在显示的进程。
                        //
                        if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
                            //BIND_NOT_FOREGROUND表示系统将阻止驻留该服务的进程具有前台优先级
                            if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
                                schedGroup = Process.THREAD_GROUP_DEFAULT;
                            }
                            if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
                                if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
                                    // Special handling of clients who are in the top state.
                                    // We *may* want to consider this process to be in the
                                    // top state as well, but only if there is not another
                                    // reason for it to be running.  Being on the top is a
                                    // special state, meaning you are specifically running
                                    // for the current top app.  If the process is already
                                    // running in the background for some other reason, it
                                    // is more important to continue considering it to be
                                    // in the background state.
                                    mayBeTop = true;
                                    //降低clientProcState
                                    clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
                                } else {
                                    // Special handling for above-top states (persistent
                                    // processes).  These should not bring the current process
                                    // into the top state, since they are not on top.  Instead
                                    // give them the best state after that.
                                    //也是降低clientProcState
                                    clientProcState =
                                            ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
                                }
                            }
                        } else {
                            if (clientProcState <
                                    ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
                                clientProcState =
                                        ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
                            }
                        }
                        if (procState > clientProcState) {
                            procState = clientProcState;
                        }
                        if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
                                && (cr.flags&Context.BIND_SHOWING_UI) != 0) {
                            app.pendingUiClean = true;
                        }
                        if (adjType != null) {
                            app.adjType = adjType;
                            app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                                    .REASON_SERVICE_IN_USE;
                            app.adjSource = cr.binding.client;
                            app.adjSourceProcState = clientProcState;
                            app.adjTarget = s.name;
                        }
                    }
                    //看成是activity
                    if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                        app.treatLikeActivity = true;
                    }
                    // 根据当前进程activity来调整adj和schedGroup
                    final ActivityRecord a = cr.activity;
                    //a 非空表示Service 是从页面a 启动。
                    //&Context.BIND_ADJUST_WITH_ACTIVITY是指当从Activity绑定到该进程时,
                              // 允许目标服务进程根据该activity的可见性来提升优先级
                    if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
                        if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
                                (a.visible || a.state == ActivityState.RESUMED
                                        || a.state == ActivityState.PAUSING)) {
                            //提高服务进程的优先级
                            adj = ProcessList.FOREGROUND_APP_ADJ;
                            if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
                                schedGroup = Process.THREAD_GROUP_DEFAULT;
                            }
                            app.cached = false;
                            app.adjType = "service";
                            app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                                    .REASON_SERVICE_IN_USE;
                            app.adjSource = a;
                            app.adjSourceProcState = procState;
                            app.adjTarget = s.name;
                        }
                    }
                }
            }
        }

这里主要是处理进程内运行了Service的情况,根据Service的启动情形有分为两种情况。

通过startService启动:

        这里Service 所在进程没有启动父ui 并且服务在30分钟活跃过,那么adj 为ProcessList.SERVICE_ADJ,其余的情形的adj 依然是在前面设置的PROCESS_STATE_CACHED_ACTIVITY。换句话说一个Service 在一定时间不在运行之后就会无效。

通过bindService 启动:

       这里主要是根据bindService 提供的Flag 来适当的提高Service 进程的adj,使得服务进程的内存没有那么容易被回收。具体Flag 的意义大家可以查询相关资料。

假设一个进程既有activity 又有Service 那么该进程的adj 取何值?

该Service 是starService 且没有被bindService绑定过,同时进程内没有ContentProvider。

由上图可以看到当一个服务进程展示过ui的情况下会修改adjType,但是没有给adj 赋值,此时adj 依然是前面设置的UNKNOW_ADJ。

updateOomAdjLocked

updateOomAdjLocked 通过computeOomAdjLocked 修改进程的adj 之后会判断进程的adj是否大于等于UNKNOWN_ADJ, 一个有ui的Service 进程的adj 是UNKNOWN_ADJ,正好满足条件

之后进程app 的adj 会被设置为CACHED_APP_MIN_ADJ到CACHED_APP_MAX_ADJ 之间的某一个值。

一般启动了服务的进程往往是希望服务在后台能够执行某些任务,这样看是不希望这些服务因为进程被杀而过早的被终止的。正确的做法是,对于期望较长时间留在后台的服务,应该将服务运行在单独的进程里,即是UI进程与Servie进程分离,这样期望长时间留在后台的Serivce会获得较小的Adj值,而占有大量内存的UI进程则会分类为Cached(后台)进程,能够在需要的时候更快地被回收。

第六部分

省略,这一部分主要是根据ContentProivder 来设置adj,逻辑类似Service。

第七部分

        //第七部分
        if (mayBeTop && procState > ActivityManager.PROCESS_STATE_TOP) {
            // A client of one of our services or providers is in the top state.  We
            // *may* want to be in the top state, but not if we are already running in
            // the background for some other reason.  For the decision here, we are going
            // to pick out a few specific states that we want to remain in when a client
            // is top (states that tend to be longer-term) and otherwise allow it to go
            // to the top state.
            switch (procState) {
                case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
                case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
                case ActivityManager.PROCESS_STATE_SERVICE:
                    // These all are longer-term states, so pull them up to the top
                    // of the background states, but not all the way to the top state.
                    procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
                    break;
                default:
                    // Otherwise, top is a better choice, so take it.
                    procState = ActivityManager.PROCESS_STATE_TOP;
                    break;
            }
        }

        //
        if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
            if (app.hasClientActivities) {
                // This is a cached process, but with client activities.  Mark it so.
                procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
                app.adjType = "cch-client-act";
            } else if (app.treatLikeActivity) {
                // This is a cached process, but somebody wants us to treat it like it has
                // an activity, okay!
                // 将Service 看成是activity .
                procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
                app.adjType = "cch-as-act";
            }
        }


//        对Service进程做一些特殊处理
        if (adj == ProcessList.SERVICE_ADJ) {
            if (doingAll) {
                //每次updateOomAdj时,将mNewNumAServiceProcs置为0
                //然后LRU list中,从后往前数,前1/3的service进程就是AService
                //其余的就是bService
                //mNumServiceProcs为上一次update时,service进程的数量
                //mNewNumAServiceProcs 表示当前处理的第几个Service
                app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
                mNewNumServiceProcs++;
                //Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);
                if (!app.serviceb) {
                     // 如果不是bService,但内存回收等级过高,也被视为bService
                    if (mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
                            && app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {
                        app.serviceHighRam = true;
                        app.serviceb = true;
                        //Slog.i(TAG, "ADJ " + app + " high ram!");
                    } else {
                        mNewNumAServiceProcs++;
                        //Slog.i(TAG, "ADJ " + app + " not high ram!");
                    }
                } else {
                    app.serviceHighRam = false;
                }
            }
            if (app.serviceb) {
                //LRU中后1/3的Service,都是AService
                adj = ProcessList.SERVICE_B_ADJ;
            }
        }
        //计算完毕
        app.curRawAdj = adj;

        //if基本没有用,maxAdj已经是最大的UNKNOW_ADJ
        if (adj > app.maxAdj) {
            adj = app.maxAdj;
            if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
                schedGroup = Process.THREAD_GROUP_DEFAULT;
            }
        }

        //最后做一些记录和调整
        app.curAdj = app.modifyRawOomAdj(adj);
        app.curSchedGroup = schedGroup;
        app.curProcState = procState;
        app.foregroundActivities = foregroundActivities;

        return app.curRawAdj;

这一部分主要是根据前面计算修改一些进程的proState以及根据服务在进程列表的位置修改adj。

所有的进程保存在一个列表里面,从后往前数,前1/3的service进程就是AService

总结

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值