背景
这是个大坑,记录下。
项目接入了tinker做热修复,可是呢一行代码不改,你猜补丁多大?
10M
加固后生成的补丁,你猜多大?
18M
这简直是不能接受啊!
结论
先说结论,因为其他都是废话,也没人关心,希望结论能帮助到他人。
matrix导致tinker补丁过大,matrix也提供了类似mapping的机制
- 项目里用例tinker+matrix,这俩是微信一家的
- matrix在做方法耗时插桩时,会在代码里每个方法里插入开始和结束然后计算耗时,因此每个方法有个ID。
而这个ID是在transform阶段收集代码中的方法时(分配一个ID,全局AtomicInteger从0开始递增)放到集合里,这过程是异步的,因此每个方法对应的ID每次都不同。也就导致了tinker补丁包过大。
找问题
这一开始,简直一点头绪都没。人家的补丁几KB,我家的都几十M,换谁也不敢用。还是简单记录下排查过程:
- 怀疑混淆导致文件每次都变。可是用了applyMapping了还是不行
- 怀疑applyMapping没生效。结果无论怎么改都不行,而且tinker日志里显示已经用了基准包的mapping文件
- 终于怀疑到了无痕埋点+apm,怀疑在过程中干了什么偷鸡摸狗的事情。然而打出来的apk反编译看了看class代码一样啊,不就是插桩嘛?
- 又开始怀疑混淆,可能插桩task和混淆task顺序上有问题呢?又想着改变下task顺序。不过这个技不如人,还没开始改。
- 突然灵光一闪,补丁过大肯定是很多地方变了,事实从tinker日志里也看到大量变更。就连续打了两次基准包,发现基准包的大小都不同。
- 取消混淆,补丁大小还是不变,于是排除混淆
- 取消无痕埋点+apm结果世界美好了,两次打的基准包大小也一样,补丁也很小。基本确定是这俩货搞的鬼。
- 然后想到可能是字节码里有差异,但实际jdgui看不出来。于是用apktool将两次基准包反解出来,用文件对比工具一对比。我去。apm的字节码有个地方一直在变阿。
- 找到问题后就去看源码了。请看结论。