Android oom_adj 更新原理(二)

2023-10-13 15:10
文章标签 android 更新 原理 adj oom

本文主要是介绍Android oom_adj 更新原理(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

源码基于:Android R

接上一篇:Android oom_adj 更新原理(一)

12. computeOomAdjLocked()

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.javaprivate 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_ADJif (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 = 0if (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,即不显示UIapp.systemNoUi = true;if (app == topApp) {  //如果进程就是topApp,那设置为false,正在显示UIapp.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 belowapp.systemNoUi = false;app.adjType = "pers-top-ui";} else if (app.getCachedHasVisibleActivities()) {app.systemNoUi = false;}// 如果该系统进程正在显示UI,调整proc_stateif (!app.systemNoUi) {if (mService.mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {// 亮屏,提升proc_state至PERSISTENT_UIapp.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);} else {// 屏灭,控制UI scheduleapp.setCurProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);}}// 设置当前 unlimit proc_stateapp.setCurRawProcState(app.getCurProcState());// adj 提升到最大,重要性下降app.curAdj = app.maxAdj;// 完成处理,将completedAdjSeq设置为当前进程 adjSeqapp.completedAdjSeq = app.adjSeq;// if curAdj is less than prevAppAdj, then this process was promotedreturn app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;}// 对于maxAdj > 0 (即大于FOREGROUND_APP_ADJ)的进程继续下面的流程,// 默认将systemNoUi该值设为falseapp.systemNoUi = false;// 该变量用以获取系统top进程的 proc_state//   该变量只有两个值:PROCESS_STATE_TOP 和 PROCESS_STATE_TOP_SLEEPINGfinal 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、procStateif (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 处于SLEEPINGadj = 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 为cacheif (!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_ACTIVITYadj = 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_ADJprocState = 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被设为了50app.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_BACKGROUNDprocState = 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_ADJif (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_ADJif (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继续更新adjif (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 upif (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的adjfor (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_SERVICEapp.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-servicesif (!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_ADJif (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运行在前台,主要更新capabilityFromFGSif (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, 如果更新所有进程,则为trueif (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的,//    所以直接采用客户端adjif (clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {newAdj = clientAdj;} else { //persistent进程// make this service persistentnewAdj = 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为250newAdj = 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,则设置200newAdj = ProcessList.PERCEPTIBLE_APP_ADJ;} else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {newAdj = clientAdj;} else {// 假如clientadj<PERCEPTIBLE_APP_ADJ,//     则设置为VISIBLE_APP_ADJif (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的adjSourceProcStateif ((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_ADJfinal 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//遍历与当前进程相关的所有providerfor (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,其他为falseif (doingAll && !cycleReEval) {//当A类Service个数 > service/3时,则加入到B类Serviceapp.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);mNewNumServiceProcs++;//Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);if (!app.serviceb) { //不在service b list中//当对于低RAM设备,则把该service直接放入B类Serviceif (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不能超过maxAdjif (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 offif (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 promotedreturn app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState|| app.curCapability != prevCapability ;}

一个函数快 1000 行代码,确实分析起来非常累,里面有很多逻辑,大致逻辑如下:

  • 通过 mAdjSeq 确认此次计算是否有必要,是否已经计算过;
  • 判断是否为空进程;
  • 当maxAdj<=FOREGROUND_APP_ADJ(都是重要的系统进程)根据是否显示系统UI、是否为TOPAPP等条件设置adj、procState等,然后return;
  • 前台进程相关处理,根据不同场景(远程动画、接受广播、运行service等)设置前台进程adj、adjType、procState、schedGroup;
  • 如果不是前台进程,但存有cache activities,通过 computeOomAdjFromActivitiesIfNecessary()确定进程cachedadj等;
  • 分别根据adj是否大于PERCEPTIBLE_APP_ADJ、HEAVY_WEIGHT_APP_ADJ、HOME_APP_ADJ、PREVIOUS_APP_ADJ等判断大致adj值,在根据activity具体运行状态进一步确认adj等值;
  • 确认是否为backup进程;
  • 遍历在进程上运行所有services,根据service的运行状态修正当前进程adj等值。还可能遍历引用service的所有client,进一步计算这些client 的adj值;
  • 同service,遍历进程上关联的providers,根据providers以及客户端进一步修正adj值;
  • 收尾,进一步确认:
    • 当一个进程20s前带有contentProvider,不会把他降到LRU list,避免provider进程陷入低内存状态;
    • procState >= PROCESS_STATE_CACHED_EMPTY时进一步调整procState和adjType;
    • 当adj==SERVICE_ADJ,确认是否在serviceb中,如果是adj改成SERVICE_B_ADJ;
    • 其他的限制确认;

这里弄个简单的流程图,方便记忆:

12.1 bind类型

binder类型说明
BIND_WAIVE_PRIORITY不会影响服务的进程优先级,像通用的应用进程一样将服务放在一个LRU表中
BIND_TREAT_LIKE_ACTIVITY将binding 视为持有一个activity,unbinding视为activity在后台,这个通常用在输入法进程,以便更快捷的切换键盘。
BIND_ALLOW_OOM_MANAGEMENT保持服务受默认的服务管理器管理,当内存不足时候,会销毁服务
BIND_ABOVE_CLIENT设置服务的进程优先级高于客户端的优先级,只有当需要服务晚于客户端被销毁这种情况才这样设置
BIND_IMPORTANT标识服务对客户端是非常重要的,会将服务提升至前台进程优先级,通常情况下,即时客户端是前台优先级,服务最多也只能被提升至可见进程优先级
BIND_NOT_FOREGROUND不会将被绑定的服务提升到前台优先级,但是这个服务也至少会和客户端在内存中优先级是相同的
BIND_SCHEDULE_LIKE_TOP_APP此标志仅用于系统调整IME(以及与top应用程序紧密配合的任何进程外用户可见组件)的调度策略。所以托管此类服务的UI能够拥有top app一样的调度策略。仅限于系统调用,否则会抛出安全异常
BIND_ADJUST_WITH_ACTIVITYService的优先级将相对于其绑定的Activity,Activity到前台,则Service优先级相对提升,Activity到后台,则Servcie优先级相对降低
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 adjif (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或上一次没压缩都返回truemCachedAppOptimizer.compactAppBfgs(app);}}// 当 adj当前值与上一次不一致时,发生变化if (app.curAdj != app.setAdj) {// setOomAdj() 通知lmkdProcessList.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 RTif (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {app.getWindowProcessController().onTopProcChanged();if (mService.mUseFifoUiScheduling) {// Switch UI pipeline for app to SCHED_FIFOapp.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 threadssetThreadPriority(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_OTHERsetThreadScheduler(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 threadssetThreadPriority(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 setProcStatemaybeUpdateUsageStatsLocked(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;}

又是一段很长逻辑的代码,分析起来特别的类,主要经历如下流程:

  • 当启动boot 完成且app compaction 使能,则进行app 压缩确认,满足条件会进行内存压缩;
  • 当app 的adj 发生变化,通过setOomAdj() 通知 lmkd(采用 socket通信方式);
  • 当schedGroup 发生变化时,更新进程的scheduler 和priority,特殊的情况会被kill;
  • 调用 updateAppFreezeStateLocked() 函数更新app 的冻结状态;
  • 设置进程的 process state;
  • 执行pss 统计操作,计算下一次 pss 时间;

13.1 Framework 调度策略

进程优先级级别:

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

组优先级:

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

调度器类别:

  • setThreadScheduler(int tid, int policy, int prioriy);
进程优先级nice 值说明
THREAD_PRIORITY_LOWEST19最低优先级
THREAD_PRIORITY_BACKGROUND10后台
THREAD_PRIORITY_LESS_FAVORABLE1比默认略低
THREAD_PRIORITY_DEFAULT0默认
THREAD_PRIORITY_MORE_FAVORABLE-1比默认略高
THREAD_PRIORITY_FOREGROUND-2前台
THREAD_PRIORITY_DISPLAY-4显示相关
THREAD_PRIORITY_URGENT_DISPLAY-8显示(更为重要),input 事件
TOP_APP_PRIORITY_BOOST-10

前台进程的主线程和render 线程boost 优先级

THREAD_PRIORITY_AUDIO-16音频相关
THREAD_PRIORITY_URGENT_AUDIO-19音频(更重要)
组优先级取值说明
THREAD_GROUP_DEFAULT-1仅用于setProcessGroup,将优先级<=10的进程提升到-2
THREAD_GROUP_BG_NONINTERACTIVE0CPU分时的时长缩短
THREAD_GROUP_FOREGROUND1CPU分时的时长正常
THREAD_GROUP_SYSTEM2系统线程组
THREAD_GROUP_AUDIO_APP3应用程序音频
THREAD_GROUP_AUDIO_SYS4系统程序音频
调度器名称说明
SCHED_OTHER默认标准round-robin分时共享策略
SCHED_BATCH批处理调度针对具有batch风格(批处理)进程的调度策略
SCHED_IDLE空闲调度针对优先级非常低的适合在后台运行的进程
SCHED_FIFO先进先出实时调度策略
SCHED_RR循环调度实时调度策略

13.2 updateLruProcessLocked()

AMS中有一个LRU列表mProcessList经过AMS启动的每一个进程,都会加入到LRU列表中进行管理,这个LRU列表并不是随意排序或者说按加入的时间顺序进行排布的,而是有一定的逻辑进行计算,而后根据每个进程的实时动态状态进行改变的。

mProcessList这个LRU列表的定义其实最终在ProcessList.java中,AMS中定义了一个processList的实体,并且在整个系统中只有一个这样的LRU列表专门用于管理AMS启动的所有进程。

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

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

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

LRU列表更新的逻辑如下:

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

参考:

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

这篇关于Android oom_adj 更新原理(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/204065

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

MySQL中的MVCC底层原理解读

《MySQL中的MVCC底层原理解读》本文详细介绍了MySQL中的多版本并发控制(MVCC)机制,包括版本链、ReadView以及在不同事务隔离级别下MVCC的工作原理,通过一个具体的示例演示了在可重... 目录简介ReadView版本链演示过程总结简介MVCC(Multi-Version Concurr

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

Linux Mint Xia 22.1重磅发布: 重要更新一览

《LinuxMintXia22.1重磅发布:重要更新一览》Beta版LinuxMint“Xia”22.1发布,新版本基于Ubuntu24.04,内核版本为Linux6.8,这... linux Mint 22.1「Xia」正式发布啦!这次更新带来了诸多优化和改进,进一步巩固了 Mint 在 Linux 桌面

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实