二 Framework OOM Adjustment 机制
Android 系统(以6.0 AOSP 代码为例),和 LMK 相关的源码主要有:
platform/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java)
platform/frameworks/base/services/core/java/com/android/server/am/ProcessList.java
platform/system/core/lmkd/lmkd.c
kernel/common/drivers/staging/Android/lowmemorykiller.c
2.1 OOM Adjustment
ADJ 定义在 ProcessList
ADJ | Value | Note |
---|---|---|
UNKNOWN_ADJ | 16 | 一般指将要会缓存进程,无法获取确定值 |
CACHED_APP_MAX_ADJ | 15 | 不可见进程的adj最大值 |
CACHED_APP_MIN_ADJ | 9 | 不可见进程的adj最小值 |
SERVICE_B_AD | 8 B | List中的Service(较老的、使用可能性更小) |
PREVIOUS_APP_ADJ | 7 | 上一个App的进程(往往通过按返回键) |
HOME_APP_ADJ | 6 | Home进程 |
SERVICE_ADJ | 5 | 服务进程(Service process) |
HEAVY_WEIGHT_APP_ADJ | 4 | 后台的重量级进程,system/rootdir/init.rc文件中设置 |
BACKUP_APP_ADJ | 3 | 备份进程 |
PERCEPTIBLE_APP_ADJ | 2 | 可感知进程,比如后台音乐播放 |
VISIBLE_APP_ADJ | 1 | 可见进程(Visible process) |
FOREGROUND_APP_ADJ | 0 | 前台进程(Foreground process |
PERSISTENT_SERVICE_ADJ | -11 | 关联着系统或persistent进程 |
PERSISTENT_PROC_ADJ | -12 | 系统persistent进程,比如telephony |
SYSTEM_ADJ | -16 | 系统进程 |
NATIVE_ADJ | -17 | native进程(不被系统管理) |
// OOM adjustments for processes in various states:
// Adjustment used in certain places where we don't know it yet.
// (Generally this is something that is going to be cached, but we
// don't know the exact value in the cached range to assign yet.)
static final int UNKNOWN_ADJ = 16;
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
static final int CACHED_APP_MAX_ADJ = 15;
static final int CACHED_APP_MIN_ADJ = 9;
// The B list of SERVICE_ADJ -- these are the old and decrepit
// services that aren't as shiny and interesting as the ones in the A list.
static final int SERVICE_B_ADJ = 8;
// This is the process of the previous application that the user was in.
// This process is kept above other things, because it is very common to
// switch back to the previous app. This is important both for recent
// task switch (toggling between the two top recent apps) as well as normal
// UI flow such as clicking on a URI in the e-mail app to view in the browser,
// and then pressing back to return to e-mail.
static final int PREVIOUS_APP_ADJ = 7;
// This is a process holding the home application -- we want to try
// avoiding killing it, even if it would normally be in the background,
// because the user interacts with it so much.
static final int HOME_APP_ADJ = 6;
// This is a process holding an application service -- killing it will not
// have much of an impact as far as the user is concerned.
static final int SERVICE_ADJ = 5;
// This is a process with a heavy-weight application. It is in the
// background, but we want to try to avoid killing it. Value set in
// system/rootdir/init.rc on startup.
static final int HEAVY_WEIGHT_APP_ADJ = 4;
// This is a process currently hosting a backup operation. Killing it
// is not entirely fatal but is generally a bad idea.
static final int BACKUP_APP_ADJ = 3;
// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
// immediately visible. An example is background music playback.
static final int PERCEPTIBLE_APP_ADJ = 2;
// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
static final int VISIBLE_APP_ADJ = 1;
// This is the process running the current foreground app. We'd really
// rather not kill it!
static final int FOREGROUND_APP_ADJ = 0;
// This is a process that the system or a persistent process has bound to,
// and indicated it is important.
static final int PERSISTENT_SERVICE_ADJ = -11;
// This is a system persistent process, such as telephony. Definitely
// don't want to kill it, but doing so is not completely fatal.
static final int PERSISTENT_PROC_ADJ = -12;
// The system process runs at the default adjustment.
static final int SYSTEM_ADJ = -16;
// Special code for native processes that are not being managed by the system (so
// don't have an oom adj assigned by the system).
static final int NATIVE_ADJ = -17;
2.2 Process State
在 ActivityManager 中定义了从-1到16共18种进程状态:
PROCESS_STATE | 取值 | 解释 |
---|---|---|
PROCESS_STATE_CACHED_EMPTY | 16 | 进程处于cached状态,且为空进程 |
PROCESS_STATE_CACHED_ACTIVITY_CLIENT | 15 | 进程处于cached状态,且为另一个cached进程(内含Activity)的client进程 |
PROCESS_STATE_CACHED_ACTIVITY | 14 | 进程处于cached状态,且内含Activity |
PROCESS_STATE_LAST_ACTIVITY | 13 | 后台进程,且拥有上一次显示的Activity |
PROCESS_STATE_HOME | 12 | 后台进程,且拥有home Activity |
PROCESS_STATE_RECEIVER | 11 | 后台进程,且正在运行receiver |
PROCESS_STATE_SERVICE | 10 | 后台进程,且正在运行service |
PROCESS_STATE_HEAVY_WEIGHT | 9 | 后台进程,但无法执行restore,因此尽量避免kill该进程 |
PROCESS_STATE_BACKUP | 8 | 后台进程,正在运行backup/restore操作 |
PROCESS_STATE_IMPORTANT_BACKGROUND | 7 | 对用户很重要的进程,用户不可感知其存在 |
PROCESS_STATE_IMPORTANT_FOREGROUND | 6 | 对用户很重要的进程,用户可感知其存在 |
PROCESS_STATE_TOP_SLEEPING | 5 | 与PROCESS_STATE_TOP一样,但此时设备正处于休眠状态 |
PROCESS_STATE_FOREGROUND_SERVICE | 4 | 拥有一个前台Service |
PROCESS_STATE_BOUND_FOREGROUND_SERVICE | 3 | 拥有一个前台Service,且由系统绑定 |
PROCESS_STATE_TOP | 2 | 拥有当前用户可见的top Activity |
PROCESS_STATE_PERSISTENT_UI | 1 | persistent系统进程,并正在执行UI操作 |
PROCESS_STATE_PERSISTENT | 0 | persistent系统进程 |
PROCESS_STATE_NONEXISTENT | -1 | 不存在的进程 |
在 ActivityManager 中的 RunningAppProcessInfo
类中定义了进程的优先级 IMPORTANCE 值:
/**
* Constant for {@link #importance}: This process is running the
* foreground UI; that is, it is the thing currently at the top of the screen
* that the user is interacting with.
*/
public static final int IMPORTANCE_FOREGROUND = 100;
/**
* Constant for {@link #importance}: This process is running a foreground
* service, for example to perform music playback even while the user is
* not immediately in the app. This generally indicates that the process
* is doing something the user actively cares about.
*/
public static final int IMPORTANCE_FOREGROUND_SERVICE = 125;
/**
* Constant for {@link #importance}: This process is running the foreground
* UI, but the device is asleep so it is not visible to the user. This means
* the user is not really aware of the process, because they can not see or
* interact with it, but it is quite important because it what they expect to
* return to once unlocking the device.
*/
public static final int IMPORTANCE_TOP_SLEEPING = 150;
/**
* Constant for {@link #importance}: This process is running something
* that is actively visible to the user, though not in the immediate
* foreground. This may be running a window that is behind the current
* foreground (so paused and with its state saved, not interacting with
* the user, but visible to them to some degree); it may also be running
* other services under the system's control that it inconsiders important.
*/
public static final int IMPORTANCE_VISIBLE = 200;
/**
* Constant for {@link #importance}: This process is not something the user
* is directly aware of, but is otherwise perceptable to them to some degree.
*/
public static final int IMPORTANCE_PERCEPTIBLE = 130;
/**
* Constant for {@link #importance}: This process is running an
* application that can not save its state, and thus can't be killed
* while in the background.
* @hide
*/
public static final int IMPORTANCE_CANT_SAVE_STATE = 170;
/**
* Constant for {@link #importance}: This process is contains services
* that should remain running. These are background services apps have
* started, not something the user is aware of, so they may be killed by
* the system relatively freely (though it is generally desired that they
* stay running as long as they want to).
*/
public static final int IMPORTANCE_SERVICE = 300;
/**
* Constant for {@link #importance}: This process process contains
* background code that is expendable.
*/
public static final int IMPORTANCE_BACKGROUND = 400;
/**
* Constant for {@link #importance}: This process is empty of any
* actively running code.
*/
public static final int IMPORTANCE_EMPTY = 500;
/**
* Constant for {@link #importance}: This process does not exist.
*/
public static final int IMPORTANCE_GONE = 1000;
/** @hide */
public static int procStateToImportance(int procState) {
if (procState == PROCESS_STATE_NONEXISTENT) {
return IMPORTANCE_GONE;
} else if (procState >= PROCESS_STATE_HOME) {
return IMPORTANCE_BACKGROUND;
} else if (procState >= PROCESS_STATE_SERVICE) {
return IMPORTANCE_SERVICE;
} else if (procState > PROCESS_STATE_HEAVY_WEIGHT) {
return IMPORTANCE_CANT_SAVE_STATE;
} else if (procState >= PROCESS_STATE_IMPORTANT_BACKGROUND) {
return IMPORTANCE_PERCEPTIBLE;
} else if (procState >= PROCESS_STATE_IMPORTANT_FOREGROUND) {
return IMPORTANCE_VISIBLE;
} else if (procState >= PROCESS_STATE_TOP_SLEEPING) {
return IMPORTANCE_TOP_SLEEPING;
} else if (procState >= PROCESS_STATE_FOREGROUND_SERVICE) {
return IMPORTANCE_FOREGROUND_SERVICE;
} else {
return IMPORTANCE_FOREGROUND;
}
}
2.3 Framework ADJ 调整算法
ActivityManagerService
中三个核心方法:
-
updateOomAdjLocked
:更新adj,当目标进程为空,或者被杀则返回false;否则返回true; -
computeOomAdjLocked
:计算adj,返回计算后RawAdj值; -
applyOomAdjLocked
:应用adj,当需要杀掉目标进程则返回false;否则返回true。
updateOomAdjLocked
中会调用 computeOomAdjLocked
和 applyOomAdjLocked
。
ADJ 的更新时机
-
Activity
- ASS.realStartActivityLocked: 启动Activity
- AS.resumeTopActivityInnerLocked: 恢复栈顶Activity
- AS.finishCurrentActivityLocked: 结束当前Activity
- AS.destroyActivityLocked: 摧毁当前Activity
-
Service
- realStartServiceLocked: 启动服务
- bindServiceLocked: 绑定服务(只更新当前app)
- unbindServiceLocked: 解绑服务 (只更新当前app)
- bringDownServiceLocked: 结束服务 (只更新当前app)
- sendServiceArgsLocked: 在bringup或则cleanup服务过程调用 (只更新当前app)
-
Broadcast
- BQ.processNextBroadcast: 处理下一个广播
- BQ.processCurBroadcastLocked: 处理当前广播
- BQ.deliverToRegisteredReceiverLocked: 分发已注册的广播 (只更新当前app)
-
ContentProvider
- AMS.removeContentProvider: 移除provider
- AMS.publishContentProviders: 发布provider (只更新当前app)
- AMS.getContentProviderImpl: 获取provider (只更新当前app)
-
Process
- AMS.setSystemProcess: 创建并设置系统进程
- AMS.addAppLocked: 创建persistent进程
- AMS.attachApplicationLocked: 进程创建后attach到system_server的过程;
- AMS.trimApplications: 清除没有使用app
- AMS.appDiedLocked: 进程死亡
- AMS.killAllBackgroundProcesses: 杀死所有后台进程.即(ADJ>9或removed=true的普通进程)
- AMS.killPackageProcessesLocked: 以包名的形式 杀掉相关进程;
updateOomAdjLocked
ActivityManagerService 会在每次需要更新 app oom_adj 的时候调用updateOomAdjLocked
方法更新每个进程的 oom_adj。
final void updateOomAdjLocked() {
// 获取栈顶 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();
if (false) {
RuntimeException e = new RuntimeException();
e.fillInStackTrace();
Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
}
// 重置所有uid记录,把curProcState设置成16(空进程)
// 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();
}
mAdjSeq++;
mNewNumServiceProcs = 0;
mNewNumAServiceProcs = 0;
final int emptyProcessLimit;
final int cachedProcessLimit;
// mProcessLimit默认值等于32,通过开发者选择可设置,或者厂商会自行调整
if (mProcessLimit <= 0) {
emptyProcessLimit = cachedProcessLimit = 0;
} else if (mProcessLimit == 1) {
emptyProcessLimit = 1;
cachedProcessLimit = 0;
} else {
// emptyProcessLimit = 16, cachedProcessLimit = 16
emptyProcessLimit = ProcessList.computeEmptyProcessLimit(mProcessLimit);
cachedProcessLimit = mProcessLimit - 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.
// 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;
}
int emptyFactor = numEmptyProcs/numSlots;
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.
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.
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 > 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;
}
if (app.isolated && app.services.size() <= 0) {
// If this is an isolated process, and there are no
// services running in it, 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.curProcState > app.curProcState) {
uidRec.curProcState = app.curProcState;
}
}
if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedByAm) {
numTrimming++;
}
}
}
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 <= ProcessList.TRIM_CACHED_APPS
&& numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
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, "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!");
}
}
mLastMemoryLevel = memFactor;
mLastNumProcesses = mLruProcesses.size();
boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleeping(), 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;
}
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;
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());
}
// Update from any uid changes.
for (int i=mActiveUids.size()-1; i>=0; i--) {
final UidRecord uidRec = mActiveUids.valueAt(i);
if (uidRec.setProcState != uidRec.curProcState) {
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"Changes in " + uidRec + ": proc state from " + uidRec.setProcState
+ " to " + uidRec.curProcState);
uidRec.setProcState = uidRec.curProcState;
enqueueUidChangeLocked(uidRec, false);
}
}
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");
}
}
}