背景:为什么会去看这个?-有时候会遇到应用启动的时候在systrace中看到大量的android.bg线程,android.bg线程会抢占应用启动过程的时候的cpu,从而拖慢了应用启动的速度,因此才会来看看android.bg是什么东西.
总结:
- android.bg是一个framework层提供的一个工具类,方便在使用的时候来创建一个异步的线程,拥有独立的handler,在应用启动过程中AMS也会使用这个工具类.
- 多次测试在应用启动的过程中并不会必现大量的android.bg,且在pss收集的时间google在ProcessList中已经配置好了,可对其做细微的调整,在这里看来暂时没有必要调整.所以需要再进一步进行测试观察拖慢应用启动速度的其他原因.
next:该文的代码只是一个引入,其中有更多的内容暂未深纠.先贴收藏一些文档后方便后续查看.
- Android applyOomAdjLocked https://www.jianshu.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 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平台快霸相关的内容(略过).