作者:刘洋

一、覆盖率踩过的坑

在项目中使用 JaCoCo 覆盖率的时候,也遇到过各种奇葩的问题,在这里列出来分享下,问题和实际的项目关系密切,希望对有遇到过相似问题的童鞋有所启发。

1.1 覆盖率包在部分手机 6.0 上安装失败

事情起因:在测试新功能时,用打的覆盖率包,外包反馈部分手机 6.0 上安装不了。

问题重现:试了在自己的手机,华为 mate8 的 6.0 系统上安装正常,属于部分机型问题。

将问题小米手机借来后,发现用豌豆荚或者应用宝确实安装失败,提示 “该应用签名有问题,无法安装。” 通过 adb install 安装,提示 INSTALL_PARSE_FAILED_NO_CERTIFICATES

怀疑是部分厂商对签名的校验级别比较高。

问题排解:网上有种说法,jdk1.7 以后变更了默认的加密算法,而签名程序没有,所以需要在签名时用参数指定。具体方法:在签名命令后加入-digestalg SHA1 -sigalg MD5withRSA

1.会不会这种情况导致:查了应用宝的打包脚本,签名部分已经增加。

此种情况排除

2、会不会签名文件有问题?

重新排查了打包过程的签名,密钥和口令都和 RDM 打包一样,对 ANDROIDR.RSA、ANDROIDR.SF、MANIFEST.MF,清除掉签名,重新进行签名,问题仍然存在。

此种情况排除

3、JaCoCo 的 jar 包重新签名

和 RDM 打包,也就增加了 JaCoCo 部分,会不会是 JaCoCo 的两个 jar 包 jacocoagent.jar 和 jacocoagent.jar 出的问题?

这两个 jar 包已经是签名过的,会不会需要用应用宝的签名进行重新签?
使用 jarsigner 重新对这两个 jar 包用应用宝的密钥进行签名,打包安装,问题仍然存在。

此种情况排除

到这里,网上的各种方法基本都试过了,没任何效果,问题纠结在这里了。
静下心来,网上的方法没任何效果,还是回到项目中,重新一步一步的对比 RDM 打包和覆盖率打包的区别,逐步排查吧。

4、RDM 打包和覆盖率打包逐一对比

....(这里省略一万字,都是排查)

签名部分的日志对比:

我们还是回到打包签名的 target:sign_obfuscated

逐行对比 RDM 和我们覆盖率打包的日志:

发现了一个不同的点:

RDM 的:

我们打包的:

大家看出差别了没 (红色部分)

红色部分为 jacocoagent.jar 包里的非 class 文件,signer 对这两个文件也进行了签名。

到这里都不是问题。

问题还是应用宝脚本本身 (┬_┬哭~)

签名后做 compress 和 zipalign,据说是极限压缩,减少包的大小。

Compress 会调用 compress_yingyongbao.sh 脚本,这里列出了所有要压缩的文件

看到没,看到没,它重新按这里的文件列表压缩打包,丢掉了上面 JaCoCo 里面的两个文件应用在打包后,签名文件是存在 JaCoCo 这两个文件的,但打包后找不到这两个文件,因此安装时有的手机提示签名有问题。

解决方法:

JaCoCo 这两个文件,一个是属性文件,一个是生成 xml 的 dtd 文件,对我们生成覆盖率没多大作用,我们把这两个从 jar 包里删除,在重新打包,这两个文件不存在了,也就不用签名了,问题就解决了。

1.2 覆盖率包在部分 4.X 版本手机上生成 ec 文件失败

事情起因:在测试新功能时,用打的覆盖率包,外包反馈部分 4.X 手机生成不了 ec 文件

问题重现:试了在自己的手机,华为 mate8 的 6.0 系统上生成正常,属于部分机型问题。

将问题手机借来后,生成 ec 文件提示失败。

问题排解:

查看 logcat 日志:

java.lang.IllegalAccessError:
07-02 16:21:19.768: W/dalvikvm(557): Class resolved by unexpected DEX: Lorg.JaCoCo.agent.rt.internal.Agent(0x44f0d158):0x128f18 ref [Lorg.JaCoCo.agent.rt.internal.Agent;] Lorg.JaCoCo.agent.rt.internal.Agent;(0x44f0d158):0x11df68

还有一段:

反射 RT 类的 getAgent() 方法是提示

java.lang.reflect.InvocationTargetException
(1) 反射在其他手机是正常的,按道理不应该在部分问题手机会失败,但也做一下排查报错的代码行:

网上有说 InvocationTargetException 问题可能是没有设置可见就访问私有先看看 RT 的这个方法

在看看 Agent 类的这个方法:

尝试把私有字段可见,在去调用

结果问题仍然存在,此种情况排除

(2) 那我们就回到第一个错误, Class resolved by unexpected DEX
Agent 出了两个地址。

我们在回过头来看应用宝的打包脚本,看看 dex 干了什么。


调用 dex,输入 classes,输出 dex,下面对 excludes 里面的 jar 进行了排除

调用 dex_sub,输入 subclasses,输出 second_dex,下面对 excludes 里面的 jar 进行了排除

回过头来在看看我们的插桩脚本,对 dex、dex_sub 这块只改了 classes 为 classes_instr(用插桩后的打 dex)

应用宝这个分包的逻辑,会分别打两个 dex。

问题就找到了,因为没有改 excludes 部分,jacocoagent.jar 是放在应用宝 libs 目录下的,默认 dex 和 dex_sub 都把 jacocoagent.jar 打了进去,运行时就会出现新的 dex 想要替换之前校验过的 dex,也就出现 agent 有两个地址的缘故。

解决方法:
覆盖率打包的脚本,对 dex_sub 的 excludes 中加入 jacocoagent.jar,这样两次 dex 只打一次 jacocoagent.jar。

重新打包,ec 文件正常生成。

1.3 覆盖率报告生成后看不到源码覆盖情况

源码和类文件都正确指定了,为什么生成的报告看不到源码覆盖?
**
解决方法:**

(1) 编译的时候 debug="true" 这个一定要设置,比如

(2) 如果 1 没有错误,那就要看看你的源码和 class 文件路径指定正确没,JaCoCo 是按照包名去搜索的,这个一定要确定好,很多项目会自建代码目录的。

二、覆盖率一些需要注意的地方

由于 Android 不能通过 JVM 停止后自动 dump 覆盖率数据,因此当 Android 应用进程不存在或停止的时候,覆盖率数据不会生成。

也就有了如下需要注意的地方

(1) 没有启动应用进程,生成覆盖率数据会失败。

(2) 覆盖率生成工具进程杀不杀掉,不影响覆盖率生成结果。

(3) 测试过程中,杀掉应用进程,内存中的覆盖率数据会丢失。

(4) 覆盖率数据是可以追加记录的,但最好在杀掉应用进程前先备份。

建议养成良好的操作习惯,,定期生成覆盖率文件。

如果有杀掉应用进程的需求操作,请在操作前生成一次,这样之前的数据就有所保留了。

一次测试前,一定要保证先清理掉以前覆盖率的数据,否则以现有追加文件的方式的形式,会导致旧新的覆盖率柔和在一起,有可能 merge 时候会失败。

本章完~

原文链接:enter link description here


TMQ(腾讯移动品质中心)是腾讯最早专注在移动 APP 测试的团队
我们专注于移动测试技术精华,饱含腾讯多款亿级 APP 的品质秘密,文章皆独家原创,我们不谈虚的,只谈干货!

扫码关注我们

扫一扫 关注 TMQ
精彩分享不断


↙↙↙阅读原文可查看相关链接,并与作者交流