背景:為什么會去看這個?-有時候會遇到應用啟動的時候在systrace中看到大量的android.bg線程,android.bg線程會搶占應用啟動過程的時候的cpu,從而拖慢了應用啟動的速度,因此才會來看看android.bg是什么東西.
總結:
- android.bg是一個framework層提供的一個工具類,方便在使用的時候來創建一個異步的線程,擁有獨立的handler,在應用啟動過程中AMS也會使用這個工具類.
- 多次測試在應用啟動的過程中并不會必現大量的android.bg,且在pss收集的時間google在ProcessList中已經配置好了,可對其做細微的調整,在這里看來暫時沒有必要調整.所以需要再進一步進行測試觀察拖慢應用啟動速度的其他原因.
next:該文的代碼只是一個引入,其中有更多的內容暫未深糾.先貼收藏一些文檔后方便后續查看.
- Android applyOomAdjLocked http://www.lxweimin.com/p/ded0eb2e0182
- Android進程調度之adj算法 http://gityuan.com/2016/08/07/android-adj/
- Android進程生命周期與ADJ http://gityuan.com/2015/10/01/process-lifecycle/
- Android LowMemoryKiller原理分析 http://gityuan.com/2016/09/17/android-lowmemorykiller/
- Android進程調度之adj算法 https://blog.csdn.net/ccjhdopc/article/details/52818012
1簡介
何為PSS, 概念可以從百度得知是實際物理內存使用的大小,有個概念需要清楚,這里所說的使用物理內存的大小的計算方式也包括了使用共享庫的大小,但是不是全部大小.
比如進程A使用了libc庫,進程B也使用了libc庫,這個時候進程A單獨占用物理內存X, libc占用物理內存Y
那么進程A的PSS=X+Y/2,采用把共享so庫的內存平分到使用它的進程當中,而進程A的USS=X,表示進程A獨占的內存不包括共享庫的內存.
該文章主要討論AMS中是如何來收集PSS等信息,收集了又有什么用?
2 PSS收集
2.1 工具類
在android系統中提供了這樣工具類:
/**
* Shared singleton background thread for each process.
*/
public final class BackgroundThread extends HandlerThread {
private static BackgroundThread sInstance;
private static Handler sHandler;
private BackgroundThread() {
super("android.bg", android.os.Process.THREAD_PRIORITY_BACKGROUND);
}
private static void ensureThreadLocked() {
if (sInstance == null) {
sInstance = new BackgroundThread();
sInstance.start();
sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER);
sHandler = new Handler(sInstance.getLooper());
}
}
public static BackgroundThread get() {
synchronized (BackgroundThread.class) {
ensureThreadLocked();
return sInstance;
}
}
public static Handler getHandler() {
synchronized (BackgroundThread.class) {
ensureThreadLocked();
return sHandler;
}
}
}
這個類主要是通過單例的方式提供了一個獨立的handler,該handler的looper對象不依賴使用這的主線程looper.
2.2 AMS中使用
AMS中有一種使用方式就是通過bg的形式來手機pss信息.
2.3 什么時候開始收集?
如下的函數是發送msg啟動收集的地方
/**
* Schedule PSS collection of a process.
*/
void requestPssLocked(ProcessRecord proc, int procState) {
if (mPendingPssProcesses.contains(proc)) {
return;
}
if (mPendingPssProcesses.size() == 0) {
mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
}
if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting PSS of: " + proc);
proc.pssProcState = procState;
mPendingPssProcesses.add(proc);
}
調用它的地方只有一個:
private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
long nowElapsed) {
......
......
......
if (app.setProcState == ActivityManager.PROCESS_STATE_NONEXISTENT
|| ProcessList.procStatesDifferForMem(app.curProcState, app.setProcState)) {
if (false && mTestPssMode && app.setProcState >= 0 && app.lastStateTime <= (now-200)) {
// Experimental code to more aggressively collect pss while
// running test... the problem is that this tends to collect
// the data right when a process is transitioning between process
// states, which well tend to give noisy data.
long start = SystemClock.uptimeMillis();
long pss = Debug.getPss(app.pid, mTmpLong, null);
recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], mTmpLong[1], now);
mPendingPssProcesses.remove(app);
Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
+ " to " + app.curProcState + ": "
+ (SystemClock.uptimeMillis()-start) + "ms");
}
app.lastStateTime = now;
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
mTestPssMode, isSleepingLocked(), now);
if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
+ ProcessList.makeProcStateString(app.setProcState) + " to "
+ ProcessList.makeProcStateString(app.curProcState) + " next pss in "
+ (app.nextPssTime-now) + ": " + app);
} else {
if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
&& now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
mTestPssMode)))) {
requestPssLocked(app, app.setProcState);
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
mTestPssMode, isSleepingLocked(), now);
} else if (false && DEBUG_PSS) Slog.d(TAG_PSS,
"Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
}
......
......
}
我們只關注applyOomAdjLocked中調用requestPssLocked的地方,其他地方暫時忽略;大家都知道applyOomAdjLocked是在updateOomAdjLocked中調用,
而updateOomAdjLocked是在進程的狀態發生變化的時候會進行更新.
如下圖所示:
關于updateOomAdjLocked屬于內存管理和進程管理的內容,這里就不詳細跟蹤,會另起文章單獨在前人的基礎上在看看這一塊.
回到正題,這里注意研究什么時候開始收集.
在一個新的進程啟動給的時候會在ActivityThread中的Main函數中會調用attach, 緊接著調用到AMS中的attachApplicationLocked中,最后調用了updateOomAdjLocked.
在applyOomAdjLocked中以上代碼中會判斷:
- 當前進程狀態的上一次進程狀態時候為ActivityManager.PROCESS_STATE_NONEXISTENT
- 或者當前狀態是否與上次不同.
如果滿足條件則會計算下一次收集pss時間:
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,//可以進入進一步看時間如何確定
mTestPssMode, isSleepingLocked(), now);
在接下來進入updataoomadjlocked時候就會進入else分支取requestPssLocked.
2.4 如何收集
final Handler mBgHandler = new Handler(BackgroundThread.getHandler().getLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case COLLECT_PSS_BG_MSG: {
long start = SystemClock.uptimeMillis(); //開始收集的時間點
MemInfoReader memInfo = null;
synchronized (ActivityManagerService.this) {
if (mFullPssPending) {//是否進行全面收集
mFullPssPending = false;
memInfo = new MemInfoReader();
}
}
if (memInfo != null) { //需要進行全面收集的時候才會進入這個分支
updateCpuStatsNow();//更新當前cpu狀態
long nativeTotalPss = 0;
final List<ProcessCpuTracker.Stats> stats;//cpuTracker的List
synchronized (mProcessCpuTracker) {
stats = mProcessCpuTracker.getStats( (st)-> {
return st.vsize > 0 && st.uid < FIRST_APPLICATION_UID;
});
}
final int N = stats.size();//stats大小
for (int j = 0; j < N; j++) {
synchronized (mPidsSelfLocked) {
if (mPidsSelfLocked.indexOfKey(stats.get(j).pid) >= 0) {
// This is one of our own processes; skip it.
continue;
}
}
/// M: DuraSpeed
//nativeTotalPss += Debug.getPss(stats.get(j).pid, null, null);
long nativePss = Debug.getPss(stats.get(j).pid, mTmpLong, null);
nativeTotalPss += nativePss;
synchronized (ActivityManagerService.this) {
ActivityStack stack = mStackSupervisor.getFocusedStack();
if (stack != null) {
ActivityRecord topActivityRecord = stack.topActivity();
if (topActivityRecord != null) {
mAmsExt.onRecordST(stats, j, (nativePss + mTmpLong[1]),
mPidsSelfLocked, topActivityRecord.packageName,
ActivityManagerService.this);
}
}
}
}
memInfo.readMemInfo();//讀取信息通過Debug讀取底層節點/proc/meminfo信息存儲在meminfo中
synchronized (ActivityManagerService.this) {
if (DEBUG_PSS) Slog.d(TAG_PSS, "Collected native and kernel memory in "
+ (SystemClock.uptimeMillis()-start) + "ms");
final long cachedKb = memInfo.getCachedSizeKb(); //獲取信息
final long freeKb = memInfo.getFreeSizeKb();
final long zramKb = memInfo.getZramTotalSizeKb();
final long kernelKb = memInfo.getKernelUsedSizeKb();
EventLogTags.writeAmMeminfo(cachedKb*1024, freeKb*1024, zramKb*1024,
kernelKb*1024, nativeTotalPss*1024);
mProcessStats.addSysMemUsageLocked(cachedKb, freeKb, zramKb, kernelKb,
nativeTotalPss);//添加到進程狀態中
}
}
int num = 0;
long[] tmp = new long[2];
do {
ProcessRecord proc;
int procState;
int pid;
long lastPssTime;
synchronized (ActivityManagerService.this) {
if (mPendingPssProcesses.size() <= 0) {//判斷待收集的數組中是否小于等于0,決定是否退出
if (mTestPssMode || DEBUG_PSS) Slog.d(TAG_PSS,
"Collected PSS of " + num + " processes in "
+ (SystemClock.uptimeMillis() - start) + "ms");
mPendingPssProcesses.clear();
return;
}
proc = mPendingPssProcesses.remove(0);//移除頂部的process
procState = proc.pssProcState;//暫存進程狀態
lastPssTime = proc.lastPssTime;//暫存進程lastpssTime
if (proc.thread != null && procState == proc.setProcState
&& (lastPssTime+ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE)
< SystemClock.uptimeMillis()) { //如果進程沒有掛,且當前請求pss的進程狀態等于上一次進程狀態,且在狀態改變后1s一秒內
pid = proc.pid;
} else {
proc = null;
pid = 0;
}
}
if (proc != null) {//如果在進程狀態切換后1s內,且進程proc不為null
long pss = Debug.getPss(pid, tmp, null);// 獲得pss值(Debug類通過jni到cpp層讀取節點值并綜合計算結果返回)
synchronized (ActivityManagerService.this) {
if (pss != 0 && proc.thread != null && proc.setProcState == procState
&& proc.pid == pid && proc.lastPssTime == lastPssTime) {
num++;//已經收集的進程個數
recordPssSampleLocked(proc, procState, pss, tmp[0], tmp[1],
SystemClock.uptimeMillis());//記錄新的狀態
}
}
}
} while (true);
}
/// M: DuraSpeed
case AmsExt.COLLECT_PSS_FG_MSG: {
synchronized (ActivityManagerService.this) {
ActivityStack stack = mStackSupervisor.getFocusedStack();
if (stack != null) {
ActivityRecord topActivityRecord = stack.topActivity();
if (topActivityRecord != null) {
mAmsExt.onStoreRecord(null, -1, mPidsSelfLocked,
topActivityRecord.packageName, ActivityManagerService.this);
}
}
}
break;
}
}
}
};
如上,主要看COLLECT_PSS_BG_MSG消息是用來觸發pss收集的信息,COLLECT_PSS_FG_MSG消息應該是MTK平臺快霸相關的內容(略過).