传统测试启动速度的方法是录屏分帧,即手工录制启动过程,然后通过分帧软件将启动过程的每一帧抽取出来,选取启动帧与结束帧,从而计算出差值作为启动速度。显然,这个方法有如下缺点:
这种简单暴力的操作显然需要耗费人力与大量时间进行测试、数据收集以及分析。
由于一轮测试需要耗费大量时间,所以测试的次数有限,样本量较少,一次异常的数据就有可能会影响最终的结论。既然是简单粗暴重复的劳动,我们是不是可以考虑使用自动化来实现呢?答案是肯定的,我们采用了另一个更为高效准确的方法——读取系统日志获取启动耗时。
下面就来分享一下 “懒人的智慧”。
通过 ActivityManager 这个 TAG,我们可以获取一个 Activity 的启动耗时。
下面是冷启动(清除数据后启动)的 Log 信息:
01
下面是热启动(点击返回键后启动)的 Log 信息:
02
可以看到冷启动有两条耗时的日志,这是因为首次安装启动存在闪屏,所以冷启动过程划分成了【点击图标 - 进入闪屏】以及【闪屏结束后点击按钮 - 进入应用首页】两个阶段。
通过 Log 可知:
(1)冷启动耗时为:636ms + 993ms = 1629ms;
(2)热启动耗时为:1520ms
这里需要说明一下,在某些情况下会出现以下类型的 Log:
03
其中前者是 This Time,后者是 Total Time,关于二者的区别可以参考代码:
04
这里有三个关键变量,它们各自的定义如下:
(1)curTime:该函数调用时的时间点。
(2)launchTime:一连串启动 Activity 中最后一个 Activity 的启动时间点。
(3)mInitialStartTime:一连串启动 Activity 中第一个 Activity 的启动时间点。
通常情况下,点击图标只会启动一个 Activity,此时 launchTime 与 mInitialStartTime 指向同一个时间点,即 thisTime=totalTime;但有些应用在启动的时候会启动一个无界面的 Activity 做逻辑处理,然后再启动一个有界面的 Activity,此时 launchTime 指向有界面 Activity 的启动时间,mInitialStartTime 指向无界面 Activity 的启动时间,thisTime<totalTime。
如图所示:
05
小结
通过 ActivityManager 这个 TAG 可以获取 Activity 启动耗时。对于单个 Activity 的启动,我们可直接使用 thisTime 作为启动耗时;对于多个 Activity 的启动,我们则使用 totalTime 作为启动耗时。
为了实现自动化测试,brookechen 编写了一个实现性能自动化测试的框架,通过 python 和 uiautomator 驱动用例执行、实现数据收集。关于框架的详细介绍可以参考 TMQ 系列文章《Android 场景化性能测试 - 方向与框架篇》。
框架大体可分为两个部分:用例执行与数据收集处理,依次执行:
suite_up()、set_up()、test()、tear_down() 、suite_down()。
关于启动速度的用例执行比较简单,在此不赘述,每轮测试包括了冷启动与热启动,主要在 test() 内执行以下步骤:
清除数据 - 启动应用 - 滑动闪屏进入首页 - 返回桌面 - 再次启动应用。
06
而数据的收集,会在 set_up() 方法内开启一个线程收集数据,通过 adb 命令:
logcat -v time ActivityManager:I *:S
我们可以只收集 ActivityManager 这个 TAG 的日志,但是这个日志除了我们需要获取的耗时信息,还有其他一些启动相关的日志,在这里我们还需对日志做进一步的筛选过滤,具体规则如下:
(1)不含 Displayed 的日志行丢弃;
(2)不含指定包名的日志行丢弃;
(3)不含指定 Activity 名的日志行丢弃。
07
获取了有用的日志行之后,我们还需要对日志行提取出启动耗时的数据,即从 09-26 19:57:03.332: I/ActivityManager(932): Displayed com.tencent.wifimanager/com.tencent.server.fore.QuickLoadActivity: +944ms 提取出 944ms,这里我们可以通过正则表达式来获取,具体代码如下:
08
有了自动化脚本,我们就可以对历史版本的启动速度做一个对比,并将测试数据以折线图的形式直观地展示出来,从而更直接地反映不同版本启动速度的差异。
09
10
得出测试数据后,若测试结论不理想,我们可以通过 Android Device Monitor 的 trace viewer 来观察不同线程及不同方法的执行耗时。
11
对于上半部分的图表,我们主要关注不同线程占用的耗时,颜色横条越长越多,表示该线程占用耗时越大。
对于下半部分的表格,我们主要关注对应线程下不同方法的占用耗时,主要关注以下三个字段:
(1)Cpu Time/Call:该方法平均占用 CPU 的时间;
(2)Real Time/Call:该方法平均执行时间,包括切换、阻塞的时间;
(3)Calls+RecurCalls/Total:该方法调用、递归次数。
以上三个字段数值越大,表示方法占用耗时越大。
为了方便开发定位,我们还可以将生成的 traceview 文件提供给开发,具体的目录可以将鼠标放到 traceview 名称上,对应的目录就会显示出来。
12
至此,启动速度数据的收集以及分析已经介绍完毕,水平有限,无法一一详尽,阅读过程中有任何的疑问或修正都欢迎随时提出,一同讨论。
关注微信公众号:腾讯移动品质中心 TMQ,获取更多测试干货!