Tinker: 下发补丁后,部分机型上报crash:java.lang.VerifyError...

Created on 24 May 2017  ·  35Comments  ·  Source: Tencent/tinker

异常类型:app运行时异常

tinker版本:1.7.7

gradle版本:2.10

是否使用热更新SDK:无

系统:Mac

堆栈/日志:
2017-05-23 20:04:43:504 10.3.3.5 28469 1 main MyMoney-CrashReport > -------------------------------------------------------------------
java.lang.VerifyError: Rejecting class io.reactivex.internal.operators.observable.ObservableZip because it failed compile-time verification (declaration of 'io.reactivex.internal.operators.observable.ObservableZip' appears in /data/user/0/com.mymoney/tinker/patch-125e62ff/dex/classes3.dex.jar)
at fgs.a(Observable.java:4448)
at fgs.a(Observable.java:3976)
at bgt.c(FinanceDataPresenter.java:61)
at bhm.m(FinanceProductFragment.java:176)
at bhl.j(BaseFinanceFragment.java:63)
at bhl.onActivityCreated(BaseFinanceFragment.java:38)
at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1970)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1051)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1207)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1572)
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:545)
at android.support.v4.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:163)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1106)
at android.support.v4.view.ViewPager.populate(ViewPager.java:952)
at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1474)
at android.view.View.measure(View.java:19146)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:607)
at android.support.design.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:674)
at android.view.View.measure(View.java:19146)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:223)
at android.view.View.measure(View.java:19146)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:223)
at android.support.v7.internal.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:124)
at android.view.View.measure(View.java:19146)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:223)
at android.view.View.measure(View.java:19146)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:223)
at android.view.View.measure(View.java:19146)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1723)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:788)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:648)
at android.view.View.measure(View.java:19146)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:223)
at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2690)
at android.view.View.measure(View.java:19146)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2521)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1485)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1739)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1366)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6753)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:896)
at android.view.Choreographer.doCallbacks(Choreographer.java:698)
at android.view.Choreographer.doFrame(Choreographer.java:633)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:882)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5710)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:900)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)

enhancement question

Most helpful comment

@HolenZhou
这个crash的原因是rxjava里的特殊代码逻辑加上art对aput这个指令的校验方式凑在一起产生的,可以尝试按下面步骤手动构造加以验证:

S1. 创建一个接口类ITestClass
S2. 创建一个类实现这个接口,如TestClass implements ITestClass
S3. 创建一个类,里面增加一个这样的方法:

void badMethod() {
    ITestClass[] arr = new TestClass[3];
    if (随便搞个条件) {
        arr = new ITestClass[3];
    }
    arr[0] = new TestClass();
}

然后把badMethod所在的类和TestClass分到同一个dex,写个demo加载这个dex,再尝试调用badMethod,就会出错了。

本质上这是因为art在校验aput指令的时候会去确认指向目标数组的寄存器的类型,如果因为分支语句导致有多种可能,则要求每个可能的类型都要能被resolve。由于补丁dex是分开进行dex2oat的,导致dex2oat在编译这个dex的时候找不到ITestClass,也就没法resolve,因此使badMethod所在的类被打上verifyerror标志。运行时一旦尝试加载有verifyerror标志的类,就会crash。

而直接安装完整的apk没问题,是因为apk里面所有符合classN命名的dex是一起做dex2oat的,这样就不会有某些类resolve不到的问题了。

暂时的解决方法: 分包的时候注意把rxjava相关的类全部分到同一个dex(不一定要在主dex)就可以了。

All 35 comments

是否出现过回退补丁的操作

@shwenzhang 没有,这是我们app线上下发补丁之后,收到的crash上报

@shwenzhang 同样出现这个问题,下发补丁后,执行RxJava zipWith方法的时候报出这个问题,没有做过回退补丁操作。

异常类型:app运行时异常
手机型号:如:华为麦芒4 RIO-AL00
手机系统版本:如:Android 6.0.1
tinker版本:1.7.9
gradle版本:3.3
是否使用热更新SDK: Bugly SDK
系统:Win10

堆栈/日志:
java.lang.VerifyError: Rejecting class io.reactivex.internal.operators.observable.ObservableZip because it failed compile-time verification (declaration of 'io.reactivex.internal.operators.observable.ObservableZip' appears in /data/user/0/com.mallestudio.gugu.app/tinker/patch-3d667f50/dex/classes2.dex.jar)
at io.reactivex.Observable.zipArray(Observable.java:4255)
at io.reactivex.Observable.zip(Observable.java:3627)
at io.reactivex.Observable.zipWith(Observable.java:12769)
at com.mallestudio.gugu.common.utils.rx.RxUtil.newIORetryHandler(RxUtil.java:19)
at com.mallestudio.gugu.modules.create.controllers.CreateController$2.apply(CreateController.java:280)
at com.mallestudio.gugu.modules.create.controllers.CreateController$2.apply(CreateController.java:277)
at io.reactivex.internal.operators.observable.ObservableInternalHelper$RetryWhenInner.apply(ObservableInternalHelper.java:292)
at io.reactivex.internal.operators.observable.ObservableInternalHelper$RetryWhenInner.apply(ObservableInternalHelper.java:278)
at io.reactivex.internal.operators.observable.ObservableRedo.subscribeActual(ObservableRedo.java:59)
at io.reactivex.Observable.subscribe(Observable.java:10179)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$1.run(ObservableSubscribeOn.java:39)
at io.reactivex.Scheduler$1.run(Scheduler.java:134)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:154)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:833)

Rejecting class io.reactivex.internal.operators.observable.ObservableZip because it failed compile-time verification (declaration of 'io.reactivex.internal.operators.observable.ObservableZip' 这个异常是指在加载类的时候,之前由于static部分出现了异常

@shwenzhang 这是应该是打补丁引起的问题吧,因为不打补丁之前是正常的。针对这个问题,现在有解决方案吗?

不一定是补丁引起的,这个问题可能有几个原因:1. 类的static 代码本身有bug 2. odex损坏 ,这个新版本有检测 3. 某些手机的问题

我跟踪了下这个问题,复现了一下,发现是必现的,应该跟手机没关系,加载补丁成功重启后,app可以正常启动,但进入使用了rx的zip操作符的模块就会crash,卸载补丁重启后恢复正常。我查看了代码,发现报crash这一块也只有这个zip操作符是static的方法,其他也没用到什么static的类或者字段。
odex损坏的问题我不太了解,我明天看一下。
@shwenzhang 以上是不是能提供什么线索定位下具体的问题呢?因为补丁合成后,其他模块都是没有问题的,只有使用了zip操作符的模块有问题。

@HolenZhou 你可以在tinker的demo上面先复现出来,然后把复现步骤跟demo的链接给我一下

@shwenzhang Hi,我复现了,Demo在:https://github.com/HolenZhou/tinker-sample-android 原因是因为把rx依赖分在非maindex中导致的,麻烦张大神有空帮忙看下是不是使用姿势不对

@HolenZhou
这个crash的原因是rxjava里的特殊代码逻辑加上art对aput这个指令的校验方式凑在一起产生的,可以尝试按下面步骤手动构造加以验证:

S1. 创建一个接口类ITestClass
S2. 创建一个类实现这个接口,如TestClass implements ITestClass
S3. 创建一个类,里面增加一个这样的方法:

void badMethod() {
    ITestClass[] arr = new TestClass[3];
    if (随便搞个条件) {
        arr = new ITestClass[3];
    }
    arr[0] = new TestClass();
}

然后把badMethod所在的类和TestClass分到同一个dex,写个demo加载这个dex,再尝试调用badMethod,就会出错了。

本质上这是因为art在校验aput指令的时候会去确认指向目标数组的寄存器的类型,如果因为分支语句导致有多种可能,则要求每个可能的类型都要能被resolve。由于补丁dex是分开进行dex2oat的,导致dex2oat在编译这个dex的时候找不到ITestClass,也就没法resolve,因此使badMethod所在的类被打上verifyerror标志。运行时一旦尝试加载有verifyerror标志的类,就会crash。

而直接安装完整的apk没问题,是因为apk里面所有符合classN命名的dex是一起做dex2oat的,这样就不会有某些类resolve不到的问题了。

暂时的解决方法: 分包的时候注意把rxjava相关的类全部分到同一个dex(不一定要在主dex)就可以了。

@HolenZhou 下个版本我考虑把所有的补丁放在同一个apk里面一起做dex2oat,可以解决这个问题

@tomystang @shwenzhang 多谢大神!目前我们的分包方案DexKnife只能明确指定第一个dex中的类,不能明确指定第二个dex以后的类。而且我提供的demo中是把rxjava相关的类都放在了dex2中(因为它只有两个dex),但还是出现相同的问题。所以我只能期待新版本了!

你指定把rx相关的类都放在主dex就可以了

我也出现同样的问题:

异常类型:app运行时异常

tinker版本:1.7.11

gradle版本:2.3.0

是否使用热更新SDK: Bugly SDK
系统:Win 7

手机:Meizu M3 Note

java.lang.VerifyError
Rejecting class io.reactivex.internal.operators.observable.ObservableCombineLatest because it failed compile-time verification (declaration of 'io.reactivex.internal.operators.observable.ObservableCombineLatest' appears in /data/data/com.wanguqu.app/tinker/patch-5fd48592/dex/classes2.dex.jar)

@shwenzhang 我试了把rx相关的类都放在主dex,但因为目前项目的分包方案不是很成熟,无法智能排除不需要放在maindex中的类,而且rx相关的类有多,所以一指定到主dex就会报错 "Too many classes in --main-dex-list, main dex capacity exceeded",而且这确实也不是根本的解决办法哦

这个问题其实很难遇到,这个库的某些特殊写法导致。下个版本会解决,其实只要把rx的相关类统一放到一起就行,你可以强制将他们指定不在主dex

等待解决,也出现了同样的问题,比较严重。线上已更新的补丁的用户,暂时拿他们没办法。

@shwenzhang @tomystang
因为rx的方法数太多放在主dex会导致方法数溢出,按照建议,我将rx相关的类都全部移出主dex,放在dex2中了,并在demo中测试了:https://github.com/HolenZhou/tinker-sample-android ,发现依然会出现相同的crash,麻烦看一下是不是有什么其他的原因造成的呢?

@HolenZhou
我用你的repo上的demo在7.1.1和6.0.1的系统上都试过了,在补丁生效之后点“test rxzip"按钮没有crash哦。

@tomystang 刚我在6.0.1一加和5.0.2红米note2上又试了一遍,确实是crash了哦,不知道为什么你不能复现啊,我是打的Release包,然后改代码生成补丁包,操作应该没问题,而且报的错误都是一样的。

@HolenZhou
要不你留个邮箱,我把我这边编的demo发给你看看你那边能不能复现吧。

@tomystang [email protected]

@tomystang 已回复邮件,用assembleRelease和tinkerPatchRelease构建出来的包,确实是crash的

@shwenzhang 同样遇到上面所述问题,冒昧问一下,预计能什么时候修复这个问题发布新版本?

用的版本是1.7.11

这个问题不修复之前 热更新用不了了。。。。

@HolenZhou @yangwuan55 可以看看dev分支,这个问题应该已经修复

try with 1.8.0

各位可以尝试本人的分包方案来解决这个问题,http://www.jianshu.com/p/2a0bef2e3f61

1.8.1应该不会有这个问题

我在三星手机上出现了类似的pre-verify的问题,系统是4.4和4.3。但是在华为手机上没有问题,系统是6.0。
java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
10-20 17:26:33.541 27601-27601/? W/System.err: at com.yixin.itoumi.c.a.d.(Unknown Source)
10-20 17:26:33.541 27601-27601/? W/System.err: at com.yixin.itoumi.c.a.d.a(Unknown Source)
10-20 17:26:33.541 27601-27601/? W/System.err: at com.yixin.itoumi.c.b.(Unknown Source)
10-20 17:26:33.541 27601-27601/? W/System.err: at com.yixin.itoumi.c.b.a(Unknown Source)
10-20 17:26:33.541 27601-27601/? W/System.err: at com.yixin.itoumi.ApplicationMy.onCreate(Unknown Source)
10-20 17:26:33.541 27601-27601/? W/System.err: at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1025)
10-20 17:26:33.541 27601-27601/? W/System.err: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4551)
10-20 17:26:33.541 27601-27601/? W/System.err: at android.app.ActivityThread.access$1500(ActivityThread.java:163)
10-20 17:26:33.541 27601-27601/? W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1317)
10-20 17:26:33.541 27601-27601/? W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102)
10-20 17:26:33.541 27601-27601/? W/System.err: at android.os.Looper.loop(Looper.java:157)
10-20 17:26:33.541 27601-27601/? W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5335)
10-20 17:26:33.541 27601-27601/? W/System.err: at java.lang.reflect.Method.invokeNative(Native Method)
10-20 17:26:33.541 27601-27601/? W/System.err: at java.lang.reflect.Method.invoke(Method.java:515)
10-20 17:26:33.541 27601-27601/? W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
10-20 17:26:33.541 27601-27601/? W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
10-20 17:26:33.541 27601-27601/? W/System.err: at dalvik.system.NativeStart.main(Native Method)
10-20 17:26:33.541 27601-27601/? E/Debug Message - > >: 崩溃时间:2017-10-20 17:26:33
10-20 17:26:33.541 27601-27601/? E/Debug Message - > >: 崩溃简短信息:Class ref in pre-verified class resolved to unexpected implementation
10-20 17:26:33.541 27601-27601/? E/Debug Message - > >: 崩溃原因:null
10-20 17:26:33.541 27601-27601/? E/Debug Message - > >: 崩溃线程名称:main崩溃线程ID:1

“下个版本我考虑把所有的补丁放在同一个apk里面一起做dex2oat,可以解决这个问题”

目前在使用360加固的时候,仍出现了这个问题。加固模式下有采取类似地措施吗?
@shwenzhang

“下个版本我考虑把所有的补丁放在同一个apk里面一起做dex2oat,可以解决这个问题”

目前在使用360加固的时候,仍出现了这个问题。加固模式下有采取类似地措施吗?
@shwenzhang

我看到tinker日志是合到一起dex2oat但还是报这个错,是用了梆梆加固

@hqzxzwb 哥们一样的错阿。解决了吗

@hqzxzwb @shwenzhang 把reactivex都配到dex.loader[]下面好了- -!

Was this page helpful?
0 / 5 - 0 ratings