面对02机器上pcdroid异常情况频发,已经影响到自动化测试的稳定性,因此,花了四天时间对当前的Android模拟器进行调研,试图去寻找一款性能稳定,支持多系统版本的模拟器,从而解决当前自动化测试多系统、多异常的问题。
(一)初步思考
我一直相信,当前我们所面临的窘境对于一些顶级团队来说,可能已经有完美的解决方案。起初对于Android模拟器的思考,还仅限于Android官方与SDK一起提供的模拟器,不过根据之前经验来说,官方的模拟器能解决多版本系统的问题,但是由于Android官方的模拟器使用了仿真技术,在x86系统上模拟ARM指令集,从而导致性能低下,根本无法进行自动化操作。因此,起初基于这个优化的构想,发现了Android官网提供了基于模拟器的x86镜像,不过由于最近g o o g l e服务器被封,并且android的服务器也在被封范围之列,因此暂时放弃了这种想法。不过令人兴奋的是,随后发现google团队的几名工程师设计了一款基于VirtualBox的x86 Android模拟器,并且声称在性能上有质的飞越。
(二)沟通
在这里不得不提一下沟通带来的收益,首先是跟团购的QA沟通,发现团购那边是使用Supserjs进行前端测试,superjs是基于phantomjs设计的一款前端自动化框架,由于内核为webkit,并且支持在linux部署,因此成为了前端解决自动化测试限制的一种方式,不过对于更精确的webapp测试来说,存在以下两个问题:首先,无法模拟定位,对于LBS业务来说,与定位相关功能的验证会受到影响。其次,虽然同基于webkit内核,但是仍然不能解决多系统版本的问题。同时,如果自动化测试改为superjs,势必会导致自动化框架及用例的调整,投入产出比低。并且,对于superjs的折中方案,是使用ghostDriver,从而利用phantomjs解决因为机器导致的测试瓶颈,但是同样存在不精确的问题。
第二个沟通的人是爽姐,在沟通过程中,爽姐提到了之前曾经用过一款g o o g l e的Android模拟器——genymotion。稳定性还ok,执行速度快(后面baidu了下才知道,这款模拟器据说是当前最快的Android模拟器,堪比真机),但是之前只应用在手工测试阶段,对于genymotion投入自动化环境,还需要进一步调研。
第三个沟通的是一位Android地图客户端的rd,沟通了下Android-x86的可行性,最后感觉都很“靠谱”,也就带着一种试一试的态度,进行探索。(参看:http://www.oschina.net/question/12_32695)
(三)模拟器安装
根据当前思考的方案,进行了分析,从当前情况上来看,首要解决的问题是将Android-86和genymotion的环境安装完成。对于genymotion的环境搭建比较顺利,直接http://www.genymotion.com/进入官网,下载个人版,然后注册账号,下载模拟器,OK环境搞定。速度的确是相当之快,支持的功能也比较全面,不过由于是个人版,没有对api的支持,因此对于后续自动化持续集成工作,带来了很大的难度。
接下来是Android-x86的安装,第一个遇到的问题是Android-x86官网(http://www.android-x86.org/)无法访问了,google被墙后带来资源的匮乏。无奈,先看看能不能通过其他途径找到镜像文件,不行也只能购买VPN服务翻 墙了!~
功夫不负有心人,下到了Android-x86-4.4 和 Android-x86-4.3的两个镜像。搜了一篇安装x86虚拟机的帖子(参考:http://www.cnblogs.com/gao241/archive/2013/03/11/2953669.html),按照这个步骤一步一步往下捋,结果在第一步卡住了,每次按照镜像就会重启,镜像无法正确安装,后来修改了安装的命令,在命令后面添加了 idle=poll操作,解决了安装的问题。
初步测试了下,这两个环境的性能相当棒,从启动速度上来说,Android-x86保持在将近120秒,genymotion在160秒逊色于x86,从响应速度来说,genymotion较x86好一些。
(四)连接到设备
当虚拟机都安装ok,下一个解决的问题是怎么将模拟器与adb连接起来。由于虚拟机的特殊性,不能通过usb监测的方式进行连接,只能通过adb connect IP:<Port>的方式进行连接。以这种方式进行连接,首先要保证虚拟机的IP跟当前机器在一个网段,同时要获取到当前机器的IP。 对于Android-x86来说,最方便的莫过于Alt+F1的控制台,通过netcfg的方式直接获取到IP,而genymotion就没有控制台了,后来发现通过genymotion的virtualbox虚拟机在启动阶段会显示当前机器的IP,OK,IP已经获取到了,接下来就是connect。
不过没有这么顺利,connect连接不上机器,网上找了N多方法尝试,仍然无法解决。苦无对策,但是填到酬勤,正如德国化学家凯库勒梦到一条收尾相接的蛇而突然明白了苯环的结构,eclipse的Device视图是否能连接上虚拟机呢?
尝试了下,正常的方式当然是不能,后来从网上找到了一种设置IP的方式,然后经由device中的reset进行重启,就可以connect到虚拟设备了。
(五)脚本化准备
能够连接到设备,下面就可以进行自动化测试了。按照webdriver、端口映射、run,自动化case成功在虚拟机上执行。初步评测稳定性还算可以,美中不足是不能模拟定位。由于整个测试操作已经打通,接下来的工作是如何将当前的工作脚本化。
启动虚拟机,直接使用VirtualBox提供的命令 startvm即可启动(参考http://blog.sina.com.cn/s/blog_4c451e0e0100smar.html)。但是connect的时候,之前是使用eclipse连接的,现在需要以脚本的方式connect。为了解决这个问题,在这里了解了下eclipse插件,找到了与android相关的几个插件。
Device窗口归属于DDMS视图,因此DDMS插件也成为了主要关注的对象。使用XJar反编译之,发现了惊喜。
打开文件,顺藤摸瓜
。。。。最终找到在ddmlib.jar目录中存在AndroidDebugBridge.java,存在reset方法可以满足当前需求。
于是,简单验证之。
不过通过这种方式只能连接一个虚拟机,后面了解到,可以结合adb tcpip + connect的方式对后续虚拟机进行连接。连接问题基本解决。
(六)模拟定位
最后一个难点,如何模拟GPS定位。这个问题困惑了我将近2天的时间。从网上找到的解决方案是先通过telnet命令登录到虚拟机,然后经由“geo fix 经度 维度”的方式设定。但是在实践过程中发现,telnet无法登录到genymotion和x86虚拟机,geo fix也无从下手。
第二个实施方案同样想到了DDMS中的EmulatorControl窗口,既然eclipse能支持模拟定位,那么就照葫芦画瓢。
同样使用了EmulatorControlConsole插件,发现仅有DeviceMonitor的类才能使用模拟定位操作,而虚拟机被Android认定为Device,因此也不具备了模拟定位功能。
方案三是通过Android自带的tools目录下的Emulator -gps 来实现模拟定位操作,后来也是出现了与方案二相同的原因而放弃。(参考:http://api.apkbus.com/guide/developing/tools/emulator.html)
通过上面三种思考,可以说通过现有工具去解决模拟定位问题很难再有突破,此时开始从Android内核着手,试着去模仿和制造模拟定位功能。通过查资料了解到GPS在Android中实现是基于nmea标准(国家海事电子协会文件)(参考http://android.tgbus.com/Android/tutorial/201204/418964.shtml)并了解到nmea的数据格式(参考:http://blog.csdn.net/highdam/article/details/2646291)。于是开始查Android文件结构相关的文档,找到了几个与gps定位相关的文件,不过一直没有找到所说的nmea目录,于是想到了pcdroid一直在用的gpstool工具,由于时间比较晚了,就放到上班后去解决。
Android源码目录结构文档 http://www.cnblogs.com/yyangblog/archive/2011/03/02/1968880.html
Android操作系统结构文档 http://skynet86.blog.163.com/blog/static/17958121520111701719908/
Android目录结构 http://blog.csdn.net/chizhaolin/article/details/5722598
Android源码所有生成目录 http://www.cnblogs.com/scue/p/3738882.html
周一上班,与白宇沟通了下pcdroid模拟定位的问题,得到最大的收获是给了我一个pcdroid的api文档(参考http://pcdroid.baidu.com/api.php),文档里面提供了一种新的模拟定位方式 adb shell gps 经度 维度。通过adb shell命令查看了pcdroid内核的system/bin目录,发现两个比较特别的文件,gps和agps.sh
pull下来发现是经由gps调用agps.sh,通过查询sqlite数据库中的数据,对gps数据进行设置。
稍后查了下Android关于GPS的实现:
Android GPS分析 http://blog.csdn.net/xnwyd/article/details/7198728
Android GPS驱动模块开发 http://blog.csdn.net/vv0_0vv/article/details/7998596
Android GPS架构分析 http://www.eefocus.com/chongzi865458/blog/2012-03/232232_50018.html
发现com.android.location.provider.jar包是Framework层实现。不过由于时间问题,现阶段已经没有时间对这个jar包进行深入研究。修改Android系统涉及到的坑可能还有很多,在此暂时放弃了对Android内核修改的调研。
在准备放弃模拟定位的同时,一个灵感对当前情况产生逆转。既然genymotion模拟器可以通过自带的工具进行gps模拟定位,那么我设置完毕之后,经由虚拟机启动会不会仍然可以定位呢?尝试了下,答案是可以。整体上的技术难点已经初步解决,接下来就是修改自动化脚本,试水genymotion新框架了。
续:后面发现可以通过setProp设定系统的定位参数来完成模拟定位(上面那个是转化为python脚本的截图),从而也完成了多系统模拟器的调研工作,投入生产过程中。由于效率较优,自动化的速度从1小时30分左右提升到1小时20分,同时模拟器导致的稳定性问题也大大降低。