Emmagee是网易杭州研究院QA团队开发的一个简单易上手的Android性能监测小工具,主要用于监控单个App的CPU,内存,流量,启动耗时,电量,电流等性能状态的变化,且用户可自定义配置监控的频率以及性能的实时显示,并最终生成一份性能统计文件。
测试QQ的效果如下:
/**
* 通过pid获取应用占用的内存
* @return
*/
public int getPidMemorySize(int pid, Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
int[] myMempid = new int[] { pid };
Debug.MemoryInfo[] memoryInfo = am.getProcessMemoryInfo(myMempid);
memoryInfo[0].getTotalSharedDirty();
int memSize = memoryInfo[0].getTotalPss();
return memSize;
}
/**
* 获取设备可用内存
*/
public long getFreeMemorySize(Context context) {
ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
am.getMemoryInfo(outInfo);
long avaliMem = outInfo.availMem;
return avaliMem / 1024;
}
/**
* 获取设备总内存
*/
public long getTotalMemory() {
String memInfoPath = "/proc/meminfo";
String readTemp = "";
String memTotal = "";
long memory = 0;
try {
FileReader fr = new FileReader(memInfoPath);
BufferedReader localBufferedReader = new BufferedReader(fr, 8192);
while ((readTemp = localBufferedReader.readLine()) != null) {
if (readTemp.contains("MemTotal")) {
String[] total = readTemp.split(":");
memTotal = total[1].trim();
}
}
localBufferedReader.close();
String[] memKb = memTotal.split(" ");
memTotal = memKb[0].trim();
Log.d(LOG_TAG, "memTotal: " + memTotal);
memory = Long.parseLong(memTotal);
} catch (IOException e) {
Log.e(LOG_TAG, "IOException: " + e.getMessage());
}
return memory;
}
/**
* 获取dalvik与native分别占用的内存,仅root可用
*/
public static String[][] parseMeminfo(int pid) {
boolean infoStart = false;
// [][],00:native heap size,01:native heap alloc;10: dalvik heap
// size,11: dalvik heap alloc
String[][] heapData = new String[2][2];
try {
Runtime runtime = Runtime.getRuntime();
process = runtime.exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("dumpsys meminfo " + pid + "\n");
os.writeBytes("exit\n");
os.flush();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = bufferedReader.readLine()) != null) {
line = line.trim();
if (line.contains("Permission Denial")) {
break;
} else {
// 当读取到MEMINFO in pid 这一行时,下一行就是需要获取的数据
if (line.contains("MEMINFO in pid")) {
infoStart = true;
} else if (infoStart) {
String[] lineItems = line.split("\\s+");
int length = lineItems.length;
if (line.startsWith("size")) {
heapData[0][0] = lineItems[1];
heapData[1][0] = lineItems[2];
} else if (line.startsWith("allocated")) {
heapData[0][1] = lineItems[1];
heapData[1][1] = lineItems[2];
break;
} else if (line.startsWith("Native")) {
Log.d(LOG_TAG, "Native");
Log.d(LOG_TAG, "lineItems[4]=" + lineItems[4]);
Log.d(LOG_TAG, "lineItems[5]=" + lineItems[5]);
heapData[0][0] = lineItems[length-3];
heapData[0][1] = lineItems[length-2];
} else if (line.startsWith("Dalvik")) {
Log.d(LOG_TAG, "Dalvik");
Log.d(LOG_TAG, "lineItems[4]=" + lineItems[4]);
Log.d(LOG_TAG, "lineItems[5]=" + lineItems[5]);
heapData[1][0] = lineItems[length-3];
heapData[1][1] = lineItems[length-2];
break;
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return heapData;
}
/**
* 获取cpu个数,即处理器核心数
* @return
*/
public int getCpuNum() {
try {
// Get directory containing CPU info
File dir = new File("/sys/devices/system/cpu/");
// Filter to only list the devices we care about
File[] files = dir.listFiles(new CpuFilter());
return files.length;
} catch (Exception e) {
e.printStackTrace();
return 1;
}
}
/**
* 获取cpu列表
*/
public ArrayList<String> getCpuList() {
ArrayList<String> cpuList = new ArrayList<String>();
try {
// Get directory containing CPU info
File dir = new File("/sys/devices/system/cpu/");
// Filter to only list the devices we care about
File[] files = dir.listFiles(new CpuFilter());
for (int i = 0; i < files.length; i++) {
cpuList.add(files[i].getName());
}
return cpuList;
} catch (Exception e) {
e.printStackTrace();
cpuList.add("cpu0");
return cpuList;
}
}
public String getCpuName() {
try {
RandomAccessFile cpuStat = new RandomAccessFile("/proc/cpuinfo", "r");
// check cpu type
String line;
while (null != (line = cpuStat.readLine())) {
String[] values = line.split(":");
if (values[0].contains("model name") || values[0].contains("Processor")) {
cpuStat.close();
Log.d(LOG_TAG, "CPU name="+values[1]);
return values[1];
}
}
} catch (IOException e) {
Log.e(LOG_TAG, "IOException: " + e.getMessage());
}
return "";
}
/**
* 获取网络流量,上传和下载的总和
*/
public long getTrafficInfo() {
Log.i(LOG_TAG, "get traffic information");
long rcvTraffic = -1;
long sndTraffic = -1;
// Use getUidRxBytes and getUidTxBytes to get network traffic,these API
// return both tcp and udp usage
rcvTraffic = TrafficStats.getUidRxBytes(Integer.parseInt(uid));
sndTraffic = TrafficStats.getUidTxBytes(Integer.parseInt(uid));
if (rcvTraffic == -1 || sndTraffic == -1) {
return -1;
} else
return rcvTraffic + sndTraffic;
}
cpu使用率的计算稍微有些不同:
// 先获取当前pid的占用情况
String processPid = Integer.toString(pid);
String cpuStatPath = "/proc/" + processPid + "/stat";
try {
// monitor cpu stat of certain process
RandomAccessFile processCpuInfo = new RandomAccessFile(cpuStatPath, "r");
String line = "";
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.setLength(0);
while ((line = processCpuInfo.readLine()) != null) {
stringBuffer.append(line + "\n");
}
String[] tok = stringBuffer.toString().split(" ");
processCpu = Long.parseLong(tok[13]) + Long.parseLong(tok[14]);
processCpuInfo.close();
} catch (FileNotFoundException e) {
Log.w(LOG_TAG, "FileNotFoundException: " + e.getMessage());
} catch (IOException e) {
e.printStackTrace();
}
// 再获取总的cpu使用情况
try {
// monitor total and idle cpu stat of certain process
RandomAccessFile cpuInfo = new RandomAccessFile(CPU_STAT, "r");
String line = "";
while ((null != (line = cpuInfo.readLine())) && line.startsWith("cpu")) {
String[] toks = line.split("\\s+");
idleCpu.add(Long.parseLong(toks[4]));
totalCpu.add(Long.parseLong(toks[1]) + Long.parseLong(toks[2]) + Long.parseLong(toks[3]) + Long.parseLong(toks[4])
+ Long.parseLong(toks[6]) + Long.parseLong(toks[5]) + Long.parseLong(toks[7]));
}
cpuInfo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
当前进行所占CPU的算法是:100*(processCpuTimeS-processCpuTimeF) / (totalCpuTimeS-totalCpuTimeF)
CPU总数用率的算法是:100*((totalCpuTimeS-totalCpuTimeF) - (idelS-idelF)) / (totalCpuTimeS - totalCpuTimeF)
参考:http://blog.csdn.net/l2show/article/details/40950657
if (null != totalCpu2 && totalCpu2.size() > 0) {
processCpuRatio = fomart.format(100 * ((double) (processCpu - processCpu2) / ((double) (totalCpu.get(0) - totalCpu2.get(0)))));
for (int i = 0; i < (totalCpu.size() > totalCpu2.size() ? totalCpu2.size() : totalCpu.size()); i++) {
String cpuRatio = "0.00";
if (totalCpu.get(i) - totalCpu2.get(i) > 0) {
cpuRatio = fomart
.format(100 * ((double) ((totalCpu.get(i) - idleCpu.get(i)) - (totalCpu2.get(i) - idleCpu2.get(i))) / (double) (totalCpu
.get(i) - totalCpu2.get(i))));
}
totalCpuRatio.add(cpuRatio);
totalCpuBuffer.append(cpuRatio + Constants.COMMA);
}
} else { // 保存前一次的cpu使用情况
processCpuRatio = "0";
totalCpuRatio.add("0");
totalCpuBuffer.append("0,");
totalCpu2 = (ArrayList<Long>) totalCpu.clone();
processCpu2 = processCpu;
idleCpu2 = (ArrayList<Long>) idleCpu.clone();
}