字节码插桩介绍

什么是字节码?

Java 字节码是Java虚拟机执行的一种指令格式。Java源文件经Java编译器后得到Java字节码(.class)文件。Java字节码(.class)文件可以看作是Java虚拟机的可执行文件。这些字节码(.class)文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)

如何查看字节码

这里拿AndroidStudio举例,所有基于IDEA的IDE应该都一样。
在Settings -> Tools中添加External Tools,输入Name和下面三要素,保存即可

  • $JDKPath$\bin\javap
  • -c -verbose $FileClass$
  • $OutputPath$

showbytesetting.png
每次生成字节码之前记得先build/rebuild一下工程,不然会失败
showbytecode.png

简单分析下字节码构成

byte1.png

byte2.png

byte3.png

  • kotlin文件查看方式

showkotlin.png

字节码编程框架

字节码编程技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。字节码编程框架即用于处理Java字节码的类库。常用的字节码编程框架有AspectJJavassistASM等。

使用场景

  • 代码生成。除了 Dagger、ButterKnife 这些常用的注解生成框架,Protocol Buffers、数据库 ORM 框架也都会在编译过程生成代码。代码生成隔离了复杂的内部实现,让开发更加简单高效,而且也减少了手工重复的劳动量,降低了出错的可能性。
  • 代码监控。除了网络监控和耗电监控,我们可以利用编译插桩技术实现各种各样的性能监控。为什么不直接在源码中实现监控功能呢?首先我们不一定有第三方 SDK 的源码,其次某些调用点可能会非常分散,例如想监控代码中所有 new Thread() 调用,通过源码的方式并不那么容易实现。
  • 代码修改。我们在这个场景拥有无限的发挥空间,例如某些第三方 SDK 库没有源码,我们可以给它内部的一个崩溃函数增加 try catch,或者说替换它的图片库等。我们也可以通过代码修改实现无痕埋点。
  • 代码分析。上一期我讲到持续集成,里面的自定义代码检查就可以使用编译插桩技术实现。例如检查代码中的 new Thread() 调用、检查代码中的一些敏感权限使用等。事实上,Findbugs 这些第三方的代码检查工具也同样使用的是编译插桩技术实现。

插桩过程

App构建是将java/kotlin代码编译为.class文件,然后打包成dex文件之后输出apk

bytecodeprogress.png

所以我们需要在class文件转换为dex之前,去操作class文件的增改。
在安卓中,Gradle1.5以后提供了transform-api可以在代码转化为.class文件之后再打包成dex文件之前对它进行处理,所以我们可以自定义transform,在app的compileDebugJavaWithJavac这个gradle task之后就会走我们自定义的transform

插桩实践

Javassist+gradle transform+annotation 实现方法耗时统计

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享