* frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
*
ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_HIGH);
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
if (MONITOR_CPU_USAGE) {
ServiceManager.addService("cpuinfo", new CpuBinder(this),
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
}
* frameworks/native/cmds/dumpsys/dumpsys.cpp
*
int Dumpsys::main(int argc, char* const argv[]) {
...
if (startDumpThread(type, serviceName, args) == OK) {
...
stopDumpThread(dumpComplete);
}
...
}
status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
const Vector<String16>& args) {
sp<IBinder> service = sm_->checkService(serviceName);
...
//默认为dump,调用服务端的dump方法,即为CpuBinder等的dump方法
switch (type) {
case Type::DUMP:
err = service->dump(remote_end.get(), args);
break;
...
return;
}
...
}
type默认为dump,调用服务端的dump方法,即为CpuBinder等的dump方法
* frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
*
static class CpuBinder extends Binder {
ActivityManagerService mActivityManagerService;
private final PriorityDump.PriorityDumper mPriorityDumper =
new PriorityDump.PriorityDumper() {
@Override
public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args,
boolean asProto) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"cpuinfo", pw)) return;
synchronized (mActivityManagerService.mProcessCpuTracker) {
if (asProto) {
mActivityManagerService.mProcessCpuTracker.dumpProto(fd);
return;
}
pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentLoad());
pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentState(
SystemClock.uptimeMillis()));
}
}
};
CpuBinder(ActivityManagerService activityManagerService) {
mActivityManagerService = activityManagerService;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
//这里调用到dumpCritical
PriorityDump.dump(mPriorityDumper, fd, pw, args);
}
}
这里主要地方为mProcessCpuTracker.printCurrentLoad()(记录当前CPU负载情况)、mProcessCpuTracker.printCurrentState(SystemClock.uptimeMillis())(记录各个进程的CPU使用情况)
mProcessCpuTracker为ProcessCpuTracker,主要方法为update
update方法主要是读取/proc/stat与/proc/loadavg文件的数据来更新当前的CPU时间,其中CPU负载接口onLoadChange在LoadAverageService中有使用,用于展示一个动态的View在界面,便于查看CPU的实时数据。
/proc/stat阶段,获取截止到当前cpu运行时间,然后减去上次的时间,算出当前update和上次update之间cpu的时间,计为rel时间,然后把当前cpu运行时间计为base时间
而/proc/stat的更新
* frameworks/base/core/java/com/android/internal/os/ProcessCpuTracker.java
public void update() {
if (DEBUG) Slog.v(TAG, "Update: " + this);
final long nowUptime = SystemClock.uptimeMillis();
final long nowRealtime = SystemClock.elapsedRealtime();
final long nowWallTime = System.currentTimeMillis();
final long[] sysCpu = mSystemCpuData;
// 读取/proc/stat文件
if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
null, sysCpu, null)) {
// Total user time is user + nice time.
final long usertime = (sysCpu[0]+sysCpu[1]) * mJiffyMillis;
// Total system time is simply system time.
final long systemtime = sysCpu[2] * mJiffyMillis;
// Total idle time is simply idle time.
final long idletime = sysCpu[3] * mJiffyMillis;
// Total irq time is iowait + irq + softirq time.
final long iowaittime = sysCpu[4] * mJiffyMillis;
final long irqtime = sysCpu[5] * mJiffyMillis;
final long softirqtime = sysCpu[6] * mJiffyMillis;
//这个代码试图避免空闲时间倒退的问题
if (true || (usertime >= mBaseUserTime && systemtime >= mBaseSystemTime
&& iowaittime >= mBaseIoWaitTime && irqtime >= mBaseIrqTime
&& softirqtime >= mBaseSoftIrqTime && idletime >= mBaseIdleTime)) {
mRelUserTime = (int)(usertime - mBaseUserTime);
mRelSystemTime = (int)(systemtime - mBaseSystemTime);
mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
mRelIrqTime = (int)(irqtime - mBaseIrqTime);
mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
mRelIdleTime = (int)(idletime - mBaseIdleTime);
mRelStatsAreGood = true;
...
mBaseUserTime = usertime;
mBaseSystemTime = systemtime;
mBaseIoWaitTime = iowaittime;
mBaseIrqTime = irqtime;
mBaseSoftIrqTime = softirqtime;
mBaseIdleTime = idletime;
} else {
mRelUserTime = 0;
mRelSystemTime = 0;
mRelIoWaitTime = 0;
mRelIrqTime = 0;
mRelSoftIrqTime = 0;
mRelIdleTime = 0;
mRelStatsAreGood = false;
Slog.w(TAG, "/proc/stats has gone backwards; skipping CPU update");
return;
}
}
mLastSampleTime = mCurrentSampleTime;
mCurrentSampleTime = nowUptime;
mLastSampleRealTime = mCurrentSampleRealTime;
mCurrentSampleRealTime = nowRealtime;
mLastSampleWallTime = mCurrentSampleWallTime;
mCurrentSampleWallTime = nowWallTime;
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
try {
// 收集/proc/pid/stat文件节点信息
mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
} finally {
StrictMode.setThreadPolicy(savedPolicy);
}
// 读取/proc/loadavg文件信息
// 即最新1分钟,5分钟,15分钟的CPU负载
final float[] loadAverages = mLoadAverageData;
if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
null, null, loadAverages)) {
float load1 = loadAverages[0];
float load5 = loadAverages[1];
float load15 = loadAverages[2];
if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
mLoad1 = load1;
mLoad5 = load5;
mLoad15 = load15;
// onLoadChanged是个空实现,在LoadAverageService的内部类对它进行了重写,用来更新CPU负载的数据
onLoadChanged(load1, load5, load15);
}
}
if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: "
+ (SystemClock.uptimeMillis()-mCurrentSampleTime));
mWorkingProcsSorted = false;
mFirst = false;
}
/proc/stat数据
// [1]user, [2]nice, [3]system, [4]idle, [5]iowait, [6]irq, [7]softirq
// 1. 从系统启动开始累计到当前时刻,用户态CPU时间
// 2. nice值为负的进程所占有的CPU时间
// 3. 内核CPU时间
// 4. 除IO等待时间的其它时间
// 5. 硬盘IO等待时间
// 6. 硬中断时间
// 7. 软中断时间
// intr:系统启动以来的所有interrupts的次数情况
// ctxt: 系统上下文切换次数
// btime:启动时长(单位:秒),从Epoch(即1970零时)开始到系统启动所经过的时长,每次启动会改变。
// processes:系统启动后所创建过的进程数量。当短时间该值特别大,系统可能出现异常
// procs_running:处于Runnable状态的进程个数
// procs_blocked:处于等待I/O完成的进程个数
cpu 68492 58433 64173 913207 4512 4723 3128 0 0 0
cpu0 17900 6411 13804 95436 296 2412 2333 0 0 0
cpu1 18851 6206 14320 97948 270 691 219 0 0 0
cpu2 20928 4999 14084 97248 267 669 216 0 0 0
cpu3 2130 5028 9385 120175 205 501 196 0 0 0
cpu4 1923 6100 2192 129934 739 95 37 0 0 0
cpu5 2194 6341 2611 128902 820 100 37 0 0 0
cpu6 2540 6701 3278 127523 779 111 38 0 0 0
cpu7 2023 16644 4495 116037 1132 140 49 0 0 0
intr 5687524 0 0 0 924083 0 59701 0 11 11 3176 0 34299 0 209 238 0 0 236112 98499 0 0 6 0 25025 16596 4 0 0 0 0 0 0 0 0 0 0 0 5 789 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2722 0 11614 0 0 0 0 0 0 0 0 0 0 0 0 334 3674 243 0 0 0 0 0 0 0 0 0 0 0 0 0 300 30 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 902 0 0 2596 0 0 0 0 0 0 0 0 0 2 2 2 2 0 2 0 2 0 2 0 2 0 2 909 0 0 0 0 8909 0 0 0 67 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 3062 5 5 1 1526 2 0 0 0 206843 0 0 0 4 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 0 1 0 0 0 42 0 0 0 0 0 59 0 41 75 12 2485 315 3 7 9046 5605 0 1 0 0 0 0 10 6136 3179 814 797 0 0 42 0 0 0 0 0 0 0 0 0 0 0 869 10601 11840 8 2 0 0 0 0 0 0 0 0 0 0 0 0 2958
ctxt 7280932
btime 1601257099
processes 35299
procs_running 1
procs_blocked 0
softirq 1541041 2 661191 1898 10859 86150 0 17468 392618 5 370850
cat /proc/8032/stat
8032 (com.tencent.mm) S 787 787 0 0 -1 1077952832 50224 0 10014 0 221 157 0 0 20 0 69 0 4708 7085056000 29364 18446744073709551615 1 1 0 0 0 0 4608 4097 1073775868 0 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0
1. pid: 进程ID.
2. comm: task_struct结构体的进程名
3. state: 进程状态, 此处为S
4. ppid: 父进程ID (父进程是指通过fork方式,通过clone并非父进程)
5. pgrp:进程组ID
6. session:进程会话组ID
7. tty_nr:当前进程的tty终点设备号
8. tpgid:控制进程终端的前台进程号
9. flags:进程标识位,定义在include/linux/sched.h中的PF_*, 此处等于1077952832
10. minflt: 次要缺页中断的次数,即无需从磁盘加载内存页. 比如COW和匿名页
11. cminflt:当前进程等待子进程的minflt
12. majflt:主要缺页中断的次数,需要从磁盘加载内存页. 比如map文件
13. majflt:当前进程等待子进程的majflt
14. utime: 该进程处于用户态的时间,单位jiffies,此处等于166114
15. stime: 该进程处于内核态的时间,单位jiffies,此处等于129684
16. cutime:当前进程等待子进程的utime
17. cstime: 当前进程等待子进程的utime
18. priority: 进程优先级, 此次等于10.
19. nice: nice值,取值范围[19, -20],此处等于-10
20. num_threads: 线程个数, 此处等于221
21. itrealvalue: 该字段已废弃,恒等于0
22. starttime:自系统启动后的进程创建时间,单位jiffies,此处等于2284
23. vsize:进程的虚拟内存大小,单位为bytes
24. rss: 进程独占内存+共享库,单位pages,此处等于93087
25. rsslim: rss大小上限
第10~17行主要是随着时间而改变的量;
内核时间单位,sysconf(_SC_CLK_TCK)一般地定义为jiffies(一般地等于10ms)
starttime: 此值单位为jiffies, 结合/proc/stat的btime,可知道每一个线程启动的时间点
正常使用update的调用时机为
ActivityStack.resumeTopActivityInnerLocked
ActivityStack.startPausingLocked
ProcessList.startProcessLocked
BroadcastQueue.processNextBroadcastLocked
ActivityManagerService.batteryPowerChanged
且最小更新间隔为5s
anr
void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
String parentShortComponentName, WindowProcessController parentProcess,
boolean aboveSystem, String annotation, boolean onlyDumpSelf) {
ArrayList<Integer> firstPids = new ArrayList<>(5);
SparseArray<Boolean> lastPids = new SparseArray<>(20);
mWindowProcessController.appEarlyNotResponding(annotation, () -> kill("anr",
ApplicationExitInfo.REASON_ANR, true));
long anrTime = SystemClock.uptimeMillis();
//第一次 更新cpu统计信息
if (isMonitorCpuUsage()) {
mService.updateCpuStatsNow();
}
...
//记录ANR输出到main log
StringBuilder info = new StringBuilder();
info.setLength(0);
info.append("ANR in ").append(processName);
if (activityShortComponentName != null) {
info.append(" (").append(activityShortComponentName).append(")");
}
info.append("\n");
info.append("PID: ").append(pid).append("\n");
if (annotation != null) {
info.append("Reason: ").append(annotation).append("\n");
}
if (parentShortComponentName != null
&& parentShortComponentName.equals(activityShortComponentName)) {
info.append("Parent: ").append(parentShortComponentName).append("\n");
}
StringBuilder report = new StringBuilder();
report.append(MemoryPressureUtil.currentPsiState());
//创建CPU tracker对象
ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
ArrayList<Integer> nativePids = null;
...
// For background ANRs, don't pass the ProcessCpuTracker to
// avoid spending 1/2 second collecting stats to rank lastPids.
StringWriter tracesFileException = new StringWriter();
// To hold the start and end offset to the ANR trace file respectively.
final long[] offsets = new long[2];
//这里会调用processCpuTracker init更新一次cpu信息,然后停200ms在调用一次update,计算200ms内的cpu信息,作为实时cpu信息
File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids,
nativePids, tracesFileException, offsets);
if (isMonitorCpuUsage()) {
//再次计算cpu信息,如果间隔小于5s则,不在更新
mService.updateCpuStatsNow();
synchronized (mService.mProcessCpuTracker) {
//将anr发生时的cpu信息写入report
report.append(mService.mProcessCpuTracker.printCurrentState(anrTime));
}
info.append(processCpuTracker.printCurrentLoad());
info.append(report);
}
report.append(tracesFileException.getBuffer());
//将实时cpu信息写入info中
info.append(processCpuTracker.printCurrentState(anrTime));
Slog.e(TAG, info.toString());
...
mService.addErrorToDropBox("anr", this, processName, activityShortComponentName,
parentShortComponentName, parentPr, annotation, report.toString(), tracesFile,
null);
...
}