Android Gems — Android的LowMemoryKiller杀进程策略
Posted threepigs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Gems — Android的LowMemoryKiller杀进程策略相关的知识,希望对你有一定的参考价值。
Anroid的杀进程策略是基于kernel里的LowMemoryKiller模块,LMK的实现在这里不展开分析,大致的原理就是LMK注册了内核的shrinker(lowmem_shrinker),内核线程kswapd,在linux回收内存分页的时候,通过shrinker回调回来给LMK。LMK根据每个进程的oom_adj值,将大于某个阈值的进程都发送SIGKILL信号杀掉。oom_adj的阈值因内存情况不同而不同,具体的对应关系可以查看/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree这两个文件。oom_adj的值从-17到16,值越小,代表越重要,越晚被杀,比如一个应用如果在前台的时候,oom_adj的值就会减到0。也就是说设为负值的那些应用,会比前台应用还晚被杀。于是,系统杀进程的策略就可以通过调整每个进程的oom_adj的值来实现。
oom_adj的值有如下类:
// 不可见的Activity static final int CACHED_APP_MAX_ADJ = 15; static final int CACHED_APP_MIN_ADJ = 9; // 比较老的Service static final int SERVICE_B_ADJ = 8; // 上一个应用,这样在做任务切换,或者返回的时候,能够快速载入 static final int PREVIOUS_APP_ADJ = 7; // 桌面 App static final int HOME_APP_ADJ = 6; // Service static final int SERVICE_ADJ = 5; // 重量级应用,早期版本可以在manifest里加cantSaveState来声明,新版已经注释了,目前没看到哪里可以设置 static final int HEAVY_WEIGHT_APP_ADJ = 4; // 备份代理应用,manifest里Application标签里可以声明backAgent static final int BACKUP_APP_ADJ = 3; // 可感知的App,比如有Pause状态的Activity,Stopping状态的Activity,被一个可见的进程BindService的进程等 static final int PERCEPTIBLE_APP_ADJ = 2; // 前台可见的Activity, static final int VISIBLE_APP_ADJ = 1; // 前台App,包括Top App,Instrumentation Test App,正在接收broadcast的App,正在执行的Service等 static final int FOREGROUND_APP_ADJ = 0; // 被Persist App BindService的进程 static final int PERSISTENT_SERVICE_ADJ = -11; // 声明了persist的进程 static final int PERSISTENT_PROC_ADJ = -12; // 系统进程,比如system server static final int SYSTEM_ADJ = -16; // 不被系统管的Native进程,比如/system/bin下运行的那些服务(surfaceflinger etc) static final int NATIVE_ADJ = -17;
oom_adj的值受很多因素影响:应用是否有activity,activity是否可见,是否有service,service是否被bind的其他进程的oom_adj等等。在Framework里oom_adj的调整主要由ActivityManagerService这个类负责,任何可能会影响到进程oom_adj的值的情况,就会调用updateOomAdjLocked来更新各进程的oom_adj值,比如:
1,Activity切换
2,Service start/stop/bind
3,Broadcast分发处理
updateOomAdjLocked会遍历当前进程列表,对每个进程ProcessRecord都调用computeOomAdjLocked来重新计算oom_adj,最后applyOomAdjLocked来使oom_adj生效。
我们看看updateOomAdjLocked的实现:
系统将进程分三类:final void updateOomAdjLocked() final ActivityRecord TOP_ACT = resumedAppLocked(); final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; final long now = SystemClock.uptimeMillis(); final long oldTime = now - ProcessList.MAX_EMPTY_TIME; final int N = mLruProcesses.size(); ...... ...... for (int i=N-1; i>=0; i--) ProcessRecord app = mLruProcesses.get(i); // 找到最早的一次service活动时间 if (mEnableBServicePropagation && app.serviceb && (app.curAdj == ProcessList.SERVICE_B_ADJ)) numBServices++; for (int s = app.services.size() - 1; s >= 0; s--) ServiceRecord sr = app.services.valueAt(s); if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + app.processName + " serviceb = " + app.serviceb + " s = " + s + " sr.lastActivity = " + sr.lastActivity + " packageName = " + sr.packageName + " processName = " + sr.processName); if (SystemClock.uptimeMillis() - sr.lastActivity < mMinBServiceAgingTime) if (DEBUG_OOM_ADJ) Slog.d(TAG,"Not aged enough!!!"); continue; if (serviceLastActivity == 0) serviceLastActivity = sr.lastActivity; selectedAppRecord = app; else if (sr.lastActivity < serviceLastActivity) serviceLastActivity = sr.lastActivity; selectedAppRecord = app; if (DEBUG_OOM_ADJ && selectedAppRecord != null) Slog.d(TAG, "Identified app.processName = " + selectedAppRecord.processName + " app.pid = " + selectedAppRecord.pid); if (!app.killedByAm && app.thread != null) app.procStateChanged = false; // 重新计算进程app的oom_adj computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now); // If we haven't yet assigned the final cached adj // to the process, do that now. // 如果没找到对应的oom_adj,那么根据app的进程状态,如果有activity存在,那么oom_adj设为curCachedAdj, // 否则就是empty进程,讲oom_adj设为curEmptyAdj if (app.curAdj >= ProcessList.UNKNOWN_ADJ) switch (app.curProcState) case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: // This process is a cached process holding activities... // assign it the next cached value for that type, and then // step that cached level. app.curRawAdj = curCachedAdj; app.curAdj = app.modifyRawOomAdj(curCachedAdj); if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning activity LRU #" + i + " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj + ")"); if (curCachedAdj != nextCachedAdj) stepCached++; if (stepCached >= cachedFactor) stepCached = 0; curCachedAdj = nextCachedAdj; nextCachedAdj += 2; if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; break; default: // For everything else, assign next empty cached process // level and bump that up. Note that this means that // long-running services that have dropped down to the // cached level will be treated as empty (since their process // state is still as a service), which is what we want. app.curRawAdj = curEmptyAdj; app.curAdj = app.modifyRawOomAdj(curEmptyAdj); if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning empty LRU #" + i + " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj + ")"); if (curEmptyAdj != nextEmptyAdj) stepEmpty++; if (stepEmpty >= emptyFactor) stepEmpty = 0; curEmptyAdj = nextEmptyAdj; nextEmptyAdj += 2; if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ; break; // 调用applyOomAdjLocked使新的oom_adj生效 applyOomAdjLocked(app, true, now); // Count the number of process types. switch (app.curProcState) case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: mNumCachedHiddenProcs++; numCached++; // 计算Cached进程个数,超过cachedProcessLimit即直接kill if (numCached > cachedProcessLimit) app.kill("cached #" + numCached, true); break; case ActivityManager.PROCESS_STATE_CACHED_EMPTY: // 计算empty进程个数,超过上限即kill if (numEmpty > ProcessList.TRIM_EMPTY_APPS && app.lastActivityTime < oldTime) app.kill("empty for " + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime) / 1000) + "s", true); else numEmpty++; if (numEmpty > emptyProcessLimit) app.kill("empty #" + numEmpty, true); break; default: mNumNonCachedProcs++; break; ...... ...... // 在低内存的情况下,把过老的service的oom_adj的值调大到CACHED_APP_MAX_ADJ,以便可以被优先杀死 if ((numBServices > mBServiceAppThreshold) && (true == mAllowLowerMemLevel) && (selectedAppRecord != null)) ProcessList.setOomAdj(selectedAppRecord.pid, selectedAppRecord.info.uid, ProcessList.CACHED_APP_MAX_ADJ); selectedAppRecord.setAdj = selectedAppRecord.curAdj; if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + selectedAppRecord.processName + " app.pid = " + selectedAppRecord.pid + " is moved to higher adj"); // finish所有后台的activity,这个有系统开关可以控制,Settings.Global.ALWAYS_FINISH_ACTIVITIES,也就是开发者选项里的“不保留活动”, // 也可以通过ActivityManagerNative的setAlwaysFinish来设置,这需要声明权限android.Manifest.permission.SET_ALWAYS_FINISH if (mAlwaysFinishActivities) // Need to do this on its own message because the stack may not // be in a consistent state at this point. mStackSupervisor.scheduleDestroyAllActivities(null, "always-finish"); ...... ......
一, empty process,没有service,也没有activity,空进程没有执行逻辑,可以优先被杀,empty process有数量限制,超过限制之后就马上被kill。
二, cached process,只有不可见的activity,这类进程优先级比empty高些,但也同样可以被杀,用户不会有太明显的感知,表现就是返回到他的activity之后,
进程被重新被创建,Activity也会重新onCreate。
empty和cached进程的上限是ProcessList.MAX_CACHED_APPS=32个,而empty的上限是ProcessList.computeEmptyProcessLimit(ProcessList.MAX_CACHED_APPS),默认是16。
三,其他是第三类,包括有前台可见的Activity的进程,有前台Service的进程等。
三类进程数之和就等于LruProcesses队列的大小。
computeOomAdjLocked计算完oom_adj之后,就调用applyOomAdjLocked使之生效,applyOomAdjLocked比较简单,调用ProcessList的setOomAdj,通过LocalSocket连接到private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP, boolean doingAll, long now) if (mAdjSeq == app.adjSeq) // This adjustment has already been computed. return app.curRawAdj; if (app.thread == null) app.adjSeq = mAdjSeq; app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ); app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN; app.adjSource = null; app.adjTarget = null; app.empty = false; app.cached = false; final int activitiesSize = app.activities.size(); // app最大的adj和前台app的adj一样,说明是系统进程,adj就设为maxAdj if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) // The max adjustment doesn't allow this app to be anything // below foreground, so it is not worth doing work for it. app.adjType = "fixed"; app.adjSeq = mAdjSeq; app.curRawAdj = app.maxAdj; app.foregroundActivities = false; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; app.curProcState = 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. app.systemNoUi = true; if (app == TOP_APP) app.systemNoUi = false; else if (activitiesSize > 0) for (int j = 0; j < activitiesSize; j++) final ActivityRecord r = app.activities.get(j); if (r.visible) app.systemNoUi = false; if (!app.systemNoUi) app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI; return (app.curAdj=app.maxAdj); app.systemNoUi = false; final int PROCESS_STATE_TOP = mTopProcessState; // Determine the importance of the process, starting with most // important to least, and assign an appropriate OOM adjustment. int adj; int schedGroup; int procState; boolean foregroundActivities = false; BroadcastQueue queue; if (app == TOP_APP) // App正在系统顶层,adj设为FOREGROUND_APP_ADJ // The last app on the list is the foreground app. adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.adjType = "top-activity"; foregroundActivities = true; procState = PROCESS_STATE_TOP; if(app == mHomeProcess) mHomeKilled = false; mHomeProcessName = mHomeProcess.processName; else if (app.instrumentationClass != null) // App正执行Instrumentation,adj设为FOREGROUND_APP_ADJ // Don't want to kill running instrumentation. adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.adjType = "instrumentation"; procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; else if ((queue = isReceivingBroadcast(app)) != null) // App正在接收broadcast,adj设为FOREGROUND_APP_ADJ // An app that is currently receiving a broadcast also // counts as being in the foreground for OOM killer purposes. // It's placed in a sched group based on the nature of the // broadcast as reflected by which queue it's active in. adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = (queue == mFgBroadcastQueue) ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE; app.adjType = "broadcast"; procState = ActivityManager.PROCESS_STATE_RECEIVER; else if (app.executingServices.size() > 0) // App的Service正在执行,adj设为FOREGROUND_APP_ADJ // An app that is currently executing a service callback also // counts as being in the foreground. adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = app.execServicesFg ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE; app.adjType = "exec-service"; procState = ActivityManager.PROCESS_STATE_SERVICE; //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app); else // As far as we know the process is empty. We may change our mind later. schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; // At this point we don't actually know the adjustment. Use the cached adj // value that the caller wants us to. adj = cachedAdj; procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; // 初始状态cached和empty都设为true,根据进程的执行状态再改 app.cached = true; app.empty = true; app.adjType = "cch-empty"; // 桌面App,既不是empty也不是cached,adj设为PERSISTENT_PROC_ADJ if (mHomeKilled && app.processName.equals(mHomeProcessName)) adj = ProcessList.PERSISTENT_PROC_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.cached = false; app.empty = false; app.adjType = "top-activity"; // Examine all activities if not already foreground. if (!foregroundActivities && activitiesSize > 0) // 遍历非前台的activity for (int j = 0; j < activitiesSize; j++) final ActivityRecord r = app.activities.get(j); if (r.app != app) Slog.w(TAG, "Wtf, activity " + r + " in proc activity list not using proc " + app + "?!? Using " + r.app + " instead."); continue; if (r.visible) // 可见的Activity,如果Activity不在最顶层,而且被顶层完全挡住的时候visible状态会被设为false, // 如果是可见的,那么adj设为VISIBLE_APP_ADJ,cached和empty也设为false // App has a visible activity; only upgrade adjustment. if (adj > ProcessList.VISIBLE_APP_ADJ) adj = ProcessList.VISIBLE_APP_ADJ; app.adjType = "visible"; if (procState > PROCESS_STATE_TOP) procState = PROCESS_STATE_TOP; schedGroup = Process.THREAD_GROUP_DEFAULT; app.cached = false; app.empty = false; foregroundActivities = true; break; else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) // Pause状态的Activity,adj设为PERCEPTIBLE_APP_ADJ,cached和empty也设为false if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) adj = ProcessList.PERCEPTIBLE_APP_ADJ; app.adjType = "pausing"; if (procState > PROCESS_STATE_TOP) procState = PROCESS_STATE_TOP; schedGroup = Process.THREAD_GROUP_DEFAULT; app.cached = false; app.empty = false; foregroundActivities = true; else if (r.state == ActivityState.STOPPING) // Stopping状态的app,adj设为PERCEPTIBLE_APP_ADJ,cached和empty也设为false if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) adj = ProcessList.PERCEPTIBLE_APP_ADJ; app.adjType = "stopping"; // For the process state, we will at this point consider the // process to be cached. It will be cached either as an activity // or empty depending on whether the activity is finishing. We do // this so that we can treat the process as cached for purposes of // memory trimming (determing current memory level, trim command to // send to process) since there can be an arbitrary number of stopping // processes and they should soon all go into the cached state. if (!r.finishing) if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY; app.cached = false; app.empty = false; foregroundActivities = true; else // 进这个分支说明进程有不可见的Activity,adj会设为CACHED_APP_MIN_ADJ和CACHED_APP_MAX_ADJ之间的数 if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; app.adjType = "cch-act"; if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) // 如果有前台的Service,adj设为PERCEPTIBLE_APP_ADJ,可通过ActivityManagerNative将Service设为foreground if (app.foregroundServices) // The user is aware of this app, so make it visible. adj = ProcessList.PERCEPTIBLE_APP_ADJ; procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; app.cached = false; app.adjType = "fg-service"; schedGroup = Process.THREAD_GROUP_DEFAULT; else if (app.forcingToForeground != null) // The user is aware of this app, so make it visible. adj = ProcessList.PERCEPTIBLE_APP_ADJ; procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; app.cached = false; app.adjType = "force-fg"; app.adjSource = app.forcingToForeground; schedGroup = Process.THREAD_GROUP_DEFAULT; if (app == mHeavyWeightProcess) 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 = Process.THREAD_GROUP_BG_NONINTERACTIVE; app.cached = false; app.adjType = "heavy"; if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT; if (app == mHomeProcess) // 如果桌面App,adj设为HOME_APP_ADJ 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 = Process.THREAD_GROUP_BG_NONINTERACTIVE; app.cached = false; app.adjType = "home"; if (procState > ActivityManager.PROCESS_STATE_HOME) procState = ActivityManager.PROCESS_STATE_HOME; // 如果是刚刚切换出去的App,adj设为PREVIOUS_APP_ADJ if (app == mPreviousProcess && app.activities.size() > 0) 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 = Process.THREAD_GROUP_BG_NONINTERACTIVE; app.cached = false; app.adjType = "previous"; if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY; if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj + " reason=" + app.adjType); // By default, we use the computed adjustment. It may be changed if // there are applications dependent on our services or providers, but // this gives us a baseline and makes sure we don't get into an // infinite recursion. app.adjSeq = mAdjSeq; app.curRawAdj = adj; app.hasStartedServices = false; // Backup App,adj设为BACKUP_APP_ADJ if (mBackupTarget != null && app == mBackupTarget.app) // If possible we want to avoid killing apps while they're being backed up if (adj > ProcessList.BACKUP_APP_ADJ) if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app); adj = ProcessList.BACKUP_APP_ADJ; if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND; app.adjType = "backup"; app.cached = false; if (procState > ActivityManager.PROCESS_STATE_BACKUP) procState = ActivityManager.PROCESS_STATE_BACKUP; boolean mayBeTop = false; // 如果App有Service,adj设为SERVICE_ADJ for (int is = app.services.size()-1; is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE || procState > ActivityManager.PROCESS_STATE_TOP); is--) ServiceRecord s = app.services.valueAt(is); if (s.startRequested) app.hasStartedServices = true; if (procState > ActivityManager.PROCESS_STATE_SERVICE) procState = ActivityManager.PROCESS_STATE_SERVICE; if (app.hasShownUi && app != mHomeProcess) // 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 if (now < (s.lastActivity + ActiveServices.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"; app.cached = 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"; // 如果App有Service,那么需要检查是否有外部的App在Bind它,如果一个高优先级的App,bind了你的Service,那么你的优先级也会同样有提升 for (int conni = s.connections.size()-1; conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE || procState > ActivityManager.PROCESS_STATE_TOP); conni--) ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni); for (int i = 0; i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE || procState > ActivityManager.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 ourself is not interesting. continue; // 只有bind的时候不加BIND_WAIVE_PRIORITY这个flag才会影响对方的adj if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) ProcessRecord client = cr.binding.client; int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now); int clientProcState = client.curProcState; if (clientProcState >= ActivityManager.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 = ActivityManager.PROCESS_STATE_CACHED_EMPTY; String adjType = null; 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 != mHomeProcess) // 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.cached = false; clientAdj = adj; clientProcState = procState; else if (now >= (s.lastActivity + ActiveServices.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. if (app.hasShownUi && app != mHomeProcess && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) adjType = "cch-bound-ui-services"; else if ((cr.flags&(Context.BIND_ABOVE_CLIENT |Context.BIND_IMPORTANT)) != 0) // 如果Client Bind的时候加了BIND_ABOVE_CLIENT和BIND_IMPORTANT,那么讲client的adj值给Service,最低不小于PERSISTENT_SERVICE_ADJ adj = clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ ? clientAdj : ProcessList.PERSISTENT_SERVICE_ADJ; else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0 && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ && adj > ProcessList.PERCEPTIBLE_APP_ADJ) // 如果Client Bind的时候加了BIND_NOT_VISIBLE,并且client的adj比PERCEPTIBLE_APP_ADJ小的时候,将PERCEPTIBLE_APP_ADJ给adj adj = ProcessList.PERCEPTIBLE_APP_ADJ; else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) // 把Client的adj给adj,因为adj是> clientAdj的,所以Service的adj还是得到了提升 adj = clientAdj; else // 这里client的adj是要小于等于VISIBLE_APP_ADJ的,所以adj将会提升至VISIBLE_APP_ADJ if (adj > ProcessList.VISIBLE_APP_ADJ) adj = ProcessList.VISIBLE_APP_ADJ; if (!client.cached) app.cached = false; adjType = "service"; ...... ...... ...... // ContentProvider的连接也同样会影响到app的adj for (int provi = app.pubProviders.size()-1; provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE || procState > ActivityManager.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 == Process.THREAD_GROUP_BG_NONINTERACTIVE || procState > ActivityManager.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; int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now); int clientProcState = client.curProcState; if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) // If the other app is cached for any reason, for purposes here // we are going to consider it empty. clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; if (adj > clientAdj) if (app.hasShownUi && app != mHomeProcess && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) app.adjType = "cch-ui-provider"; else adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ ? clientAdj : ProcessList.FOREGROUND_APP_ADJ; app.adjType = "provider"; app.cached &= client.cached; app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_PROVIDER_IN_USE; app.adjSource = client; app.adjSourceProcState = clientProcState; app.adjTarget = cpr.name; ...... ...... // If the provider has external (non-framework) process // dependencies, ensure that its adjustment is at least // FOREGROUND_APP_ADJ. if (cpr.hasExternalProcessHandles()) if (adj > ProcessList.FOREGROUND_APP_ADJ) adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.cached = false; app.adjType = "provider"; app.adjTarget = cpr.name; if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; ...... ...... app.curAdj = app.modifyRawOomAdj(adj); app.curSchedGroup = schedGroup; app.curProcState = procState; app.foregroundActivities = foregroundActivities; return app.curRawAdj;
lmkd,通过进程间通信写入。
作者简介:
田力,网易彩票Android端创始人,小米视频创始人,现任roobo技术经理、视频云技术总监
欢迎关注微信公众号 磨剑石,定期推送技术心得以及源码分析等文章,谢谢
以上是关于Android Gems — Android的LowMemoryKiller杀进程策略的主要内容,如果未能解决你的问题,请参考以下文章
Android Gems — AMS的Service生命周期管理
Android Gems — AMS的Service生命周期管理
Android Gems — Fragment本质之生命周期管理
Android Gems — Fragment本质之生命周期管理