android框架_5.0的SystemUI获取CPU负载以及进程cpu时间_014


一、ProcessStats类;

1、Android源生系统中有一个叫ProcessStats类,用来获取系统的负载情况及进程时间;

public final class ProcessStats implements Parcelable {
    static final String TAG = "ProcessStats";
    static final boolean DEBUG = false;
    static final boolean DEBUG_PARCEL = false;

    public static final String SERVICE_NAME = "procstats";

2、 实现原理是读取/proc目录下的文件。linux系统运行时,内核会去更新 /proc目录下的文件,将pid的运行情况写入到/proc目录下对应文件中。

3、ProcessStats类只是一个继承Parcelable类的实体类,用来存储数据;

4、这个类会涉及到几个有用的文件: /proc/stat、/proc/loadavg、/proc/[pid]/;下面来说说这几个文件的作用和用途

4.1、/proc/stat,该文件包含了从系统启动开始累积到当前时刻的CPU活动信息。

  看下后视镜的情况,cat /proc/stat的内容如下:

root@magc6580_we_l:/ # cat /proc/stat
cpu  162058 2972 358509 433432 1809 1 11476 0 0 0
cpu0 47425 758 98133 86127 439 1 3763 0 0 0
cpu1 44337 826 97981 95662 495 0 2977 0 0 0
cpu2 40722 756 94637 103627 504 0 2816 0 0 0
cpu3 29574 632 67758 148016 371 0 1920 0 0 0
intr 15498063 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3732026 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1989504 0 0 0 0 0 68871 0 0 7984 182387 11 1475 1 0 0 0 0 0 0 0 0 54963 51544 0 00
ctxt 32175008
btime 1528343324
processes 4288
procs_running 10
procs_blocked 1
softirq 3524467 427 963234 428 714933 434 427 71579 753458 44 1019503
root@magc6580_we_l:/ #
cpu 的每一列的意思如下
user (162058 ) 从系统启动开始累计到当前时刻,用户态的CPU时间(单位:jiffies) ,不包含 nice值为负进程。1jiffies=0.01秒
nice (2972 ) 从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间(单位:jiffies)
system (358509 ) 从系统启动开始累计到当前时刻,核心时间(单位:jiffies)
idle (433432 ) 从系统启动开始累计到当前时刻,除硬盘IO等待时间以外其它等待时间(单位:jiffies)
iowait (1809 ) 从系统启动开始累计到当前时刻,硬盘IO等待时间(单位:jiffies) ,
irq (1) 从系统启动开始累计到当前时刻,硬中断时间(单位:jiffies)
softirq (11476) 从系统启动开始累计到当前时刻,软中断时间(单位:jiffies)

最后的三个都是0,具体不知道做什么用
cpu0,cpu1,cpu2,cpu3代表系统有4个核;描述同cpu一样


其他的描述如下:
“intr”这行给出中断的信息,第一个为自系统启动以来,发生的所有的中断的次数;然后每个数对应一个特定的中断自系统启动以来所发生的次数。
“ctxt”给出了自系统启动以来CPU发生的上下文交换的次数。
“btime”给出了从系统启动到现在为止的时间,单位为秒。
“processes (total_forks) 自系统启动以来所创建的任务的个数目。
“procs_running”:当前运行队列的任务的数目。
“procs_blocked”:当前被阻塞的任务的数目。

4.2、/proc/loadavg文件
系统平均负载.该文件中的所有值都是从系统启动开始累计到当前时刻。该文件只给出了所有CPU的集合信息,不能该出每个CPU的信息;通过cat /proc/loadavg查看内容如下:

root@magc6580_we_l:/ # cat /proc/loadavg                                       
16.18 16.37 15.41 12/1408 4376
root@magc6580_we_l:/ # 

每个值的含义为:

参数 解释
lavg_1 (16.18 )1-分钟平均负载
lavg_5 (16.37) 5-分钟平均负载
lavg_15(15.41) 15-分钟平均负载
nr_running (12) 在采样时刻,运行队列的任务的数目,与/proc/stat的procs_running表示相同意思
nr_threads (1408) 在采样时刻,系统中活跃的任务的个数(不包括运行已经结束的任务)

last_pid(4376) 最大的pid值,包括轻量级进程,即线程。


4.3、/proc/[pid]/文件

进程信息

1|root@magc6580_we_l:/ # cat /proc/40/stat                                     
40 (cmdq_auto_relea) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 39 0 0 4294967295 0 0 0 0 0 0 0 2147483647 0 3221514176 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0
root@magc6580_we_l:/ # cat /proc/40/statm                                      
0 0 0 0 0 0 0
root@magc6580_we_l:/ # cat /proc/40/syscall                                    
0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
root@magc6580_we_l:/ # 

二、ProcessCpuTracker类

public class ProcessCpuTracker {
    private static final String TAG = "ProcessCpuTracker";
    private static final boolean DEBUG = false;
    private static final boolean localLOGV = DEBUG || false;
  //记录/proc下的信息
    private static final int[] PROCESS_STATS_FORMAT = new int[] {
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_PARENS,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 10: minor faults
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 12: major faults
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: utime
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 15: stime
    };

    static final int PROCESS_STAT_MINOR_FAULTS = 0;
    static final int PROCESS_STAT_MAJOR_FAULTS = 1;
    static final int PROCESS_STAT_UTIME = 2;
    static final int PROCESS_STAT_STIME = 3;

    /** Stores user time and system time in jiffies. */
    private final long[] mProcessStatsData = new long[4];

1、此类为cpu跟踪记录类,首先看update方法更新了哪些信息;

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();
    // 读取/proc/stat中的cpu时间
    final long[] sysCpu = mSystemCpuData;
    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;

        // This code is trying to avoid issues with idle time going backwards,
        // but currently it gets into situations where it triggers most of the time. :(
        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;

            if (DEBUG) {
                Slog.i("Load", "Total U:" + (sysCpu[0]*mJiffyMillis)
                      + " N:" + (sysCpu[1]*mJiffyMillis)
                      + " S:" + (sysCpu[2]*mJiffyMillis) + " I:" + (sysCpu[3]*mJiffyMillis)
                      + " W:" + (sysCpu[4]*mJiffyMillis) + " Q:" + (sysCpu[5]*mJiffyMillis)
                      + " O:" + (sysCpu[6]*mJiffyMillis));
                Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
                      + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
            }

            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;
 // 读取所有/proc/[pid]/文件夹中的进行信息
    final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
    try {
        mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
    } finally {
        StrictMode.setThreadPolicy(savedPolicy);
    }
// 读取/proc/loadavg中的平均负载
    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(load1, load5, load15);
        }
    }

    if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: "
            + (SystemClock.uptimeMillis()-mCurrentSampleTime));

    mWorkingProcsSorted = false;
    mFirst = false;
}

2、再来看看进程信息的方法:

private int[] collectStats(String statsFile, int parentPid, boolean first,
        int[] curPids, ArrayList allProcs) {
		//获取全部PID
    int[] pids = Process.getPids(statsFile, curPids);
    int NP = (pids == null) ? 0 : pids.length;
    int NS = allProcs.size();
    int curStatsIndex = 0;
    //迭代PID,创建或更新PID对应的Stats对象
    for (int i=0; i pid) {
            // We have a new process!
            st = new Stats(pid, parentPid, mIncludeThreads);
            allProcs.add(curStatsIndex, st);
            curStatsIndex++;
            NS++;
            if (DEBUG) Slog.v(TAG, "New "
                    + (parentPid < 0 ? "process" : "thread")
                    + " pid " + pid + ": " + st);

            final String[] procStatsString = mProcessFullStatsStringData;
            final long[] procStats = mProcessFullStatsData;
            st.base_uptime = SystemClock.uptimeMillis();
            String path = st.statFile.toString();
            //Slog.d(TAG, "Reading proc file: " + path);
            if (Process.readProcFile(path, PROCESS_FULL_STATS_FORMAT, procStatsString,
                    procStats, null)) {
                // This is a possible way to filter out processes that
                // are actually kernel threads...  do we want to?  Some
                // of them do use CPU, but there can be a *lot* that are
                // not doing anything.
                st.vsize = procStats[PROCESS_FULL_STAT_VSIZE];
                if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
                    st.interesting = true;
                    st.baseName = procStatsString[0];
                    st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
                    st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
                    st.base_utime = procStats[PROCESS_FULL_STAT_UTIME] * mJiffyMillis;
                    st.base_stime = procStats[PROCESS_FULL_STAT_STIME] * mJiffyMillis;
                } else {
                    Slog.i(TAG, "Skipping kernel process pid " + pid
                            + " name " + procStatsString[0]);
                    st.baseName = procStatsString[0];
                }
            } else {
                Slog.w(TAG, "Skipping unknown process pid " + pid);
                st.baseName = "";
                st.base_utime = st.base_stime = 0;
                st.base_minfaults = st.base_majfaults = 0;
            }

            if (parentPid < 0) {
                getName(st, st.cmdlineFile);
                if (st.threadStats != null) {
                    mCurThreadPids = collectStats(st.threadsDir, pid, true,
                            mCurThreadPids, st.threadStats);
                }
            } else if (st.interesting) {
                st.name = st.baseName;
                st.nameWidth = onMeasureProcessName(st.name);
            }

            if (DEBUG) Slog.v("Load", "Stats added " + st.name + " pid=" + st.pid
                    + " utime=" + st.base_utime + " stime=" + st.base_stime
                    + " minfaults=" + st.base_minfaults + " majfaults=" + st.base_majfaults);

            st.rel_utime = 0;
            st.rel_stime = 0;
            st.rel_minfaults = 0;
            st.rel_majfaults = 0;
            st.added = true;
            if (!first && st.interesting) {
                st.working = true;
            }
             // 创建的流程和更新差不多
            continue;
        }

        // This process has gone away!
        st.rel_utime = 0;
        st.rel_stime = 0;
        st.rel_minfaults = 0;
        st.rel_majfaults = 0;
        st.removed = true;
        st.working = true;
        allProcs.remove(curStatsIndex);
        NS--;
        if (DEBUG) Slog.v(TAG, "Removed "
                + (parentPid < 0 ? "process" : "thread")
                + " pid " + pid + ": " + st);
        // Decrement the loop counter so that we process the current pid
        // again the next time through the loop.
        i--;
        continue;
    }

    while (curStatsIndex < NS) {
        // This process has gone away!
        final Stats st = allProcs.get(curStatsIndex);
        st.rel_utime = 0;
        st.rel_stime = 0;
        st.rel_minfaults = 0;
        st.rel_majfaults = 0;
        st.removed = true;
        st.working = true;
        allProcs.remove(curStatsIndex);
        NS--;
        if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
    }

    return pids;
}
使用这个类,来进行cpu负荷和进程时间的监控。Android5.1系统在systemui中有一个服务,就使用了这个类。

在systemui的Manifest文件,可以找到一个叫LoadAverageService的服务,它就是使用了ProcessCpuTracker获取cpu和进程信息,并把他们显示出来。

如何使用LoadAverageService这个服务,方法有两种:
1、可以在adb shell中直接运行am startservice -n com.android.systemui/.LoadAverageService
2、用【设置】->【开发者选项】->【显示cpu使用情况】打开服务桌面上即可显示cpu占用情况


在开发应用的时候,开启这个选项,可时时跟踪系统的cpu占用情况












你可能感兴趣的:(Android框架)