使用ASM进行字节码插桩

大家对于插桩这个词肯定是第一次听说,简单来说,插桩就是将一段代码通过某种策略插入到另一段代码,或替换另一段代码。那么,如何使用ASM进行字节码插桩呢?

使用ASM进行字节码插桩

1.什么是ASM

ASM是生成和转换已编译的Java类工具,就是我们插桩需要使用的工具。

2.两种API

ASM提供了两种API来生成和转换已编译类,一个是核心API,以基于事件形式来表示类;另一个是树API,以基于对象形式来表示类。

3.基于事件形式

我们通过上面的基础知识,了解到类的结构,类包含字段,方法,指令等;基于事件的API把类看作是一系列事件来表示,每一个类的事件表示一个类的元素。类似解析XML的SAX

4.基于对象形式

使用ASM进行字节码插桩

基于对象的API将类表示成一棵对象树,每个对象表示类的一部分。类似解析XML的DOM

5.优缺点比较

事件API内存占用少于对象API,因为事件API不需要在内存中创建和存储对象树。

事件API实现难度比对象API大,因为事件API在任意时刻类中只有一个元素可使用,但是对象API能获得整个类。

插桩实践

目标 : 删除所有以test开头的方法

接下来我们来完成一个非常小的需求,删除所有以test开头的方法。为什么说这是一个小需求,因为这并不涉及指令的操作,所有操作通过方法名完成即可。通过完成这个demo,只是抛砖引玉。如若后期需要,可以逐步深入到指令级别替换。

1.新建buildSrc目录,用来存放源代码位置。针对不同语言可以新建不同目录。

使用ASM进行字节码插桩

2.在buildSrc的gradle文件中我们需要配置如下代码。

3.重写Transform API在groovy目录下新建一个groovy类并继承Transform,注意导包com.android.build.api.transform,并实现抽象方法和transform方法。

4.实现字节码修改逻辑

Transform我们已经定义完成,接下来就要针对读入的字节码进行修改。我们采用对象API进行解析class文件。一共就是3个步骤:

(1)将输入流转化为ClassNode.

(2)处理ClassNode,这里就是我们的业务逻辑所在。

(3)将ClassNode转为字节数组输出。

5.上面我们完成了字节码修改逻辑以及定义Transform,但是并没有完成插件的定义。结合Transform API我们了解到,需要将我们自定义的Transform注册到插件中。

6.插件完成了,但是怎么才能对外使用呢?上面我们说到,我们采取3种插件形式之一的buildSrc。我们上文中创建了plugin.properties文件。只需要在该文件中编辑实现类即可。

7.应用方应用插件,在应用方的gradle文件中做如下配置。

原创文章,作者:金香槟运营,如若转载,请注明出处:https://www.jxbin.com/72032.html