Tinker: 修复成功 小米推送还是会崩溃

Created on 8 Dec 2017  ·  11Comments  ·  Source: Tencent/tinker

异常类型:app运行时异常

手机型号:三星 galaxy S7 edge

手机系统版本:如:Android 7.0

tinker版本:1.9.1

gradle版本:2.3.3

是否使用热更新SDK: 是

堆栈/日志:

12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: catch exception when loading tinker:java.lang.NoClassDefFoundError: avb
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.push.protobuf.b$a.b(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.slim.b.l(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.slim.d.a(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.slim.d.b(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.slim.f.a(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.smack.h.b(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.push.service.XMPushService.o(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.push.service.XMPushService.n(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.push.service.XMPushService.f(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.push.service.XMPushService$d.a(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.push.service.XMPushService$h.run(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.push.service.i$c.run(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: Caused by: java.lang.VerifyError: Verifier rejected class avb: int avb.c(int) failed to verify: int avb.c(int): [0x1] rejecting non-direct call to constructor int avf.(int, int)Verifier rejected class avb: void avb.c(int, int) failed to verify: void avb.c(int, int): [0x0] rejecting non-direct call to constructor int avf.(int, int) (declaration of 'avb' appears in /data/user/0/com.sjyx8.tzsy/tinker/patch-d2bf3089/dex/classes.dex.jar)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.push.protobuf.b$b.b(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at ave.c(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.push.service.bf.a(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.slim.d.a(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.slim.f.b(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.smack.h.a(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.smack.h.a(Unknown Source)
12-08 15:49:06.755 1575 1597 E Tinker.UncaughtHandler: at com.xiaomi.smack.h.s(Unknown Source)

question

Most helpful comment

分析了一半,确定和proguard最近的变更有关,源码细节还没翻到,着急的可以先按照如下处理解决:
-optimizations !method/inlining/short,亲测有效;
完整分析过程:https://docs.google.com/document/d/1FOGbxa2Q93ur0xkGiiK-xa_suqzVSbqRorahkSn4iT4/edit?usp=sharing

结论概述:

打基准包留下来一个mapping,如上截图,意思如下:a混淆成a,并且原来的静态变量调用a的直接inline(short inline);

打热更新包的时候(tinkerPatchXXX),会先打一个目标APK,这时候会apply这个mapping;proguard在applyMapping的时候,先将a方法按照mapping保留了一个a方法,然后做inline操作,在inline的时候,尝试保持上个mapping的inline配置,但是由于mapping信息上不能识别是short还是uniqe,所以错误的直接把a方法完全inline到中,外部调用这个就会抛出上述错误; ---- 以上尚未考证源码,等阅读完再补充细节;

至此,我们基本确定了proguard在applyMapping上的问题,考虑到build-tools从26升级到27才出现,因此怀疑这是proguard新版本的bug,解决方法:

`方案一:禁用short方法inline,如下配置:-optimizations !method/inlining/short,或者直接关掉优化: -dontoptimize

方案二:确定哪个版本的proguard引入的问题,目前看到build-tools在26没问题,暂时猜测可能跟升级build-tools 27有关系,可以考虑回退。`

All 11 comments

此奔溃必现

试试在proguard里keep小米推送有关的类,然后重新打base包和patch包?

我这边小米push一直是keep的

方便的话把app/build/outputs/apk/tinkerPatch目录打包发到我的邮箱吧,或者用demo复现之后把这个目录打包发过来也行,我确认一下是不是合成的dex有问题吧:
[email protected]

tinkerPatch包 已经发到邮件 请查收

我遇到了同样的rejecting non-direct call to constructor,tinker version 1.9.9,请问这个问题找到原因了么?

java.lang.VerifyError:Verifier rejected class com.google.protobuf.micro.c: int com.google.protobuf.micro.c.a(int) failed to verify: int com.google.protobuf.micro.c.a(int): [0x1] rejecting non-direct call to constructor int com.google.protobuf.micro.f.<clinit>(int, int)Verifier rejected class com.google.protobuf.micro.c: void com.google.protobuf.micro.c.e(int, int) failed to verify: void com.google.protobuf.micro.c.e(int, int): [0x0] rejecting non-direct call to constructor int com.google.protobuf.micro.f.<clinit>(int, int) (declaration of 'com.google.protobuf.micro.c' appears in /data/user/0/com.smile.gifmaker/tinker/patch-7ad58aab/dex/tinker_classN.apk:classes4.dex)

 com.xiaomi.push.c.b$b.b(Unknown Source)
 com.google.protobuf.micro.e.c(Unknown Source)
 com.xiaomi.push.service.av.a(Unknown Source)
 com.xiaomi.e.f.c(Unknown Source)
 com.xiaomi.smack.h.o(Unknown Source)
 com.xiaomi.push.service.XMPushService.h(Unknown Source)
 com.xiaomi.push.service.XMPushService$d.a(Unknown Source)
 com.xiaomi.push.service.XMPushService$i.run(Unknown Source)
 com.xiaomi.push.service.bl$c.run(Unknown Source)

分析了一半,确定和proguard最近的变更有关,源码细节还没翻到,着急的可以先按照如下处理解决:
-optimizations !method/inlining/short,亲测有效;
完整分析过程:https://docs.google.com/document/d/1FOGbxa2Q93ur0xkGiiK-xa_suqzVSbqRorahkSn4iT4/edit?usp=sharing

结论概述:

打基准包留下来一个mapping,如上截图,意思如下:a混淆成a,并且原来的静态变量调用a的直接inline(short inline);

打热更新包的时候(tinkerPatchXXX),会先打一个目标APK,这时候会apply这个mapping;proguard在applyMapping的时候,先将a方法按照mapping保留了一个a方法,然后做inline操作,在inline的时候,尝试保持上个mapping的inline配置,但是由于mapping信息上不能识别是short还是uniqe,所以错误的直接把a方法完全inline到中,外部调用这个就会抛出上述错误; ---- 以上尚未考证源码,等阅读完再补充细节;

至此,我们基本确定了proguard在applyMapping上的问题,考虑到build-tools从26升级到27才出现,因此怀疑这是proguard新版本的bug,解决方法:

`方案一:禁用short方法inline,如下配置:-optimizations !method/inlining/short,或者直接关掉优化: -dontoptimize

方案二:确定哪个版本的proguard引入的问题,目前看到build-tools在26没问题,暂时猜测可能跟升级build-tools 27有关系,可以考虑回退。`

@scutqingbowang @shwenzhang @tomystang

已查明:
proguard的MappingReader里面默认会把inline也解析成method映射了,可以查看processClassMemberMapping()方法, 这个是proguard历史版本一直都有的问题,所以只要mapping里面有类似1000:1000:int a(int,int):0:0 -> 的映射时,下次applyMapping一定出错
proguard 6.0版本开始,对short method的inline长度判断,对android从默认长度为8改成了默认32,且新版本的proguard对/存在inline,导致android上部分短方法开始被inline,从而出现问题,详细代码可以阅读MethodInliner在proguard5.3.3的源码,以及6.0.1的源码。
解决方法:
回退到proguard 5.x版本,等待progurd修复这个问题,由于proguard不开源,所以目前只邮件给eric处理了;
禁用短方法内联:-optimizations !method/inlining/short

1005

在8.x以上的机器上,该问题表现为合成失败,因为在dexoat的过程中就检查错误了;在8.x(不包含)以下的机器上表现为运行失败VerifyError,也就是runtime才检查。

VerifyError的崩溃分布:
image
可以看到最高到API=25这个,因为从API=26开始,dexoat会提前检查了,并抛出Failure to verify dex file '/data/user/0/com.smile.gifmaker/tinker/patch-244dc6d0/dex/tinker_classN.apk': must have descriptor ()V错误。

@tomystang

Was this page helpful?
0 / 5 - 0 ratings