本文正在参加「金石计划 . 瓜分6万现金大奖」
请点赞重视,你的支撑对我意义严重。

🔥 Hi,我是小余。
本文已收录到 GitHub · Androider-Planet 中。这儿有 Android 进阶成长常识体系,重视大众号 [小余的自习室] ,在成功的路上不迷路!

前语

前面一篇文章介绍了关于WMS在整个Android体系中的效果,首要能够划分为四类责任
1.窗口办理 2.窗口动画 3.Surface办理 4.输入事件中转站

假如把WMS比作古代将军,那么这四类责任便是将军手下几元大将,而AMS作为Android整个体系的统筹者,天经地义的便是古代的皇帝。

而今日要讲的是Android体系中比较重要的一个概念:AMS进程办理

传统的进程是指程序履行的载体,进程退出也就意味着程序退出了,而在Android中,进程的概念被弱化了,进程成为一个运转组件的容器。如运用中Service,即能够在宿主进程中运转也能够在服务进程中运转,服务进程退出,只是某个Service的退出,并非运用退出。

在Android中,谷歌将进程的办理和调度封装在了AMS中,运用层无需关怀进程是怎么作业的。

AMS对进程的办理首要体现在两个方面:

  • 1.进程LRU列表动态更新:动态调整进程在mLruProcesses列表的方位
  • 2.进程优先级动态调整:实际是调整进程oom_adj的值。

这两项调整和体系进行自动回收有关,当内存不足时,体系会封闭一些进程来开释内存、

下面笔者就依据这两方面来看下AMS是怎么办理进程的。

目录

进程LRU列表动态更新

假如你进程看Android源码,应该会常常看看下面这个办法:updateLruProcessLocked。当时或许只是了解有这么个办法做了个缓存进程的事,可是具体是怎么完成的并不知晓,总感觉看代码少了点什么,下面咱们会围绕这个办法打开。

AMS中的updateLruProcessLocked完成了对进程LRU列表动态更新:
在解说updateLruProcessLocked办法前,咱们先来解说下mLruProcesses进程列表在AMS中的模型。

LRU进程列表数据结构

AMS进程的LRU列表mLruProcesses:

final ArrayList<ProcessRecord> mLruProcesses = new ArrayList<ProcessRecord>();

AMS启动的每个进程都会被添加到LRU列表中,这个LRU列表不是随意排序的或许只是依据先后顺序排序的,而是依据具体规矩进行核算,以及进程的当时状况进行改动的
LRU列表中存储的是一个个ProcessRecord,AMS中运用ProcessRecord来代表一个进程、内部存储了一个进程所有的信息。

LRU列表被分为3段:

  • 1.hasActivity:带Activity的进程
  • 2.hasService:带Service的进程
  • 3.other:其他进程。

这三段运用两个字段切割开:mLruProcessServiceStartmLruProcessActivityStart,分别表明hasActivity段的开端方位以及hasService段的开端方位。

大约模型如下:

每次优先级较高的进程,如带前台Activity的进程就会优先被放到尾部,所以进程优先级由头到尾

有了上面这个模型根底,下面咱们从源码视点来看LRU列表就更轻松了。

关键办法详解

AMS运用updateLruProcessLocked办法对进程列表进行更新操作

updateLruProcessLocked()办法在ActivityStack类中有3处或许被调用

其间2处调用方位都处于ActivityStack类中的resumeTopActivityInnerLocked()办法

  • 1.pausing:经过home键回来或许back键退出一个Activity,此刻进程中不止一个Activity、

  • 2.resume:热启动Activity

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
      	//省掉。。
      	if (pausing && !resumeWhilePausing) {
      		if (next.app != null && next.app.thread != null) {
      			mService.updateLruProcessLocked(next.app, true, null);
      		}
      	}
        //省掉
        if (next.app != null && next.app.thread != null) {
            mService.updateLruProcessLocked(next.app, true, null);
            next.app.thread.scheduleResumeActivity(next.appToken....);
        }
        //省掉
    }
    

1处坐落**destroyActivityLocked()**办法:如按back键退出最终一个Activity的时分

final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
  	if (hadApp) {
		if (r.app.activities.isEmpty()) {
			mService.updateLruProcessLocked(r.app, false, null);
			mService.updateOomAdjLocked();
		}
	}
	r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,..;
}                   

下面具体来看下该办法:

final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
		ProcessRecord client) {
	//1.判别该进程是否存在Activity
	final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities
			|| app.treatLikeActivity;
	//2.判别进程是否存在Service
	final boolean hasService = false; // not impl yet. app.services.size() > 0;
	//3.给LRU的序列号+1
	mLruSeq++;
	//4.假如hasActivity为true
	if (hasActivity) {
        final int N = mLruProcesses.size();
        //假如当时进程有Activity且mLruProcesses最尾部的元素是当时进程,则什么都不用处理,直接退出
        if (N > 0 && mLruProcesses.get(N-1) == app) {
            if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top activity: " + app);
            return;
        }
    } else {
        //假如当时进程没有Activity且在Other段的top元素是当时进程,则也不处理,直接退出。
        if (mLruProcessServiceStart > 0
                && mLruProcesses.get(mLruProcessServiceStart-1) == app) {
            if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top other: " + app);
            return;
        }
    }
    //5.获取当时进程在mLruProcesses中的索引
    int lrui = mLruProcesses.lastIndexOf(app);
    //6.假如是persistent永久进程,且索引不为0,则直接退出不处理
    if (app.persistent && lrui >= 0) {
        return;
    }
    //7.索引大于等于0的状况下,对mLruProcessActivityStart和mLruProcessServiceStart进行更改并删去列表对应的索引上的进程
    if (lrui >= 0) {
        if (lrui < mLruProcessActivityStart) {
            mLruProcessActivityStart--;
        }
        if (lrui < mLruProcessServiceStart) {
            mLruProcessServiceStart--;
        }
        mLruProcesses.remove(lrui);
    }
    int nextIndex;
    if (hasActivity) {
        final int N = mLruProcesses.size();
        //8.假如hasActivity为true可是app.activities.size为0,其实便是1处的第二种判别app.hasClientActivities为true,且mLruProcessActivityStart切割点没超过列表进程数
        if (app.activities.size() == 0 && mLruProcessActivityStart < (N - 1)) {
            //9.将进程添加到mLruProcesses列表的倒数第二个方位,因为倒数第一个方位是提供给有Activity的进程运用。牢记带索引的add办法只是插入不会掩盖,被代替的元素自动后移
            mLruProcesses.add(N - 1, app);
            final int uid = app.info.uid;
            //10.为了避免当时进程创立许多Client端的进程,导致进程被乱用,将当时进程的子进程Client往重要性低处的列表排序,直到碰到不是当时进程的子进程Client端停止。
            for (int i = N - 2; i > mLruProcessActivityStart; i--) {
                ProcessRecord subProc = mLruProcesses.get(i);
                if (subProc.info.uid == uid) {
                    if (mLruProcesses.get(i - 1).info.uid != uid) {
                        //交流i和i-1方位的进程元素
                        ProcessRecord tmp = mLruProcesses.get(i);
                        mLruProcesses.set(i, mLruProcesses.get(i - 1));
                        mLruProcesses.set(i - 1, tmp);
                        i--;
                    }
                } else {
                    // A gap, we can stop here.
                    //假如呈现一个uid不一致的退出for循环交流
                    break;
                }
            }
        } else {
            //11.关于有Activity的进程,则直接将进程添加到结尾。		
            mLruProcesses.add(app);
        }
        //设置nextIndex为mLruProcessServiceStart
        nextIndex = mLruProcessServiceStart;
    } else if (hasService) {
        //12.假如是有Service的进程,则将进程插入到hasService段的结尾,也便是hasActivity段的开头方位
        mLruProcesses.add(mLruProcessActivityStart, app);
        //设置nextIndex为mLruProcessServiceStart
        nextIndex = mLruProcessServiceStart;
        //将mLruProcessActivityStart hasActivity的开始索引+1;
        mLruProcessActivityStart++;
    } else  {
        // Process not otherwise of interest, it goes to the top of the non-service area.
        int index = mLruProcessServiceStart;
        //办法的第三个参数client一般都为null,这儿不进入
        if (client != null) {
            //省掉。。
        }
        //13.关于其他也没Activity也没Service的状况,则将进程目标下添加到Other字段结尾:此刻index = mLruProcessServiceStart,也便是Other字段的结尾。
        mLruProcesses.add(index, app);
        //插入的索引的前一个索引方位
        nextIndex = index-1;
        //mLruProcessActivityStart和mLruProcessServiceStart索引均向后移动1位。
        mLruProcessActivityStart++;
        mLruProcessServiceStart++;
    }
    //关于有Service和ContentProvider的状况,也需求将Service的进程和ContentProvider的进程目标也插入到列表中。
    for (int j=app.connections.size()-1; j>=0; j--) {
        ConnectionRecord cr = app.connections.valueAt(j);
        if (cr.binding != null && !cr.serviceDead && cr.binding.service != null
                && cr.binding.service.app != null
                && cr.binding.service.app.lruSeq != mLruSeq
                && !cr.binding.service.app.persistent) {
            nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,
                    "service connection", cr, app);
        }
    }
    for (int j=app.conProviders.size()-1; j>=0; j--) {
        ContentProviderRecord cpr = app.conProviders.get(j).provider;
        if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.persistent) {
            nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,
                    "provider reference", cpr, app);
        }
    }
}

办法每个步骤已经在代码中做了阐明,假如你细心对照前面说的模型去看,一定能看懂。
这儿额外阐明下两点:

  • 1.关于永久性的进程即设置了persistent标志的进程在列表中的方位不会更改
  • 2.mLruProcessActivityStart和mLruProcessServiceStart会随着列表的改动而改动,而不是固定的
  • 3.为了避免某些进程自己又没Activity,却或许创立许多Client端的进程,导致进程被乱用的状况。会将当时进程的子进程Client往重要性低处的列表排序,直到碰到不是当时进程的子进程Client端停止
  • 4.关于有Service和ContentProvider的状况,也需求将Service的进程和ContentProvider的进程目标也插入到LRU列表中。

看图说话:

好了,关于进程列表的动态更新就讲到这儿。下面咱们来解说进程优先级动态调整

进程优先级动态调整

AMS中的updateOomAdjLocked办法完成了进程优先级的动态更新。
在解说updateOomAdjLocked办法前,咱们先来了解下与进程相关的几个重要概念。

进程优先级(OOM_ADJ)

OOM_ADJ定义在ProcessList.java文件,大约划分为20个级。

ADJ等级 adjString 取值 解说
UNKNOWN_ADJ 1001 预留的最低等级,一般关于缓存的进程才有或许设置成这个等级
CACHED_APP_MAX_ADJ 999 不可见进程的adj最大值,在内存不足的状况下就会优先被kill。
CACHED_APP_LMK_FIRST_ADJ 950 lowmem 查杀的最小等级
CACHED_APP_MIN_ADJ cch 900 不可见进程的adj最小值,在内存不足的状况下就会优先被kill
SERVICE_B_ADJ svcb 800 非活跃进程,B List中的Service(运转时间较长、运用或许性更小)
PREVIOUS_APP_ADJ prev 700 上一个App的进程(上一个stopActivity的进程/20s内刚被运用的provider进程)
HOME_APP_ADJ home 600 Home进程
SERVICE_ADJ svc 500 服务进程(Service process)
HEAVY_WEIGHT_APP_ADJ hvy 400 后台的重量级进程
BACKUP_APP_ADJ bkup 300 备份进程
PERCEPTIBLE_LOW_APP_ADJ prcl 250 由体系(或其他运用程序)绑定的进程,它比服务更重要,但不易察觉(clientAdj<200经过BIND_NOT_PERCEPTIBLE bind)
PERCEPTIBLE_APP_ADJ prcp 200 可感知进程,比如后台音乐播映 (前台服务/display an overlay UI/currently used for toasts/clientAdj<200经过BIND_NOT_VISIBLE bind)
VISIBLE_APP_ADJ(VISIBLE_APP_LAYER_MAX200-100-1) vis 100 可见进程(Visible process) ,一般是100+当时可见的layer数:activity不在前台,可是确实可见的或许正在运转远程动画
PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ 50 运用有前台服务,从前台切换到前台service,且在15s内到过前台
FOREGROUND_APP_ADJ fg 0 前台进程(Foreground process):运用本身便是在前台或许正在接纳处理广播isReceivingBroadcastLocked或许服务履行进程中
PERSISTENT_SERVICE_ADJ psvc -700 相关着体系或persistent进程(由startIsolatedProcess()方式启动的进程,或许是由system_server或许persistent进程所绑定的服务进程)
PERSISTENT_PROC_ADJ pers -800 体系persistent进程,比如telephony(一般不会被杀,即便被杀或crash,立即重启)
SYSTEM_ADJ sys -900 体系进程(system_server进程)
NATIVE_ADJ ntv -1000 native进程(由init进程fork出的进程,并不受system管控)

获取oom_adj:

adb shell ps|grep com.android.yuhb.test
adb shell cat /proc/21375/oom_adj

每个等级的进程又有对应的优先级,运用oom_adj值来表明,进程回收机制便是依据这个adj值来进行的
前台进程adj值最低,代表进程优先级最高,空进程adj值越高,最简单被kill,关于持平优先级的进程:运用的内存越多越简单被杀死

进程state等级(ProcState)

ProcState定义在ActivityManager.java文件,大约划分为22类。用来表明当时进程的一组状况

state等级 procStateString 取值 解说
PROCESS_STATE_NONEXISTENT NONE 20 不存在的进程
PROCESS_STATE_CACHED_EMPTY CEM 19 处于cached状况的空进程
PROCESS_STATE_CACHED_RECENT CRE 18 有activity在最近使命列表的cached进程
PROCESS_STATE_CACHED_ACTIVITY_CLIENT CACC 17 进程处于cached状况,且为另一个cached进程(内含Activity)的client进程
PROCESS_STATE_CACHED_ACTIVITY CAC 16 进程处于cached状况(内含Activity)
PROCESS_STATE_LAST_ACTIVITY LAST 15 后台进程(具有上一次显现的Activity)
PROCESS_STATE_HOME HOME 14 后台进程(具有home Activity)
PROCESS_STATE_HEAVY_WEIGHT HVY 13 后台进程(但无法履行restore,因此尽量避免kill该进程)
PROCESS_STATE_TOP_SLEEPING TPSL 12 与PROCESS_STATE_TOP一样,但此刻设备正处于休眠状况
PROCESS_STATE_RECEIVER RCVR 11 后台进程,且正在运转receiver
PROCESS_STATE_SERVICE SVC 10 后台进程,且正在运转service
PROCESS_STATE_BACKUP BKUP 9 后台进程,正在运转backup/restore操作
PROCESS_STATE_TRANSIENT_BACKGROUND TRNB 8 后台进程
PROCESS_STATE_IMPORTANT_BACKGROUND IMPB 7 对用户很重要的进程,用户不可感知其存在
PROCESS_STATE_IMPORTANT_FOREGROUND IMPF 6 对用户很重要的进程,用户可感知其存在
PROCESS_STATE_BOUND_FOREGROUND_SERVICE , BFGS 5 经过体系绑定具有一个前台Service
PROCESS_STATE_FOREGROUND_SERVICE FGS 4 具有一个前台Service
PROCESS_STATE_BOUND_TOP BTOP 3 绑定到top运用的进程
PROCESS_STATE_TOP TOP 2 具有当时用户可见的top Activity
PROCESS_STATE_PERSISTENT_UI PERU 1 persistent体系进程,并正在履行UI操作
PROCESS_STATE_PERSISTENT PER 0 persistent体系进程
PROCESS_STATE_UNKNOWN -1 UNKNOWN进

进程组schedGroup

用来表明当时进程地点的进程调度组序列。

schedGroup 意义
SCHED_GROUP_BACKGROUN 0 后台进程组
SCHED_GROUP_RESTRICTED 1
SCHED_GROUP_DEFAULT 2 前台进程组
SCHED_GROUP_TOP_APP 3 TOP进程组
SCHED_GROUP_TOP_APP_BOUND 4 TOP进程组

LMK机制

LMK 全称 Low Memory Killer`。

在Android中,即便当用户退出运用程序后,运用进程也还会存在内存中,便利下次能够快速进入运用而不需求从头创立进程
这样带来的直接影响便是因为进程数量越来越多,体系内存会越来越少,这个时分就需求杀死一部分进程来缓解内存压力。
至于哪些进程会被杀死,这个时分就需求用到Low Memory Killer机制来进行断定。

Android的Low Memory Killer依据Linux的OOM机制
在Linux中,内存是以页面为单位分配的,当申请页面分配时假如内存不足会经过以下流程选择bad进程来杀掉从而开释内存

alloc_pages -> out_of_memory() -> select_bad_process() -> badness()

LMK驱动层在用户空间指定了一组内存临界值及与之一一对应的一组oom_adj值,
当体系剩下内存坐落内存临界值中的一个范围内时,假如一个进程的oom_adj值大于或等于这个临界值对应的oom_adj值就会被杀掉。

运用命令:cat /sys/module/lowmemorykiller/parameters/minfree来检查某个手机的内存阈值

18432,23040,27648,32256,36864,46080

留意这些数字的单位是page. 1 page = 4 kb.上面的六个数字对应的便是(MB): 72,90,108,126,144,180
如数180代表内存低于180M时会清除优先级最低的空进程。

LMK还维护着一个办理体系中所有进程及其adj信息的双向链表数组,这个双向链表数组的每一个元素都是一个双向链表,一个数组元素中的双向链表里面的元素,都是adj相同的进程
在体系可用内存较低时,就会选择性杀死进程的战略。避免内存过低影响体系运转。
LMK杀死进程的两个目标:
1.oom_adj 2.内存占用巨细

而AMS经过四大组件的运转状况更新这些组件相相关的进程的oom_adj(包括adj,proc_state,schedule_group等值),
AMS核算好每个进程的oom_adj,经过socket向lmkd服务发送恳求,让lmkd去更新进程的优先级,lmkd收到恳求后,会经过/proc文件体系去更新内核中的进程优先级这样AMS就能够间接经过LMK完成对进程的动态办理。

LMKD与AMS交互图:

有了上面的根底,咱们再来具体看下updateOomAdjLocked是怎么进行动态更新adj的。

6.关键办法详解

前面说过,当AMS需求更新进程的优先级时,就会调用它的updateOomAdjLocked办法,这儿只提取办法的updateOomAdjLocked的一些中心代码:

final void updateOomAdjLocked() {
	//省掉。。。
	for (int i=N-1; i>=0; i--) {
		ProcessRecord app = mLruProcesses.get(i);
		if (!app.killedByAm && app.thread != null) {
			app.procStateChanged = false;
			computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
			//...
			applyOomAdjLocked(app, true, now, nowElapsed);
			//...
		}
	}
}

能够看到updateOomAdjLocked内部首要是对LUR进程列表中的每个进程调用computeOomAdjLocked以及applyOomAdjLocked处理

中心办法:computeOomAdjLocked以及applyOomAdjLocked

  • 1.computeOomAdjLocked:核算adj,回来核算后RawAdj值
  • 2.applyOomAdjLocked:将核算后的adj写入lmkd,当需求杀掉目标进程则回来false;否则回来true。

computeOomAdjLocked:

该办法会传入需求更新adj的进程描述符ProcessRecord,然后根据参数核算出当时进程乃至相关客户端进程的优先级,进程状况,进程组等信息

因为这个办法较长,这儿列出代码流程。

  • 1.经过mAdjSeq字段判别此轮更新是否已经核算过adj,是的话直接回来当时app.curRawAdj
  • 2.判别进程的客户端线程是否存在,不存在,则:将adj设置为CACHED_APP_MAX_ADJ。
  • 3.判别是否是前台进程,假如不是:则依据TOP_APP,app.hasTopUi,activitiesSize,systemNoUi等参数核算adj。
  • 4.前台进程持续往下,初始化一些前台进程相关的默认值,后续再依据具体状况细化。
  • 5.依据是否为TOP_APP,是否有正在接受的动画,是否有正在履行的服务,是否有正在运转的Activity以及Activity的状况等对adj等参数赋值
  • 6.对可见进程或许具有可感知的前台服务或许后台服务等参数设置adj
  • 7.对后台进程设置优先级
  • 8.遍历在进程上运转的Service,依据Service的状况进一步更新adj等值。
  • 9.同Service。**遍历进程上的ContentProvider,**依据ContentProvider的状况进一步更新adj等值。
  • 10.依据cache进程运转状况,细分出cache进程还有empty进程
  • 11.将核算好的adj等值赋值给对应的进程特点

代码就不列出来了,笔者依据代码,画了个流程图,便利大家检查,感兴趣的能够依据这个图自行去阅读源码。

applyOomAdjLocked:

这个办法首要有三个效果:

  • 1.设置进程优先级:将前面核算好的curAdj传递给LMKD服务
  • 2.设置进程状况:将curProcState线程状况回传给运用进程ApplicationThread
  • 3.设置进程的调度战略:将schedGroup设置为对应的进程调度组。
1.设置进程优先级

在applyOomAdjLocked办法中比较重要的一段代码:

if (app.curAdj != app.setAdj) {
    ProcessList.setOomAdj(app.pid, app.info.uid, app.curAdj);
    if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
            "Set " + app.pid + " " + app.processName + " adj " + app.curAdj + ": "
            + app.adjType);
    app.setAdj = app.curAdj;
    app.verifiedAdj = ProcessList.INVALID_ADJ;
}

持续看ProcessList的setOomAdj办法:

public static final void setOomAdj(int pid, int uid, int amt) {
    if (amt == UNKNOWN_ADJ)
        return;
    long start = SystemClock.elapsedRealtime();
    ByteBuffer buf = ByteBuffer.allocate(4 * 4);
    buf.putInt(LMK_PROCPRIO);
    buf.putInt(pid);
    buf.putInt(uid);
    buf.putInt(amt);
    writeLmkd(buf);
    long now = SystemClock.elapsedRealtime();
    if ((now-start) > 250) {
        Slog.w("ActivityManager", "SLOW OOM ADJ: " + (now-start) + "ms for pid " + pid
                + " = " + amt);
    }
}
private static void writeLmkd(ByteBuffer buf) {
    for (int i = 0; i < 3; i++) {
        if (sLmkdSocket == null) {
                if (openLmkdSocket() == false) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ie) {
                    }
                    continue;
                }
        }
        try {
            sLmkdOutputStream.write(buf.array(), 0, buf.position());
            return;
        } catch (IOException ex) {
            Slog.w(TAG, "Error writing to lowmemorykiller socket");
            try {
                sLmkdSocket.close();
            } catch (IOException ex2) {
            }
            sLmkdSocket = null;
        }
    }
}
private static boolean openLmkdSocket() {
    try {
        sLmkdSocket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET);
        sLmkdSocket.connect(
            new LocalSocketAddress("lmkd",
                    LocalSocketAddress.Namespace.RESERVED));
        sLmkdOutputStream = sLmkdSocket.getOutputStream();
    } catch (IOException ex) {
        Slog.w(TAG, "lowmemorykiller daemon socket open failed");
        sLmkdSocket = null;
        return false;
    }
	return true;
}

能够看到最终将adj,pid,uid写入名为lmkd的Socket通道中。之后的进程adj更新便是由lmkd来负责了
lmkd依据传入的参数,去Proc文件体系中更新进程优先级信息。

2.设置进程状况

代码片段:

if (app.repProcState != app.curProcState) {
    app.repProcState = app.curProcState;
    if (app.thread != null) {
        try {
            app.thread.setProcessState(app.repProcState);
        } catch (RemoteException e) {
        }
    }
}

这儿调用了运用进程的ApplicationThread的setProcessState办法:

public void setProcessState(int state) {
	updateProcessState(state, true);
}
public void updateProcessState(int processState, boolean fromIpc) {
	synchronized (this) {
		if (mLastProcessState != processState) {
			mLastProcessState = processState;
			// Update Dalvik state based on ActivityManager.PROCESS_STATE_* constants.
			final int DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE = 0;
			final int DALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1;
			int dalvikProcessState = DALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE;
			// TODO: Tune this since things like gmail sync are important background but not jank perceptible.
			if (processState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
				dalvikProcessState = DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE;
			}
			VMRuntime.getRuntime().updateProcessState(dalvikProcessState);
			if (false) {
				Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState
						+ (fromIpc ? " (from ipc": ""));
			}
		}
	}
}

ApplicationThread的setProcessState办法:
判别当时processState是否小余或等于ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND状况值,将其改为虚拟机运转时环境能够识别的DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE值。
最终调用到了VMRuntime.getRuntime().updateProcessState(dalvikProcessState),将状况设置到AndroidRuntime运转时环境中。这儿其实便是告知ART运转时当时进程的可感知才能,
用来切换虚拟机之间的GC算法,即到底是前台进程GC仍是后台进程GC,前台GC算法效率高,可是会发生碎片,后台GC效率低,可是不会发生碎片。

具体能够参考下面这篇文章:
[ART运转时Foreground GC和Background GC切换进程分析](罗生阳)

3.设置进程调度战略
if (app.setSchedGroup != app.curSchedGroup) {
	int oldSchedGroup = app.setSchedGroup;
	app.setSchedGroup = app.curSchedGroup;
	switch (app.curSchedGroup) {
		case ProcessList.SCHED_GROUP_BACKGROUND:
			processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
			break;
		case ProcessList.SCHED_GROUP_TOP_APP:
		case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
			processGroup = THREAD_GROUP_TOP_APP;
			break;
		default:
			processGroup = THREAD_GROUP_DEFAULT;
			break;
	}
	long oldId = Binder.clearCallingIdentity();
	try {
		Process.setProcessGroup(app.pid, processGroup);    //1 
		if (app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
			// do nothing if we already switched to RT
			if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
				mVrController.onTopProcChangedLocked(app);
				if (mUseFifoUiScheduling) {
					//...
				} else {
					// Boost priority for top app UI and render threads
					setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST);//2
					if (app.renderThreadTid != 0) {
						try {
							setThreadPriority(app.renderThreadTid,
									TOP_APP_PRIORITY_BOOST);
						} catch (IllegalArgumentException e) {
							// thread died, ignore
						}
					}
				}
			}
		} 
	} catch (Exception e) {                  
	} 
}

这段代码首要做了两件事情:

  • 1.调用Process.setProcessGroup(int pid, int group)去设置进程调度战略,原理便是:
    使用linux的cgroup机制,依据进程状况将进程放入预先设定的cgroup分组中,分组中包含了对cpu运用率、cpuset、cpu调频等子资源的装备,以满足特定状况进程对体系资源的需求
  • 2.对schedGroup在某前台和后台之间切换时,调用setThreadPriority办法,切换主线程以及绘制线程的优先级,以提高用户的响应速度

总结

这篇文章首要解说了关于Android体系中常见的进程办理相关的常识点:
其间对AMS中两个比较常见的办法:updateLruProcessLocked以及updateOomAdjLocked做了具体介绍。

作为运用开发或许咱们平常用不到这些,可是在做一些功能优化,进程保活的操作时,这些储备常识却是必备的。一些高阶用法,需求你去了解更深层次的东西,而不仅局限于外表

期望这篇文章对你有协助。假如你想了解更多关于Framework的常识请重视我、

笔者大众号:“小余的自习室”