Android oom_adj 更新原則 (2)

ソースコードベース: Android R

前回記事:Android oom_adj 更新原則(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 ;
    }

関数はほぼ1,000 行のコードです。分析するのは確かに非常に疲れます。関数には多くのロジックが含まれています。一般的なロジックは次のとおりです:

  • mAdjSeq を使用して、この計算が必要かどうか、および計算済みかどうかを確認します。
  • 空のプロセスかどうかを判断します。
  • maxAdj<=FOREGROUND_APP_ADJ (すべての重要なシステム プロセス) の場合、システム UI が表示されているかどうか、TOPAPP であるかどうかなどに応じて adj、procState などを設定して戻ります。
  • フォアグラウンド プロセス関連の処理。さまざまなシナリオ (リモート アニメーション、ブロードキャストの受信、サービスの実行など) に応じてフォアグラウンド プロセス adj、adjType、procState、schedGroup を設定します。
  • フォアグラウンド プロセスではないが、キャッシュ アクティビティが存在する場合は、computeOomAdjFromActivitiesIfNecessary(); を通じてプロセスの cachedj などを決定します。
  • adj が PERCEPTIBLE_APP_ADJ、HEAVY_WEIGHT_APP_ADJ、HOME_APP_ADJ、PREVIOUS_APP_ADJ などより大きいかどうかに基づいておおよその adj 値を決定し、アクティビティの特定の実行ステータスに基づいて adj 相当値をさらに確認します。
  • バックアッププロセスであるかどうかを確認します。
  • プロセス上で実行されているすべてのサービスを調べ、サービスの実行ステータスに従って現在のプロセスの adj 相当値を修正します。サービスを参照するすべてのクライアントを横断し、これらのクライアントの調整値をさらに計算することもできます。
  • サービスと同様に、プロセスに関連付けられたプロバイダーを横断し、プロバイダーとクライアントに従って adj 値をさらに変更します。
  • 最後に、さらなる確認:
    • 20 秒前にプロセスに contentProvider があった場合、プロバイダー プロセスがメモリ不足状態に陥るのを防ぐために、そのプロセスは LRU リストに降格されません。
    • procState >= PROCESS_STATE_CACHED_EMPTY の場合、procState と adjType をさらに調整します。
    • adj==SERVICE_ADJ の場合、サービス中かどうかを確認します b. adj の場合は、SERVICE_B_ADJ に変更します。
    • その他の制限事項の確認。

覚えやすいように、簡単なフローチャートを次に示します。

12.1 バインドタイプ

バインダータイプ 説明する
BIND_WAIVE_PRIORITY サービスのプロセス優先度には影響せず、サービスは一般的なアプリケーションプロセスと同様にLRUテーブルに配置されます。
BIND_TREAT_LIKE_ACTIVITY バインドはアクティビティを保持しているとみなされ、バインド解除はバックグラウンドでのアクティビティとみなされ、これは通常、キーボードをより迅速に切り替えるために入力メソッドのプロセスで使用されます。
BIND_ALLOW_OOM_MANAGEMENT サービスはデフォルトのサービス マネージャーによって管理されたままにしてください。メモリが不足すると、サービスは破棄されます。
BIND_ABOVE_CLIENT サービスのプロセス優先度をクライアントの優先度よりも高く設定します。これは、サービスをクライアントよりも後で破棄する必要がある場合にのみ行われます。
BIND_IMPORTANT サービスを識別することはクライアントにとって非常に重要であり、サービスをフォアグラウンド プロセスの優先順位に昇格させます。通常、クライアントがフォアグラウンドの優先順位であっても、サービスは最大でも目に見えるプロセスの優先順位までしか昇格できません。
BIND_NOT_FOREGROUND バインドされたサービスはフォアグラウンド優先順位に昇格されませんが、サービスはメモリ内で少なくともクライアントと同じ優先順位を持ちます。
BIND_SCHEDULE_LIKE_TOP_APP このフラグは、IME (および最上位のアプリケーションと密接に連携するプロセス外のユーザーに表示されるコンポーネント) のスケジュール ポリシーを調整するためにシステムによってのみ使用されます。したがって、そのようなサービスをホストする UI は、トップ アプリと同じスケジュール戦略を持つことができます。システムコールのみに制限されます。それ以外の場合は、安全な例外がスローされます。
BIND_ADJUST_WITH_ACTIVITY サービスの優先度は、バインドされたアクティビティに対して相対的に決まります。アクティビティがフォアグラウンドに移動すると、サービスの優先度は相対的に高くなります。アクティビティがバックグラウンドに移動すると、サービスの優先度は相対的に低くなります。
BIND_AUTO_CREATE サービスをバインドするときに、サービスがまだ作成されていない場合は、サービスは自動的に作成されます。

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;
    }

これも非常に長い論理コードですが、特殊クラスを解析する際には主に次のようなプロセスを経ます。

  • 起動が完了し、アプリの圧縮が有効になっている場合、アプリの圧縮確認が行われ、条件を満たしていればメモリ圧縮が行われます。
  • アプリの adj が変更されると、setOomAdj() (ソケット通信メソッドを使用) を通じて lmkd に通知されます。
  • schedGroup が変更されると、プロセスのスケジューラと優先度が更新され、特殊な場合には強制終了されます。
  • updateAppFreezeStateLocked() 関数を呼び出して、アプリのフリーズ状態を更新します。
  • プロセスのプロセス状態を設定します。
  • pss 統計演算を実行し、次の pss 時間を計算します。

13.1 フレームワークのスケジューリング戦略

プロセスの優先順位:

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

グループの優先度:

  • setProcessGroup(int pid, int group);
  • setThreadGroup(int tid, int グループ);

スケジューラ カテゴリ:

  • setThreadScheduler(int tid, int ポリシー, int priority);
プロセスの優先順位 素敵な価値 説明する
THREAD_PRIORITY_LOWEST 19 最も優先度が低い
THREAD_PRIORITY_BACKGROUND 10 バックステージ
THREAD_PRIORITY_LESS_FAVORABLE 1 デフォルトよりわずかに低い
THREAD_PRIORITY_DEFAULT 0 デフォルト
THREAD_PRIORITY_MORE_FAVORABLE -1 デフォルトよりわずかに高い
THREAD_PRIORITY_FOREGROUND -2 フロント
THREAD_PRIORITY_DISPLAY -4 番組関連
THREAD_PRIORITY_URGENT_DISPLAY -8 表示 (さらに重要)、入力イベント
TOP_APP_PRIORITY_BOOST -10

メインスレッドとレンダースレッドはフォアグラウンドプロセスの優先順位を高めます

THREAD_PRIORITY_AUDIO -16 オーディオ関連
THREAD_PRIORITY_URGENT_AUDIO -19 オーディオ (さらに重要)
グループの優先順位 価値 説明する
THREAD_GROUP_DEFAULT -1 setProcessGroup でのみ使用され、優先度が 10 以下のプロセスを -2 に上げます。
THREAD_GROUP_BG_NONINTERACTIVE 0 CPU タイムシェアリング期間の短縮
THREAD_GROUP_FOREGROUND 1 CPU タイムシェアリングの継続時間は正常です
THREAD_GROUP_SYSTEM 2 システムスレッドグループ
THREAD_GROUP_AUDIO_APP 3 アプリケーションオーディオ
THREAD_GROUP_AUDIO_SYS 4 システムプログラム音声
スケジューラー 名前 説明する
SCHED_OTHER デフォルト 標準的なラウンドロビン時間共有戦略
SCHED_BATCH バッチスケジュール バッチスタイル (バッチ) プロセスのスケジュール戦略
SCHED_IDLE アイドルスケジュール バックグラウンドでの実行に適した非常に優先度の低いプロセスの場合
SCHED_FIFO 先入先出 リアルタイムのスケジューリング戦略
SCHED_RR ラウンドロビンスケジューリング リアルタイムのスケジューリング戦略

13.2 updateLruProcessLocked()

AMS には LRU リスト mProcessList があり、AMS が起動したプロセスはすべて LRU リストに追加されて管理されます この LRU リストはランダムにソートされたり、追加された時点で並べられたものではなく、一定のロジックを持って計算され、変更されます各プロセスのリアルタイムの動的ステータスに従って。

mProcessList LRU リストの定義は、実際には最終的に ProcessList.java にあります。AMS は processList エンティティを定義し、AMS によって開始されるすべてのプロセスの管理専用のこのような LRU リストはシステム全体で 1 つだけ存在します。

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

おすすめ

転載: blog.csdn.net/jingerppp/article/details/131685304