一、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 的每一列的意思如下
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:/ #
每个值的含义为:
参数 解释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中有一个服务,就使用了这个类。
在开发应用的时候,开启这个选项,可时时跟踪系统的cpu占用情况