赞
踩
* 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); ... }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。