Android 原生底层驱动应用面极广,但一直没有很好的办法进行质量追踪。本文借助星云精准测试的高可靠性的测试技术手段,针对 Android 原生底层驱动进行分析、插桩、编译、采集数据、数据分析等,逐步讲解精准测试是如何实现 android 原生底层驱动的对接。
在本文中,我们可以清晰地查看到如何进行技术对接的每一步,比如如何使用星云精准测试进行代码插桩、实现测试用例与采集底层驱动运行代码的数据追溯、对最终采集的数据进行一系列分析等。
经分析 android 源码的编译主要依靠 Android.bp 为纽带连接起来;在编译时,只需要在想要编译的模块目录下执行 mm 命令即可自动的根据当前目录下的 Android.bp 文件对其所包含的模块进行编译。
主要流程大致为:先将 ZOA 通信库源码复制进去并加入某一层次的 Android.bp 中,再通过对包含所有 Android.bp 编译信息的 ninja 文件的解析可以得到 Shell 认可的插桩 json 文件,Shell 通过 json 文件对对应目录的代码进行插桩,插桩完成后,把对 ZOA 通信库的引用加入该模块的 Android.bp 中再放入 ZoaInstru.h 头文件后就可以正常编译出插桩程序了。
1.安卓原生 8.1.0 系统源码,放于/data/source2/目录下
2.shell.tar.gz 插桩工具包放于/data/目录下
3.ZOAMQLib 通信库源码放于/data/source2/ frameworks/av/目录下
4.谷歌官方装有原生 8.1.0 系统手机一部
本例是对/data/source2/ frameworks/av/camera 模块进行插桩编译,首先 source build/envsetup.sh 配置环境变量,再 lunch 后输入 2 选择 aosp_arm64-eng,再 mm 编译模块
在存放精准测试插桩工具包的/data/目录下执行命令
tar -zxvf shell.tar.gz
将精准测试插桩工具包解压
cd /data/shell/bin
进入 shell 包 bin 目录下打开并修改 Server.cfg 的 [SERVER] 字段的 ip 为星云精准测试服务端 ip,对 [LOCAL] 字段的 ip,客户端若与服务端在同一主机则保持 127.0.0.1,若在不同主机则写明客户端 ip。
本次选择 av 模块进行精准测试的插桩编译验证模块,在对 av 模块进行深入了解后,解析出其 Android,bp 的连接其结构大致如此,每一个最终节点就代表会生成一个动态库或者静态库。
av 大致结构与 ZOA 通信库加入安卓体系示意图:
注:由于第二层 mediadrm 模块库目录过多不便展开,但原理又是相同,所以仅对该模块展示骨架信息;绿色部分代表会产生一个库文件,mediadrm 只是骨架结构所以未标识。
本次是将写好对应的 Android.bp 文件的 ZOA 通信库源代码目录整个复制到 av 目录下,并在 av 目录下的 Android.bp 文件中加入 ZOA 通信库的目录。
cd /data/source2/frameworks/av/
进入 av 模块
vi Android.bp
打开 av 模块的 Android.bp 文件,并将 ZOAMQLib 目录加入其中
ZOA 通信库加入 av 模块的 Android.bp 图示:
然后在 ZOAMQLib 目录下直接执行 mm 命令,编译出安卓体系下的 ZOA 通信库。
android 源码在进行编译时他会将所有的 Android.bp 中的信息提取出来并添加一些编译信息来生成一个 build.ninja 文件。该文件中含有编译的模块、源代码和编译参数等信息。
通过 android 自带的 ninja 工具可以将该 build.ninja 文件转化为包含源代码路径、源代码名字和编译参数信息的 json 文件;再通过工具可以将要插桩模块的部分提取出来生成该模块的插桩 json 文件
生成 json 文件的命令:
/data/source2/prebuilts/build-tools/linux-x86/bin/ninja -t compdb g.cc.cc > compile_commands.json
其中/data/source2/为安卓源代码路径
shell 编译器可以通过该 json 文件对该模块进行插桩或还原操作。
插桩代码命令 shell 的路径/shell -p json 文件的路径/ compile_commands.json
还原代码命令 shell 的路径/shell -r json 文件的路径/ compile_commands.json
本次插桩与还原命令:
/data/shell/bin/shell -p /data/source2/compile_commands.json
/data/shell/bin/shell -r /data/source2/compile_commands.json
插桩成功后在客户端重新加载版本数据:
cd /data/source2/frameworks/av/camera
进入 camera 目录下
vi Android.bp
打开 camera 模块的 Android.bp 文件并在 shared_libs 中加入 ZOA 通信库的名字
camera 的 Android.bp 加入 ZOA 通信库链接图示:
cp /data/shell/include/ZoaInstru.h /data/source2/frameworks/av/camera/include/
将 ZOA 的头文件加入被插桩的 camera 的头文件夹中
然后就可以按照正常的编译流程来进行编译,执行 mm 编译该模块。
本例是将安卓原生 8.1.0 代码进行插桩后,放入谷歌官方 8.1.0 系统并获得 root 权限的手机中进行测试
本次插桩的是 av 模块的 camera 部分,所以我们将
camera 模块库:
/data/source2/out/soong/.intermediates/frameworks/av/camera/libcamera_client/android_arm64_armv8-a_shared_core/libcamera_client.so
ZOA 通信库:
/data/source2/out/soong/.intermediates/frameworks/av/ZOAMQLib/libZOAMQLib/android_arm64_armv8-a_shared_core /libZOAMQLib.so
这两个库放进手机的/system/lib64/目录中开机进行相机测试。
测试概念图:
将被测手机开机后用 usb 线连接到电脑上,采用 adb 端口映射的方法将程序运行时产生的动态数据传输到星云精准测试工具上,再通过示波器进行波形展示。
数据传输图:
在星云精准测试工具客户端打开示波器界面,建立测试用例并选择测试用例后点击 开始 并对手机进行相机功能的操作就可以在接收到动态数据并示波器看到波形了。
示波器接收数据图:
在对测试用例录制完成后就可以在主界面看到覆盖率等相关信息。
在函数列表中随便点开一个函数就可以查看该函数的各项覆盖率。
1.SCO 覆盖率
SCO 覆盖率即为语句块覆盖率,在函数内顺序执行遇见 if、for、while 等就算为一个语句块。
SC0 覆盖率图示:
2.MCDC 覆盖率
MCDC 修订条件判定覆盖,精准测试中对 mcdc 做了量化展示,分别统计单一条件个数,针对每一个条件判断是否满足 mcdc 覆盖如果满足如上图绿色表示条件满足 mcdc 覆盖,蓝色表示不满足。并对 MCDC 做了详细信息的展示(选择 MCDC 覆盖,点击判定,显示 MCDC 的详细信息)
MCDC 覆盖率图示:
注:
1.覆盖率信息一共有七种,分别为 SCO 语句块覆率、True、Flase、Both 等条件覆盖率、Branch 条件分支覆盖率、CDC 条件判定覆盖率、MCDC 修正条件判定。
2.精准测试默认是不关联源码的,如需要关联源代码使用,请将源码复制到客户端本地,在版本上右键选择修改源码路径,然后添加源码路径来关联源码。
函数调用图,只有函数调用的关系,能够比较清楚地看清函数调用的层次关系。当点击其中的某个函数时,能显示以该函数为中心,调用该函数的上三层和下三层调用 (可点击设置层级进行层级的调整)。
当接收过动态数据后还能将各项数据显示在图像界面中。
控制流程图基础功能是展示函数的控制流程,即控制流程图,用于表示函数的控制流程、显示测试覆盖率结果、实现半自动高效率测试用例设计,进行逻辑流程查错,以及源码、测试用例和相关文档之间的双向自动追溯等。
简易控制流程图功能,以语句块的形式清晰的展示函数内部的控制逻辑,界面上可以直观的看出控制流各节点的测试覆盖情况,在展示中,简易控制流程图还可以通过颜色对每个程序块进行覆盖率标识,在缩略图中整个模块的覆盖率非常直观。(背景色为绿色表示有测试用例覆盖到该块)关联源码后点击语句块可定位到代码具体行。
由于精准测试的测试用例与执行过的函数绑定,可以在测试台通过选择不同的测试用例来正向追溯找到它执行过的函数;或者通过选择不同的函数或代码来反向追溯找到执行过它的测试用例。
正向追溯图示:
该正向追溯是通过在左上侧选择测试用例来在下方展示该测试用例运行过的函数
反向追溯图示:
反向追溯既可以通过左下角的函数来追溯运行过该函数的测试用例,还可以通过选择代码块来追溯运行过该块的测试用例。
在第一个版本测试完成后对第二个版本进行插桩后就在星云精准测试工具生成了第二个工程版本。此时我们要做的不是立马对新版本进行测试,而是使用我们星云精准测试的回归功能对新插桩的版本进行回归,它会根据版本之间代码的变化的来分析出与该函数相关的测试用例,然后根据测试用例内函数改变的多少进行回归优先级的排序,智能的推荐出需要重新跑的测试用例,以及显示出不需要跑的测试用例。
智能回归示例:
cd /data/source2/frameworks/av/camera 进入到 camera 目录下
vi ICamera.cpp 打开该源码进行修改
在 getParameters 函数中加入 if(1==1);条件
然后对 camera 模块进行插桩,再在客户端使用选取回归测试用例功能进行回归
由于 getParameters 函数内新增条件发生变化,所以运行过该函数的测试用例的回归计数就加一,然后该测试用例就被推荐出来需要重新去跑一遍。
回归图示:
对精准测试而言,其是采用在测试阶段,将测试用例和它所执行过的函数绑定的方法。在版本迭代时会将上一个版本的测试用例继承下来,通过回归跟上个版本进行比较,哪个函数有了变化,那么与其相关的测试用例的功能都可能会发生变化,所以在回归时会推荐出要重新测试的测试用例;而当一个测试用例里面关联的所有函数都没发生变化时他的功能也不会发生变化,那么此时再去测试一遍该用例是没有意义的事情。所以,在新版本插桩完毕后和以前的进行回归后就可以看出哪些用例需要重新跑哪些完全不用再跑。
该部分是执行插桩程序进行动态数据接收时保存的最后五十个语句块执行的时序关系图
它可以点击每一步次序查看执行块的代码
聚类算法中个数的设置是需要手动设置的,一般看颗粒度的粗细进行设置。聚类算法是通过测试用例的代码相似程度得出结果的,所以可以帮助我们划分出来有哪些测试用例的代码相似程度比较高,
本次共设计 7 个测试用例,两次拍照、两次录视频、一次随便侧、一次打开相机、一次打开相机后闲置。
选择分类个数为 5 后,聚类结果为:
切换为图形模式为:
使用折线图清晰的展现每天该版本覆盖率的变化情况
左下角雷达图展示了预期的各项覆盖率与实际各项覆盖看的差距
右下角对比了当前版本与最新版本各项覆盖率的差异
在一个程序中,往往有成百上千的函数,这些函数有的是关联整个程序核心、有的则是开发人员弃而不用,但一直保留迟迟不肯删除的,针对这些大量的函数,“精准测试” 采用通过静态、动态指标的综合分析,在大量的程序函数中,通过计算直接筛选潜在的高危的测试漏洞,通过报表给予展示。
当一个函数复杂度很高但覆盖率却很低的时候其出现风险的概率就可能比较高
当函数扇入扇出越大时,意味着其关联函数越多,结合其覆盖率信息也可能是风险较高。