cpu,内存监控作为android性能测试的一部分,在日常工作中使用也比较频繁,一般测试人员都是直接adb命令输出结果或者android studio上查看内存,Cpu的趋势,再深入一点就是性能分析定位了。由于本人水平有限,就先分享个android apk 监控指定应用的cpu和内存。先附上两张效果图:
原理如下
输入需要监控的应用包名,输入监控的间隔时间,输入监控的总时间,点击监控就会执行监控命令,点击监控统计会在图标显示各项参数的最大值,最小值,平局值。点击监控详情会跳转到新的界面,展示详细的监控参数
代码如下
1.先在manifest文件加上如下权限
2.MainActivity代码如下
package com.example.monitor;
import android.content.Intent;
import android.os.CountDownTimer;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
EditText editText_times,editText_min,editText_package;
Button button_top,button_reporte,cpu_btn,start_app,start_time;
TextView countDown,cpu_max,cpu_min,cpu_ave,rss_max,rss_min,rss_ave,vss_max,vss_min,vss_ave;
TextView total_time,wait_time,completa_time;
FileUtils fu=new FileUtils();
List cpu,rss,vss=new ArrayList();
ListUtils lu=new ListUtils();
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//监控详情按钮,点击后通过intent传值到新的activity
cpu_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
cpu= fu.readcpu("/mnt/sdcard/topInfo.txt",editText_package);
rss= fu.readrss("/mnt/sdcard/topInfo.txt",editText_package);
vss=fu.readvss("/mnt/sdcard/topInfo.txt",editText_package);
String times=fu.read("/mnt/sdcard/totime.csv");
String totalTime=fu.read("/mnt/sdcard/totaltime.csv");
Intent intent = new Intent(MainActivity.this,TopDetailActivity.class);
intent.putExtra("times",times);
intent.putExtra("totalTime",totalTime);
intent.putStringArrayListExtra("cpu", (ArrayList) cpu);//key就是自己定义一个String的字符串就行了
intent.putStringArrayListExtra("vss", (ArrayList) vss);
intent.putStringArrayListExtra("rss", (ArrayList) rss);
startActivity(intent);
} catch (Exception e) {
Toast toast=Toast.makeText(MainActivity.this, "监控文件被删除", Toast.LENGTH_SHORT);
toast.show();
}
}
});
//监控报告按钮
button_reporte.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {//在run()方法实现业务逻辑;
//...
//更新UI操作;
handler.post(new Runnable() {
@Override
public void run() {
Liststr_cpu= null;
Liststr_vss= null;
Liststr_rss= null;
try {
str_cpu = fu.readcpu("/mnt/sdcard/topInfo.txt",editText_package);
str_rss=fu.readrss("/mnt/sdcard/topInfo.txt",editText_package);
str_vss=fu.readvss("/mnt/sdcard/topInfo.txt",editText_package);
List cpu_info=lu.StrToInt(str_cpu);
List rss_info=lu.StrToInt(str_rss);
List vss_info=lu.StrToInt(str_vss);
double ave=lu.listAverage(cpu_info);
double ave1=lu.listAverage(rss_info);
double ave2=lu.listAverage(vss_info);
Log.i("cpuinfo", Collections.max(str_cpu));
Log.i("cpuinfo", Collections.min(str_cpu));
Log.i("cpuinfo", cpu_info+"");
Log.i("cpuinfo", ave+"");
cpu_max.setText(Collections.max(str_cpu)+"%");
cpu_min.setText(Collections.min(str_cpu)+"%");
cpu_ave.setText(ave+"%");
rss_max.setText(Collections.max(str_rss)+"K");
rss_min.setText(Collections.min(str_rss)+"K");
rss_ave.setText(ave1+"K");
vss_max.setText(Collections.max(str_vss)+"K");
vss_min.setText(Collections.min(str_vss)+"K");
vss_ave.setText(ave2+"K");
} catch (IOException e) {
Toast toast=Toast.makeText(MainActivity.this, "监控失败", Toast.LENGTH_SHORT);
toast.show();
}catch (NoSuchElementException elementException){
Toast toast=Toast.makeText(MainActivity.this, "监控应用未启动", Toast.LENGTH_SHORT);
toast.show();
}
}
});
}
}.start();
}
});
//监控按钮
button_top.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(editText_times.getText().toString().equals("")||editText_min.getText().toString().equals("")){
Toast toast=Toast.makeText(MainActivity.this, "监控总时间和监控时间是必填参数", Toast.LENGTH_SHORT);
toast.show();
}
else{
String total=editText_min.getText().toString();
threadpool(5);
//timer.start();
int totalTime=Integer.parseInt(total);
new CountDownTimer(totalTime*1000*60, 1000) {
@Override
public void onTick(long millisUntilFinished) {
button_top.setEnabled(false);
button_top.setText("监控中");
countDown.setText((millisUntilFinished/1000)+"S");
}
@Override
public void onFinish() {
button_top.setEnabled(true);
button_top.setText("启动监控");
countDown.setEnabled(true);
countDown.setText("ok");
}
}.start();
}
}
});
}
private void initView() {
editText_min=(EditText) findViewById(R.id.ed_topmin);
editText_times=(EditText)findViewById(R.id.ed_toptimes);
editText_package=(EditText)findViewById(R.id.ed_package);
button_top=(Button)findViewById(R.id.button_topbegin);
button_reporte=(Button) findViewById(R.id.button_reporte);
cpu_btn=(Button)findViewById(R.id.cpu_btn);
countDown=(TextView)findViewById(R.id.timer);
cpu_max=(TextView)findViewById(R.id.cpu_max);
cpu_min=(TextView)findViewById(R.id.cpu_min);
cpu_ave=(TextView) findViewById(R.id.cpu_ave);
rss_max=(TextView) findViewById(R.id.rss_max);
rss_min=(TextView)findViewById(R.id.rss_min);
rss_ave=(TextView) findViewById(R.id.rss_ave);
vss_max=(TextView) findViewById(R.id.vss_max);
vss_min=(TextView) findViewById(R.id.vss_min);
vss_ave=(TextView)findViewById(R.id.vss_ave);
}
public void threadpool(int case_num) {
ExecutorService cacheThreadPool = Executors.newFixedThreadPool(5);
if (case_num == 5) {
cacheThreadPool.execute(new Runnable() {
// final int index =1;
@Override
public void run() {
// String times=editText_times.getText().toString();
String times = editText_times.getText().toString();
//监控间隔时间
int times_num = Integer.parseInt(times);
String min = editText_min.getText().toString();
//监控总时间
int min_num = Integer.parseInt(min);
//次数
int n = min_num * 60 / times_num;
//如果监控文件不存在则创建文件
if (fu.topfileIsExists("/mnt/sdcard/totaltime.csv") == false) {
ShellUtils.execCommand("touch /mnt/sdcard/totaltime.csv", true);
}
if (fu.topfileIsExists("/mnt/sdcard/totime.csv") == false) {
ShellUtils.execCommand("touch /mnt/sdcard/totime.csv", false);
}
fu.writeTofile("/mnt/sdcard/totaltime.csv", min);
fu.writeTofile("/mnt/sdcard/totime.csv", times);
ShellUtils.execCommand("top -m 5 -d " + times + " -n " + n + " >/mnt/sdcard/topInfo.txt", false);
}
});
}
}
}
3.MainActivity布局代码如下
4.String转list工具类
package com.example.monitor;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2017/9/6.
*/
public class ListUtils {
public List StrToInt(List str){
List cpu_num=new ArrayList();
for(int i = 0;i list){
int sum=0;
double average;
for (int i = 0; i < list.size(); i++) {
sum+=list.get(i);
}
if(list.size()==0){
average=0;
}
else{
average = sum / list.size();
}
Log.i("ave","======"+average);
return average;
}
}
5.文件处理工具类
package com.example.monitor;
import android.widget.EditText;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2017/8/9.
*/
public class FileUtils {
// 判断文件是否存在
public static void judeDirExists(File file) {
if (file.exists()&&file.isDirectory()) {
System.out.println("dir exists");
} else {
System.out.println("dir not exists, create it ...");
file.mkdir();
}
}
public boolean topfileIsExists(String path){
try{
File f=new File(path);
if(!f.exists()){
return false;
}
}catch (Exception e) {
// TODO: handle exception
return false;
}
return true;
}
//写入到csv中
public void writeTofile(String filepath, String content){
String path=filepath;
File writepath=new File(path);
FileWriter writer=null;
try {
//"E:\\YallaTest\\YallaResult.csv"
// 打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件
writer = new FileWriter(writepath,false);
writer.write(content);
//\r\n表示换行
//,表示换一格
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(writer != null){
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String read(String path) throws IOException{
BufferedReader br = new BufferedReader(new FileReader(path));
StringBuffer sb = new StringBuffer();
String line = null;
while((line= br.readLine()) != null) {
sb.append(line);
}
System.out.println(sb.toString()); //sb包含所有文本内容
return sb.toString();
}
public List readcpu(String path,EditText editText) throws IOException{
String aa=editText.getText().toString();
BufferedReader br = new BufferedReader(new FileReader(path));
List list_str=new ArrayList();
String line = null;
while((line= br.readLine()) != null) {
if(line.contains(aa)){
String m=line.substring(line.indexOf("%")-2, line.indexOf("%"));
//System.out.println(m);
list_str.add(m);
}
}
// System.out.println(sb.toString()); //sb包含所有文本内容
return list_str;
}
public List readvss(String path,EditText editText) throws IOException{
String aa=editText.getText().toString();
BufferedReader br = new BufferedReader(new FileReader(path));
List list_str=new ArrayList();
String line = null;
while((line= br.readLine()) != null) {
if(line.contains(aa)){
String q=line.substring(line.indexOf("K")-7, line.indexOf("K"));
list_str.add(q);
}
}
// System.out.println(sb.toString()); //sb包含所有文本内容
return list_str;
}
public List readrss(String path,EditText editText) throws IOException{
String aa=editText.getText().toString();
BufferedReader br = new BufferedReader(new FileReader(path));
List list_str=new ArrayList();
String line = null;
while((line= br.readLine()) != null) {
if(line.contains(aa)){
String g=line.substring(line.indexOf("K",line.indexOf("K")+1 )-6, line.indexOf("K",line.indexOf("K")+1 ));
list_str.add(g);
}
}
// System.out.println(sb.toString()); //sb包含所有文本内容
return list_str;
}
}
6.shell工具类
package com.example.monitor;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
/**
* Created by Administrator on 2017/7/13.
* 有效启动shell类
*/
public class ShellUtils {
public static final String COMMAND_SU = "su";
public static final String COMMAND_SH = "sh";
public static final String COMMAND_EXIT = "exit\n";
public static final String COMMAND_LINE_END = "\n";
private ShellUtils() {
throw new AssertionError();
}
/**
* check whether has root permission
*
* @return
*/
public static boolean checkRootPermission() {
return execCommand("echo root", true, false).result == 0;
}
/**
* execute shell command, default return result msg
*
* @param command command
* @param isRoot whether need to run with root
* @return
* @see ShellUtils#execCommand(String[], boolean, boolean)
*/
public static CommandResult execCommand(String command, boolean isRoot) {
return execCommand(new String[] {command}, isRoot, true);
}
/**
* execute shell commands, default return result msg
*
* @param commands command list
* @param isRoot whether need to run with root
* @return
* @see ShellUtils#execCommand(String[], boolean, boolean)
*/
public static CommandResult execCommand(List commands, boolean isRoot) {
return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, true);
}
/**
* execute shell commands, default return result msg
*
* @param commands command array
* @param isRoot whether need to run with root
* @return
* @see ShellUtils#execCommand(String[], boolean, boolean)
*/
public static CommandResult execCommand(String[] commands, boolean isRoot) {
return execCommand(commands, isRoot, true);
}
/**
* execute shell command
*
* @param command command
* @param isRoot whether need to run with root
* @param isNeedResultMsg whether need result msg
* @return
* @see ShellUtils#execCommand(String[], boolean, boolean)
*/
public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) {
return execCommand(new String[] {command}, isRoot, isNeedResultMsg);
}
/**
* execute shell commands
*
* @param commands command list
* @param isRoot whether need to run with root
* @param isNeedResultMsg whether need result msg
* @return
* @see ShellUtils#execCommand(String[], boolean, boolean)
*/
public static CommandResult execCommand(List commands, boolean isRoot, boolean isNeedResultMsg) {
return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, isNeedResultMsg);
}
/**
* execute shell commands
*
* @param commands command array
* @param isRoot whether need to run with root
* @param isNeedResultMsg whether need result msg
* @return
* - if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and
* {@link CommandResult#errorMsg} is null.
* - if {@link CommandResult#result} is -1, there maybe some excepiton.
*
*/
public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
int result = -1;
if (commands == null || commands.length == 0) {
return new CommandResult(result, null, null);
}
Process process = null;
BufferedReader successResult = null;
BufferedReader errorResult = null;
StringBuilder successMsg = null;
StringBuilder errorMsg = null;
DataOutputStream os = null;
try {
process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
os = new DataOutputStream(process.getOutputStream());
for (String command : commands) {
if (command == null) {
continue;
}
// donnot use os.writeBytes(commmand), avoid chinese charset error
os.write(command.getBytes());
os.writeBytes(COMMAND_LINE_END);
os.flush();
}
os.writeBytes(COMMAND_EXIT);
os.flush();
result = process.waitFor();
// get command result
if (isNeedResultMsg) {
successMsg = new StringBuilder();
errorMsg = new StringBuilder();
successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String s;
while ((s = successResult.readLine()) != null) {
successMsg.append(s);
}
while ((s = errorResult.readLine()) != null) {
errorMsg.append(s);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
if (successResult != null) {
successResult.close();
}
if (errorResult != null) {
errorResult.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (process != null) {
process.destroy();
}
}
return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null
: errorMsg.toString());
}
/**
* result of command
*
* - {@link CommandResult#result} means result of command, 0 means normal, else means error, same to excute in
* linux shell
* - {@link CommandResult#successMsg} means success message of command result
* - {@link CommandResult#errorMsg} means error message of command result
*
*
* @author Trinea 2013-5-16
*/
public static class CommandResult {
/** result of command **/
public int result;
/** success message of command result **/
public String successMsg;
/** error message of command result **/
public String errorMsg;
public CommandResult(int result) {
this.result = result;
}
public CommandResult(int result, String successMsg, String errorMsg) {
this.result = result;
this.successMsg = successMsg;
this.errorMsg = errorMsg;
}
}
}
7.新建一个activity命名为TopDetailActivity
package com.example.monitor;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TopDetailActivity extends AppCompatActivity {
private TextView textView_title;
ArrayList cpuList,rssList,vssList = new ArrayList();
String title;
ListView listView_detail;
List
8.TopDetailActivity布局代码如下
9.新建一个布局文件monitor_item.xml
10.在drawable目录下新建edittext_border.xml
11.在drawable目录下新建textview_border.xml