前言
在我之前写的一篇文章Android App响应时间测试方法研究提到一种比较通用的测试启动时间或者响应时间的方案,即利用Monkeyrunner的图片对比接口进行截图比较。但是由于MonkeyRunner的sameAs接口耗时1秒左右,再加上Android的截图工具耗时也需要2秒左右。这些耗时带来的误差对测试结果的影响非常大。因此,我们通过minicap和图像算法对该方案进行了优化。下面介绍一下优化方案。
minicap
minicap是一个工具组件,提供一个socket接口实时传输Android设备的屏幕截图数据流。STF使用minicap工具将设备的屏幕截图数据流通过nodejs服务实时渲染到web页面,从而达到远程屏幕的效果。研究了minicap的原理后,发现它是通过高频率截图的方式,形成视频流的效果。经过计算,发现minicap的截图速度可以达到30ms以下。于是,我想到利用minicap的方式来替代Android的截图API,从而减少截图带来的误差。由于minicap提供的是不间断的屏幕截图数据流,因此,我们需要分析出每张截图在流中的起终点,并截取生成图片。关于如何使用minicap的原理介绍以及如何将二进制数据流转成截图,可以参考Q博士的博文STF框架之minicap工具。
图像相似度算法
之前方案中另一个带来误差的地方在于monkeyrunner的图像比对接口。也是在网上找了一大堆的图像比较算法,比如智能算法尺度不变特征转换(Scale-invariant feature transform或SIFT)。这些算法一般都是对图像进行精确对比,算法都比较复杂,效率也不高。回顾我们的需求,其实是为了确认一个场景切换到另一个场景是否完成。在App交互中,两个发生切换后,比如从启动页面进入首页,界面还是会发生非常大的变化。而我们只需要检测到这些比较明显的差异即可。那么图像比较算法其实没必要那么精确,最简单的做法,我们只要比较整张图片的RGB分布值即可。同时,我们设置一个阈值,如果两张的图片RGB分布超过20%不同,则可以认为场景发生了变化。这样一个算法的耗时可以降低到200ms左右。关键代码可以参考下面
public static boolean sameAs(BufferedImage myImage,BufferedImage otherImage, double percent){
if (otherImage.getWidth() != myImage.getWidth()) {
return false;
}
if (otherImage.getHeight() != myImage.getHeight()) {
return false;
}
int width = myImage.getWidth();
int height = myImage.getHeight();
int numDiffPixels = 0;
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
if(myImage.getRGB(x, y) != otherImage.getRGB(x, y)){
numDiffPixels++;
}
}
}
double numberPixels = height * width;
double diffPercent = numDiffPixels / numberPixels;
System.out.println(diffPercent);
return percent > 1.0D - diffPercent;
}
新方案实现
有了前面提到的minicap截图以及图像比较算法的调研,我们就可以开始研究下新方案的实现。从下图可以看到,我们一共开启了三个线程。线程一负责收集minicap的发送的二进制流,线程二负责将二进制流转换成图片,线程三负责比较前后两张图片的相似度。
方案流程图这里最关键的是截图比较线程,我们可以在线程开始的时候,启动App或者加载初始截图,然后对比前后截图的相似度,当相似度>0.9即停止测试,代码可以参考下面:
class ImageCompare implements Runnable {
@Override
public void run() {
while(isRunning){
if (imageQueue.size() <= 2) {
// LOG.info("数据队列为空");
continue;
}
ImageInfo imageinfo1 = imageQueue.poll();
ImageInfo imageinfo2 = imageQueue.poll();
if(ImageTools.sameAs(imageinfo1.getImage(), imageinfo2.getImage(), 0.9) || (System.currentTimeMillis()-startTime) > 20000){
loadingTime = imageinfo2.getTimestamp()-startTime;
isRunning = false;
}
}
}
}
误差分析
下图是在乐视手机实测的日志结果,可以看出相似度分析的耗时在200ms左右,截图的耗时在100ms左右。因此,通过该方式进行响应时间的测试,误差可以控制在300ms以内。
日志
总结
上面的优化方法,相比之前的方案,误差从3秒减少到了300ms。这样一个误差范围,如果用于启动时间的测试,是可以接受的。对于页面响应时间的测试,300ms的误差还是有点大。如果对精确度要求比较高,建议还是通过代码插桩的方式比较好。
网友评论