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


一、背景

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

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

该指令创建了一个SurfaceTexture对象,但是并未调用其方法,这意味着构造方法没有执行,但是这个类重写了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 )
未经允许不得转载:紫竹林-程序员中文网 » R8疑难杂症分析实战:外联优化设计缺陷引起的崩溃|得物技术

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
关于我们 免责申明 意见反馈 隐私政策
程序员中文网:公益在线网站,帮助学习者快速成长!
关注微信 技术交流
推荐文章
每天精选资源文章推送
推荐文章
随时随地碎片化学习
推荐文章
发现有趣的