参考文章
Android 性能测试初探(二)
Android中级篇之区分系统程序和安装程序
原理
其实在前面的文章Emmagee-Cpu读取的实现分析 没有提到,当我们点击界面的开始测试时,程序会启动EmmageeService,之后所有的数据统计以及更新都是EmmageeService进行处理的。 EmmageeService会启动一个线程,进行数据的更新同时会尝试从logcat中获取到软件的启动时间。下来我们来看看实现的代码
/**
* Try to get start time from logcat.
*/
private void getStartTimeFromLogcat() {
//先判断是否已经获取到启动时间的值,后者说获取的次数大于5次则不继续往下执行
if (!isGetStartTime || getStartTimeCount >= MAX_START_TIME_COUNT) {
return;
}
try {
// filter logcat by Tag:ActivityManager and Level:Info
// 输出标记为“ActivityManager”且优先级大于等于“Info”
String logcatCommand = "logcat -v time -d ActivityManager:I *:S";
Process process = Runtime.getRuntime().exec(logcatCommand);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder strBuilder = new StringBuilder();
String line = BLANK_STRING;
while ((line = bufferedReader.readLine()) != null) {
strBuilder.append(line);
strBuilder.append(Constants.LINE_END);
//通过正则表达式过滤出启动的时间,并且用toast显示
String regex = ".*Displayed.*" + startActivity + ".*\\+(.*)ms.*";
if (line.matches(regex)) {
Log.w("my logs", line);
if (line.contains("total")) {
line = line.substring(0, line.indexOf("total"));
}
startTime = line.substring(line.lastIndexOf("+") + 1, line.lastIndexOf("ms") + 2);
Toast.makeText(EmmageeService.this, getString(R.string.start_time) + startTime, Toast.LENGTH_LONG).show();
isGetStartTime = false;
break;
}
}
getStartTimeCount++;
} catch (IOException e) {
Log.d(LOG_TAG, e.getMessage());
}
}
获取的软件启动时间其实挺简单的,主要还是靠ActivityManger来获取时间。但是问题出来了在4.1以上的系统上执行时,发现无法读取到内容,但是通过cmd执行logcat的时候仍然能够获取到。我们在Emmagee的wiki里面找到了答案Emmageee-wiki
From Jelly Bean, Emmagee can not get launched time, because READ_LOGS permission is not granted to 3rd party applications from Jelly Bean
大体的意思就是从4.1开始,google考虑到安全性的问题,所以禁止了第三方的应用拥有READ_LOGS 的权限了。
其实我们在写cvs文件的时候,Emmagee也是做了判断的。
if (isGrantedReadLogsPermission()) {
bw.write(START_TIME);
}
也只有系统允许读取log权限时,Emmagee才会运行写软件的启动时间
遇到的坑
这里说下在使用过程中遇到的一个问题,Emmagee在默认加载软件列表的时候实际上回过滤掉我们系统的软件,只显示第三方的应用程序。这样子会导致很多可能我们需要测试的软件都没加载出来。
ProcessInfo.java
for (ApplicationInfo appinfo : getPackagesInfo(context)) {
Programe programe = new Programe();
if (((appinfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0) || ((appinfo.processName != null) && (appinfo.processName.equals(PACKAGE_NAME)))) {
continue;
}
....
}
所以我们如果需要测试系统的应用程序时,记得要注释掉这行代码
结论
软件启动时间计算:logcat -v time -d ActivityManager:I *:S 找出对应的Displayed的Activity 当然另外也有其他方法,可以看参考文章。