本篇主要分三部分
- oomadj的計算時機
- oomadj的計算過程
- oomadj計算結果應用
一 架構圖
二 流程圖
三 常用命令
- adb shell dumpsys meminfo com.google.android.apps.maps -d
- cat /proc/meminfo
四 源碼解析
4.1oomadj的更新范圍
oomadj的更新分為兩部分
- 指定proc更新oomadj
- 更新全部進程的oomadj
@GuardedBy("this")
final void updateOomAdjLocked(@OomAdjReason int oomAdjReason) {
mOomAdjuster.updateOomAdjLocked(oomAdjReason);
}
/**
* Update OomAdj for a specific process and its reachable processes.
*
* @param app The process to update
* @param oomAdjReason
* @return whether updateOomAdjLocked(app) was successful.
*/
@GuardedBy("this")
final boolean updateOomAdjLocked(ProcessRecord app, @OomAdjReason int oomAdjReason) {
return mOomAdjuster.updateOomAdjLocked(app, oomAdjReason);
}
ams提供兩個api方法以供調(diào)用,參數(shù)含有proc則指定更新進程踏揣,否則更新全部進程气筋。
4.2 oomadj的更新過程漓摩。
冷啟動一個activity進程秉颗,觀察其oomadj的變化煎楣。
4.2.1 AMS-attachApplicationLocked]
app.mState.setCurAdj(ProcessList.INVALID_ADJ);
app.mState.setSetAdj(ProcessList.INVALID_ADJ);
app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ);
mOomAdjuster.setAttachingSchedGroupLSP(app);
app.mState.setForcingToImportant(null);
clearProcessForegroundLocked(app);
app.mState.setHasShownUi(false);
app.mState.setCached(false);
在應用進程啟動后綁定AMS時,adj是默認的-10000隔显。 是否cached進程設置為false崎溃。
4.2.2 ActivityTaskSupervisor-realStartActivityLocked
// Perform OOM scoring after the activity state is set, so the process can be updated with
// the latest state.
proc.onStartActivity(mService.mTopProcessState, r.info);
realStartActivityLocked ->
WindowProcessController.onStartActivity->
ProcessRecord.onStartActivity->
ProcessRecord.updateProcessInfo->
AMS.updateOomAdjLocked(this, OOM_ADJ_REASON_ACTIVITY);
mOomAdjuster.updateOomAdjLocked(app, oomAdjReason);
4.2.3 OomAdjuster.updateOomAdjLocked
/**
* Update OomAdj for specific process and its reachable processes (with direction/indirect
* bindings from this process); Note its clients' proc state won't be re-evaluated if this proc
* is hosting any service/content provider.
*
* @param app The process to update, or null to update all processes
* @param oomAdjReason
*/
@GuardedBy("mService")
boolean updateOomAdjLocked(ProcessRecord app, @OomAdjReason int oomAdjReason) {
synchronized (mProcLock) {
return updateOomAdjLSP(app, oomAdjReason);
}
}
更新指定進程的adj并且將它client端的oomadj也進行更新蜻直。
@GuardedBy({"mService", "mProcLock"})
private boolean updateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
if (app == null || !mConstants.OOMADJ_UPDATE_QUICK) {
updateOomAdjLSP(oomAdjReason);
return true;
}
//如果正在更新oomadj那么退出。
if (checkAndEnqueueOomAdjTargetLocked(app)) {
// Simply return true as there is an oomAdjUpdate ongoing
return true;
}
try {
//正在更新oomadj
mOomAdjUpdateOngoing = true;
//執(zhí)行更新oomadj
return performUpdateOomAdjLSP(app, oomAdjReason);
} finally {
// Kick off the handling of any pending targets enqueued during the above update
mOomAdjUpdateOngoing = false;
updateOomAdjPendingTargetsLocked(oomAdjReason);
}
}
【performUpdateOomAdjLSP】
@GuardedBy({"mService", "mProcLock"})
private boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
//從ams拿到topApp。
final ProcessRecord topApp = mService.getTopApp();
//開始抓trace
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
mService.mOomAdjProfiler.oomAdjStarted();
mAdjSeq++;
// Firstly, try to see if the importance of itself gets changed
final ProcessStateRecord state = app.mState;
final boolean wasCached = state.isCached();
final int oldAdj = state.getCurRawAdj();
//新啟動的proc概而,adj開始在ams被賦值INVALID_ADJ -10000.這個理給他賦值UNKNOWN_ADJ
final int cachedAdj = oldAdj >= CACHED_APP_MIN_ADJ
? oldAdj : UNKNOWN_ADJ;
//...省略
boolean success = performUpdateOomAdjLSP(app, cachedAdj, topApp,
SystemClock.uptimeMillis(), oomAdjReason);
【performUpdateOomAdjLSP】
private boolean performUpdateOomAdjLSP(ProcessRecord app, int cachedAdj,
ProcessRecord topApp, long now, @OomAdjReason int oomAdjReason) {
if (app.getThread() == null) {
return false;
}
// ...省略
computeOomAdjLSP(app, cachedAdj, topApp, false, now, false, true);
//呼巷。。赎瑰。省略
return applyOomAdjLSP(app, false, now, SystemClock.elapsedRealtime(), oomAdjReason);
4.2.4 計算oomadj-computeOomAdjLSP
【computeOomAdjLSP】
這個函數(shù)是真正為proc計算oomadj的函數(shù)王悍。
@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;
//。餐曼。压储。省略
//1.如果進程是為啟動activity,則會走這里
if (app == topApp && PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP) {
// The last app on the list is the foreground app.
adj = FOREGROUND_APP_ADJ;
if (mService.mAtmInternal.useTopSchedGroupForTopProcess()) {
schedGroup = SCHED_GROUP_TOP_APP;
state.setAdjType("top-activity");
} else {
// Demote the scheduling group to avoid CPU contention if there is another more
// important process which also uses top-app, such as if SystemUI is animating.
schedGroup = SCHED_GROUP_DEFAULT;
state.setAdjType("intermediate-top-activity");
}
foregroundActivities = true;
hasVisibleActivities = true;
procState = PROCESS_STATE_TOP;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
}
//是否正在運行動畫
} else if (state.isRunningRemoteAnimation()) {
adj = VISIBLE_APP_ADJ;
schedGroup = SCHED_GROUP_TOP_APP;
state.setAdjType("running-remote-anim");
procState = PROCESS_STATE_CUR_TOP;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making running remote anim: " + app);
}
//是否正在做測試
} else if (app.getActiveInstrumentation() != null) {
// Don't want to kill running instrumentation.
adj = FOREGROUND_APP_ADJ;
schedGroup = SCHED_GROUP_DEFAULT;
state.setAdjType("instrumentation");
procState = PROCESS_STATE_FOREGROUND_SERVICE;
capability |= PROCESS_CAPABILITY_BFSL;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making instrumentation: " + app);
}
//是否啟動進程接收廣播
} else if (state.getCachedIsReceivingBroadcast(mTmpSchedGroup)) {
// 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 = FOREGROUND_APP_ADJ;
schedGroup = mTmpSchedGroup[0];
state.setAdjType("broadcast");
procState = ActivityManager.PROCESS_STATE_RECEIVER;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making broadcast: " + app);
}
//是否啟動進程執(zhí)行service
} else if (psr.numberOfExecutingServices() > 0) {
// An app that is currently executing a service callback also
// counts as being in the foreground.
adj = FOREGROUND_APP_ADJ;
schedGroup = psr.shouldExecServicesFg()
? SCHED_GROUP_DEFAULT : SCHED_GROUP_BACKGROUND;
state.setAdjType("exec-service");
procState = PROCESS_STATE_SERVICE;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making exec-service: " + app);
}
//是否進程是前臺進程
} else if (app == topApp) {
adj = FOREGROUND_APP_ADJ;
schedGroup = SCHED_GROUP_BACKGROUND;
state.setAdjType("top-sleeping");
foregroundActivities = true;
procState = PROCESS_STATE_CUR_TOP;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top (sleeping): " + app);
}
//啟動了一個空進程
} else {
// As far as we know the process is empty. We may change our mind later.
schedGroup = SCHED_GROUP_BACKGROUND;
// At this point we don't actually know the adjustment. Use the cached adj
// value that the caller wants us to.
adj = cachedAdj;
procState = PROCESS_STATE_CACHED_EMPTY;
if (!state.containsCycle()) {
state.setCached(true);
state.setEmpty(true);
state.setAdjType("cch-empty");
}
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making empty: " + app);
}
}
//源譬。集惋。。省略
//踩娘。刮刑。。 為此進程相關的綁定進程提權
// 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.
state.setCurAdj(adj);
state.setCurCapability(capability);
state.setCurrentSchedulingGroup(schedGroup);
state.setCurProcState(procState);
state.setCurRawProcState(procState);
state.updateLastInvisibleTime(hasVisibleActivities);
state.setHasForegroundActivities(foregroundActivities);
state.setCompletedAdjSeq(mAdjSeq);
state.setCurBoundByNonBgRestrictedApp(boundByNonBgRestricted);
// if curAdj or curProcState improved, then this process was promoted
// 如果此進程的adj提高了霸饲,返回true为朋。
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
|| state.getCurCapability() != prevCapability;
這里我們啟動的是activity進程,因此會為進程賦值以下數(shù)據(jù)
- adj = FOREGROUND_APP_ADJ厚脉;
- schedGroup = SCHED_GROUP_TOP_APP;
- state.setAdjType("top-activity");
- procState = PROCESS_STATE_TOP;
4.2.5 applyOomAdjLSP
通過computeOomAdjLSP為proc經(jīng)確計算了adj和綁定到它之上組件的proc adj习寸。這個函數(shù)
ProcessList
OOM adjustments for processes in various states:
// OOM adjustments for processes in various states:
// Uninitialized value for any major or minor adj fields
public static final int INVALID_ADJ = -10000;
// 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.)
public static final int UNKNOWN_ADJ = 1001;
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
public static final int CACHED_APP_MAX_ADJ = 999;
public static final int CACHED_APP_MIN_ADJ = 900;
// This is the oom_adj level that we allow to die first. This cannot be equal to
// CACHED_APP_MAX_ADJ unless processes are actively being assigned an oom_score_adj of
// CACHED_APP_MAX_ADJ.
public static final int CACHED_APP_LMK_FIRST_ADJ = 950;
// Number of levels we have available for different service connection group importance
// levels.
static final int CACHED_APP_IMPORTANCE_LEVELS = 5;
// 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.
public static final int SERVICE_B_ADJ = 800;
// 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.
public static final int PREVIOUS_APP_ADJ = 700;
// 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.
public static final int HOME_APP_ADJ = 600;
// This is a process holding an application service -- killing it will not
// have much of an impact as far as the user is concerned.
public static final int SERVICE_ADJ = 500;
// 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.
public static final int HEAVY_WEIGHT_APP_ADJ = 400;
// This is a process currently hosting a backup operation. Killing it
// is not entirely fatal but is generally a bad idea.
public static final int BACKUP_APP_ADJ = 300;
// This is a process bound by the system (or other app) that's more important than services but
// not so perceptible that it affects the user immediately if killed.
public static final int PERCEPTIBLE_LOW_APP_ADJ = 250;
// This is a process hosting services that are not perceptible to the user but the
// client (system) binding to it requested to treat it as if it is perceptible and avoid killing
// it if possible.
public static final int PERCEPTIBLE_MEDIUM_APP_ADJ = 225;
// 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.
public static final int PERCEPTIBLE_APP_ADJ = 200;
// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
public static final int VISIBLE_APP_ADJ = 100;
static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;
// This is a process that was recently TOP and moved to FGS. Continue to treat it almost
// like a foreground app for a while.
// @see TOP_TO_FGS_GRACE_PERIOD
public static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;
// This is the process running the current foreground app. We'd really
// rather not kill it!
public 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.
public static final int PERSISTENT_SERVICE_ADJ = -700;
// This is a system persistent process, such as telephony. Definitely
// don't want to kill it, but doing so is not completely fatal.
public static final int PERSISTENT_PROC_ADJ = -800;
// The system process runs at the default adjustment.
public static final int SYSTEM_ADJ = -900;
// Special code for native processes that are not being managed by the system (so
// don't have an oom adj assigned by the system).
public static final int NATIVE_ADJ = -1000;
// Memory pages are 4K.
static final int PAGE_SIZE = 4 * 1024;
// Activity manager's version of an undefined schedule group
static final int SCHED_GROUP_UNDEFINED = Integer.MIN_VALUE;
// Activity manager's version of Process.THREAD_GROUP_BACKGROUND
static final int SCHED_GROUP_BACKGROUND = 0;
// Activity manager's version of Process.THREAD_GROUP_RESTRICTED
static final int SCHED_GROUP_RESTRICTED = 1;
// Activity manager's version of Process.THREAD_GROUP_DEFAULT
static final int SCHED_GROUP_DEFAULT = 2;
// Activity manager's version of Process.THREAD_GROUP_TOP_APP
public static final int SCHED_GROUP_TOP_APP = 3;
// Activity manager's version of Process.THREAD_GROUP_TOP_APP
// Disambiguate between actual top app and processes bound to the top app
static final int SCHED_GROUP_TOP_APP_BOUND = 4;
Process
Keep in sync with SP_* constants of enum type SchedPolicy
declared in system/core/include/cutils/sched_policy.h,
except THREAD_GROUP_DEFAULT does not correspond to any SP_* value.
/**
* Default thread group -
* has meaning with setProcessGroup() only, cannot be used with setThreadGroup().
* When used with setProcessGroup(), the group of each thread in the process
* is conditionally changed based on that thread's current priority, as follows:
* threads with priority numerically less than THREAD_PRIORITY_BACKGROUND
* are moved to foreground thread group. All other threads are left unchanged.
* @hide
*/
public static final int THREAD_GROUP_DEFAULT = -1;
/**
* Background thread group - All threads in
* this group are scheduled with a reduced share of the CPU.
* Value is same as constant SP_BACKGROUND of enum SchedPolicy.
* @hide
*/
public static final int THREAD_GROUP_BACKGROUND = 0;
/**
* Foreground thread group - All threads in
* this group are scheduled with a normal share of the CPU.
* Value is same as constant SP_FOREGROUND of enum SchedPolicy.
* Not used at this level.
* @hide
**/
private static final int THREAD_GROUP_FOREGROUND = 1;
/**
* System thread group.
* @hide
**/
public static final int THREAD_GROUP_SYSTEM = 2;
/**
* Application audio thread group.
* @hide
**/
public static final int THREAD_GROUP_AUDIO_APP = 3;
/**
* System audio thread group.
* @hide
**/
public static final int THREAD_GROUP_AUDIO_SYS = 4;
/**
* Thread group for top foreground app.
* @hide
**/
public static final int THREAD_GROUP_TOP_APP = 5;
/**
* Thread group for RT app.
* @hide
**/
public static final int THREAD_GROUP_RT_APP = 6;
/**
* Thread group for bound foreground services that should
* have additional CPU restrictions during screen off
* @hide
**/
public static final int THREAD_GROUP_RESTRICTED = 7;
為ams開啟的線程設置進程組和cpust
// bind background threads to little cores
// this is expected to fail inside of framework tests because apps can't touch cpusets directly
// make sure we've already adjusted system_server's internal view of itself first
updateOomAdjLocked(OOM_ADJ_REASON_SYSTEM_INIT);
try {
Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(),
Process.THREAD_GROUP_SYSTEM);
Process.setThreadGroupAndCpuset(
mOomAdjuster.mCachedAppOptimizer.mCachedAppOptimizerThread.getThreadId(),
Process.THREAD_GROUP_SYSTEM);
} catch (Exception e) {
Slog.w(TAG, "Setting background thread cpuset failed");
}
將后臺線程綁定到小核上。例如UIThread則會綁定到大核上傻工,如下:
[UIThread.java]
@Override
public void run() {
// Make sure UiThread is in the fg stune boost group
Process.setThreadGroup(Process.myTid(), Process.THREAD_GROUP_TOP_APP);
super.run();
}
ProcessRecord
/**
* Profiling info of the process, such as PSS, cpu, etc.
*/
final ProcessProfileRecord mProfile;
/**
* All about the services in this process.
*/
final ProcessServiceRecord mServices;
/**
* All about the providers in this process.
*/
final ProcessProviderRecord mProviders;
/**
* All about the receivers in this process.
*/
final ProcessReceiverRecord mReceivers;
/**
* All about the error state(crash, ANR) in this process.
*/
final ProcessErrorStateRecord mErrorState;
/**
* All about the process state info (proc state, oom adj score) in this process.
*/
final ProcessStateRecord mState;
ProcessProfileRecord :Profiling info of the process, such as PSS, cpu, etc.
ProcessStateRecord 用于記錄oom adj score霞溪。
AppProfiler
/**
* A helper class taking care of the profiling, memory and cpu sampling of apps
*/
public class AppProfiler {
cpuSet介紹
根據(jù)我搜索到的結果,cpuset 是 Linux cgroup 子系統(tǒng)的一部分中捆,它可以為 cgroup 任務分配單獨的 CPU 和內(nèi)存1鸯匹。Android 系統(tǒng)使用 cpuset 來控制不同優(yōu)先級的應用可以使用的 CPU 范圍,以保證更好的交互響應和性能23泄伪。cpuset 的設置和操作是通過 cgroup 抽象層和任務配置文件來實現(xiàn)的殴蓬,這些文件可以在 Android 10 及更高版本中自定義12。cpuset 的名稱和屬性可以在 cgroups.json 文件和 task_profiles.json 文件中查看12蟋滴。例如染厅,Android 系統(tǒng)中有以下幾種 cpuset:
- foreground:表示前臺應用的 cpuset,它可以使用所有的 CPU 核心12津函。
- background:表示后臺應用的 cpuset肖粮,它只能使用小核心12。
- system-background:表示系統(tǒng)后臺服務的 cpuset尔苦,它也只能使用小核心12涩馆。
- top-app:表示當前用戶可見的最前臺的應用的 cpuset行施,它可以使用所有的 CPU 核心,并且有最高的優(yōu)先級12魂那。
- restricted:表示受限制的 cpuset蛾号,它只能使用一個小核心,并且有最低的優(yōu)先級12涯雅。
你可以參考這篇文章來了解更多關于 Android/Linux EAS 優(yōu)化的知識须教。
<cib-overlay></cib-overlay>