一、背景
R8作为谷歌官方的编译优化工具,在编译阶段会对字节码进行大规模修改,以追求包体优化和性能提升。但是Android应用开发者数量太过庞大,无论测试流程多么完善,终究难以避免在一些特定场景下出现问题。
近期我们在升级项目的AGP,遇到了一个指向系统SurfaceTexture类的native崩溃问题。经反编译分析发现问题最终指向了smali字节码中多余的一行new-instance指令。


该指令创建了一个SurfaceTexture对象,但是并未调用其


二、复现问题
我们注意到多出来的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多次尝试,可以确认满足以下条件能够必现该问题:
- 使用了高于当前minSdkVersion的系统函数/变量(仅限系统类,自己写的无效)
- 用synchronized或者try语句块包裹了该调用,或者给该函数传参时有任何计算行为(除了传局部变量)。例如:
- new SurfaceTexture( getParmas() )
- new SurfaceTexture( if(enable) 1 : 2)
- new SurfaceTexture ( (boolean) enable )
未经允许不得转载:紫竹林-程序员中文网 » R8疑难杂症分析实战:外联优化设计缺陷引起的崩溃|得物技术