本文转载自:Android源码阅读:AMS调整adj
本文基于android-13.0.0_r1
1.OomAdjuster简介和adj调整前的检查
1.1 OomAdjuster的实例化
AMS调整adj最核心的逻辑都在OomAdjuster中实现,OomAdjuster仅在AMS的构造函数中实例化。
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
OomAdjuster mOomAdjuster;
public ActivityManagerService(Injector injector, ServiceThread handlerThread) {
// ...
mOomAdjuster = hasHandlerThread
? new OomAdjuster(this, mProcessList, activeUids, handlerThread) : null;
// ...
}
// frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
this(service, processList, activeUids, createAdjusterThread());
}
private static ServiceThread createAdjusterThread() {
// The process group is usually critical to the response time of foreground app, so the
// setter should apply it as soon as possible.
final ServiceThread adjusterThread =
new ServiceThread(TAG, THREAD_PRIORITY_TOP_APP_BOOST, false /* allowIo */);
adjusterThread.start();
return adjusterThread;
}
1.2 adj调整的入口:updateOomAdjLocked
adj调整是从调用updateOomAdjLocked函数开始的。
// frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
@GuardedBy("mService")
boolean updateOomAdjLocked(ProcessRecord app, String oomAdjReason) {
synchronized (mProcLock) {
return updateOomAdjLSP(app, oomAdjReason);
}
}
@GuardedBy("mService")
void updateOomAdjLocked(String oomAdjReason) {
synchronized (mProcLock) {
updateOomAdjLSP(oomAdjReason);
}
}
两个updateOomAdjLocked函数,分别针对某一特定进程,和针对LRU列表中所有进程。
两个函数都是在已持有AMS锁的情况下,加mProcLock锁调用updateOomAdjLSP。
这里LSP是“locked by mService& mProcLock”的含义。
那么哪里会调用到updateOomAdjLocked呢?
ActivityManagerService.java和ProcessList.java中都有针对LRU队列全部更新的调用,ActiveServices.java、ContentProviderHelper.java、ProcessStateRecord.java、ProcessRecord.java等都有针对单个进程的更新。
1.3 updateOomAdjLSP
以全部更新为例,updateOomAdjLSP函数主要的内容是:检查是否有更新正在进行,没有的话再设置mOomAdjUpdateOngoing为true,标志adj更新正式开始,然后调用performUpdateOomAdjLSP。
@GuardedBy({"mService", "mProcLock"})
private void updateOomAdjLSP(String oomAdjReason) {
if (checkAndEnqueueOomAdjTargetLocked(null)) {
// Simply return as there is an oomAdjUpdate ongoing
// 有更新正在进行,直接返回
return;
}
try {
mOomAdjUpdateOngoing = true;
performUpdateOomAdjLSP(oomAdjReason);
} finally {
// Kick off the handling of any pending targets enqueued during the above update
mOomAdjUpdateOngoing = false;
updateOomAdjPendingTargetsLocked(oomAdjReason);
}
}
检查是否有更新正在进行是通过checkAndEnqueueOomAdjTargetLocked函数获取,其内容比较简单,主要是判断mOomAdjUpdateOngoing是否为true。
在有更新正在进行的情况下,会将待更新的进程塞入mPendingProcessSet,或者在全部更新的请求时设置mPendingFullOomAdjUpdate为true。
@GuardedBy("mService")
private boolean checkAndEnqueueOomAdjTargetLocked(@Nullable ProcessRecord app) {
if (!mOomAdjUpdateOngoing) {
return false;
}
if (app != null) {
mPendingProcessSet.add(app);
} else {
mPendingFullOomAdjUpdate = true;
}
return true;
}
2.adj调整和计算
2.1 performUpdateOomAdjLSP
经过前面的检查,到performUpdateOomAdjLSP可以认为正式开始对adj的更新。
该函数中清除待更新的进程,获取当前Top应用所在的进程topApp,并调用updateOomAdjInnerLSP继续更新。
@GuardedBy({"mService", "mProcLock"})
private void performUpdateOomAdjLSP(String oomAdjReason) {
final ProcessRecord topApp = mService.getTopApp();
// Clear any pending ones because we are doing a full update now.
// 清除所有待处理的问题,因为我们现在正在进行全面更新。
mPendingProcessSet.clear();
mService.mAppProfiler.mHasPreviousProcess = mService.mAppProfiler.mHasHomeProcess = false;
updateOomAdjInnerLSP(oomAdjReason, topApp , null, null, true, true);
}
2.2 updateOomAdjInnerLSP
该函数中内容较多,比较核心的内容是:
(1)获取AMS中维护的进程列表,遍历并逐个计算adj
final boolean fullUpdate = processes == null;
ArrayList<ProcessRecord> activeProcesses = fullUpdate ? mProcessList.getLruProcessesLOSP()
: processes;
final int numProc = activeProcesses.size();
// 遍历,逐个计算adj
for (int i = numProc - 1; i >= 0; i--) {
ProcessRecord app = activeProcesses.get(i);
final ProcessStateRecord state = app.mState;
if (!app.isKilledByAm() && app.getThread() != null) {
state.setProcStateChanged(false);
computeOomAdjLSP(app, ProcessList.UNKNOWN_ADJ, topApp, fullUpdate, now, false,
computeClients); // It won't enter cycle if not computing clients.
// if any app encountered a cycle, we need to perform an additional loop later
retryCycles |= state.containsCycle();
// Keep the completedAdjSeq to up to date.
state.setCompletedAdjSeq(mAdjSeq);
}
}
(2)遍历并调用applyOomAdjLSP将adj修改
boolean allChanged = updateAndTrimProcessLSP(now, nowElapsed, oldTime, activeUids);
2.3 computeOomAdjLSP:adj的计算
computeOomAdjLSP基本上是最重要的函数了,adj的具体调整策略都是在其中进行的,通常想对某些进程的adj进行干预都会在该函数中进行修改。
@GuardedBy({"mService", "mProcLock"})
private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
boolean computeClients) {
final ProcessStateRecord state = app.mState;
// ......
state.setCurRawAdj(adj);
state.setCurAdj(psr.modifyRawOomAdj(adj));
state.setCurProcState(procState);
state.setCurRawProcState(procState);
// if curAdj or curProcState improved, then this process was promoted
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
|| state.getCurCapability() != prevCapability;
}
函数内容有非常多的判断逻辑,adj和procState计算出后会放在app.mState的“CurRaw”中,其中adj会通过modifyRawOomAdj修正一下,再赋值给“Cur”。也就是说计算出的adj、procState,都暂时存放在app.mState的CurAdj和CurProcState中。
3.adj的应用
3.1 applyOomAdjLSP
计算adj之后通过applyOomAdjLSP函数进行应用,主要是将计算出的各种状态赋值给以Set开头的变量。
/** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
/* 应用计算出的 oomadj、procstate 和 sched 组值,并将它们冻结在 set* 中 */
@GuardedBy({"mService", "mProcLock"})
private boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
long nowElapsed) {
final ProcessStateRecord state = app.mState;
// 将 CurRawAdj 赋值给 SetRawAdj
if (state.getCurRawAdj() != state.getSetRawAdj()) {
state.setSetRawAdj(state.getCurRawAdj());
}
// 将 CurAdj 赋值给 SetAdj
if (state.getCurAdj() != state.getSetAdj()) {
ProcessList.setOomAdj(app.getPid(), app.uid, state.getCurAdj());
if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {
String msg = "Set " + app.getPid() + " " + app.processName + " adj "
+ state.getCurAdj() + ": " + state.getAdjType();
reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
}
state.setSetAdj(state.getCurAdj());
if (uidRec != null) {
uidRec.noteProcAdjChanged();
}
state.setVerifiedAdj(ProcessList.INVALID_ADJ);
}
// .......
}
该函数中内容也比较多,比较重要的是将 CurAdj 赋值给 SetAdj,并调用ProcessList.setOomAdj
3.2 ProcessList.setOomAdj:与lmkd通信写入adj
// frameworks/base/services/core/java/com/android/server/am/ProcessList.java
public static void setOomAdj(int pid, int uid, int amt) {
// This indicates that the process is not started yet and so no need to proceed further.
if (pid <= 0) {
return;
}
if (amt == UNKNOWN_ADJ)
return;
long start = SystemClock.elapsedRealtime();
ByteBuffer buf = ByteBuffer.allocate(4 * 4);
buf.putInt(LMK_PROCPRIO);
buf.putInt(pid);
buf.putInt(uid);
buf.putInt(amt);
writeLmkd(buf, null);
long now = SystemClock.elapsedRealtime();
if ((now-start) > 250) {
Slog.w("ActivityManager", "SLOW OOM ADJ: " + (now-start) + "ms for pid " + pid
+ " = " + amt);
}
}
四个字节的buffer里,先写入LMK_PROCPRIO的控制指令,代表要做优先级的修改。 然后是pid、uid、adj
之后调用writeLmkd与lmkd进程通信。
private static boolean writeLmkd(ByteBuffer buf, ByteBuffer repl) {
if (!sLmkdConnection.isConnected()) {
// try to connect immediately and then keep retrying
sKillHandler.sendMessage(
sKillHandler.obtainMessage(KillHandler.LMKD_RECONNECT_MSG));
// wait for connection retrying 3 times (up to 3 seconds)
if (!sLmkdConnection.waitForConnection(3 * LMKD_RECONNECT_DELAY_MS)) {
return false;
}
}
return sLmkdConnection.exchange(buf, repl);
}
后续通信可以看LmkdConnection.java以及lmkd.cpp,lmkd接收到adj修改的命令后,会去修改/proc/[pid]/oom_score_adj节点的值。