在Android APP开发过程中,一些高功耗功能需要实时监控CPU使用情况(CPU作为手机功耗的核心模块,几乎占据了性能消耗的绝大部分,因此基本上可以理解为监视CPU手机的当前运行状态。
当前可用的某些用于监视CPU的程序适用于某些型号的CPU(例如,高通公司的Trepen用于Snapdragon芯片,MTK用于联发科的Mali),并且某些程序只能监视整个CPU,而不能监视某些型号。监视应用程序(例如PerfMon)的占用情况;
Android Studio随附的Android Profiler工具在更新到特定版本后仅支持API 21之后的模型。无法使用旧型号;更严重的是,我测试了多个模型。在模型中发现,打开Android Profiler将启动调试监视过程。此监视过程会影响某些模型(主要是小米)的实际CPU使用率。一旦打开,CPU使用率将迅速增加,甚至会出现可见性。滞后情况;

针对此问题,我正在从多个来源查询数据,选择一种不影响实际性能的方法,并实现适用于所有模型的CPU监视工具。 github地址:
核心类是CPUCollector:

/*
* Copyright (C) 2019 jjoeyang. All Rights Reserved.
*/
package com.yzz.cpucollector;
import android.util.Log;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* CPU占用统计类
* 单例,进入APP时通过setPkgName()设置应用包名,调用getCPURate()即可输出CPU统计信息,退出时调用release()
*
* Created by jjoeyang on 19/5/6
*/
public class CPUCollector {
public static final String TAG = CPUCollector.class.getSimpleName();
private String mPkgName = null;
private String mLastCPU = "";
private Thread mCpuThread;
private boolean enableCPU = true;
private boolean isRunning = false;
private boolean doCollect = false;
private static final String COMMAND_SH = "sh";
private static final String COMMAND_LINE_END = "\n";
private static final String COMMAND_EXIT = "exit\n";
private int maxFrameCount = 5; // 统计的总次数,可修改
private int resultFrameTimes = 0; // 统计次数
private double resultAVGValue;
private String mAvgCPUValue;
private static CPUCollector mInstance = null;
private CPUCollector() {
if (mCpuThread == null) {
mCpuThread = new Thread(new Runnable() {
@Override
public void run() {
while (enableCPU) {
if (doCollect && !isRunning) {
doCollect = false;
isRunning = true;
mLastCPU = getCPUFromTopCMD();
isRunning = false;
} else {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
mCpuThread.setName("CpuCollectorThread");
mCpuThread.start();
}
}
public static synchronized CPUCollector getInstance() {
if (mInstance == null) {
mInstance = new CPUCollector();
}
return mInstance;
}
public void setPkgName(String pkgName) {
mPkgName = pkgName;
}
public String getCPURate() {
if (!isRunning && mPkgName != null) {
doCollect = true;
}
return mLastCPU;
}
public String getAvgCPU() {
return mAvgCPUValue;
}
public void release() {
mPkgName = null;
mAvgCPUValue = null;
enableCPU = false;
mCpuThread = null;
}
private String getCPUFromTopCMD() {
String cpu = "";
List result = execute("top -n 1 -s cpu | grep " + mPkgName);
if (result != null && result.size() > 0) {
String r = result.get(0);
if (r != null && r.contains("%")) {
int end = r.indexOf("%");
int start = -1;
for (int i = end; i >= 0; i--) {
if (Character.isWhitespace(r.charAt(i))) {
start = i;
break;
}
}
if (start >= 0) {
cpu = r.substring(start, end);
calculateAVGValue(Double.parseDouble(cpu));
}
}
}
return cpu;
}
/**
* 执行单条命令
*
* @param command
* @return
*/
private List execute(String command) {
return execute(new String[]{command});
}
/**
* 可执行多行命令(bat)
*
* @param commands
* @return
*/
private List execute(String[] commands) {
List results = new ArrayList();
int status = -1;
if (commands == null || commands.length == 0) {
return null;
}
Process process = null;
BufferedReader successReader = null;
BufferedReader errorReader = null;
StringBuilder errorMsg = null;
DataOutputStream dos = null;
try {
process = Runtime.getRuntime().exec(COMMAND_SH);
dos = new DataOutputStream(process.getOutputStream());
for (String command : commands) {
if (command == null) {
continue;
}
dos.write(command.getBytes());
dos.writeBytes(COMMAND_LINE_END);
dos.flush();
}
dos.writeBytes(COMMAND_EXIT);
dos.flush();
status = process.waitFor();
errorMsg = new StringBuilder();
successReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String lineStr;
while ((lineStr = successReader.readLine()) != null) {
results.add(lineStr);
}
while ((lineStr = errorReader.readLine()) != null) {
errorMsg.append(lineStr);
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (dos != null) {
dos.close();
}
if (successReader != null) {
successReader.close();
}
if (errorReader != null) {
errorReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (process != null) {
process.destroy();
}
}
Log.d(TAG, (String.format(Locale.CHINA, "execute command end, errorMsg:%s, and status %d: ",
errorMsg, status)));
return results;
}
private void calculateAVGValue(double resultTime) {
if (resultFrameTimes >= maxFrameCount) {
if (resultFrameTimes == maxFrameCount) {
resultFrameTimes++;
}
mAvgCPUValue = String.format("%.2f", resultAVGValue);
resultFrameTimes = 0;
resultAVGValue = 0;
return;
}
resultFrameTimes++;
double allResultTime = (resultFrameTimes - 1) * resultAVGValue;
resultAVGValue = (allResultTime + resultTime) / resultFrameTimes;
}
}
核心原理是通过代码定期调用adb监视CPU命令(adb shell top -m 100 -n 1 -s cpu),以输出当前应用程序的CPU占用率;支持获取当前占用并执行N帧的平均统计信息。有关特定的API调用和使用方法,请参阅github中的演示
第一个版本是日志输出的CPU信息。在演示中过滤了以下日志:
05-13 12:03:4 8. 914 12240-12240 / com.yzz.cpucollector E / duguju-cpu:当前CPU使用率:4%平均:5. 2%
将来,我们将进行一些界面,操作优化和其他更新,敬请期待〜
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-357834-1.html
可能是包装破了
你如果在伊拉克对美国说“关你鸟事”
超出设计寿命