copy from : http://gityuan.com/2018/05/19/android-process-adj/
本文基于原生Android 9.0源码来解读进程优先级原理,基于篇幅考虑会精炼部分代码
Android框架对进程创建与管理进行了封装,对于APP开发者只需知道Android四大组件的使用。当Activity, Service, ContentProvider, BroadcastReceiver任一组件启动时,当其所承载的进程存在则直接使用,不存在则由框架代码自动调用startProcessLocked创建进程。一个APP可以拥有多个进程,多个APP也可以运行在同一个进程,通过配置Android:process属性来决定。所以说对APP来说进程几乎是透明的,但了解进程对于深刻理解Android系统是至关关键的。
Android系统的设计理念正是希望应用进程能尽量长时间地存活,以提升用户体验。应用首次打开比较慢,这个过程有进程创建以及Application等信息的初始化,所以应用在启动之后,即便退到后台并非立刻杀死,而是存活一段时间,这样下次再使用则会非常快。对于APP同样希望自身尽可能存活更长的时间,甚至探索各种保活黑科技。物极必反,系统处于低内存的状态下,手机性能会有所下降;系统继续放任所有进程一直存活,系统内存很快就会枯竭而亡,那么需要合理地进程回收机制。
到底该回收哪个进程呢?系统根据进程的组件状态来决定每个进程的优先级值ADJ,系统根据一定策略先杀优先级最低的进程,然后逐步杀优先级更低的进程,依此类推,以回收预期的可用系统资源,从而保证系统正常运转。
谈到优先级,可能有些人会想到Linux进程本身有nice值,这个能决定CPU资源调度的优先级;而本文介绍Android系统中的ADJ,主要决定在什么场景下什么类型的进程可能会被杀,影响的是进程存活时间。ADJ与nice值两者定位不同,不过也有一定的联系,优先级很高的进程,往往也是用户不希望被杀的进程,是具有有一定正相关性。
ADJ级别 | 取值 | 含义 |
---|---|---|
NATIVE_ADJ | -1000 | native进程 |
SYSTEM_ADJ | -900 | 仅指system_server进程 |
PERSISTENT_PROC_ADJ | -800 | 系统persistent进程 |
PERSISTENT_SERVICE_ADJ | -700 | 关联着系统或persistent进程 |
FOREGROUND_APP_ADJ | 0 | 前台进程 |
VISIBLE_APP_ADJ | 100 | 可见进程 |
PERCEPTIBLE_APP_ADJ | 200 | 可感知进程,比如后台音乐播放 |
BACKUP_APP_ADJ | 300 | 备份进程 |
HEAVY_WEIGHT_APP_ADJ | 400 | 重量级进程 |
SERVICE_ADJ | 500 | 服务进程 |
HOME_APP_ADJ | 600 | Home进程 |
PREVIOUS_APP_ADJ | 700 | 上一个进程 |
SERVICE_B_ADJ | 800 | B List中的Service |
CACHED_APP_MIN_ADJ | 900 | 不可见进程的adj最小值 |
CACHED_APP_MAX_ADJ | 906 | 不可见进程的adj最大值 |
从Android 7.0开始,ADJ采用100、200、300;在这之前的版本ADJ采用数字1、2、3,这样的调整可以更进一步地细化进程的优先级,比如在VISIBLE_APP_ADJ(100)与PERCEPTIBLE_APP_ADJ(200)之间,可以有ADJ=101、102级别的进程。
为了防止剩余内存过低,Android在内核空间有lowmemorykiller(简称LMK),LMK是通过注册shrinker来触发低内存回收的,这个机制并不太优雅,可能会拖慢Shrinkers内存扫描速度,已从内核4.12中移除,后续会采用用户空间的LMKD + memory cgroups机制,这里先不展开LMK讲解。
进程刚启动时ADJ等于INVALID_ADJ,当执行完attachApplication(),该该进程的curAdj和setAdj不相等,则会触发执行setOomAdj()将该进程的节点/proc/pid
/oom_score_adj写入oomadj值。下图参数为Android原生阈值,当系统剩余空闲内存低于某阈值(比如147MB),则从ADJ大于或等于相应阈值(比如900)的进程中,选择ADJ值最大的进程,如果存在多个ADJ相同的进程,则选择内存最大的进程。 如下是64位机器,LMK默认阈值图:
在updateOomLevels()过程,会根据手机屏幕尺寸或内存大小来调整scale,默认大多数手机内存都大于700MB,则scale等于1。对于64位手机,阈值会更大些,具体如下。
private void updateOomLevels(int displayWidth, int displayHeight, boolean write) { ... for (int i=0; i<mOomAdj.length; i++) { int low = mOomMinFreeLow[i]; int high = mOomMinFreeHigh[i]; if (is64bit) { if (i == 4) high = (high*3)/2; else if (i == 5) high = (high*7)/4; } mOomMinFree[i] = (int)(low + ((high-low)*scale)); } }
接下来,解读每个ADJ值都对应着怎样条件的进程,包括正在运行的组件以及这些组件的状态几何。这里重点介绍上图标红的ADJ级别所对应的进程。
Android系统中计算各进程ADJ算法的核心方法:
当Android四大组件状态改变时会updateOomAdjLocked()来同步更新相应进程的ADJ优先级。这里需要说明一下,当同一个进程有多个决定其优先级的组件状态时,取优先级最高的ADJ作为最终的ADJ。另外,进程会通过设置maxAdj来限定ADJ的上限。
关于分析进程ADJ相关信息,常用命令如下:
再来说一下其他优先级:
SYSTEM_ADJ: 仅指system_server进程。在执行SystemServer的startBootstrapServices()过程会调用AMS.setSystemProcess(),将system_server进程的maxAdj设置成SYSTEM_ADJ,源码如下:
public void setSystemProcess() { ... ApplicationInfo info = mContext.getPackageManager().getApplicationInfo( "android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY); mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader()); synchronized (this) { ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0); app.persistent = true; app.pid = MY_PID; app.maxAdj = ProcessList.SYSTEM_ADJ; app.makeActive(mSystemThread.getApplicationThread(), mProcessStats); synchronized (mPidsSelfLocked) { mPidsSelfLocked.put(app.pid, app); } updateLruProcessLocked(app, false, null); updateOomAdjLocked(); } ... }
但system_server的ADJ并非等于-900,而是-800?是由于startPersistentApps()过程直接把其adj重新被设置为-800,这算是一个小BUG,但 其实目前来说对于ADJ<0的进程,LMK不会杀,两者没有什么区别。
PERSISTENT_PROC_ADJ:在AndroidManifest.xml中申明android:persistent=”true”的系统(即带有FLAG_SYSTEM标记)进程,称之为persistent进程。对于persistent进程常规情况都不会被杀,一旦被杀或者发生Crash,进程会立即重启。
AMS.addAppLocked()或AMS.newProcessRecordLocked()过程会赋值:
场景1: newProcessRecordLocked
final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess, boolean isolated, int isolatedUid) { String proc = customProcess != null ? customProcess : info.processName; final int userId = UserHandle.getUserId(info.uid); int uid = info.uid; ... final ProcessRecord r = new ProcessRecord(stats, info, proc, uid); if (!mBooted && !mBooting && userId == UserHandle.USER_SYSTEM && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { r.persistent = true; r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ; } if (isolated && isolatedUid != 0) { r.maxAdj = ProcessList.PERSISTENT_SERVICE_ADJ; } return r; }
在每一次进程启动的时候都会判断该进程是否persistent进程,如果是则会设置maxAdj=PERSISTENT_PROC_ADJ。 system_server进程应该也是persistent进程?
场景2:addAppLocked
final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, String abiOverride) { ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName, info.uid, true); } else { app = null; } if (app == null) { app = newProcessRecordLocked(info, customProcess, isolated, 0); updateLruProcessLocked(app, false, null); updateOomAdjLocked(); } ... if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { app.persistent = true; app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ; } if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); startProcessLocked(app, "added application", customProcess != null ? customProcess : app.processName, abiOverride); } return app; }
开机过程会先启动persistent进程,并赋予maxAdj为PERSISTENT_PROC_ADJ,调用链:
startOtherServices() AMS.systemReady AMS.startPersistentApps AMS.addAppLocked
PERSISTENT_SERVICE_ADJ: startIsolatedProcess()方式启动的进程,或者是由system_server或者persistent进程所绑定的服务进程。
场景1:newProcessRecordLocked
final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess, boolean isolated, int isolatedUid) { String proc = customProcess != null ? customProcess : info.processName; final int userId = UserHandle.getUserId(info.uid); int uid = info.uid; ... final ProcessRecord r = new ProcessRecord(stats, info, proc, uid); if (!mBooted && !mBooting && userId == UserHandle.USER_SYSTEM && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { r.persistent = true; r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ; } if (isolated && isolatedUid != 0) { //startIsolatedProcess r.maxAdj = ProcessList.PERSISTENT_SERVICE_ADJ; } return r; }
调用链:
startOtherServices WebViewUpdateService.prepareWebViewInSystemServer WebViewUpdateServiceImpl.prepareWebViewInSystemServer WebViewUpdater.prepareWebViewInSystemServer WebViewUpdater.onWebViewProviderChanged SystemImpl.onWebViewProviderChanged WebViewFactory.onWebViewProviderChanged WebViewLibraryLoader.prepareNativeLibraries WebViewLibraryLoader.createRelros WebViewLibraryLoader.createRelroFile AMS.startIsolatedProcess
if (mBackupTarget != null && app == mBackupTarget.app) { if (adj > ProcessList.BACKUP_APP_ADJ) { adj = ProcessList.BACKUP_APP_ADJ; if (procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) { procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND; } app.adjType = "backup"; app.cached = false; } if (procState > ActivityManager.PROCESS_STATE_BACKUP) { procState = ActivityManager.PROCESS_STATE_BACKUP; app.adjType = "backup"; } }
当类型为ACTIVITY_TYPE_HOME的应用启动后会设置mHomeProcess,比如桌面APP。
场景1:用户上一个使用的包含UI的进程,为了给用户在两个APP之间更好的切换体验,将上一个进程ADJ设置到PREVIOUS_APP_ADJ的档次。 当activityStoppedLocked()过程会更新上一个应用。
if (app == mPreviousProcess && app.activities.size() > 0) { if (adj > ProcessList.PREVIOUS_APP_ADJ) { adj = ProcessList.PREVIOUS_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_BACKGROUND; app.cached = false; app.adjType = "previous"; } if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) { procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY; app.adjType = "previous"; } }
场景2: 当provider进程,上一次使用时间不超过20S的情况下,优先级不低于PREVIOUS_APP_ADJ。provider进程这个是Android 7.0以后新增的逻辑 ,这样做的好处是在内存比较低的情况下避免拥有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.cached = false; app.adjType = "recent-provider"; } if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) { procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY; app.adjType = "recent-provider"; } }
场景1:满足以下任一条件的进程都属于FOREGROUND_APP_ADJ(0)优先级:
源码如下:
if (PROCESS_STATE_CUR_TOP == ActivityManager.PROCESS_STATE_TOP && app == TOP_APP) { adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_TOP_APP; app.adjType = "top-activity"; foregroundActivities = true; procState = PROCESS_STATE_CUR_TOP; } else if (app.instr != null) { adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_DEFAULT; app.adjType = "instrumentation"; procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; } else if (isReceivingBroadcastLocked(app, mTmpBroadcastQueue)) { adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = (mTmpBroadcastQueue.contains(mFgBroadcastQueue)) ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND; app.adjType = "broadcast"; procState = ActivityManager.PROCESS_STATE_RECEIVER; } else if (app.executingServices.size() > 0) { adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = app.execServicesFg ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND; app.adjType = "exec-service"; procState = ActivityManager.PROCESS_STATE_SERVICE; } else if (app == TOP_APP) { adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_BACKGROUND; app.adjType = "top-sleeping"; foregroundActivities = true; procState = PROCESS_STATE_CUR_TOP; } else { schedGroup = ProcessList.SCHED_GROUP_BACKGROUND; adj = cachedAdj; procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; app.cached = true; app.empty = true; app.adjType = "cch-empty"; }
场景2: 当客户端进程activity里面调用bindService()方法时flags带有BIND_ADJUST_WITH_ACTIVITY参数,并且该activity处于可见状态,则当前服务进程也属于前台进程,源码如下:
for (int is = app.services.size()-1; is >= 0; is--) { ServiceRecord s = app.services.valueAt(is); for (int conni = s.connections.size()-1; conni >= 0; conni--) { ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni); for (int i = 0; i < clist.size(); i++) { ConnectionRecord cr = clist.get(i); if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) { ... } final ActivityRecord a = cr.activity; if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) { if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ && (a.visible || a.state == ActivityState.RESUMED || a.state == ActivityState.PAUSING)) { adj = ProcessList.FOREGROUND_APP_ADJ; if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) { if ((cr.flags&Context.BIND_IMPORTANT) != 0) { schedGroup = ProcessList.SCHED_GROUP_TOP_APP_BOUND; } else { schedGroup = ProcessList.SCHED_GROUP_DEFAULT; } } app.cached = false; app.adjType = "service"; app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_SERVICE_IN_USE; app.adjSource = a; app.adjSourceProcState = procState; app.adjTarget = s.name; } } } } }
场景3: 对于provider进程,还有以下两个条件能成为前台进程:
for (int provi = app.pubProviders.size()-1; provi >= 0; provi--) { ContentProviderRecord cpr = app.pubProviders.valueAt(provi); //根据client来调整provider进程的adj和procState for (int i = cpr.connections.size()-1; i >= 0; i--) { ContentProviderConnection conn = cpr.connections.get(i); ProcessRecord client = conn.client; int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now); if (adj > clientAdj) { if (app.hasShownUi && app != mHomeProcess && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { ... } else { adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ ? clientAdj : ProcessList.FOREGROUND_APP_ADJ; adjType = "provider"; } app.cached &= client.cached; } ... } //根据provider外部依赖情况来调整adj和schedGroup if (cpr.hasExternalProcessHandles()) { if (adj > ProcessList.FOREGROUND_APP_ADJ) { adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_DEFAULT; app.cached = false; app.adjType = "ext-provider"; app.adjTarget = cpr.name; } } }
可见进程:当ActivityRecord的visible=true,也就是Activity可见的进程。
if (!foregroundActivities && activitiesSize > 0) { int minLayer = ProcessList.VISIBLE_APP_LAYER_MAX; for (int j = 0; j < activitiesSize; j++) { final ActivityRecord r = app.activities.get(j); if (r.visible) { if (adj > ProcessList.VISIBLE_APP_ADJ) { adj = ProcessList.VISIBLE_APP_ADJ; app.adjType = "vis-activity"; } if (procState > PROCESS_STATE_CUR_TOP) { procState = PROCESS_STATE_CUR_TOP; app.adjType = "vis-activity"; } schedGroup = ProcessList.SCHED_GROUP_DEFAULT; app.cached = false; app.empty = false; foregroundActivities = true; final TaskRecord task = r.getTask(); if (task != null && minLayer > 0) { final int layer = task.mLayerRank; if (layer >= 0 && minLayer > layer) { minLayer = layer; } } break; } ... } if (adj == ProcessList.VISIBLE_APP_ADJ) { adj += minLayer; } }
从Android P开始,进一步细化ADJ级别,增加了VISIBLE_APP_LAYER_MAX(99),是指VISIBLE_APP_ADJ(100)跟PERCEPTIBLE_APP_ADJ(200)之间有99个槽,则可见级别ADJ的取值范围为[100,199]。 算法会根据其所在task的mLayerRank来调整其ADJ,100加上mLayerRank就等于目标ADJ,layer越大,则ADJ越小。
关于TaskRecord的mLayerRank的计算方式是在updateOomAdjLocked()过程调用ASS的rankTaskLayersIfNeeded()方法,如下:
[-> ActivityStackSupervisor.java]void rankTaskLayersIfNeeded() { if (!mTaskLayersChanged) { return; } mTaskLayersChanged = false; for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); displayNdx++) { final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); int baseLayer = 0; for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = display.getChildAt(stackNdx); baseLayer += stack.rankTaskLayers(baseLayer); } } }
[-> ActivityStack.java]final int rankTaskLayers(int baseLayer) { int layer = 0; for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = mTaskHistory.get(taskNdx); ActivityRecord r = task.topRunningActivityLocked(); if (r == null || r.finishing || !r.visible) { task.mLayerRank = -1; } else { task.mLayerRank = baseLayer + layer++; } } return layer; }
当TaskRecord顶部的ActivityRecord为空或者结束或者不可见时,则设置该TaskRecord的mLayerRank等于-1; 每个ActivityDisplay的baseLayer都是从0开始,从最上面的TaskRecord开始,第一个ADJ=100,从上至下依次加1,直到199为上限。
ServiceRecord的成员变量startRequested=true,是指被显式调用了startService()方法。当service被stop或kill会将其置为false。
一般情况下,即便客户端进程处于前台进程(ADJ=0)级别,服务进程只会提升到可见(ADJ=1)级别。以下flags是由调用bindService()过程所传递的flags来决定的。
flag | 含义 |
---|---|
BIND_WAIVE_PRIORITY | 是指客户端进程的优先级不会影响目标服务进程的优先级。比如当调用bindService又不希望提升目标服务进程的优先级的情况下,可以使用该flags |
BIND_ADJUST_WITH_ACTIVITY | 是指当从Activity绑定到该进程时,允许目标服务进程根据该activity的可见性来提升优先级 |
BIND_ABOVE_CLIENT | 当客户端进程绑定到一个服务进程时,则服务进程比客户端进程更重要 |
BIND_IMPORTANT | 标记该服务对于客户端进程很重要,当客户端进程处于前台进程(ADJ=0)级别时,会把服务进程也提升到前台进程级别 |
BIND_NOT_VISIBLE | 当客户端进程处于可见(ADJ=1)级别,也不允许被绑定的服务进程提升到可见级别,该类服务进程的优先级上限为可感知(ADJ=2)级别 |
BIND_NOT_FOREGROUND | 不允许被绑定的服务进程提升到前台调度优先级,但是内存优先级可以提升到前台级别。比如不希望服务进程占用 |
作为工程师很多时候可能还是想看看源码,show me the code。但是关于ADJ计算这一块源码场景computeOomAdjLocked(),Google真心写得比较乱,为了更清晰地说明客户端进程如何影响服务进程,在保证不失去原意的情况下重写了这块部分逻辑:
这个过程主要根据service本身、client端情况以及activity状态分别来调整adj和schedGroup
for (int is = app.services.size()-1; is >= 0; is--) { ServiceRecord s = app.services.valueAt(is); if (s.startRequested) { ... // 根据service本身调整adj和adjType } for (int conni = s.connections.size()-1; conni >= 0; conni--) { ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni); for (int i = 0; i < clist.size(); i++) { ConnectionRecord cr = clist.get(i); //根据client端来调整adj if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) { if (adj > clientAdj) { if (app.hasShownUi && app != mHomeProcess && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { ... } else { int newAdj = clientAdj; if ((cr.flags&(Context.BIND_ABOVE_CLIENT |Context.BIND_IMPORTANT)) != 0) { if(clientAdj < ProcessList.PERSISTENT_SERVICE_ADJ) { newAdj = PERSISTENT_SERVICE_ADJ; } } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0) { if(clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ) { newAdj = PERCEPTIBLE_APP_ADJ; } } else { if (clientAdj < ProcessList.VISIBLE_APP_ADJ) { newAdj = VISIBLE_APP_ADJ; } } if (adj > newAdj) { adj = newAdj; adjType = "service"; } } } } final ActivityRecord a = cr.activity; // 根据client的activity来调整adj和schedGroup if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) { ... } } } }
上段代码说明服务端进程优先级(adj)不会低于客户端进程优先级(newAdj),而newAdj的上限受限于flags,具体服务端进程受客户端进程影响的ADJ上限如下:
由此,可见当bindService过程带有BIND_ABOVE_CLIENT或者BIND_IMPORTANT flags的同时,客户端进程ADJ小于或等于PERSISTENT_SERVICE_ADJ的情况下,该进程则为PERSISTENT_SERVICE_ADJ。另外,即便是启动过Activity的进程,当客户端进程ADJ<=200时,还是可以提升该服务进程的优先级。
可感知进程:当该进程存在不可见的Activity,但Activity正处于PAUSING、PAUSED、STOPPING状态,则为PERCEPTIBLE_APP_ADJ
if (!foregroundActivities && activitiesSize > 0) { int minLayer = ProcessList.VISIBLE_APP_LAYER_MAX; for (int j = 0; j < activitiesSize; j++) { final ActivityRecord r = app.activities.get(j); if (r.visible) { ... } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) { if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { adj = ProcessList.PERCEPTIBLE_APP_ADJ; app.adjType = "pause-activity"; } if (procState > PROCESS_STATE_CUR_TOP) { procState = PROCESS_STATE_CUR_TOP; app.adjType = "pause-activity"; } schedGroup = ProcessList.SCHED_GROUP_DEFAULT; app.cached = false; app.empty = false; foregroundActivities = true; } else if (r.state == ActivityState.STOPPING) { if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { adj = ProcessList.PERCEPTIBLE_APP_ADJ; app.adjType = "stop-activity"; } if (!r.finishing) { if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) { procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY; app.adjType = "stop-activity"; } } app.cached = false; app.empty = false; foregroundActivities = true; } } }
满足以下任一条件的进程也属于可感知进程:
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ || procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) { if (app.foregroundServices) { adj = ProcessList.PERCEPTIBLE_APP_ADJ; procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; app.cached = false; app.adjType = "fg-service"; schedGroup = ProcessList.SCHED_GROUP_DEFAULT; } else if (app.hasOverlayUi) { adj = ProcessList.PERCEPTIBLE_APP_ADJ; procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; app.cached = false; app.adjType = "has-overlay-ui"; schedGroup = ProcessList.SCHED_GROUP_DEFAULT; } } if (adj > ProcessList.PERCEPTIBLE_APP_ADJ || procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) { if (app.forcingToImportant != null) { adj = ProcessList.PERCEPTIBLE_APP_ADJ; procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND; app.cached = false; app.adjType = "force-imp"; app.adjSource = app.forcingToImportant; schedGroup = ProcessList.SCHED_GROUP_DEFAULT; } }
服务进程:没有启动过Activity,并且30分钟之内活跃过的服务进程。 startRequested为true,则代表执行startService()且没有stop的进程。
for (int is = app.services.size()-1; is >= 0; is--) { ServiceRecord s = app.services.valueAt(is); if (s.startRequested) { app.hasStartedServices = true; if (procState > ActivityManager.PROCESS_STATE_SERVICE) { procState = ActivityManager.PROCESS_STATE_SERVICE; app.adjType = "started-services"; } if (app.hasShownUi && app != mHomeProcess) { if (adj > ProcessList.SERVICE_ADJ) { app.adjType = "cch-started-ui-services"; } } else { if (now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) { if (adj > ProcessList.SERVICE_ADJ) { adj = ProcessList.SERVICE_ADJ; app.adjType = "started-services"; app.cached = false; } } } } for (int conni = s.connections.size()-1; conni >= 0; conni--) { ... //根据client情况来调整adj } }
进程由SERVICE_ADJ(500)降低到SERVICE_B_ADJ(800),有以下两种情况:
源码如下:
if (adj == ProcessList.SERVICE_ADJ) { if (doingAll) { app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3); mNewNumServiceProcs++; if (!app.serviceb) { if (mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL && app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) { app.serviceHighRam = true; app.serviceb = true; } else { mNewNumAServiceProcs++; } } else { app.serviceHighRam = false; } } if (app.serviceb) { adj = ProcessList.SERVICE_B_ADJ; } }
这里顺便一下,内存因子ADJ_MEM_FACTOR共有4个级别,当前处于哪个内存因子级别,取决于当前进程中cached进程和空进程的个数。
final int numCachedAndEmpty = numCached + numEmpty; int memFactor; if (numCached <= mConstants.CUR_TRIM_CACHED_PROCESSES && numEmpty <= mConstants.CUR_TRIM_EMPTY_PROCESSES) { if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) { memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL; } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) { memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW; } else { memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE; } } else { memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL; }
ADJ内存因子:决定允许后台运行Jobs的最大上限,以及决定TrimMemory的级别(包括ThreadedRenderer的回收级别),再进一步来看看内存因子:
内存因子 | 取值 | 先决条件 |
---|---|---|
ADJ_MEM_FACTOR_CRITICAL | 3 | Cached+Empty<=3 |
ADJ_MEM_FACTOR_LOW | 2 | Cached+Empty<=5 |
ADJ_MEM_FACTOR_MODERATE | 1 | Cached<=5 && Empty<=8 |
ADJ_MEM_FACTOR_NORMAL | 0 | Cached>5或者Empty>8 |
也就是说
默认情况取值如下:
当mOverrideMaxCachedProcesses有值的情况下,最大缓存进程个数和最大空进程个数上限优先取mOverrideMaxCachedProcesses,可通过AMS.setProcessLimit(int max)调整mOverrideMaxCachedProcesses值;Trim的缓存进程和空进程上限不受mOverrideMaxCachedProcesses影响。
再来看看cached和empty进程:
final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES; final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES - emptyProcessLimit; final long oldTime = now - ProcessList.MAX_EMPTY_TIME; switch (app.curProcState) { case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: mNumCachedHiddenProcs++; numCached++; //默认cachedProcessLimit=16 if (numCached > cachedProcessLimit) { app.kill("cached #" + numCached, true); } break; case ActivityManager.PROCESS_STATE_CACHED_EMPTY: //默认CUR_TRIM_EMPTY_PROCESSES=8, 且满足30min if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES && app.lastActivityTime < oldTime) { app.kill("empty for " + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime) / 1000) + "s", true); } else { numEmpty++; //默认cachedProcessLimit=16 if (numEmpty > emptyProcessLimit) { app.kill("empty #" + numEmpty, true); } } break; default: mNumNonCachedProcs++; break;
用于限制empty或cached进程的上限为16个,并且empty超过8个时会清理掉30分钟没有活跃的进程。 cached和empty主要是区别是否有Activity。
缓存进程优先级从CACHED_APP_MIN_ADJ(900)到 CACHED_APP_MAX_ADJ(906)。
ADJ的转换算法:
final int N = mLruProcesses.size(); //numSlots等于3 int numSlots = (ProcessList.CACHED_APP_MAX_ADJ - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2; //mNumNonCachedProcs是指empty和cached之外的进程, mNumCachedHiddenProcs代表的是cached进程个数 int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs; if (numEmptyProcs > cachedProcessLimit) { numEmptyProcs = cachedProcessLimit; } //emptyFactor和cachedFactor分别代表每个slot里面包括的进程个数,大于或等于1 int emptyFactor = numEmptyProcs/numSlots; int cachedFactor = (mNumCachedHiddenProcs > 0 ? mNumCachedHiddenProcs : 1)/numSlots; mNumNonCachedProcs = 0; mNumCachedHiddenProcs = 0; int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ; int nextCachedAdj = curCachedAdj+1; int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ; int nextEmptyAdj = curEmptyAdj+2; 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); if (app.curAdj >= ProcessList.UNKNOWN_ADJ) { switch (app.curProcState) { case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: case ActivityManager.PROCESS_STATE_CACHED_RECENT: app.curRawAdj = curCachedAdj; app.curAdj = app.modifyRawOomAdj(curCachedAdj); if (curCachedAdj != nextCachedAdj) { stepCached++; if (stepCached >= cachedFactor) { stepCached = 0; curCachedAdj = nextCachedAdj; nextCachedAdj += 2; //每次加2 if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; } } } break; default: app.curRawAdj = curEmptyAdj; //ADJ阈值 app.curAdj = app.modifyRawOomAdj(curEmptyAdj); if (curEmptyAdj != nextEmptyAdj) { stepEmpty++; if (stepEmpty >= emptyFactor) { stepEmpty = 0; curEmptyAdj = nextEmptyAdj; nextEmptyAdj += 2; //每次加2 if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) { nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ; } } } break; } } applyOomAdjLocked(app, true, now, nowElapsed); ... } }
numSlots=3, emptyFactor= 空进程个数/3, cachedFactor= 缓存进程个数/3,
再来看看PROCESS_STATE_CACHED_ACTIVITY的定义:
if (!foregroundActivities && activitiesSize > 0) { for (int j = 0; j < activitiesSize; j++) { final ActivityRecord r = app.activities.get(j); if (r.visible) { ... } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) { ... } else if (r.state == ActivityState.STOPPING) { ... } else { if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) { procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; app.adjType = "cch-act"; } } } }
foregroundActivities代表当前不是前台(FOREGROUND_APP_ADJ)进程,并且存在Activity的进程,当该Activity窗口不可见,并且不处于PAUSING(正在)、PAUSED(onPause个)、STOPPING的任一状态的情况下,则设置该进程为PROCESS_STATE_CACHED_ACTIVITY。
PROCESS_STATE_CACHED_ACTIVITY_CLIENT的定义:
if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) { if (app.hasClientActivities) { procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT; app.adjType = "cch-client-act"; } else if (app.treatLikeActivity) { procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; app.adjType = "cch-as-act"; } }
当该进程Service的客户端进程存在Activity或者是treatLikeActivity的进程,其进程状态都是cached进程。
bindService或者startService是否前台调用取决于caller进程的调度组。当caller属于SCHED_GROUP_BACKGROUND则认为是后台调用,当不属于SCHED_GROUP_BACKGROUND则认为是前台调用。callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
关于CPU调度组:
调度级别 | 进程组 | 备注 |
---|---|---|
SCHED_GROUP_BACKGROUND(0) | THREAD_GROUP_BG_NONINTERACTIVE | 后台进程组 |
SCHED_GROUP_DEFAULT(1) | THREAD_GROUP_DEFAULT | 前台进程组 |
SCHED_GROUP_TOP_APP(2) | THREAD_GROUP_TOP_APP | TOP进程组 |
SCHED_GROUP_TOP_APP_BOUND(3) | THREAD_GROUP_TOP_APP | TOP进程组 |
当进程调度级别由非TOP切换到TOP级别,则主线程和rendThread可设置为SCHED_FIFO或者更高优先级;当由TOP级别切换回非TOP级别,则恢复原来的调度策略或优先级。
Android进程优先级ADJ的每一个ADJ级别往往都有多种场景,使用adjType完美地区分相同ADJ下的不同场景; 不同ADJ进程所对应的schedGroup不同,从而分配的CPU资源也不同,schedGroup大体分为TOP(T)、前台(F)、后台(B); ADJ跟AMS中的procState有着紧密的联系。
为了说明整体关系,以ADJ为中心来讲解跟adjType,schedGroup,procState的对应关系,下面以一幅图来诠释整个ADJ算法的精髓,几乎涵盖了ADJ算法调整的绝大多数场景。
CPU调度组:
调度级别 | 缩写 | 解释 |
---|---|---|
SCHED_GROUP_BACKGROUND(0) | B | 后台进程组 |
SCHED_GROUP_DEFAULT(1) | F | 前台进程组 |
SCHED_GROUP_TOP_APP(2) | T | TOP进程组 |
SCHED_GROUP_TOP_APP_BOUND(3) | T | TOP进程组 |
最后,给广大应用开发者一些友好的建议: