R8疑难杂症分析实战:外联优化设计缺陷引起的崩溃|得物技术

一、背景

R8作为谷歌官方的编译优化工具,在编译阶段会对字节码进行大规模修改,以追求包体优化和性能提升。但是Android应用开发者数量太过庞大,无论测试流程多么完善,终究难以避免在一些特定场景下出现问题。

近期我们在升级项目的AGP,遇到了一个指向系统SurfaceTexture类的native崩溃问题。经反编译分析发现问题最终指向了smali字节码中多余的一行new-instance指令。

该指令创建了一个SurfaceTexture对象,但是并未调用其<init>方法,这意味着构造方法没有执行,但是这个类重写了finalize方法,后续被gc回收时会调用其中的nativeFinalize这个JNI方法,最终在native层执行析构函数时触发了SIGNALL 11的内存访问错误.

二、复现问题

我们注意到多出来的new-instance指令下面紧接着的是对a0.e 类中的静态方法 i() 的调用,其内部实现就是SurfaceTexture的构造方法。这是典型的代码外联操作,即一段相同的代码在工程中多次出现,则会被抽出来单独作为一个静态函数,原先的调用点则替换成该函数的调用,这样可以减小代码体积,是常见的编码思路。

例如:

class Activity{
    void onCreate(){
        // ...
        String a = xx.xxx();
        String b = xx.xxx();
        Log.e("log",a+b);
        //...
    }


    void onReusme(){
        // ...
        String a = xx.xxx();
        String b = xx.xxx();
        Log.e("log",a+b);
        //...
    }


}
class Activity{
    void onCreate(){
        // ...
        Activity$Outline.log();
        //...
    }


    void onReusme(){
        // ...
        Activity$Outline.log();
        //...
    }
}
//外联生成的类
class Activity$Outline{
    public static void log(){
        String a = xx.xxx();
        String b = xx.xxx();
        Log.e("log",a+b);
    }
}

我们根据这个生成类的类名可以知道是R8中ApiModelOutline功能生成了这个类。

我们进到R8工程中检索下相关的关键字,再加上demo多次尝试,可以确认满足以下条件能够必现该问题:

  1. 使用了高于当前minSdkVersion的系统函数/变量(仅限系统类,自己写的无效)
  2. 用synchronized或者try语句块包裹了该调用,或者给该函数传参时有任何计算行为(除了传局部变量)。例如:
    1. new SurfaceTexture( getParmas() )
    2. new SurfaceTexture( if(enable) 1 : 2)
    3. new SurfaceTexture ( (boolean) enable )

三、问题分析

在确认复现条件之后,我们带着几个问题来逐个分析。

ApiModel外联是什么?

R8中的优化大多数跟包体优化有关,代码外联也是其中一种,但是外联的前提是代码重复的次数满足一定阈值,但是ApiModel会对所有调用了高版本系统API的代码做外联,包括只调用一次的场景。

ApiModel并非为了包体优化,我们通过R8工程的issueTracker(https://issuetracker.google.com/issues/333477035)检索到了相关的信息:

译:AGP新增的ApiModel功能是为了防止在低版本设备上不可能执行的代码引起类验证错误,从而降低App启动耗时。

从这篇介绍ART虚拟机类验证的文档(https://chromium.googlesource.com/chromium/src/+/HEAD/build/android/docs/class_verification_failures.md#chromium_s-solution)就能够理解上面这句话的含义:

ART虚拟机会在APK安装之后立刻执行 AOT clas

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值