本文基于Android 11.0源码分析
前言
继续上一篇分析进程管理。
2.4 updateLruProcessLocked()
// frameworks/base/services/core/java/com/android/server/am/ProcessList.java
final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
ProcessRecord client) {
final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities
|| app.treatLikeActivity;
final boolean hasService = false; // not impl yet. app.services.size() > 0;
if (!activityChange && hasActivity) {
// The process has activities, so we are only allowing activity-based adjustments
// to move it. It should be kept in the front of the list with other
// processes that have activities, and we don't want those to change their
// order except due to activity operations.
return;
}
mLruSeq++;//每一次调整LRU列表,系统都会分配一个唯一的编号
Log.i("ActivityManagerService-xiao", "updateLruProcessLocked app" +app+",,client :"+client+",activityChange:"+activityChange
+",mLruProcessActivityStart:"+mLruProcessActivityStart+",mLruProcessServiceStart:"+mLruProcessServiceStart);
final long now = SystemClock.uptimeMillis();
app.lastActivityTime = now;
// First a quick reject: if the app is already at the position we will
// put it, then there is nothing to do.
if (hasActivity) {//进程包含ativity,并且已经在顶层就不需要调整
final int N = mLruProcesses.size();
if (N > 0 && mLruProcesses.get(N-1) == app) {
if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top activity: " + app);
return;
}
} else {//服务进程的情况
if (mLruProcessServiceStart > 0
&& mLruProcesses.get(mLruProcessServiceStart-1) == app) {
if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top other: " + app);
return;
}
}
//获取app在mLruProcesses中的索引位置,如果进程是第一次加入的话lrui=-1
int lrui = mLruProcesses.lastIndexOf(app);
//如果是persistent进程就不做调整
if (app.persistent && lrui >= 0) {
// We don't care about the position of persistent processes, as long as
// they are in the list.
if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, persistent: " + app);
return;
}
......
if (lrui >= 0) {
if (lrui < mLruProcessActivityStart) {
mLruProcessActivityStart--;
}
if (lrui < mLruProcessServiceStart) {
mLruProcessServiceStart--;
}
/*
if (addIndex > lrui) {
addIndex--;
}
if (nextIndex > lrui) {
nextIndex--;
}
*/
//如果之前有记录,则先从数组中删掉,因为此处需要重新调整位置
mLruProcesses.remove(lrui);
}
int nextIndex;
if (hasActivity) {
final int N = mLruProcesses.size();
//此app进程没有活动的activity,但是其他进程含有此app的activity
if (app.activities.size() == 0 && mLruProcessActivityStart < (N - 1)) {
// Process doesn't have activities, but has clients with
// activities... move it up, but one below the top (the top
// should always have a real activity).
if (DEBUG_LRU) Slog.d(TAG_LRU,
"Adding to second-top of LRU activity list: " + app);
mLruProcesses.add(N - 1, app);//放在第二位
// To keep it from spamming the LRU list (by making a bunch of clients),
// we will push down any other entries owned by the app.
final int uid = app.info.uid;
//如果N-2后的进程与app uid相同就向前移动一位
for (int i = N - 2; i > mLruProcessActivityStart; i--) {
ProcessRecord subProc = mLruProcesses.get(i);
if (subProc.info.uid == uid) {
// We want to push this one down the list. If the process after
// it is for the same uid, however, don't do so, because we don't
// want them internally to be re-ordered.
if (mLruProcesses.get(i - 1).info.uid != uid) {
if (DEBUG_LRU) Slog.d(TAG_LRU,
"Pushing uid " + uid + " swapping at " + i + ": "
+ mLruProcesses.get(i) + " : " + mLruProcesses.get(i - 1));
ProcessRecord tmp = mLruProcesses.get(i);
mLruProcesses.set(i, mLruProcesses.get(i - 1));
mLruProcesses.set(i - 1, tmp);
i--;
}
} else {
// A gap, we can stop here.
break;
}
}
} else {
// Process has activities, put it at the very tipsy-top.
if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU activity list: " + app);
mLruProcesses.add(app);//有activity的进程就放在第第一位
}
nextIndex = mLruProcessServiceStart;
} else if (hasService) {
// Process has services, put it at the top of the service list.
if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU service list: " + app);
mLruProcesses.add(mLruProcessActivityStart, app);
nextIndex = mLruProcessServiceStart;
mLruProcessActivityStart++;
} else {//放在服务的顶层
// Process not otherwise of interest, it goes to the top of the non-service area.
int index = mLruProcessServiceStart;
if (client != null) {
// If there is a client, don't allow the process to be moved up higher
// in the list than that client.
int clientIndex = mLruProcesses.lastIndexOf(client);
if (DEBUG_LRU && clientIndex < 0) Slog.d(TAG_LRU, "Unknown client " + client
+ " when updating " + app);
if (clientIndex <= lrui) {
// Don't allow the client index restriction to push it down farther in the
// list than it already is.
clientIndex = lrui;
}
if (clientIndex >= 0 && index > clientIndex) {
index = clientIndex;
}
}
if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding at " + index + " of LRU list: " + app);
mLruProcesses.add(index, app);
nextIndex = index-1;
mLruProcessActivityStart++;
mLruProcessServiceStart++;
}
// If the app is currently using a content provider or service,
// bump those processes as well.
//如果该将app绑定到其他service,则要对应调整Service和ContentProvider所在进程的LRU
for (int j=app.connections.size()-1; j>=0; j--) {
ConnectionRecord cr = app.connections.valueAt(j);
if (cr.binding != null && !cr.serviceDead && cr.binding.service != null
&& cr.binding.service.app != null
&& cr.binding.service.app.lruSeq != mLruSeq
&& !cr.binding.service.app.persistent) {
nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,
"service connection", cr, app);
}
}
for (int j=app.conProviders.size()-1; j>=0; j--) {
ContentProviderRecord cpr = app.conProviders.get(j).provider;
if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.persistent) {
nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,
"provider reference", cpr, app);
}
}
}
从以上代码可知,updateLruProcessLocked的主要工作是根据app的lruWeight值调整它在数组中的位置。lruWeight值越大,其在数组中的位置就越靠后。如果该app和某些Service(仅考虑通过bindService建立关系的那些Service)或ContentProvider有交互关系,那么这些Service或ContentProvider所在的进程也需要调节lruWeight值。
2.5 updateOomAdjLocked()
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
final void updateOomAdjLocked() {
//在一般情况下,resumedAppLocked返回mResumedActivity,即当前正处于前台的Activity
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;//前台进程
final long now = SystemClock.uptimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
final int N = mLruProcesses.size();
Log.i("ActivityManagerService-xiao", "updateOomAdjLocked TOP_ACT:"+TOP_ACT+",TOP_APP:"+TOP_APP+",mLruProcesses.size():"+mLruProcesses.size() );
if (false) {
RuntimeException e = new RuntimeException();
e.fillInStackTrace();
Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
}
// Reset state in all uid records.
for (int i=mActiveUids.size()-1; i>=0; i--) {
final UidRecord uidRec = mActiveUids.valueAt(i);
if (false && DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"Starting update of " + uidRec);
uidRec.reset();
}
mStackSupervisor.rankTaskLayersIfNeeded();
mAdjSeq++;
mNewNumServiceProcs = 0;
mNewNumAServiceProcs = 0;
final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;//系统运行存在最大的空的进程数
final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES - emptyProcessLimit;系统运行存在最大的缓存的进程数
// Let's determine how many processes we have running vs.
// how many slots we have for background processes; we may want
// to put multiple processes in a slot of there are enough of
// them.
/*
下面这几句代码的作用如下:
1 根据hidden adj划分级别,一共有9个级别(即numSlots值)
2 根据mLruProcesses的成员个数计算平均落在各个级别的进程数
*/
//numSlots=3
int numSlots = (ProcessList.CACHED_APP_MAX_ADJ
- ProcessList.CACHED_APP_MIN_ADJ + 1) / 2;
int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;
if (numEmptyProcs > cachedProcessLimit) {
// If there are more empty processes than our limit on cached
// processes, then use the cached process limit for the factor.
// This ensures that the really old empty processes get pushed
// down to the bottom, so if we are running low on memory we will
// have a better chance at keeping around more cached processes
// instead of a gazillion empty processes.
numEmptyProcs = cachedProcessLimit;
}
//emptyFactor每组数量 , cachedFactor=mNumCachedHiddenProcs隐藏的进程,近期列表
int emptyFactor = numEmptyProcs/numSlots;//每3个分一组
if (emptyFactor < 1) emptyFactor = 1;
int cachedFactor = (mNumCachedHiddenProcs > 0 ? mNumCachedHiddenProcs : 1)/numSlots;
if (cachedFactor < 1) cachedFactor = 1;
int stepCached = 0;
int stepEmpty = 0;
int numCached = 0;
int numEmpty = 0;
int numTrimming = 0;
mNumNonCachedProcs = 0;
mNumCachedHiddenProcs = 0;
// First update the OOM adjustment for each of the
// application processes based on their current state.
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 we haven't yet assigned the final cached adj
// to the process, do that now.
//app.curAdj >= ProcessList.UNKNOWN_ADJ的情况
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(app, true, now, nowElapsed);
// Count the number of process types.
//计算隐藏Hidden的进程数量,计算的目的是为了判断这个进程是否超过数量
switch (app.curProcState) {
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
mNumCachedHiddenProcs++;
numCached++;
//如果隐藏的数量大于限制就会被杀死
if (numCached > cachedProcessLimit) {
app.kill("cached #" + numCached, true);
}
break;
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
//空进程数量
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++;
if (numEmpty > emptyProcessLimit) {
app.kill("empty #" + numEmpty, true);
}
}
break;
default:
mNumNonCachedProcs++;
break;
}
//独立的进程,并且还没有绑定service, app.isolatedEntryPoint是表示有没有相关的运行代码
if (app.isolated && app.services.size() <= 0 && app.isolatedEntryPoint == null) {
// If this is an isolated process, there are no services
// running in it, and it's not a special process with a
// custom entry point, then the process is no longer
// needed. We agressively kill these because we can by
// definition not re-use the same process again, and it is
// good to avoid having whatever code was running in them
// left sitting around after no longer needed.
app.kill("isolated not needed", true);
} else {
// Keeping this process, update its uid.
final UidRecord uidRec = app.uidRecord;
if (uidRec != null) {
uidRec.ephemeral = app.info.isInstantApp();
if (uidRec.curProcState > app.curProcState) {
uidRec.curProcState = app.curProcState;
}
if (app.foregroundServices) {
uidRec.foregroundServices = true;
}
}
}
if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedByAm) {
numTrimming++;
}
}
}
incrementProcStateSeqAndNotifyAppsLocked();
mNumServiceProcs = mNewNumServiceProcs;
// Now determine the memory trimming level of background processes.
// Unfortunately we need to start at the back of the list to do this
// properly. We only do this if the number of background apps we
// are managing to keep around is less than half the maximum we desire;
// if we are keeping a good number around, we'll let them use whatever
// memory they want.
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;
}
// We always allow the memory level to go up (better). We only allow it to go
// down if we are in a state where that is allowed, *and* the total number of processes
// has gone down since last time.
if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "updateOomAdjLocked oom: memFactor=" + memFactor
+ " last=" + mLastMemoryLevel + " allowLow=" + mAllowLowerMemLevel
+ " numProcs=" + mLruProcesses.size() + " last=" + mLastNumProcesses);
Log.d("ActivityManagerService-xiao", "oom: memFactor=" + memFactor
+ " last=" + mLastMemoryLevel + " allowLow=" + mAllowLowerMemLevel
+ " numProcs=" + mLruProcesses.size() + " last=" + mLastNumProcesses);
if (memFactor > mLastMemoryLevel) {
if (!mAllowLowerMemLevel || mLruProcesses.size() >= mLastNumProcesses) {
memFactor = mLastMemoryLevel;
if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "Keeping last mem factor!");
}
}
if (memFactor != mLastMemoryLevel) {
EventLogTags.writeAmMemFactor(memFactor, mLastMemoryLevel);
}
mLastMemoryLevel = memFactor;
mLastNumProcesses = mLruProcesses.size();
boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleepingLocked(), now);
final int trackerMemFactor = mProcessStats.getMemFactorLocked();
if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
if (mLowRamStartTime == 0) {
mLowRamStartTime = now;
}
int step = 0;
int fgTrimLevel;
switch (memFactor) {
case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
break;
case ProcessStats.ADJ_MEM_FACTOR_LOW:
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
break;
default:
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
break;
}
//根据mLruProcesses的成员个数计算平均落在各个级别的进程数(即factor值)
int factor = numTrimming/3;
int minFactor = 2;
if (mHomeProcess != null) minFactor++;
if (mPreviousProcess != null) minFactor++;
if (factor < minFactor) factor = minFactor;
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
//下面是计算触发GC的内存阈值
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
setProcessTrackerStateLocked(app, trackerMemFactor, now);
app.procStateChanged = false;
}
if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedByAm) {
if (app.trimMemoryLevel < curLevel && app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Trimming memory of " + app.processName + " to " + curLevel);
app.thread.scheduleTrimMemory(curLevel);
} catch (RemoteException e) {
}
if (false) {
// For now we won't do this; our memory trimming seems
// to be good enough at this point that destroying
// activities causes more harm than good.
if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
&& app != mHomeProcess && app != mPreviousProcess) {
// Need to do this on its own message because the stack may not
// be in a consistent state at this point.
// For these apps we will also finish their activities
// to help them free memory.
mStackSupervisor.scheduleDestroyAllActivities(app, "trim");
}
}
}
app.trimMemoryLevel = curLevel;
step++;
if (step >= factor) {
step = 0;
switch (curLevel) {
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
curLevel = ComponentCallbacks2.TRIM_MEMORY_MODERATE;
break;
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
curLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
break;
}
}
} else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
&& app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Trimming memory of heavy-weight " + app.processName
+ " to " + ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
app.thread.scheduleTrimMemory(
ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
} catch (RemoteException e) {
}
}
app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
} else {
if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
|| app.systemNoUi) && app.pendingUiClean) {
// If this application is now in the background and it
// had done UI, then give it the special trim level to
// have it free UI resources.
final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
if (app.trimMemoryLevel < level && app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Trimming memory of bg-ui " + app.processName
+ " to " + level);
app.thread.scheduleTrimMemory(level);
} catch (RemoteException e) {
}
}
app.pendingUiClean = false;
}
if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Trimming memory of fg " + app.processName
+ " to " + fgTrimLevel);
app.thread.scheduleTrimMemory(fgTrimLevel);
} catch (RemoteException e) {
}
}
app.trimMemoryLevel = fgTrimLevel;
}
}
} else {
if (mLowRamStartTime != 0) {
mLowRamTimeSinceLastIdle += now - mLowRamStartTime;
mLowRamStartTime = 0;
}
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
setProcessTrackerStateLocked(app, trackerMemFactor, now);
app.procStateChanged = false;
}
if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
|| app.systemNoUi) && app.pendingUiClean) {
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
&& app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Trimming memory of ui hidden " + app.processName
+ " to " + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
app.thread.scheduleTrimMemory(
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
} catch (RemoteException e) {
}
}
app.pendingUiClean = false;
}
app.trimMemoryLevel = 0;
}
}
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");
}
if (allChanged) {
requestPssAllProcsLocked(now, false, mProcessStats.isMemFactorLowered());
}
ArrayList<UidRecord> becameIdle = null;
// Update from any uid changes.
if (mLocalPowerManager != null) {
mLocalPowerManager.startUidChanges();
}
for (int i=mActiveUids.size()-1; i>=0; i--) {
final UidRecord uidRec = mActiveUids.valueAt(i);
int uidChange = UidRecord.CHANGE_PROCSTATE;
if (uidRec.curProcState != ActivityManager.PROCESS_STATE_NONEXISTENT
&& (uidRec.setProcState != uidRec.curProcState
|| uidRec.setWhitelist != uidRec.curWhitelist)) {
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"Changes in " + uidRec + ": proc state from " + uidRec.setProcState
+ " to " + uidRec.curProcState + ", whitelist from " + uidRec.setWhitelist
+ " to " + uidRec.curWhitelist);
if (ActivityManager.isProcStateBackground(uidRec.curProcState)
&& !uidRec.curWhitelist) {
// UID is now in the background (and not on the temp whitelist). Was it
// previously in the foreground (or on the temp whitelist)?
if (!ActivityManager.isProcStateBackground(uidRec.setProcState)
|| uidRec.setWhitelist) {
uidRec.lastBackgroundTime = nowElapsed;
if (!mHandler.hasMessages(IDLE_UIDS_MSG)) {
// Note: the background settle time is in elapsed realtime, while
// the handler time base is uptime. All this means is that we may
// stop background uids later than we had intended, but that only
// happens because the device was sleeping so we are okay anyway.
mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
mConstants.BACKGROUND_SETTLE_TIME);
}
}
if (uidRec.idle && !uidRec.setIdle) {
uidChange = UidRecord.CHANGE_IDLE;
if (becameIdle == null) {
becameIdle = new ArrayList<>();
}
becameIdle.add(uidRec);
}
} else {
if (uidRec.idle) {
uidChange = UidRecord.CHANGE_ACTIVE;
EventLogTags.writeAmUidActive(uidRec.uid);
uidRec.idle = false;
}
uidRec.lastBackgroundTime = 0;
}
final boolean wasCached = uidRec.setProcState
> ActivityManager.PROCESS_STATE_RECEIVER;
final boolean isCached = uidRec.curProcState
> ActivityManager.PROCESS_STATE_RECEIVER;
if (wasCached != isCached ||
uidRec.setProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
uidChange |= isCached ? UidRecord.CHANGE_CACHED : UidRecord.CHANGE_UNCACHED;
}
uidRec.setProcState = uidRec.curProcState;
uidRec.setWhitelist = uidRec.curWhitelist;
uidRec.setIdle = uidRec.idle;
enqueueUidChangeLocked(uidRec, -1, uidChange);
noteUidProcessState(uidRec.uid, uidRec.curProcState);
if (uidRec.foregroundServices) {
mServices.foregroundServiceProcStateChangedLocked(uidRec);
}
}
}
if (mLocalPowerManager != null) {
mLocalPowerManager.finishUidChanges();
}
if (becameIdle != null) {
// If we have any new uids that became idle this time, we need to make sure
// they aren't left with running services.
for (int i = becameIdle.size() - 1; i >= 0; i--) {
mServices.stopInBackgroundLocked(becameIdle.get(i).uid);
}
}
if (mProcessStats.shouldWriteNowLocked(now)) {
mHandler.post(new Runnable() {
@Override public void run() {
synchronized (ActivityManagerService.this) {
mProcessStats.writeStateAsyncLocked();
}
}
});
}
if (DEBUG_OOM_ADJ) {
final long duration = SystemClock.uptimeMillis() - now;
if (false) {
Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms",
new RuntimeException("here").fillInStackTrace());
} else {
Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms");
}
}
}
上面的代码中涉及到两个比较重要的函数computeOomAdjLocked和applyOomAdjLocked从名字大概就能猜出来他们的作用,一个计算adj的值,一个是以及计算出来adj的值来判断此app是否需要内存回收。computeOomAdjLocked后面会详讲。
上面函数主要是根据computeOomAdjLocked计算的进程adj值和curProcState来杀死一些隐藏或者空的进程。依据空进程的数量多少来判断内存的状态最后来判断是否需要GC。
2.6 computeOomAdjLocked()
// frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
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 = ProcessList.SCHED_GROUP_BACKGROUND;
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();//该应用进程包含Activity的个数
//如果maxAdj小于FOREGROUND_APP_ADJ,这类进程优先级相当高,一般属于系统进程
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.
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making fixed: " + app);
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
app.curRawAdj = app.maxAdj;
app.foregroundActivities = false;
app.curSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;//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在顶层,那就说明此进程具有UI,systemNoUi=false并且重新设置进程组
app.systemNoUi = false;
app.curSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
app.adjType = "pers-top-activity";
} else if (app.hasTopUi) {
app.systemNoUi = false;
app.curSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
app.adjType = "pers-top-ui";
} 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_CUR_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;
mTmpBroadcastQueue.clear();
//如果app为前台Activity所在的那个应用进程
if (app == TOP_APP) {
// 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) Slog.d(TAG, "Making top: " + app);
} else if (app.instr != null) {//activity正在启动,但是没有在最前台
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.adjType = "instrumentation";
procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making instrumentation: " + app);
} else if (isReceivingBroadcastLocked(app, mTmpBroadcastQueue)) {
// 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.
//此情况对应正在执行onReceive函数的广播接收者所在进程,它的优先级也很高
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;
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making broadcast: " + app);
} else if (app.executingServices.size() > 0) {
// An app that is currently executing a service callback also
// counts as being in the foreground.
//正在执行Service生命周期函数的进程
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;
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making exec-service: " + app);
//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 = 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 = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
app.cached = true;
app.empty = true;
app.adjType = "cch-empty";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making empty: " + app);
}
// Examine all activities if not already foreground.
//检查进程中无前台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.app != app) {
Log.e(TAG, "Found activity " + r + " in proc activity list using " + r.app
+ " instead of expected " + app);
if (r.app == null || (r.app.uid == app.uid)) {
// Only fix things up when they look sane
r.app = app;
} else {
continue;
}
}
if (r.visible) {
// App has a visible activity; only upgrade adjustment.
//纠正一个可见的app 进程adj的值以及procState的值
if (adj > ProcessList.VISIBLE_APP_ADJ) {
adj = ProcessList.VISIBLE_APP_ADJ;
app.adjType = "vis-activity";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to vis-activity: " + app);
}
if (procState > PROCESS_STATE_CUR_TOP) {
procState = PROCESS_STATE_CUR_TOP;
app.adjType = "vis-activity";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to vis-activity: " + app);
}
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;
} 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 (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to pause-activity: " + app);
}
if (procState > PROCESS_STATE_CUR_TOP) {
procState = PROCESS_STATE_CUR_TOP;
app.adjType = "pause-activity";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to pause-activity: " + app);
}
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 (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to stop-activity: " + app);
}
// 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) {//停止但是还没有finish
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
app.adjType = "stop-activity";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to stop-activity: " + app);
}
}
app.cached = false;
app.empty = false;
foregroundActivities = true;
} else {
if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
app.adjType = "cch-act";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to cached activity: " + app);
}
}
}
if (adj == ProcessList.VISIBLE_APP_ADJ) {
adj += minLayer;
}
}
//刚刚暂停,进程状态是前台服务,比如music
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
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 = ProcessList.SCHED_GROUP_DEFAULT;
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to fg service: " + app);
} else if (app.hasOverlayUi) {//有UI的但是目前又不可见
// The process is display an overlay UI.
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 (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to overlay ui: " + app);
}
}
//刚暂停但是后台服务还在运行,
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
if (app.forcingToImportant != null) {
// This is currently used for toasts... they are not interactive, and
// we don't want them to cause the app to become fully foreground (and
// thus out of background check), so we yes the best background level we can.
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;
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to force imp: " + app);
}
}
//如果进程是heavy-weight 进程
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 = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "heavy";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to heavy: " + app);
}
if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
app.adjType = "heavy";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to heavy: " + app);
}
}
//如果前面计算出来的adj大于HOME_APP_ADJ,并且该进程又是Home进程,则需要重新调整
if (app == mHomeProcess) {
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.cached = false;
app.adjType = "home";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to home: " + app);
}
if (procState > ActivityManager.PROCESS_STATE_HOME) {
procState = ActivityManager.PROCESS_STATE_HOME;
app.adjType = "home";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to home: " + app);
}
}
//上次运行的app,就是显示在近期列表里面
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 = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "previous";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to prev: " + app);
}
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
app.adjType = "previous";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to prev: " + app);
}
}
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;
//后台进程
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_TRANSIENT_BACKGROUND) {
procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
}
app.adjType = "backup";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to backup: " + app);
app.cached = false;
}
if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
procState = ActivityManager.PROCESS_STATE_BACKUP;
app.adjType = "backup";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to backup: " + app);
}
}
boolean mayBeTop = false;
String mayBeTopType = null;
Object mayBeTopSource = null;
Object mayBeTopTarget = null;
//下面这几段代码处理那些进程中含有Service,ContentProvider组件情况下的adj调节
for (int is = app.services.size()-1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| 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;
app.adjType = "started-services";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to started service: " + app);
}
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 + 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) Slog.d(TAG, "Raise to started service: " + app);
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";
}
}
}
for (int conni = s.connections.size()-1;
conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| 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 == ProcessList.SCHED_GROUP_BACKGROUND
|| 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;
}
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 + 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.
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
adjType = "cch-bound-ui-services";
}
} else {
int newAdj;
if ((cr.flags&(Context.BIND_ABOVE_CLIENT
|Context.BIND_IMPORTANT)) != 0) {
newAdj = 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) {
newAdj = ProcessList.PERCEPTIBLE_APP_ADJ;
} else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
newAdj = clientAdj;
} else {
if (adj > ProcessList.VISIBLE_APP_ADJ) {
newAdj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
} else {
newAdj = adj;
}
}
if (!client.cached) {
app.cached = false;
}
if (adj > newAdj) {
adj = newAdj;
adjType = "service";
}
}
}
if ((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.
if (client.curSchedGroup > schedGroup) {
if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
schedGroup = client.curSchedGroup;
} else {
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
// Special handling of clients who are in the top state.
// We *may* want to consider this process to be in the
// top state as well, but only if there is not another
// reason for it to be running. Being on the top is a
// special state, meaning you are specifically running
// for the current top app. If the process is already
// running in the background for some other reason, it
// is more important to continue considering it to be
// in the background state.
mayBeTop = true;
mayBeTopType = "service";
mayBeTopSource = cr.binding.client;
mayBeTopTarget = s.name;
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
} else {
// 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 state after that.
if ((cr.flags&Context.BIND_FOREGROUND_SERVICE) != 0) {
clientProcState =
ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
} else if (mWakefulness
== PowerManagerInternal.WAKEFULNESS_AWAKE &&
(cr.flags&Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
!= 0) {
clientProcState =
ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
} else {
clientProcState =
ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
}
}
}
} else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
if (clientProcState <
ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
clientProcState =
ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
}
} else {
if (clientProcState <
ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
clientProcState =
ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
}
}
if (procState > clientProcState) {
procState = clientProcState;
if (adjType == null) {
adjType = "service";
}
}
if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
&& (cr.flags&Context.BIND_SHOWING_UI) != 0) {
app.pendingUiClean = 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.name;
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to " + adjType
+ ": " + app + ", due to " + cr.binding.client
+ " adj=" + adj + " procState=" + procState);
}
}
if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
app.treatLikeActivity = true;
}
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;
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to service w/activity: "
+ app);
}
}
}
}
}
for (int provi = app.pubProviders.size()-1;
provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| 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 == ProcessList.SCHED_GROUP_BACKGROUND
|| 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;
}
String adjType = null;
if (adj > clientAdj) {
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adjType = "cch-ui-provider";
} else {
adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
adjType = "provider";
}
app.cached &= client.cached;
}
if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
// Special handling of clients who are in the top state.
// We *may* want to consider this process to be in the
// top state as well, but only if there is not another
// reason for it to be running. Being on the top is a
// special state, meaning you are specifically running
// for the current top app. If the process is already
// running in the background for some other reason, it
// is more important to continue considering it to be
// in the background state.
mayBeTop = true;
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
mayBeTopType = adjType = "provider-top";
mayBeTopSource = client;
mayBeTopTarget = cpr.name;
} else {
// 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 state after that.
clientProcState =
ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
if (adjType == null) {
adjType = "provider";
}
}
}
if (procState > clientProcState) {
procState = clientProcState;
}
if (client.curSchedGroup > 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) Slog.d(TAG, "Raise to " + adjType
+ ": " + app + ", due to " + client
+ " adj=" + adj + " procState=" + procState);
}
}
// 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 = ProcessList.SCHED_GROUP_DEFAULT;
app.cached = false;
app.adjType = "ext-provider";
app.adjTarget = cpr.name;
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to external provider: " + app);
}
if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
}
}
}
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 (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to recent provider: " + app);
}
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
app.adjType = "recent-provider";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to recent provider: " + app);
}
}
if (mayBeTop && procState > ActivityManager.PROCESS_STATE_TOP) {
// A client of one of our services or providers is in the top state. We
// *may* want to be in the top state, but not if we are already running in
// the background for some other reason. For the decision here, we are going
// to pick out a few specific states that we want to remain in when a client
// is top (states that tend to be longer-term) and otherwise allow it to go
// to the top state.
switch (procState) {
case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
// Something else is keeping it at this level, just leave it.
break;
case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
case ActivityManager.PROCESS_STATE_SERVICE:
// These all are longer-term states, so pull them up to the top
// of the background states, but not all the way to the top state.
procState = ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
app.adjType = mayBeTopType;
app.adjSource = mayBeTopSource;
app.adjTarget = mayBeTopTarget;
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "May be top raise to " + mayBeTopType
+ ": " + app + ", due to " + mayBeTopSource
+ " adj=" + adj + " procState=" + procState);
break;
default:
// Otherwise, top is a better choice, so take it.
procState = ActivityManager.PROCESS_STATE_TOP;
app.adjType = mayBeTopType;
app.adjSource = mayBeTopSource;
app.adjTarget = mayBeTopTarget;
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "May be top raise to " + mayBeTopType
+ ": " + app + ", due to " + mayBeTopSource
+ " adj=" + adj + " procState=" + procState);
break;
}
}
if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
if (app.hasClientActivities) {
// This is a cached process, but with client activities. Mark it so.
procState = ActivityManager.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 = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
app.adjType = "cch-as-act";
}
}
if (adj == ProcessList.SERVICE_ADJ) {
if (doingAll) {
app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
mNewNumServiceProcs++;
//Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);
if (!app.serviceb) {
// This service isn't far enough down on the LRU list to
// normally be a B service, but if we are low on RAM and it
// is large we want to force it down since we would prefer to
// keep launcher over it.
if (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 {
app.serviceHighRam = false;
}
}
if (app.serviceb) {
adj = ProcessList.SERVICE_B_ADJ;
}
}
//终于计算完毕
app.curRawAdj = adj;
//Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
// " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
//每个进程跟进他的类型设定了maxAdj最大值,计算出的adj不能大于最大
if (adj > app.maxAdj) {
adj = app.maxAdj;
if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
// 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.curSchedGroup = schedGroup;
app.curProcState = procState;
app.foregroundActivities = foregroundActivities;
return app.curRawAdj;
}
主要计算进程的 adjSeq,curRawAdj,foregroundActivities,curSchedGroup,curProcState,systemNoUi,curRawAdj。
网友评论