android dumpsys命令源码分析

初始化

* 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方法

cpuinfo

* 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);

        ...
    }
  1. 先计算一次cpu信息
  2. 重新创建一个ProcessCpuTracker,调用ActivityManagerService.dumpStackTraces计算200ms内的cpu信息,写入info中
  3. 再次计算cpu信息,如果间隔小于5s则,不在更新
  4. 将anr发生时的cpu信息写入report
  5. main log中输出包含report的info信息

你可能感兴趣的:(技术总结,dumpsys,android,cpuinfo)