Android oom_adj update principle (2)

Source code based on: Android R

Continued from the previous article: Android oom_adj update principle (1)

12. computeOomAdjLocked()

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
            boolean computeClients) {
        // 每次updateOomAdjLocked() 调用都会有个 mAdjSeq序号,用以确认该进程是否已经处理
        if (mAdjSeq == app.adjSeq) {
            if (app.adjSeq == app.completedAdjSeq) { //是否已经完成
                // This adjustment has already been computed successfully.
                return false;
            } else { //如果没有完成,将进程 containsCycle置true
                // The process is being computed, so there is a cycle. We cannot
                // rely on this process's state.
                app.containsCycle = true;

                return false;
            }
        }

        // 进程的thread不存在,应该是个empty,初始化之后放回,adj 被设为CACHED_APP_MAX_ADJ
        if (app.thread == null) {
            app.adjSeq = mAdjSeq;
            app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND);
            app.setCurProcState(PROCESS_STATE_CACHED_EMPTY);
            app.curAdj = ProcessList.CACHED_APP_MAX_ADJ;
            app.setCurRawAdj(ProcessList.CACHED_APP_MAX_ADJ);
            app.completedAdjSeq = app.adjSeq;
            app.curCapability = PROCESS_CAPABILITY_NONE;
            return false;
        }

        // 如果不是 empty进程,进一步处理,相关的属性初始化
        app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
        app.adjSource = null;
        app.adjTarget = null;
        app.empty = false;
        app.setCached(false);
        app.shouldNotFreeze = false;

        final int appUid = app.info.uid;
        final int logUid = mService.mCurOomAdjUid;

        // 存放app 的当前adj,后面curAdj会变动
        int prevAppAdj = app.curAdj;
        int prevProcState = app.getCurProcState();
        int prevCapability = app.curCapability;

        // max adj 在0 以下的进程都是重要的系统进程(maxAdj初始化都为1001),
        // 这里的FOREGROUND_APP_ADJ = 0
        if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
            ...
            app.adjType = "fixed";
            app.adjSeq = mAdjSeq;
            app.setCurRawAdj(app.maxAdj);
            app.setHasForegroundActivities(false);
            app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
            app.curCapability = PROCESS_CAPABILITY_ALL;
            app.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 的,当离开UI之后系统想trim内存
            // 这里确定是否正在显示UI,默认值为true,即不显示UI
            app.systemNoUi = true;
            if (app == topApp) {  //如果进程就是topApp,那设置为false,正在显示UI
                app.systemNoUi = false;
                app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
                app.adjType = "pers-top-activity";
            } else if (app.hasTopUi()) {  //另外进程有处理TOP UI,该值也设为false
                // sched group/proc state adjustment is below
                app.systemNoUi = false;
                app.adjType = "pers-top-ui";
            } else if (app.getCachedHasVisibleActivities()) {
                app.systemNoUi = false;
            }

            // 如果该系统进程正在显示UI,调整proc_state
            if (!app.systemNoUi) {
                if (mService.mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
                    // 亮屏,提升proc_state至PERSISTENT_UI
                    app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
                    app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
                } else {
                    // 屏灭,控制UI schedule
                    app.setCurProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
                    app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
                }
            }

            // 设置当前 unlimit proc_state
            app.setCurRawProcState(app.getCurProcState());

            // adj 提升到最大,重要性下降
            app.curAdj = app.maxAdj;

            // 完成处理,将completedAdjSeq设置为当前进程 adjSeq
            app.completedAdjSeq = app.adjSeq;
            // if curAdj is less than prevAppAdj, then this process was promoted
            return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
        }

        // 对于maxAdj > 0 (即大于FOREGROUND_APP_ADJ)的进程继续下面的流程,
        // 默认将systemNoUi该值设为false
        app.systemNoUi = false;

        // 该变量用以获取系统top进程的 proc_state
        //   该变量只有两个值:PROCESS_STATE_TOP 和 PROCESS_STATE_TOP_SLEEPING
        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.
        int adj;
        int schedGroup;
        int procState;
        int cachedAdjSeq;
        int capability = 0;

        boolean foregroundActivities = false;

        // 根据不同场景设置前台进程的 adjType,并且更新adj、schedGroup、procState
        if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp) { //前台进程
            // The last app on the list is the foreground app.
            adj = ProcessList.FOREGROUND_APP_ADJ;
            schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
            app.adjType = "top-activity";
            foregroundActivities = true;
            procState = PROCESS_STATE_CUR_TOP;
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
            }
        } else if (app.runningRemoteAnimation) { //正在运行远程动画
            adj = ProcessList.VISIBLE_APP_ADJ;
            schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
            app.adjType = "running-remote-anim";
            procState = PROCESS_STATE_CUR_TOP;
            ...
        } else if (app.getActiveInstrumentation() != null) { //与测试相关的场景
            // Don't want to kill running instrumentation.
            adj = ProcessList.FOREGROUND_APP_ADJ;
            schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
            app.adjType = "instrumentation";
            procState = PROCESS_STATE_FOREGROUND_SERVICE;
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making instrumentation: " + app);
            }
        } else if (app.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) { //cache是否在接受广播
            //处于接受广播状态的进程站在OOM killer的目的,也被认为是前台进程
            adj = ProcessList.FOREGROUND_APP_ADJ;
            schedGroup = (mTmpBroadcastQueue.contains(mService.mFgBroadcastQueue))
                    ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
            app.adjType = "broadcast";
            procState = ActivityManager.PROCESS_STATE_RECEIVER;
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making broadcast: " + app);
            }
        } 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;
            app.adjType = "exec-service";
            procState = PROCESS_STATE_SERVICE;
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making exec-service: " + app);
            }
            //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
        } else if (app == topApp) { //topApp,此时PROCESS_STATE_CUR_TOP 处于SLEEPING
            adj = ProcessList.FOREGROUND_APP_ADJ;
            schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
            app.adjType = "top-sleeping";
            foregroundActivities = true;
            procState = PROCESS_STATE_CUR_TOP;
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top (sleeping): " + app);
            }
        } else { //empty进程
            // 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;
            procState = PROCESS_STATE_CACHED_EMPTY;
            if (!app.containsCycle) {
                app.setCached(true);
                app.empty = true;
                app.adjType = "cch-empty";
            }
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making empty: " + app);
            }
        }

        // foregroundActivities 这个变量记录是否已经是前台进程(app为topapp时为true)
        // 如果不是前台进程,且存在cache activities,则需要继续确定adj,重置adj 为cache
        if (!foregroundActivities && app.getCachedHasActivities()) {
            // mTmpComputeOomAdjWindowCallback计算adj时的window回调
            // computeOomAdjFromActivitiesIfNecessary判断是否执行过
            // 如果未执行过,则调用callback.initialize把adj/prostate存储
            // 然后判断是否visible(adj=VISIBLE_APP_ADJ)、
            //     paused/stop(adj=PERCEPTIBLE_APP_ADJ)、other(procState=PROCESS_STATE_CACHED_ACTIVITY)
            // 然后把adj/prostate赋值给app.mCachedAdj/app.mCachedProcState
            // 如果执行过,则上一次计算出来的值
            app.computeOomAdjFromActivitiesIfNecessary(mTmpComputeOomAdjWindowCallback,
                    adj, foregroundActivities, procState, schedGroup, appUid, logUid,
                    PROCESS_STATE_CUR_TOP);

            // // 如果进入cache的应用,这里adj会为1001,procstate为PROCESS_STATE_CACHED_ACTIVITY
            adj = app.mCachedAdj;
            foregroundActivities = app.mCachedForegroundActivities;
            procState = app.mCachedProcState;
            schedGroup = app.mCachedSchedGroup;
        }

        //带有recentTasks的cache;如果adj过大,回拉
        if (procState > PROCESS_STATE_CACHED_RECENT && app.getCachedHasRecentTasks()) {
            procState = PROCESS_STATE_CACHED_RECENT;
            app.adjType = "cch-rec";
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to cached recent: " + app);
            }
        }

        //重要性低于可感知进程且级别高于带前台service的处理
        //对于adj大于可感知进程,级别大于带service的前台进程,分带service和overlay UI分别处理,
        //adj都是perceptible,但级别不同
        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                || procState > PROCESS_STATE_FOREGROUND_SERVICE) {
            if (app.hasForegroundServices()) { //带前台service
                // The user is aware of this app, so make it visible.
                adj = ProcessList.PERCEPTIBLE_APP_ADJ; //adj任然设为PERCEPTIBLE_APP_ADJ
                procState = PROCESS_STATE_FOREGROUND_SERVICE; //procState不同
                app.adjType = "fg-service";
                app.setCached(false);
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                ...
            } else if (app.hasOverlayUi()) { //overlay UI
                // The process is display an overlay UI.
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                procState = PROCESS_STATE_IMPORTANT_FOREGROUND;
                app.setCached(false);
                app.adjType = "has-overlay-ui";
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                ...
            }
        }

        // 从前台进程切换到带前台service,允许保持15s的更高级别adj,保证其完成一些剩余操作
        if (app.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
                && (app.lastTopTime + mConstants.TOP_TO_FGS_GRACE_DURATION > now
                || app.setProcState <= PROCESS_STATE_TOP)) {
            adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ; //adj被设为了50
            app.adjType = "fg-service-act";
            ...
        }

        //adj大于可感知进程,级别大于后台进程
        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                || procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
            if (app.forcingToImportant != null) { //使进程变成更重要的标志
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                //级别降到PROCESS_STATE_TRANSIENT_BACKGROUND
                procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
                app.setCached(false);
                app.adjType = "force-imp";
                app.adjSource = app.forcingToImportant;
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to force imp: " + app);
                }
            }
        }

        //重量级后台进程,把adj和proc_state都拉回到 heavy weight水平
        if (app.getCachedIsHeavyWeight()) {
            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 = ProcessList.SCHED_GROUP_BACKGROUND;
                app.setCached(false);
                app.adjType = "heavy";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to heavy: " + app);
                }
            }
            if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
                procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
                app.adjType = "heavy";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to heavy: " + app);
                }
            }
        }

        //HOME 进程,将其拉回HOME_APP_ADJ
        if (app.getCachedIsHomeProcess()) {
            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 = ProcessList.HOME_APP_ADJ;
                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                app.setCached(false);
                app.adjType = "home";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to home: " + app);
                }
            }
            if (procState > ActivityManager.PROCESS_STATE_HOME) {
                procState = ActivityManager.PROCESS_STATE_HOME;
                app.adjType = "home";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to home: " + app);
                }
            }
        }

        //前一个进程仍然带有activity,或者20s内刚被使用的provider进程,设置为PREVIOUS_APP_ADJ
        if (app.getCachedIsPreviousProcess() && app.getCachedHasActivities()) {
            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 = ProcessList.SCHED_GROUP_BACKGROUND;
                app.setCached(false);
                app.adjType = "previous";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app);
                }
            }
            if (procState > PROCESS_STATE_LAST_ACTIVITY) {
                procState = PROCESS_STATE_LAST_ACTIVITY;
                app.adjType = "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=" + app.adjType);

        // 当进程有关联的services或providers,还需要根据services和providers继续更新adj
        if (cycleReEval) {
            procState = Math.min(procState, app.getCurRawProcState());
            adj = Math.min(adj, app.getCurRawAdj());
            schedGroup = Math.max(schedGroup, app.getCurrentSchedulingGroup());
        }
        //前面根据不同场景更新了adj,schedGroup,proc_state等,先暂时更新到processRecord app的参数里面
        app.setCurRawAdj(adj);
        app.setCurRawProcState(procState);

        app.hasStartedServices = false;
        app.adjSeq = mAdjSeq;

        //处理service中备份的进程
        final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
        if (backupTarget != null && app == backupTarget.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_BACKUP, "oom BACKUP_APP_ADJ for " + app);
                adj = ProcessList.BACKUP_APP_ADJ;
                if (procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
                    procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
                }
                app.adjType = "backup";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to backup: " + app);
                }
                app.setCached(false);
            }
            if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
                procState = ActivityManager.PROCESS_STATE_BACKUP;
                app.adjType = "backup";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to backup: " + app);
                }
            }
        }

        int capabilityFromFGS = 0; // capability from foreground service.

        /**************以下为service连接相关的处理逻辑***************/
        //遍历adj > 前台进程的进程中正在运行的service,根据这些service进一步更新当前app的adj
        for (int is = app.numberOfRunningServices() - 1;
                is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                        || procState > PROCESS_STATE_TOP);
                is--) {
            ServiceRecord s = app.getRunningServiceAt(is);
            if (s.startRequested) {
                // 如果服务启动,则处理procState最低为PROCESS_STATE_SERVICE
                app.hasStartedServices = true;
                if (procState > PROCESS_STATE_SERVICE) {
                    procState = PROCESS_STATE_SERVICE;
                    app.adjType = "started-services";
                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
                                "Raise procstate to started service: " + app);
                    }
                }

                //有显示的UI并且不是home,则标记cch-started-ui-services
                if (!s.mKeepWarming && app.hasShownUi && !app.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.
                    if (adj > ProcessList.SERVICE_ADJ) {
                        app.adjType = "cch-started-ui-services";
                    }
                } else {
                    // 如果上一次调用service的时间间隔超过30 min,则设置adj为SERVICE_ADJ
                    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.
                        if (adj > ProcessList.SERVICE_ADJ) {
                            adj = ProcessList.SERVICE_ADJ;
                            app.adjType = "started-services";
                            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                                reportOomAdjMessageLocked(TAG_OOM_ADJ,
                                        "Raise adj to started service: " + app);
                            }
                            app.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.
                    if (adj > ProcessList.SERVICE_ADJ) {
                        app.adjType = "cch-started-services";
                    }
                }
            }

            //service运行在前台,主要更新capabilityFromFGS
            if (s.isForeground) {
                final int fgsType = s.foregroundServiceType;
                if (s.mAllowWhileInUsePermissionInFgs) {
                    capabilityFromFGS |=
                            (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
                                    != 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;

                    boolean enabled = false;
                    try {
                        enabled = mPlatformCompat.isChangeEnabled(
                                CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, s.appInfo);
                    } catch (RemoteException e) {
                    }
                    if (enabled) {
                        capabilityFromFGS |=
                                (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA : 0;
                        capabilityFromFGS |=
                                (fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE)
                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE : 0;
                    } else {
                        capabilityFromFGS |= PROCESS_CAPABILITY_FOREGROUND_CAMERA
                                | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
                    }
                }
            }

             //该服务还被其他客户端连接时,遍历所有连接该service的客户端,对该服务进行adj计算
            ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections();
            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);
                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 cr = clist.get(i);
                    if (cr.binding.client == app) { //连接到自己,不处理
                        // Binding to oneself is not interesting.
                        continue;
                    }

                    boolean trackedProcState = false;

                    ProcessRecord client = cr.binding.client; //获取客户端的ProcessRecord
                    /传入的参数,是否计算客户端的adj, 如果更新所有进程,则为true
                    if (computeClients) {
                        computeOomAdjLocked(client, cachedAdj, topApp, doingAll, now,
                                cycleReEval, true);
                    } else {
                        client.setCurRawAdj(client.setAdj);
                        client.setCurRawProcState(client.setProcState);
                    }

                    int clientAdj = client.getCurRawAdj();
                    int clientProcState = client.getCurRawProcState();

                    // 假如不包含BIND_WAIVE_PRIORITY状态,即没有加入特殊标记不影响服务进程优先级
                    if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
                        if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
                            continue;
                        }

                        if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
                            capability |= client.curCapability;
                        }

                        // 如果客户端进程是cache,则认为是empty进程
                        if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
                            // If the other app is cached for any reason, for purposes here
                            // we are going to consider it empty.  The specific cached state
                            // doesn't propagate except under certain conditions.
                            clientProcState = PROCESS_STATE_CACHED_EMPTY;
                        }
                        String adjType = null;

                        // BIND_ALLOW_OOM_MANAGEMENT代表保持服务受默认的服务管理器管理,
                        //    当内存不足时候,会销毁服务
                        if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
                            // Not doing bind OOM management, so treat
                            // this guy more like a started service.
                            if (app.hasShownUi && !app.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.
                                if (adj > clientAdj) {
                                    adjType = "cch-bound-ui-services";
                                }
                                app.setCached(false);
                                clientAdj = adj;
                                clientProcState = procState;
                            } else {
                                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.
                                    if (adj > clientAdj) {
                                        adjType = "cch-bound-services";
                                    }
                                    clientAdj = adj;
                                }
                            }
                        }

                        // 假如服务进程的优先级小于客户端进程,则提升优先级
                        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.
                            // 如果当前进程有activity,但是与他关联的进程大于可感知状态
                            if (app.hasShownUi && !app.getCachedIsHomeProcess()
                                    && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
                                    adjType = "cch-bound-ui-services";
                                }
                            } else {
                                int newAdj;
                                // BIND_ABOVE_CLIENT表明service比连接他的客户端更重要,
                                //    则客户端进程adj赋值给当前进程
                                // BIND_IMPORTANT 标识服务对客户端是非常重要的
                                if ((cr.flags&(Context.BIND_ABOVE_CLIENT
                                        |Context.BIND_IMPORTANT)) != 0) {
                                    // clientAdj 一般是大于PERSISTENT_SERVICE_ADJ的,
                                    //    所以直接采用客户端adj
                                    if (clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
                                        newAdj = clientAdj;
                                    } else { //persistent进程
                                        // make this service persistent
                                        newAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
                                        schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                                        procState = ActivityManager.PROCESS_STATE_PERSISTENT;
                                        cr.trackProcState(procState, mAdjSeq, now);
                                        trackedProcState = true;
                                    }
                                } else if ((cr.flags & Context.BIND_NOT_PERCEPTIBLE) != 0
                                        && clientAdj <= ProcessList.PERCEPTIBLE_APP_ADJ
                                        && adj >= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
                                    // 不是可感知服务,但是adj优先级大于等于可感知,
                                    //    则设置newadj为250
                                    newAdj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
                                } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
                                        && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
                                        && adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
                                    //  假如绑定服务状态BIND_NOT_VISIBLE,则设置200
                                    newAdj = ProcessList.PERCEPTIBLE_APP_ADJ;
                                } else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
                                    newAdj = clientAdj;
                                } else {
                                    // 假如clientadj<PERCEPTIBLE_APP_ADJ,
                                    //     则设置为VISIBLE_APP_ADJ
                                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
                                        // TODO: Is this too limiting for apps bound from TOP?
                                        newAdj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
                                    } else {
                                        newAdj = adj;
                                    }
                                }
                                if (!client.isCached()) {
                                    app.setCached(false);
                                }
                                if (adj >  newAdj) {
                                    adj = newAdj;
                                    app.setCurRawAdj(adj);
                                    adjType = "service";
                                }
                            }
                        }

                        // 根据后台情况,处理clientProcState,
                        //    然后赋值给当前ProcessRecord的adjSourceProcState
                        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.
                            final int curSchedGroup = client.getCurrentSchedulingGroup();
                            if (curSchedGroup > schedGroup) {
                                if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
                                    schedGroup = curSchedGroup;
                                } else {
                                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                                }
                            }
                            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.
                                if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
                                    clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;                                                                                                                       ;
                                } else if (mService.mWakefulness
                                        == PowerManagerInternal.WAKEFULNESS_AWAKE
                                        && (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
                                                != 0) {
                                    clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
                                } else {
                                    clientProcState =
                                            PROCESS_STATE_IMPORTANT_FOREGROUND;
                                }
                            } 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;
                                boolean enabled = false;
                                try {
                                    enabled = mPlatformCompat.isChangeEnabled(
                                            PROCESS_CAPABILITY_CHANGE_ID, client.info);
                                } catch (RemoteException e) {
                                }
                                if (enabled) {
                                    if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
                                        // TOP process passes all capabilities to the service.
                                        capability |= PROCESS_CAPABILITY_ALL;
                                    } else {
                                        // TOP process passes no capability to the service.
                                    }
                                } else {
                                    // TOP process passes all capabilities to the service.
                                    capability |= PROCESS_CAPABILITY_ALL;
                                }
                            }
                        } else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
                            if (clientProcState <
                                    PROCESS_STATE_TRANSIENT_BACKGROUND) {
                                clientProcState =
                                        PROCESS_STATE_TRANSIENT_BACKGROUND;
                            }
                        } else {
                            if (clientProcState <
                                    PROCESS_STATE_IMPORTANT_BACKGROUND) {
                                clientProcState =
                                        PROCESS_STATE_IMPORTANT_BACKGROUND;
                            }
                        }

                        if (schedGroup < ProcessList.SCHED_GROUP_TOP_APP
                                && (cr.flags & Context.BIND_SCHEDULE_LIKE_TOP_APP) != 0) {
                            schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
                        }

                        if (!trackedProcState) {
                            cr.trackProcState(clientProcState, mAdjSeq, now);
                        }

                        if (procState > clientProcState) {
                            procState = clientProcState;
                            app.setCurRawProcState(procState);
                            if (adjType == null) {
                                adjType = "service";
                            }
                        }
                        if (procState < PROCESS_STATE_IMPORTANT_BACKGROUND
                                && (cr.flags & Context.BIND_SHOWING_UI) != 0) {
                            app.setPendingUiClean(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.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));
                            }
                        }
                    } else { // BIND_WAIVE_PRIORITY == true
                        // 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.
                        if (clientAdj < ProcessList.CACHED_APP_MIN_ADJ) {
                            app.shouldNotFreeze = true;
                        }
                    }
                    if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                        app.treatLikeActivity = true;
                    }

                    // 假如客户端进程的activity可见,
                    //   则提升当前ProcessRecord的adj为FOREGROUND_APP_ADJ
                    final ActivityServiceConnectionsHolder a = cr.activity;
                    if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
                        if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ
                                && a.isActivityVisible()) {
                            adj = ProcessList.FOREGROUND_APP_ADJ;
                            app.setCurRawAdj(adj);
                            if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
                                if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
                                    schedGroup = ProcessList.SCHED_GROUP_TOP_APP_BOUND;
                                } else {
                                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                                }
                            }
                            app.setCached(false);
                            app.adjType = "service";
                            app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                                    .REASON_SERVICE_IN_USE;
                            app.adjSource = a;
                            app.adjSourceProcState = procState;
                            app.adjTarget = s.instanceName;
                            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                                reportOomAdjMessageLocked(TAG_OOM_ADJ,
                                        "Raise to service w/activity: " + app);
                            }
                        }
                    }
                }
            }
        }

        /**************provider相关的处理*****************/
        //根据provider客户端的状态确定当前app的 adj,scheduleGroup 和 ProcState
        //遍历与当前进程相关的所有provider
        for (int provi = app.pubProviders.size() - 1;
                provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                        || procState > PROCESS_STATE_TOP);
                provi--) {
            ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
            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 conn = cpr.connections.get(i);
                ProcessRecord client = conn.client;
                if (client == app) {
                    // Being our own client is not interesting.
                    continue;
                }
                if (computeClients) {
                    computeOomAdjLocked(client, cachedAdj, topApp, doingAll, now, cycleReEval,
                            true);
                } else {
                    client.setCurRawAdj(client.setAdj);
                    client.setCurRawProcState(client.setProcState);
                }

                if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
                    continue;
                }

                int clientAdj = client.getCurRawAdj();
                int clientProcState = client.getCurRawProcState();

                if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
                    // If the other app is cached for any reason, for purposes here
                    // we are going to consider it empty.
                    clientProcState = PROCESS_STATE_CACHED_EMPTY;
                }
                String adjType = null;
                if (adj > clientAdj) {
                    if (app.hasShownUi && !app.getCachedIsHomeProcess()
                            && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                        adjType = "cch-ui-provider";
                    } else {
                        adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
                                ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
                        app.setCurRawAdj(adj);
                        adjType = "provider";
                    }
                    app.setCached(app.isCached() & client.isCached());
                }

                if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) {
                    if (adjType == null) {
                        adjType = "provider";
                    }
                    if (clientProcState == PROCESS_STATE_TOP) {
                        clientProcState = PROCESS_STATE_BOUND_TOP;
                    } else {
                        clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
                    }
                }

                conn.trackProcState(clientProcState, mAdjSeq, now);
                if (procState > clientProcState) {
                    procState = clientProcState;
                    app.setCurRawProcState(procState);
                }
                if (client.getCurrentSchedulingGroup() > schedGroup) {
                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                }
                if (adjType != null) {
                    app.adjType = adjType;
                    app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                            .REASON_PROVIDER_IN_USE;
                    app.adjSource = client;
                    app.adjSourceProcState = clientProcState;
                    app.adjTarget = cpr.name;
                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                        reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
                                + ": " + app + ", due to " + client
                                + " adj=" + adj + " procState="
                                + ProcessList.makeProcStateString(procState));
                    }
                }
            }

            //provider有非framework层的外部进程依赖,保证其adj不高于前台进程
            if (cpr.hasExternalProcessHandles()) {
                if (adj > ProcessList.FOREGROUND_APP_ADJ) {
                    adj = ProcessList.FOREGROUND_APP_ADJ;
                    app.setCurRawAdj(adj);
                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                    app.setCached(false);
                    app.adjType = "ext-provider";
                    app.adjTarget = cpr.name;
                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
                                "Raise adj to external provider: " + app);
                    }
                }
                if (procState > PROCESS_STATE_IMPORTANT_FOREGROUND) {
                    procState = PROCESS_STATE_IMPORTANT_FOREGROUND;
                    app.setCurRawProcState(procState);
                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
                                "Raise procstate to external provider: " + app);
                    }
                }
            }
        }


        /**************收尾工作,有些数据需要特殊限制*****************/
        //当一个进程20s前带有contentProvider,不会把他降到LRU list,避免provider进程陷入低内存状态
        if (app.lastProviderTime > 0 &&
                (app.lastProviderTime + mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) {
            if (adj > ProcessList.PREVIOUS_APP_ADJ) {
                adj = ProcessList.PREVIOUS_APP_ADJ;
                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                app.setCached(false);
                app.adjType = "recent-provider";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
                            "Raise adj to recent provider: " + app);
                }
            }
            if (procState > PROCESS_STATE_LAST_ACTIVITY) {
                procState = PROCESS_STATE_LAST_ACTIVITY;
                app.adjType = "recent-provider";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
                            "Raise procstate to recent provider: " + app);
                }
            }
        }

        //对cache进程进一步细分
        if (procState >= PROCESS_STATE_CACHED_EMPTY) {
            if (app.hasClientActivities()) {
                // This is a cached process, but with client activities.  Mark it so.
                procState = 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!
                procState = PROCESS_STATE_CACHED_ACTIVITY;
                app.adjType = "cch-as-act";
            }
        }

        //由adj判断是服务进程
        if (adj == ProcessList.SERVICE_ADJ) {
            //doingAll:传入的参数,只有一参的时候传入为true,其他二参、三参、五参都为false
            // cycleReEval:传入的参数,只有一参的时候为true,其他为false
            if (doingAll && !cycleReEval) {
                //当A类Service个数 > service/3时,则加入到B类Service
                app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
                mNewNumServiceProcs++;
                //Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);
                if (!app.serviceb) { //不在service b list中
                    //当对于低RAM设备,则把该service直接放入B类Service
                    if (mService.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 { //在service b list中
                    app.serviceHighRam = false;
                }
            }
            if (app.serviceb) {
                adj = ProcessList.SERVICE_B_ADJ;
            }
        }

        app.setCurRawAdj(adj);

        //进一步计算之后的adj情况,可以选择打印
        //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
        //      " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);

        //计算好的adj不能超过maxAdj
        if (adj > app.maxAdj) {
            adj = app.maxAdj;
            if (app.maxAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
            }
        }

        // Put bound foreground services in a special sched group for additional
        // restrictions on screen off
        if (procState >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
                && mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE) {
            if (schedGroup > ProcessList.SCHED_GROUP_RESTRICTED) {
                schedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
            }
        }

        // apply capability from FGS.
        if (app.hasForegroundServices()) {
            capability |= capabilityFromFGS;
        }

        capability |= getDefaultCapability(app, procState);

        // 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.
        app.curAdj = app.modifyRawOomAdj(adj);
        app.curCapability = capability;
        app.setCurrentSchedulingGroup(schedGroup);
        app.setCurProcState(procState);
        app.setCurRawProcState(procState);
        app.setHasForegroundActivities(foregroundActivities);
        app.completedAdjSeq = mAdjSeq;

        // if curAdj or curProcState improved, then this process was promoted
        return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState
                || app.curCapability != prevCapability ;
    }

A function is almost 1,000 lines of code . It is indeed very tiring to analyze. There is a lot of logic in it. The general logic is as follows:

  • Use mAdjSeq to confirm whether this calculation is necessary and whether it has been calculated;
  • Determine whether it is an empty process;
  • When maxAdj<=FOREGROUND_APP_ADJ (all important system processes) set adj, procState, etc. according to whether the system UI is displayed, whether it is TOPAPP, etc., and then return;
  • Foreground process related processing, set the foreground process adj, adjType, procState, schedGroup according to different scenarios (remote animation, receiving broadcasts, running services, etc.);
  • If it is not a foreground process, but cache activities exist, determine the process cachedj, etc. through computeOomAdjFromActivitiesIfNecessary();
  • Determine the approximate adj value based on whether adj is greater than PERCEPTIBLE_APP_ADJ, HEAVY_WEIGHT_APP_ADJ, HOME_APP_ADJ, PREVIOUS_APP_ADJ, etc., and further confirm the adj equivalent value based on the specific running status of the activity;
  • Confirm whether it is a backup process;
  • Traverse all services running on the process, and correct the adj equivalent value of the current process according to the running status of the service. It is also possible to traverse all clients that reference the service and further calculate the adj values ​​of these clients;
  • Same as service, traverse the providers associated with the process, and further modify the adj value according to the providers and the client;
  • Closing, further confirmation:
    • When a process has a contentProvider 20 seconds ago, it will not be demoted to the LRU list to prevent the provider process from falling into a low memory state;
    • When procState >= PROCESS_STATE_CACHED_EMPTY, further adjust procState and adjType;
    • When adj==SERVICE_ADJ, confirm whether it is in serviceb. If it is adj, change it to SERVICE_B_ADJ;
    • Confirmation of other restrictions;

Here is a simple flow chart to make it easier to remember:

12.1 bind type

binder type illustrate
BIND_WAIVE_PRIORITY It will not affect the process priority of the service. The service is placed in an LRU table like a general application process.
BIND_TREAT_LIKE_ACTIVITY Binding is regarded as holding an activity, and unbinding is regarded as the activity in the background. This is usually used in the input method process to switch keyboards more quickly.
BIND_ALLOW_OOM_MANAGEMENT Keep the service managed by the default service manager. When there is insufficient memory, the service will be destroyed.
BIND_ABOVE_CLIENT Set the process priority of the service to be higher than the priority of the client. This is only done when the service needs to be destroyed later than the client.
BIND_IMPORTANT Identifying the service is very important to the client and will promote the service to the foreground process priority. Normally, even if the client is the foreground priority, the service can only be promoted to the visible process priority at most.
BIND_NOT_FOREGROUND The bound service will not be promoted to the foreground priority, but the service will have at least the same priority in memory as the client.
BIND_SCHEDULE_LIKE_TOP_APP This flag is only used by the system to adjust the scheduling policy of the IME (and any out-of-process user-visible components that work closely with the top application). Therefore, the UI hosting such services can have the same scheduling strategy as the top app. Restricted to system calls only, otherwise a safe exception will be thrown
BIND_ADJUST_WITH_ACTIVITY The priority of Service will be relative to its bound Activity. If the Activity goes to the foreground, the Service priority will be relatively elevated. If the Activity goes to the background, the Servcie priority will be relatively reduced.
BIND_AUTO_CREATE When binding a service, if the service has not been created yet, the service will be created automatically.

13. ApplyOomAdjLocked()

    private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
            long nowElapsed) {
        boolean success = true;

        // setAdj 上次设置的adj
        // curAdj 当前的adj
        // setRawAdj 上一次设置的 unlimit adj
        // curRawAdj 当前unlimit adj

        if (app.getCurRawAdj() != app.setRawAdj) {
            app.setRawAdj = app.getCurRawAdj();
        }

        int changes = 0;

        // 在bootup 阶段不压缩
        // useCompaction() 是app compact是否使能
        if (mCachedAppOptimizer.useCompaction() && mService.mBooted) {
            // 如果跟上次的adj 不一样,有变化
            if (app.curAdj != app.setAdj) {
                // 当app从perceptible变为home/previous,执行some等级内存压缩
                // 当app变成cached,执行full等级内存压缩
                if (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ &&
                        (app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||
                                app.curAdj == ProcessList.HOME_APP_ADJ)) {
                    mCachedAppOptimizer.compactAppSome(app);
                } else if ((app.setAdj < ProcessList.CACHED_APP_MIN_ADJ
                                || app.setAdj > ProcessList.CACHED_APP_MAX_ADJ)
                        && app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ
                        && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) {
                    mCachedAppOptimizer.compactAppFull(app);
                }
            } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE  //非唤醒状态
                    && app.setAdj < ProcessList.FOREGROUND_APP_ADJ
                    && mCachedAppOptimizer.shouldCompactPersistent(app, now)) {
                //处于非唤醒状态,且上一次重要性高于前台进程adj,
                //  且上一次压缩的时间已经尝过10min或者上次没压缩都返回true,
                //  进行persistent 级别压缩
                mCachedAppOptimizer.compactAppPersistent(app);
            } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
                    && app.getCurProcState()
                        == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
                    && mCachedAppOptimizer.shouldCompactBFGS(app, now)) {
                // 非唤醒状态,且当前进程状态为绑定一个前台service进程
                //   且上一次压缩的时间已经超过10min或上一次没压缩都返回true
                mCachedAppOptimizer.compactAppBfgs(app);
            }
        }

        // 当 adj当前值与上一次不一致时,发生变化
        if (app.curAdj != app.setAdj) {
            // setOomAdj() 通知lmkd
            ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
            app.setAdj = app.curAdj;
            app.verifiedAdj = ProcessList.INVALID_ADJ;
            synchronized (mCachedAppOptimizer) {
                app.mSetAdjForCompact = app.setAdj;
            }
        }

        final int curSchedGroup = app.getCurrentSchedulingGroup();
        // schedGroup 发生了变化
        if (app.setSchedGroup != curSchedGroup) {
            int oldSchedGroup = app.setSchedGroup;
            app.setSchedGroup = curSchedGroup;

            //进程等待被kill,且当前进程关联的广播为空,
            //  且上一次设置的schedGroup为SCHED_GROUP_BACKGROUND,进行kill处理,
            //  且标记此次 applyOom 失败
            if (app.waitingToKill != null && app.curReceivers.isEmpty()
                    && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
                app.kill(app.waitingToKill, ApplicationExitInfo.REASON_USER_REQUESTED,
                        ApplicationExitInfo.SUBREASON_UNKNOWN, true);
                success = false;
            } else {
                int processGroup;
                switch (curSchedGroup) {
                    case ProcessList.SCHED_GROUP_BACKGROUND:
                        processGroup = THREAD_GROUP_BACKGROUND;
                        break;
                    case ProcessList.SCHED_GROUP_TOP_APP:
                    case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
                        processGroup = THREAD_GROUP_TOP_APP;
                        break;
                    case ProcessList.SCHED_GROUP_RESTRICTED:
                        processGroup = THREAD_GROUP_RESTRICTED;
                        break;
                    default:
                        processGroup = THREAD_GROUP_DEFAULT;
                        break;
                }
                mProcessGroupHandler.sendMessage(mProcessGroupHandler.obtainMessage(
                        0 /* unused */, app.pid, processGroup, app.processName));
                try {
                    if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                        // do nothing if we already switched to RT
                        if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
                            app.getWindowProcessController().onTopProcChanged();
                            if (mService.mUseFifoUiScheduling) {
                                // Switch UI pipeline for app to SCHED_FIFO
                                app.savedPriority = Process.getThreadPriority(app.pid);
                                mService.scheduleAsFifoPriority(app.pid, /* suppressLogs */true);
                                if (app.renderThreadTid != 0) {
                                    mService.scheduleAsFifoPriority(app.renderThreadTid,
                                            /* suppressLogs */true);
                                    if (DEBUG_OOM_ADJ) {
                                        Slog.d("UI_FIFO", "Set RenderThread (TID " +
                                                app.renderThreadTid + ") to FIFO");
                                    }
                                } else {
                                    if (DEBUG_OOM_ADJ) {
                                        Slog.d("UI_FIFO", "Not setting RenderThread TID");
                                    }
                                }
                            } else {
                                // Boost priority for top app UI and render threads
                                setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST);
                                if (app.renderThreadTid != 0) {
                                    try {
                                        setThreadPriority(app.renderThreadTid,
                                                TOP_APP_PRIORITY_BOOST);
                                    } catch (IllegalArgumentException e) {
                                        // thread died, ignore
                                    }
                                }
                            }
                        }
                    } else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
                            curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
                        app.getWindowProcessController().onTopProcChanged();
                        if (mService.mUseFifoUiScheduling) {
                            try {
                                // Reset UI pipeline to SCHED_OTHER
                                setThreadScheduler(app.pid, SCHED_OTHER, 0);
                                setThreadPriority(app.pid, app.savedPriority);
                                if (app.renderThreadTid != 0) {
                                    setThreadScheduler(app.renderThreadTid,
                                            SCHED_OTHER, 0);
                                }
                            } catch (IllegalArgumentException e) {
                                Slog.w(TAG,
                                        "Failed to set scheduling policy, thread does not exist:\n"
                                                + e);
                            } catch (SecurityException e) {
                                Slog.w(TAG, "Failed to set scheduling policy, not allowed:\n" + e);
                            }
                        } else {
                            // Reset priority for top app UI and render threads
                            setThreadPriority(app.pid, 0);
                        }

                        if (app.renderThreadTid != 0) {
                            setThreadPriority(app.renderThreadTid, THREAD_PRIORITY_DISPLAY);
                        }
                    }
                } catch (Exception e) {
                    if (DEBUG_ALL) {
                        Slog.w(TAG, "Failed setting thread priority of " + app.pid, e);
                    }
                }
            }
        }
        if (app.repForegroundActivities != app.hasForegroundActivities()) {
            app.repForegroundActivities = app.hasForegroundActivities();
            changes |= ActivityManagerService.ProcessChangeItem.CHANGE_ACTIVITIES;
        }

       // 更新app 的冻结状态
        updateAppFreezeStateLocked(app);

        // 如果进程状态发成变化,更新下进程状态
        if (app.getReportedProcState() != app.getCurProcState()) {
            app.setReportedProcState(app.getCurProcState());
            if (app.thread != null) {
                try {
                    if (false) {
                        //RuntimeException h = new RuntimeException("here");
                        Slog.i(TAG, "Sending new process state " + app.getReportedProcState()
                                + " to " + app /*, h*/);
                    }
                    app.thread.setProcessState(app.getReportedProcState());
                } catch (RemoteException e) {
                }
            }
        }

        // 执行pss统计操作,以及计算下一次pss的时间
        if (app.setProcState == PROCESS_STATE_NONEXISTENT
                || ProcessList.procStatesDifferForMem(app.getCurProcState(), app.setProcState)) {
            if (false && mService.mTestPssMode
                    && app.setProcState >= 0 && app.lastStateTime <= (now-200)) {
                // Experimental code to more aggressively collect pss while
                // running test...  the problem is that this tends to collect
                // the data right when a process is transitioning between process
                // states, which will tend to give noisy data.
                long start = SystemClock.uptimeMillis();
                long startTime = SystemClock.currentThreadTimeMillis();
                long pss = Debug.getPss(app.pid, mTmpLong, null);
                long endTime = SystemClock.currentThreadTimeMillis();
                mService.recordPssSampleLocked(app, app.getCurProcState(), pss,
                        mTmpLong[0], mTmpLong[1], mTmpLong[2],
                        ProcessStats.ADD_PSS_INTERNAL_SINGLE, endTime-startTime, now);
                mService.mPendingPssProcesses.remove(app);
                Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
                        + " to " + app.getCurProcState() + ": "
                        + (SystemClock.uptimeMillis()-start) + "ms");
            }
            app.lastStateTime = now;
            app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
                    app.procStateMemTracker, mService.mTestPssMode,
                    mService.mAtmInternal.isSleeping(), now);
            if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
                    + ProcessList.makeProcStateString(app.setProcState) + " to "
                    + ProcessList.makeProcStateString(app.getCurProcState()) + " next pss in "
                    + (app.nextPssTime-now) + ": " + app);
        } else {
            if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
                    && now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
                    mService.mTestPssMode)))) {
                if (mService.requestPssLocked(app, app.setProcState)) {
                    app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
                            app.procStateMemTracker, mService.mTestPssMode,
                            mService.mAtmInternal.isSleeping(), now);
                }
            } else if (false && DEBUG_PSS) {
                Slog.d(TAG_PSS,
                        "Not requesting pss of " + app + ": next=" + (app.nextPssTime-now));
            }
        }
        if (app.setProcState != app.getCurProcState()) {
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) {
                String msg = "Proc state change of " + app.processName
                        + " to " + ProcessList.makeProcStateString(app.getCurProcState())
                        + " (" + app.getCurProcState() + ")" + ": " + app.adjType;
                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
            }
            boolean setImportant = app.setProcState < PROCESS_STATE_SERVICE;
            boolean curImportant = app.getCurProcState() < PROCESS_STATE_SERVICE;
            if (setImportant && !curImportant) {
                // This app is no longer something we consider important enough to allow to use
                // arbitrary amounts of battery power. Note its current CPU time to later know to
                // kill it if it is not behaving well.
                app.setWhenUnimportant(now);
                app.lastCpuTime = 0;
            }
            // Inform UsageStats of important process state change
            // Must be called before updating setProcState
            maybeUpdateUsageStatsLocked(app, nowElapsed);

            maybeUpdateLastTopTime(app, now);

            app.setProcState = app.getCurProcState();
            if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
                app.notCachedSinceIdle = false;
            }
            if (!doingAll) {
                mService.setProcessTrackerStateLocked(app,
                        mService.mProcessStats.getMemFactorLocked(), now);
            } else {
                app.procStateChanged = true;
            }
        } else if (app.reportedInteraction && (nowElapsed - app.getInteractionEventTime())
                > mConstants.USAGE_STATS_INTERACTION_INTERVAL) {
            // For apps that sit around for a long time in the interactive state, we need
            // to report this at least once a day so they don't go idle.
            maybeUpdateUsageStatsLocked(app, nowElapsed);
        } else if (!app.reportedInteraction && (nowElapsed - app.getFgInteractionTime())
                > mConstants.SERVICE_USAGE_INTERACTION_TIME) {
            // For foreground services that sit around for a long time but are not interacted with.
            maybeUpdateUsageStatsLocked(app, nowElapsed);
        }

        if (app.curCapability != app.setCapability) {
            changes |= ActivityManagerService.ProcessChangeItem.CHANGE_CAPABILITY;
            app.setCapability = app.curCapability;
        }

        if (changes != 0) {
            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                    "Changes in " + app + ": " + changes);
            ActivityManagerService.ProcessChangeItem item =
                    mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
            item.changes |= changes;
            item.foregroundActivities = app.repForegroundActivities;
            item.capability = app.setCapability;
            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                    "Item " + Integer.toHexString(System.identityHashCode(item))
                            + " " + app.toShortString() + ": changes=" + item.changes
                            + " foreground=" + item.foregroundActivities
                            + " type=" + app.adjType + " source=" + app.adjSource
                            + " target=" + app.adjTarget + " capability=" + item.capability);
        }

        return success;
    }

It is another very long logical code. When analyzing a special class, it mainly goes through the following process:

  • When the boot is completed and app compaction is enabled, app compression confirmation will be performed. If the conditions are met, memory compression will be performed;
  • When the adj of the app changes, lmkd is notified through setOomAdj() (using socket communication method);
  • When schedGroup changes, the scheduler and priority of the process are updated, and will be killed in special cases;
  • Call the updateAppFreezeStateLocked() function to update the frozen state of the app;
  • Set the process state of the process;
  • Perform pss statistical operations and calculate the next pss time;

13.1 Framework scheduling strategy

Process priority level:

  • process.setThreadPriority(int tid, int priority);

Group priority:

  • setProcessGroup(int pid, int group);
  • setThreadGroup(int tid, int group);

Scheduler category:

  • setThreadScheduler(int tid, int policy, int prioriy);
process priority nice value illustrate
THREAD_PRIORITY_LOWEST 19 lowest priority
THREAD_PRIORITY_BACKGROUND 10 Backstage
THREAD_PRIORITY_LESS_FAVORABLE 1 Slightly lower than default
THREAD_PRIORITY_DEFAULT 0 default
THREAD_PRIORITY_MORE_FAVORABLE -1 Slightly higher than default
THREAD_PRIORITY_FOREGROUND -2 front desk
THREAD_PRIORITY_DISPLAY -4 Show related
THREAD_PRIORITY_URGENT_DISPLAY -8 Display (more important), input event
TOP_APP_PRIORITY_BOOST -10

The main thread and render thread boost priority of the foreground process

THREAD_PRIORITY_AUDIO -16 audio related
THREAD_PRIORITY_URGENT_AUDIO -19 Audio (more important)
Group priority value illustrate
THREAD_GROUP_DEFAULT -1 Only used with setProcessGroup, raises processes with priority <=10 to -2
THREAD_GROUP_BG_NONINTERACTIVE 0 CPU timesharing duration reduced
THREAD_GROUP_FOREGROUND 1 The duration of CPU time sharing is normal
THREAD_GROUP_SYSTEM 2 System thread group
THREAD_GROUP_AUDIO_APP 3 application audio
THREAD_GROUP_AUDIO_SYS 4 System program audio
scheduler name illustrate
SCHED_OTHER default Standard round-robin time sharing strategy
SCHED_BATCH batch scheduling Scheduling strategy for batch-style (batch) processes
SCHED_IDLE Idle scheduling For very low priority processes suitable for running in the background
SCHED_FIFO first in first out real-time scheduling strategy
SCHED_RR Round robin scheduling real-time scheduling strategy

13.2 updateLruProcessLocked()

There is an LRU list mProcessList in AMS. Every process started by AMS will be added to the LRU list for management. This LRU list is not randomly sorted or arranged according to the time of addition, but has a certain logic. Calculated and then changed according to the real-time dynamic status of each process.

The definition of the mProcessList LRU list is actually ultimately in ProcessList.java. AMS defines a processList entity, and there is only one such LRU list in the entire system dedicated to managing all processes started by AMS.

AMS中有一个成员变量 mLruProcesses,所有通过ams启动的java进程都会记录在里面,按照进程的使用时间以及进程种类,按照重要性由低到高排序,即越重要在 arraylist 中的index越大kill的时候也是先 kill index 小的进程, 总体来说index从小到大放置3类的进程:其他进程、含有service组件的进程、和activity有关的进程(包含 activity 或 client 包含 activity )

调用 updateLruProcessLocked 更新LRU列表的地方:

  • ASM 启动一个进程的时候
  • 绑定/解绑服务:bindserviceLocked
  • start/kill service的时候
  • remove connection的时候
  • update processInfo的时候
  • 处理boardCastor receive的时候
  • setSystemProcess的时候
  • getContentProvider和addApp(AMS启动新进程的方法)的时候

LRU列表更新的逻辑如下:

  • 首先LRU列表被分为三段,这三段分别放置带activity的进程,带service的进程以及其他以外的进程,使用两个标志mLruProcessServiceStart和mLruProcessActivityStart间隔开;其中,mLruProcessServiceStart表示带service的那一段进程的开始,如图所示,mLruProcessActivityStart表示带activity的那一段进程的开始,如图所示;这样区分是为了让LRU列表尾部的进程变得更重要,而头部就没这么重要;所以LRU列表中的进程重要性是从头到位逐步递增的。
  • 在对一个进程进行逻辑计算adj值时,会对其所处的当前状态进行分析,判断其是否带有一些提升自身重要性的一些组件(带有activity,service或者provider等等),将其对应的分到三段进程中的某一段;
  • 当进程被分到其对应的那一段进程的时候,其插入点默认都是那一段的尾部开始插入的;比如,当一个进程A,带有service时,他就被分到hasService这一段进程列表中,如果他本身就已经在LRU列表中(即不是新启动的进程),需要将其先从LRU列表删除,再将其插入到hasService这一段LRU列表的尾部,即mLruProcessActivityStart的前一个位置;如果他是新启动的进程,即原先不在LRU列表中,则直接找到对应的地方插入即可,而不必删除原先的进程
  • 值得注意的是,mLruProcessServiceStart和mLruProcessActivityStart这两个标志是用于间隔开other,hasService和hasActivity列表的,所以任何一个对LRU列表进行的操作都要及时更新这两个标志位的位置(这两个标志位其实就相当于两个指针,用于插入一个新的进程时使用)
  • AMS在更新所有的进程的adj的时候,都会调用updateLruProcessLocked 方法对LRU列表进行更新,实时更新每一个进程在LRU列表的位置,每一个进程一旦其状态有所改变(前后台切换,service切换等),其在LRU列表中的位置都将会被修改到合适的位置。
  • 在对进程进行插入的时候,为什么要从尾部进行插入???之前说过,LRU列表中,进程的重要性都是从头到尾逐步增加的;也即是说这三段列表中,尾部的进程都是最重要的,头部的是没有这么重要的。当一个进程的状态被更新,其在LRU列表中的位置被更新,代表该进程最近的状态有被修改过,也就是说这个进程最近是有活跃过的;这样,每一次更新进程在LRU列表中的位置,都表示被更新的进程是最新的(最近活跃的),这样子逐步更新之后,那些老的进程,不活跃的,其状态没有改变,那么他在LRU列表中的位置就会逐步被沉淀到列表尾部,进一步变老,其重要性就越来越显得不这么重要了。就这样,经过逐步的迭代更新,最终LRU列表维护的进程都是越靠近尾部越重要的。
     

参考:

https://blog.csdn.net/zhzhangnews/article/details/110474461

Guess you like

Origin blog.csdn.net/jingerppp/article/details/131685304