likes
comments
collection
share

AMS的内存管理ADJ算法(Android12)

作者站长头像
站长
· 阅读数 9

Android的知识体系搭建

AMS系列

AMS之AMS的启动流程

AMS之进程的启动流程

AMS之进程管理LRU算法

[AMS的内存管理ADJ算法]-本篇

一概述

之前我们介绍了 AMS 进程管理中的 LRU 算法,今天接着来说说 AMS 的进程管理中的进程优先级管理。

总所周知,Android 系统的资源是有限的,而当我们运行过多的应用时,从而造成系统资源紧张时,系统就会根据一定的算法,来杀掉部分进程,从而缓解系统资源不足的问题。这也就是我们经常说的“杀后台“。

而系统杀后台所依赖的算法之一,就是通过 ADJ 进程优先级算法。今天,我们就来说说 Android 系统的 ADJ 算法。

二 进程管理

在说 ADJ 算法之前,我们先来简单聊一下 Android 中,AMS 的进程管理。我们之前说过了,AMS 在 Android 系统中有着很多的任务,其中之一就是进程管理。AMS 用于进程管理的算法有很多,包含之前说的 LRU 算法,今天要说的 ADJ 算法,还有一些经常被人提起的 LMK 算法(Low Memory Kill)。

ADJ 的全称是 adjustment,它表示 Android 系统中的进程优先级,从字面意思理解,它表示一个进程,在 Android 系统中的重要与否。越重要的进程,自然系统越会保证它的存活,这也是早起流氓软件保活的思路。

接下来,我们就来说说 AMS 关于进程优先级的具体算法。

首先,我们还是要从在 AMS 的启动流程看起,在 AMS 的启动过程中,我们说过这样一个函数 setSystemProcess,这个函数中有如下代码

2.1 setSystemProcess

public void setSystemProcess() {
    try {
        ...

        synchronized (this) {
        	// 将当前进程(系统进程)的信息封装到一个 ProcessRecord 中
            ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName,
                    false,
                    0,
                    new HostingRecord("system"));
            app.setPersistent(true);
            app.setPid(MY_PID);
            app.mState.setMaxAdj(ProcessList.SYSTEM_ADJ);
            app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);

            // 讲进程信息 ProcessRecord 添加进 mPidsSelfLocked
            addPidLocked(app);
            // 更新进程在 LRU 队列中的优先级
            updateLruProcessLocked(app, false, null);
            // 更新进程在
            updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
        }
    }

这段代码中,将系统进程添加进了 mProcessList 这个进程列表,并且还调用了 addPidLockedupdateLruProcessLockedupdateOomAdjLocked 这三个函数

其中,addPidLocked 是将进程信息 ProcessRecord 添加进对于的列表 mPidsSelfLocked。而 updateLruProcessLocked 和 updateOomAdjLocked 则是进程和内存管理的重点。updateLruProcessLocked 在前面的进程管理 LRU 算法篇中已经介绍了,今天我们来看一看另一个函数,updateOomAdjLocked 的内存管理

2.2 addPidLocked

void addPidLocked(ProcessRecord app) {
    final int pid = app.getPid();
    synchronized (mPidsSelfLocked) {
        mPidsSelfLocked.doAddInternal(pid, app);
    }
    synchronized (sActiveProcessInfoSelfLocked) {
        if (app.processInfo != null) {
            sActiveProcessInfoSelfLocked.put(pid, app.processInfo);
        } else {
            sActiveProcessInfoSelfLocked.remove(pid);
        }
    }
    mAtmInternal.onProcessMapped(pid, app.getWindowProcessController());
}

addPidLocked 其实就是将进程添加到 mPidsSelfLocked 列表。

2.3 updateOomAdjLocked

@GuardedBy("this")
final void updateOomAdjLocked(String oomAdjReason) {
    mOomAdjuster.updateOomAdjLocked(oomAdjReason);
}

然后调用 updateOomAdjLocked 开始调整当前进程的优先级。因为我们现在是从 AMS 启动时,setSystemProcess 调用过来的,也就是说 AMS 这个进程一启动,就会给它自己先计算对应的优先级。

三 OomAdjuster

OomAdjuster 则是 AMS 中,内存管理的部分。在 OomAdjuster 中,会根据进程的情况来调整它在内存中的优先级

3.1 updateOomAdjLocked

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

@GuardedBy("mService")
void updateOomAdjLocked(String oomAdjReason) {
    synchronized (mProcLock) {
        updateOomAdjLSP(oomAdjReason);
    }
}

首先是调用 updateOomAdjLSP 函数,关于 LSP 前面我们解释了,它是一个加锁函数,锁是 mService 和 mProcLock。

3.2 updateOomAdjLSP

@GuardedBy({"mService", "mProcLock"})
private boolean updateOomAdjLSP(ProcessRecord app, String oomAdjReason) {
    if (app == null || !mConstants.OOMADJ_UPDATE_QUICK) {
	    // 调用同名函数
        updateOomAdjLSP(oomAdjReason);
        return true;
    }

    if (checkAndEnqueueOomAdjTargetLocked(app)) {
        // Simply return true as there is an oomAdjUpdate ongoing
        return true;
    }

    try {
        mOomAdjUpdateOngoing = true;
        return performUpdateOomAdjLSP(app, oomAdjReason);
    } finally {
        // Kick off the handling of any pending targets enqueued during the above update
        mOomAdjUpdateOngoing = false;
        updateOomAdjPendingTargetsLocked(oomAdjReason);
    }
}

3.3 updateOomAdjLSP

@GuardedBy({"mService", "mProcLock"})
private void updateOomAdjLSP(String oomAdjReason) {
    if (checkAndEnqueueOomAdjTargetLocked(null)) {
        // Simply return as there is an oomAdjUpdate ongoing
        return;
    }
    try {
        mOomAdjUpdateOngoing = true;
        performUpdateOomAdjLSP(oomAdjReason);
    } finally {
        // Kick off the handling of any pending targets enqueued during the above update
        mOomAdjUpdateOngoing = false;
        updateOomAdjPendingTargetsLocked(oomAdjReason);
    }
}

3.4 performUpdateOomAdjLSP

@GuardedBy({"mService", "mProcLock"})
private boolean performUpdateOomAdjLSP(ProcessRecord app, String oomAdjReason) {

    final ProcessRecord topApp = mService.getTopApp();

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);
    mService.mOomAdjProfiler.oomAdjStarted();
    // 内存优先级也存在一个唯一的序号,每次加 1
    mAdjSeq++;

    // 首先看一下这个进程的优先级是否发生了改变
    final ProcessStateRecord state = app.mState;
    final boolean wasCached = state.isCached();
    // 先取出旧的优先级 oldAdj
    final int oldAdj = state.getCurRawAdj();
    // cachedAdj 为缓存进程的 adj 值,它最小为 CACHED_APP_MIN_ADJ(900)
    // 对于 900 以后的进程,是非常容易被系统杀死的,当然,是否杀死取决于进程所占的内存
    final int cachedAdj = oldAdj >= ProcessList.CACHED_APP_MIN_ADJ
            ? oldAdj : ProcessList.UNKNOWN_ADJ;
            
    final boolean wasBackground = ActivityManager.isProcStateBackground(
            state.getSetProcState());
    final int oldCap = state.getSetCapability();
    state.setContainsCycle(false);
    state.setProcStateChanged(false);
    state.resetCachedInfo();
    // 检查此进程是否也在待处理列表中,如果是则从待处理列表中删除。
    mPendingProcessSet.remove(app);
    // 调用计算内存优先级的函数
    boolean success = performUpdateOomAdjLSP(app, cachedAdj, topApp,
            SystemClock.uptimeMillis());
    // The 'app' here itself might or might not be in the cycle, for example,
    // the case A <=> B vs. A -> B <=> C; anyway, if we spot a cycle here, re-compute them.
    if (!success || (wasCached == state.isCached() && oldAdj != ProcessList.INVALID_ADJ
            && mProcessesInCycle.isEmpty() /* Force re-compute if there is a cycle */
            && oldCap == state.getCurCapability()
            && wasBackground == ActivityManager.isProcStateBackground(
                    state.getSetProcState()))) {
        mProcessesInCycle.clear();
        // Okay, it's unchanged, it won't impact any service it binds to, we're done here.

        mService.mOomAdjProfiler.oomAdjEnded();
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        return success;
    }

    // Next to find out all its reachable processes
    ArrayList<ProcessRecord> processes = mTmpProcessList;
    ActiveUids uids = mTmpUidRecords;
    mPendingProcessSet.add(app);

    // Add all processes with cycles into the list to scan
    for (int i = mProcessesInCycle.size() - 1; i >= 0; i--) {
        mPendingProcessSet.add(mProcessesInCycle.valueAt(i));
    }
    mProcessesInCycle.clear();

    boolean containsCycle = collectReachableProcessesLocked(mPendingProcessSet,
            processes, uids);

    // Clear the pending set as they should've been included in 'processes'.
    mPendingProcessSet.clear();

    if (!containsCycle) {
        // Reset the flag
        state.setReachable(false);
        // Remove this app from the return list because we've done the computation on it.
        processes.remove(app);
    }

    int size = processes.size();
    if (size > 0) {
        mAdjSeq--;
        // 更新内存优先级
        updateOomAdjInnerLSP(oomAdjReason, topApp, processes, uids, containsCycle, false);
    } else if (state.getCurRawAdj() == ProcessList.UNKNOWN_ADJ) {
        processes.add(app);
        // 给进程分配一个缓存的 adj 值(900 以上)
        assignCachedAdjIfNecessary(processes);
        applyOomAdjLSP(app, false, SystemClock.uptimeMillis(),
                SystemClock.elapsedRealtime());
    }
    mTmpProcessList.clear();
    mService.mOomAdjProfiler.oomAdjEnded();
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    return true;
}

3.5 performUpdateOomAdjLSP

更新指定进程的内存优先级。

@GuardedBy({"mService", "mProcLock"})
private boolean performUpdateOomAdjLSP(ProcessRecord app, int cachedAdj,
        ProcessRecord topApp, long now) {
    if (app.getThread() == null) {
        return false;
    }

    app.mState.resetCachedInfo();
    UidRecord uidRec = app.getUidRecord();
    if (uidRec != null) {
        uidRec.reset();
    }

    // 检查此进程是否也在待处理列表中,如果是,则从待处理列表中删除。
    mPendingProcessSet.remove(app);

    mProcessesInCycle.clear();
    // 计算内存优先级
    computeOomAdjLSP(app, cachedAdj, topApp, false, now, false, true);
    
    ...

	// 应用
    return applyOomAdjLSP(app, false, now, SystemClock.elapsedRealtime());
}

computeOomAdjLSP 这个函数是真正计算进程的内存优先级的,它的代码量非常长,所以我们将它分为几个部分来看。

四 Android 中的进程优先级

4.1 优先级简述

首先,我们要知道几个知识点,就是在 Android 中,进程的优先级越小,代码这个进程越重要,越不容易被杀。在 Android 系统中,预先定义好了一系列的优先,它们在目录 frameworks/base/services/core/java/com/android/server/am/ProcessList.java 下,我们先来简单介绍一下。

    // 未初始化的状态
    public static final int INVALID_ADJ = -10000;

    // 不知道在什么地方用到的进程。通常这是要缓存的内容。
    public static final int UNKNOWN_ADJ = 1001;

    // 不可见的进程,从 900 到 999,共 1000 个,一般是缓存
    public static final int CACHED_APP_MAX_ADJ = 999;
    public static final int CACHED_APP_MIN_ADJ = 900;

    // 会杀进程的首个进程优先级
    public static final int CACHED_APP_LMK_FIRST_ADJ = 950;

    // 不同服务连接组重要性级别可用的级别数。
    static final int CACHED_APP_IMPORTANCE_LEVELS = 5;

    // 服务的 B 列表,代表旧的服务
    public static final int SERVICE_B_ADJ = 800;

    // 用户切换的上一个进程,比如用户从 A 进程跳转到 B 进程
    // 那么 A 就是上一个进程,为了用户两个进程间切换的体验,
    // 所以上一个进程也会比较重要
    public static final int PREVIOUS_APP_ADJ = 700;

    // Home 进程,通常旧不会被杀
    public static final int HOME_APP_ADJ = 600;

    // 服务进程
    public static final int SERVICE_ADJ = 500;

    // 重量级进程
    public static final int HEAVY_WEIGHT_APP_ADJ = 400;

    // 备份进程
    public static final int BACKUP_APP_ADJ = 300;

    // 系统或其他应用绑定使用的进程
    public static final int PERCEPTIBLE_LOW_APP_ADJ = 250;

    // 这是一个托管服务的进程,一般情况下用户无法感知这些服务,     
    // 但如果客户端绑定到它,就会可感知,一般不会被杀
    public static final int PERCEPTIBLE_MEDIUM_APP_ADJ = 225;

    // 这是一个只承载组件的进程,这些组件可被用户使用
    // 一般避免杀死他们,虽然它们不是立即可见。 例如背景音乐播放。
    public static final int PERCEPTIBLE_APP_ADJ = 200;

    // 可见进程
    public static final int VISIBLE_APP_ADJ = 100;
    
    static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;

    // This is a process that was recently TOP and moved to FGS. Continue to treat it almost
    // like a foreground app for a while.
    // @see TOP_TO_FGS_GRACE_PERIOD
    // 从顶部进程,到前台的优先级
    public static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;

    // 前台进程
    public static final int FOREGROUND_APP_ADJ = 0;

    // 持久化服务进程,基本不会被杀
    public static final int PERSISTENT_SERVICE_ADJ = -700;

    // 持久化进程,基本不会被杀
    public static final int PERSISTENT_PROC_ADJ = -800;

    // 系统服务
    public static final int SYSTEM_ADJ = -900;

    // 不受系统管理的本机进程(因此没有系统分配的 oom adj)。
    public static final int NATIVE_ADJ = -1000;

在这些优先级中,我们需要注意这么几个

  • CACHED_APP_MIN_ADJ(900):缓存的优先级
  • CACHED_APP_LMK_FIRST_ADJ(950):缓存的进程中,LMK 开始的进程优先级。(LMK 是 Low Memory Kill 的缩写,它也是 Android 系统中,AMS 管理进程的一个算法)
  • SERVICE_ADJ(500):服务进程的优先级
  • VISIBLE_APP_ADJ(100):可见进程的优先级
  • FOREGROUND_APP_ADJ(0):前台进程的优先级
  • SYSTEM_ADJ(-900):系统服务的优先级

4.2 Android 中的进程组

Android 中除了对不同进程做了优先级的划分,还规定了 5 种不同的进程组,这个也就是我们经常老生常谈的五大进程状态。

  1. 前台进程
  2. 可见进程
  3. 服务进程
  4. 后台进程
  5. 空进程

对应到代码中的定义如下,我们可以发现它并不是完全按照字面意思翻译的。进程组的值则是越大越重要。

[frameworks/base/services/core/java/com/android/server/am/ProcessList.java]

// 后台
static final int SCHED_GROUP_BACKGROUND = 0;
// 限制
static final int SCHED_GROUP_RESTRICTED = 1;
// 默认
static final int SCHED_GROUP_DEFAULT = 2;
// 顶部
public static final int SCHED_GROUP_TOP_APP = 3;
// 顶级并绑定
static final int SCHED_GROUP_TOP_APP_BOUND = 4;

除此之外,Android 还定义了一堆的进程状态,在 frameworks/base/core/java/android/app/ActivityManager.java 中。

最后小结一下,Android 中,对一个进程有三个定义

  1. 进程优先级(越小越重要,越大越容易被杀)
  2. 进程组(越大越重要,adj 算法只会杀 SCHED_GROUP_BACKGROUND 进程组的进程)
  3. 进程状态(表示当前进程的运行状态)

五 computeOomAdjLSP

了解清楚了系统中,定义好的具体进程优先级之后,我们再来看看具体进程优先级的计算过程。

@GuardedBy({"mService", "mProcLock"})
private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
        ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
        boolean computeClients) {
    final ProcessStateRecord state = app.mState;
    if (mAdjSeq == state.getAdjSeq()) {
        if (state.getAdjSeq() == state.getCompletedAdjSeq()) {
            // 如果此进程已经计算完成就直接返回。
            return false;
        } else {
            // 这个过程正在被计算,所以有一个循环。我们不能依赖这个进程的状态。
            state.setContainsCycle(true);
            mProcessesInCycle.add(app);
            return false;
        }
    }

	// IApplicationThread 为空,说明这个进程是缓存进程
    if (app.getThread() == null) {
        state.setAdjSeq(mAdjSeq);
        // 设置进程组,为后台进程组
        state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND);
        // 设置进程状态,为缓存的空进程
        state.setCurProcState(PROCESS_STATE_CACHED_EMPTY);
        // 设置进程优先级,为最大优先级 999(数值越大优先级越低,越容易被杀)
        state.setCurAdj(ProcessList.CACHED_APP_MAX_ADJ);
        state.setCurRawAdj(ProcessList.CACHED_APP_MAX_ADJ);
        state.setCompletedAdjSeq(state.getAdjSeq());
        state.setCurCapability(PROCESS_CAPABILITY_NONE);
        return false;
    }
  • 首先是状态判断,如果进程的状态已经计算过,就直接返回。
  • 如果进程是空,说明这个进程是一个缓存进程,就将进程对于的三个变量进行修改,然后返回。

接着是第二部分,与前台优先级对比,如果小于前台优先级,就做对应的处理,一般只有系统的 system_server、常驻进程 PERSISTENT 或者 isolated 的 app 才会有这么低的优先级数值。

    ...

	// 如果当前进程的优先级小于前台优先级,FOREGROUND_APP_ADJ = 0
	// 一般情况,0 是我们应用能够拿到的最小 adj 值,小于 0 的一般都是系统进程
    if (state.getMaxAdj() <= ProcessList.FOREGROUND_APP_ADJ) {
        state.setAdjType("fixed");
        state.setAdjSeq(mAdjSeq);
        state.setCurRawAdj(state.getMaxAdj());
        state.setHasForegroundActivities(false);
        state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
        state.setCurCapability(PROCESS_CAPABILITY_ALL);
        state.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);

        // 系统进程可以操作 UI,当它们操作 UI 时,我们希望系统在在用户离开 UI 后修剪它们的内存。
        // 为了方便这一点,这里我们需要确定它当前是否显示 UI。
        // 判断当前的进程是否没有操作正在显示的 UI,true 表示没有操作
        // 操作正在显示的 UI 有三种:
        // 1. 此进程是最顶部的进程
        // 2. 此进程有顶部的 UI
        // 3. 此进程包含可见的 Activity
        state.setSystemNoUi(true);
        if (app == topApp) {
            state.setSystemNoUi(false);
            state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
            state.setAdjType("pers-top-activity");
        } else if (state.hasTopUi()) {
            // 调度组/进程状态调整如下
            state.setSystemNoUi(false);
            state.setAdjType("pers-top-ui");
        } else if (state.getCachedHasVisibleActivities()) {
            state.setSystemNoUi(false);
        }
        if (!state.isSystemNoUi()) {
            if (mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE
                    || state.isRunningRemoteAnimation()) {
                // 屏幕打开或动画,提升 UI
                state.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
                state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
            } else {
                // 屏幕关闭,限制 UI 调度
                state.setCurProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
                state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
            }
        }
        state.setCurRawProcState(state.getCurProcState());
        state.setCurAdj(state.getMaxAdj());
        state.setCompletedAdjSeq(state.getAdjSeq());
        state.bumpAllowStartFgsState(state.getCurProcState());
        // 如果当前的 curAdj 小于之前的 prevAppAdj,说明进程优先级升级了(越小越难被杀)
        return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState;
    }

然后判断这个进程的优先级是否小于前台进程的优先级(0),如果小于,就分三种情况处理

  1. 如果这个进程的最顶部的进程
  2. 如果这个进程不是最顶部的进程,但是有最顶部的 UI
  3. 不满足上述两种情况,但是有可见的 Activity

接下来是第三部分,根据四大组件的状态,来调整进程的优先级和进程组。分为 7 中情况

    state.setSystemNoUi(false);

    final int PROCESS_STATE_CUR_TOP = mService.mAtmInternal.getTopProcessState();

    // 确定进程的重要性,从最重要到最不重要,并分配适当的 OOM 调整。
    int adj;
    int schedGroup;
    int procState;
    int cachedAdjSeq;
    int capability = 0;

    boolean foregroundActivities = false;
    boolean hasVisibleActivities = false;
    if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp) {
        // 【情况 1】如果当前进程处于 PROCESS_STATE_TOP,并且当前进程也在最顶部,
        // 一般就是当前正在运行的进程
        // adj = 0
        adj = ProcessList.FOREGROUND_APP_ADJ;
        // 进程组设置为 SCHED_GROUP_TOP_APP
        schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
        state.setAdjType("top-activity");
        // 前台 Activity 和可见 Activity 都为 true
        foregroundActivities = true;
        hasVisibleActivities = true;
        // 进程状态设置为 PROCESS_STATE_CUR_TOP
        procState = PROCESS_STATE_CUR_TOP;
        state.bumpAllowStartFgsState(PROCESS_STATE_TOP);
    } else if (state.isRunningRemoteAnimation()) {
	    // 【情况 2】如果不是情况 1,并且当前进程还在跑动画
	    // 那么设置优先级为可见级,adj = 100
        adj = ProcessList.VISIBLE_APP_ADJ;
        // 进程组也设置为 SCHED_GROUP_TOP_APP
        schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
        state.setAdjType("running-remote-anim");
        procState = PROCESS_STATE_CUR_TOP;

    } else if (app.getActiveInstrumentation() != null) {
        // 【情况 3】如果当前进程是正在启动 Activity 的进程
        // 也不会轻易被杀,adj = 0
        adj = ProcessList.FOREGROUND_APP_ADJ;
        schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
        state.setAdjType("instrumentation");
        procState = PROCESS_STATE_FOREGROUND_SERVICE;
    } else if (state.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) {
        // 【情况 4】如果当前进程正在接受 BroadcastReceiver ,adj = 0
        adj = ProcessList.FOREGROUND_APP_ADJ;
        // 这里还会区分前台广播和后台广播
        schedGroup = (mTmpBroadcastQueue.contains(mService.mFgBroadcastQueue))
                ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
        state.setAdjType("broadcast");
        procState = ActivityManager.PROCESS_STATE_RECEIVER;
    } else if (psr.numberOfExecutingServices() > 0) {
        // 【情况 5】如果当前进程正在执行 Service 的回调,adj = 0
        adj = ProcessList.FOREGROUND_APP_ADJ;
        // 这里还会区分前台服务还是后台服务
        schedGroup = psr.shouldExecServicesFg()
                ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
        state.setAdjType("exec-service");
        procState = PROCESS_STATE_SERVICE;
    } else if (app == topApp) {
	    // 【情况 6】最顶部的进程,但是在休眠,adj = 0
        adj = ProcessList.FOREGROUND_APP_ADJ;
        schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
        state.setAdjType("top-sleeping");
        foregroundActivities = true;
        procState = PROCESS_STATE_CUR_TOP;
    } else {
        // 除了以上 6 种其他情况,其他都暂时安排到后台进程,后面还可能会修改
        schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;

        adj = cachedAdj;
        // 进程状态设置为空进程组
        procState = PROCESS_STATE_CACHED_EMPTY;
        if (!state.containsCycle()) {
            state.setCached(true);
            state.setEmpty(true);
            state.setAdjType("cch-empty");
        }
    }

根据进程中,四大组件的情况,分别对进程的优先级和进程组进行调整。调整完毕之后,再来根据调整后的优先级来进行处理。如果是后台进程,进程组就会变成 SCHED_GROUP_BACKGROUND。(我们需要注意 SCHED_GROUP_BACKGROUND 这个值,因为在 adj 算法中,系统只会杀 SCHED_GROUP_BACKGROUND 值的进程)

    // 检查所有不在前台的 Activity
    if (!foregroundActivities && state.getCachedHasActivities()) {
        state.computeOomAdjFromActivitiesIfNecessary(mTmpComputeOomAdjWindowCallback,
                adj, foregroundActivities, hasVisibleActivities, procState, schedGroup,
                appUid, logUid, PROCESS_STATE_CUR_TOP);
		// 拿到计算后的优先级,前台状况,可见状态,进程状态和进程组状态
        adj = state.getCachedAdj();
        foregroundActivities = state.getCachedForegroundActivities();
        hasVisibleActivities = state.getCachedHasVisibleActivities();
        procState = state.getCachedProcState();
        schedGroup = state.getCachedSchedGroup();
    }

    if (procState > PROCESS_STATE_CACHED_RECENT && state.getCachedHasRecentTasks()) {
        procState = PROCESS_STATE_CACHED_RECENT;
        state.setAdjType("cch-rec");
    }

    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
            || procState > PROCESS_STATE_FOREGROUND_SERVICE) {
        if (psr.hasForegroundServices()) {
            // 用户知道此应用程序,因此使其可见。
            adj = ProcessList.PERCEPTIBLE_APP_ADJ;
            procState = PROCESS_STATE_FOREGROUND_SERVICE;
            state.bumpAllowStartFgsState(PROCESS_STATE_FOREGROUND_SERVICE);
            state.setAdjType("fg-service");
            state.setCached(false);
            schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
        } else if (state.hasOverlayUi()) {
            // 该过程是显示覆盖 UI。
            adj = ProcessList.PERCEPTIBLE_APP_ADJ;
            procState = PROCESS_STATE_IMPORTANT_FOREGROUND;
            state.setCached(false);
            state.setAdjType("has-overlay-ui");
            schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
        }
    }

然后就是处理没有前台 Activity 的情况。

    // 如果应用程序最近处于前台并移动到前台服务状态,则与其他前台服务相比,
    // 允许它在内存中获得更高的排名一段时间,以便它可以完成执行内存中状态的任何持久化处理。
    // 如果应用程序,刚刚从前台的 Activity 变成前台服务,那么运行它在内存中更活跃一段时间,等会再收拾它
    if (psr.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
            && (state.getLastTopTime() + mConstants.TOP_TO_FGS_GRACE_DURATION > now
            || state.getSetProcState() <= PROCESS_STATE_TOP)) {
        adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
        state.setAdjType("fg-service-act");
    }

    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
            || procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
        if (state.getForcingToImportant() != null) {
	        // 系统提供的组件进程,例如音乐播放
            adj = ProcessList.PERCEPTIBLE_APP_ADJ;
            procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
            state.setCached(false);
            state.setAdjType("force-imp");
            state.setAdjSource(state.getForcingToImportant());
            schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
        }
    }

    if (state.getCachedIsHeavyWeight()) {
        if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
            // 如果是重量级进程,就不会轻易被杀
            adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
            schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
            state.setCached(false);
            state.setAdjType("heavy");
        }
        if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
            procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
            state.setAdjType("heavy");
        }
    }

    if (state.getCachedIsHomeProcess()) {
        if (adj > ProcessList.HOME_APP_ADJ) {
            // 如果是 Home 进程
            adj = ProcessList.HOME_APP_ADJ;
            schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
            state.setCached(false);
            state.setAdjType("home");
        }
        if (procState > ActivityManager.PROCESS_STATE_HOME) {
            procState = ActivityManager.PROCESS_STATE_HOME;
            state.setAdjType("home");
        }
    }

    if (state.getCachedIsPreviousProcess() && state.getCachedHasActivities()) {
        if (adj > ProcessList.PREVIOUS_APP_ADJ) {
            // 如果进程是刚刚操作过 UI 的进程,那么也会稍微保留一下,
            // 这样两个进程相互切换体验更好
            adj = ProcessList.PREVIOUS_APP_ADJ;
            schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
            state.setCached(false);
            state.setAdjType("previous");
        }
        if (procState > PROCESS_STATE_LAST_ACTIVITY) {
            procState = PROCESS_STATE_LAST_ACTIVITY;
            state.setAdjType("previous");
        }
    }

    if (cycleReEval) {
        procState = Math.min(procState, state.getCurRawProcState());
        adj = Math.min(adj, state.getCurRawAdj());
        schedGroup = Math.max(schedGroup, state.getCurrentSchedulingGroup());
    }
    state.setCurRawAdj(adj);
    state.setCurRawProcState(procState);

    state.setHasStartedServices(false);
    state.setAdjSeq(mAdjSeq);

	// 正在备份的进程,也尽量不要去杀
    final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
    if (backupTarget != null && app == backupTarget.app) {
        // 如果可能的话,我们希望避免在备份应用程序时杀死它们
        if (adj > ProcessList.BACKUP_APP_ADJ) {
            adj = ProcessList.BACKUP_APP_ADJ;
            if (procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
                procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
            }
            state.setAdjType("backup");
            state.setCached(false);
        }
        if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
            procState = ActivityManager.PROCESS_STATE_BACKUP;
            state.setAdjType("backup");
        }
    }

接下来的几个,就是刚刚切换的进程处理,系统的进程处理。

	
    int capabilityFromFGS = 0; // capability from foreground service.
    boolean scheduleLikeTopApp = false;
    for (int is = psr.numberOfRunningServices() - 1;
            is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                    || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                    || procState > PROCESS_STATE_TOP);
            is--) {
        
        // 计算服务的能力,并调整服务的优先级   
        ...

		// 开始处理 binder 服务,binder 服务会根据客户端的 flag 来调整自己的优先级。
        ...
    }

接下来就是计算服务的能力(权限),并且还会调整 Binder 服务的优先级,客户端的调用,会调整 Binder 服务的 adj 值保证它不容易被杀。

然后就是调整四大组件中,内容提供者的优先级。


    final ProcessProviderRecord ppr = app.mProviders;
    for (int provi = ppr.numberOfProviders() - 1;
            provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                    || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                    || procState > PROCESS_STATE_TOP);
            provi--) {
        ContentProviderRecord cpr = ppr.getProviderAt(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);
            ...
        }
        //如果提供商有外部(非框架)流程
        // 依赖项,确保其调整至少 FOREGROUND_APP_ADJ。
        if (cpr.hasExternalProcessHandles()) {
            if (adj > ProcessList.FOREGROUND_APP_ADJ) {
                adj = ProcessList.FOREGROUND_APP_ADJ;
                state.setCurRawAdj(adj);
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                state.setCached(false);
                state.setAdjType("ext-provider");
                state.setAdjTarget(cpr.name);
            }
            if (procState > PROCESS_STATE_IMPORTANT_FOREGROUND) {
                procState = PROCESS_STATE_IMPORTANT_FOREGROUND;
                state.setCurRawProcState(procState);
            }
        }
    }
	...

然后是四大组件中,服务的调整。

	// 调整服务的进程优先级,服务有两个进程优先级,
	// 一个是 SERVICE_ADJ(500),一个是 SERVICE_B_ADJ(800)
    if (adj == ProcessList.SERVICE_ADJ) {
        if (doingAll && !cycleReEval) {
	        // 服务服务数占用总进程数的 1/3,就设置为 SERVICE_B_ADJ(800)
            state.setServiceB(mNewNumAServiceProcs > (mNumServiceProcs / 3));
            mNewNumServiceProcs++;
            if (!state.isServiceB()) {
                // 如果当前系统的内存较少,这个服务占用的内存有多,
                // 就把他调整到 SERVICE_B_ADJ(800)里去。更容易被杀了。
                // 所以写程序注意优化内存
                if (!mService.mAppProfiler.isLastMemoryLevelNormal()
                        && app.mProfile.getLastPss()
                        >= mProcessList.getCachedRestoreThresholdKb()) {
                    state.setServiceHighRam(true);
                    state.setServiceB(true);
                } else {
                    mNewNumAServiceProcs++;
                }
            } else {
                state.setServiceHighRam(false);
            }
        }
        if (state.isServiceB()) {
            adj = ProcessList.SERVICE_B_ADJ;
        }
    }

    state.setCurRawAdj(adj);

    if (adj > state.getMaxAdj()) {
        adj = state.getMaxAdj();
        if (adj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
            schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
        }
    }


    // 将绑定的前台服务放在一个特殊的计划组中,以对屏幕关闭进行额外限制
    if (procState >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
            && mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
            && !scheduleLikeTopApp) {
        if (schedGroup > ProcessList.SCHED_GROUP_RESTRICTED) {
            schedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
        }
    }

    // 应用 FGS 应用能力。
    if (psr.hasForegroundServices()) {
        capability |= capabilityFromFGS;
    }

    capability |= getDefaultCapability(psr, procState);

    // 对 adj 做最后的修改。
    // 稍后计算最终缓存的 adj 时。
    state.setCurAdj(psr.modifyRawOomAdj(adj));
    state.setCurCapability(capability);
    state.setCurrentSchedulingGroup(schedGroup);
    state.setCurProcState(procState);
    state.setCurRawProcState(procState);
    state.updateLastInvisibleTime(hasVisibleActivities);
    state.setHasForegroundActivities(foregroundActivities);
    state.setCompletedAdjSeq(mAdjSeq);

    return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
            || state.getCurCapability() != prevCapability;
}

完成了内存优先级的计算,接下来就是根据这个内存的优先级,做对应的处理了。该死的也要被杀了。

六 applyOomAdjLSP

@GuardedBy({"mService", "mProcLock"})
private boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
		long nowElapsed, String oomAdjReson) {
	// 返回值 success,如果由于系统内存的原因,导致进程被杀,这个值就会被修改为 false
	boolean success = true;
	final ProcessStateRecord state = app.mState;
	final UidRecord uidRec = app.getUidRecord();

	if (state.getCurRawAdj() != state.getSetRawAdj()) {
		state.setSetRawAdj(state.getCurRawAdj());
	}

	int changes = 0;

	// 内存优化(内存压缩)
	...

	final int curSchedGroup = state.getCurrentSchedulingGroup();
	// 如果新的进程组和旧的进程组不一样
	if (state.getSetSchedGroup() != curSchedGroup) {
		// curSchedGroup 是进程当前所在的进程组信息
		// oldSchedGroup 是进程先前所在进程组的信息
		// 通过判断这两个值,可以知道进程是从前台切到后台,还是后台切到前台
		int oldSchedGroup = state.getSetSchedGroup();
		state.setSetSchedGroup(curSchedGroup);

		if (app.getWaitingToKill() != null && app.mReceivers.numberOfCurReceivers() == 0
				&& state.getSetSchedGroup() == ProcessList.SCHED_GROUP_BACKGROUND) {
			// 杀进程,并修改 success(success 只会在这里修改)
			// 注意,AMS 杀进程的必要条件是进程组为 SCHED_GROUP_BACKGROUND 后台
			app.killLocked(app.getWaitingToKill(), ApplicationExitInfo.REASON_USER_REQUESTED,
					ApplicationExitInfo.SUBREASON_REMOVE_TASK, 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.getPid(), processGroup, app.processName));
			try {
				// 拿到渲染线程的 id
				final int renderThreadTid = app.getRenderThreadTid();
				// 当前如果是是前台进程组
				if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
					// 如果之前不是前台进程,即后台切到前台
					if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
						app.getWindowProcessController().onTopProcChanged();
						if (mService.mUseFifoUiScheduling) {
							// 将应用程序的 UI 管道切换到 SCHED_FIFO
							state.setSavedPriority(Process.getThreadPriority(app.getPid()));
							mService.scheduleAsFifoPriority(app.getPid(), true);
							if (renderThreadTid != 0) {
								mService.scheduleAsFifoPriority(renderThreadTid,
										/* suppressLogs */true);
							}
						} else {
							// 提升顶级应用程序 UI 和渲染线程的优先级
							setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
							if (renderThreadTid != 0) {
								try {
									setThreadPriority(renderThreadTid,
											THREAD_PRIORITY_TOP_APP_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 {
							// 将 UI 管道重置为 SCHED_OTHER
							setThreadScheduler(app.getPid(), SCHED_OTHER, 0);
							setThreadPriority(app.getPid(), state.getSavedPriority());
							if (renderThreadTid != 0) {
								setThreadScheduler(renderThreadTid,
										SCHED_OTHER, 0);
							}
						}
					} else {
						// 重置顶级应用程序 UI 和渲染线程的优先级
						setThreadPriority(app.getPid(), 0);
					}

					if (renderThreadTid != 0) {
						setThreadPriority(renderThreadTid, THREAD_PRIORITY_DISPLAY);
					}
				}
			}
		}
	}
	
	if (state.hasRepForegroundActivities() != state.hasForegroundActivities()) {
		state.setRepForegroundActivities(state.hasForegroundActivities());
		changes |= ActivityManagerService.ProcessChangeItem.CHANGE_ACTIVITIES;
	}

	// 更新 app 的冻结状态
	updateAppFreezeStateLSP(app, oomAdjReson);

	...
	
	...

	return success;
}

在 applyOomAdjLSP 中完成了对进程优先级的调整,性能的调整,并杀掉了 SCHED_GROUP_BACKGROUND 进程组中的进程。

七 总结

最后,我们再来总结一下。AMS 的内存管理,会通过一下几个因素来对进程的优先级进行调整。

  1. 进程是否重要:例如一些系统进程,或者持久化的进程,或者被其他进程依赖的进程,它们的进程组和优先级都是很难被杀的。
  2. 进程的状态:Android 中系统为进程定义了很多种进程状态,最简单的就是,当前在前台运行的进程比后台进程更难被杀,优先级更低。
  3. 进程的使用情况:对于最近使用的进程,系统会给与一些便利。(其实,如果一个进程经常被使用,系统同样会给与一些优先)。

根据以上三种情况,系统计算出一个综合的 adj 值和进程组,如果在内存不足,就会根据标记的进程组,来杀进程组为 SCHED_GROUP_BACKGROUND 的进程。换句话说,如果不是后台进程组 SCHED_GROUP_BACKGROUND,那么就不会在这里被系统杀死(当然,其他的进程管理也会有另外的杀进程逻辑,其他进程组的进程也有被杀的情况)。