ASMDex实践总结

ASMDex字节码插桩技术是AOP编程中一个重要的知识点。ASM技术的优势在于代码侵入性小,使用方式灵活。缺点在于上手难度较大。下面针对ASM技术实践时遇到的一些问题进行总结。

一、ASM使用原理

android开发时,我们都知道,在打包过程中,是先将java文件编译成class文件,之后再把class文件编译成dex文件。如果我们想要对代码进行一些修改操作的话,可以在class文件打包成dex文件的过程中,扫描代码,找出我们想要修改的代码进行修改。ASM可以帮助我们重新生成class文件,把处理后的代码生成class文件,之后打包成dex文件。

二、gradle配置

打包的过程是gradle帮助我们实现的,通过自己定义的gradle文件,可以帮助我们实现修改代码的操作,之后在打包编译阶段,运行gradle文件时,就会执行我们修改代码相关的gradle文件,运行其中的代码进行修改。

gradle作为一个插件,其目录结构分为groovy目录和resources目录。其中groovy目录是用于编写gradle程序的,都是以groovy后缀结尾的文件,其语言兼容java语言。resources目录主要是配置一个properties文件,使得在引用插件时,可以通过该文件的名字找到插件。通常,都会有一个自定义的类,继承plugin类,作为插件的入口。该类配置在properties文件中。

三、gradle发布与引用

在我们自定义的gradle文件中,通常需要配置名字与版本号,这两项决定了我们引用的gradle插件版本,当我们更新了插件的代码后,需要重新发布,并升级其版本。之后再引用插件的地方,更新其版本号即可。

发布到远程仓库可以借助发布网站及其提供的gradle配置项,修改项目中相关配置,使用新生成的task完成发布。值得一提的是,发布后不会马上得到更新,而是需要进行审核。

四、Transform API

Android Gradle1.5版本后,提供了Transform API,允许第三方插件在打包过程中对class文件进行操作。我们可以通过Transform遍历class文件,并进行修改替换。

使用时,我们要自定义一个类继承Transform类,并实现其中的方法,做到遍历时对遍历得到的信息进行处理,如增加Log打印,插入修改代码。

五、Java字节码学习

我们项目中的Java文件,在打包编译时会被翻译成字节码,使用javac命令就可以将Java文件编译成字节码文件。

打开字节码文件,可以看到是一堆16进制的字节。这些字节,从左到右依次表示,魔数,版本号,常量池,访问标志,类索引,父类索引,接口索引,字段表集合,方法以及属性。

魔数是用来区分文件类型的标志。

版本号分为主版本和次版本号。

常量池是class文件的资源仓库,主要存储两大类常量,分为字面量和符号引用。

访问标志信息包括该class文件是类还是接口,是否被定义为public,是否是abstract,如果是类,是否被声明成final。

类索引用于确定类的全限定名。

父类索引与类索引一样。

接口索引提供了接口数量和接口的表。

字段表用于描述类和接口中声明的变量。

方法的字节码比较复杂,前六个字节表示索引以及属性长度。剩下的根据字节码表进行翻译,可以表达将null推送到栈顶,将Int型1推送到栈顶,将引用变量推送到栈顶等等。

六、UTF-8编码

UTF-8编码和ANSI、GBK等常在一起提及。

很早以前,一批人,决定用8个可以开关的晶体管组合成不同的状态,以表示世界上的万物,他们称之为“字节”。8个字节可以组成2的8次方,共256种状态。其中0-32用来表示控制码,如00X10表示终端换行,00X07终端向人嘟嘟叫。之后又把空格,数字,英文以及符号等通过这种形式表示,编码到了127号。这就是ANSI编码。

后来随着世界上使用计算机的人越来越多,越来越多的符号及文字被引入,把一些横线竖线等形状编码,从128一直编到了255。从128-255这一页的字符集被称为“扩展字符集”。

后来在中国人使用时为了解决汉字问题,规定小于127的编码还保留原意,大于127的连在一起的字符就表示汉字,使用高位和低位共同组成。高位低位共同组成的编码,又重新编码了一次0-127,这样的称为全角字符。而原来的只有8字节的编码,称为半角字符。

中国人看到这样编码很不错,就成这种方案为GB2312,它是ASCII的扩展。

之后发现中国文字实在是太多了,又对其进行了一次扩展,称之为GBK。之后加入了少数民族文字,又扩展成为GBK18030。

当时每个国家都像中国一样,搞了一套自己的编码,但是各国之间使用时就乱套了,终于ISO(国际标准化组织)看不下去了,站了出来,出了一套UNICODE编码来统一世界上所有文字。

UNICODE在订制时并没有考虑与其他编码的兼容,于是GBK与UNICODE在保存打开时就会出现乱码。

当计算机时代到来,UNICODE的传输也出现了问题。于是面向众多传输,UTF(UCS Transfer Format)标准出现了。UTF-8就是传输时一次传输8位,而UTF-16是传输时一次传输16位。

七、ClassVisitor与MethodVisitor

ASM在读取.class文件内容时,会按照递此顺序进行调用。每拜访一个结构中的成员都会使用相应接口,相应关系如下:

Class-ClassVisitor

Field-FieldVisitor

Method-MethodVisitor

Annotation-AnnotationVisitor

各种Visitor中的方法较多,就不一一介绍了。总之,遍历时,我们可以获取到类,方法等属性信息,可以根据这些信息建立筛选条件,最终找到我们想要修改的类或方法等。

八、如何修改

ASM提供了AdviceAdapter工具类用于在method字节码中插入增强代码,onMethodEnter、onMethodExit等是比较好的切入点。

插入时要了解字节码指令,与栈帧的操作。

 

本文只是对自己做过的项目进行一个整理,梳理出一个ASM代码增强的大概流程,以后有机会,还要深入研究。

结尾附上学习参考资料:

UTF-8编码知识 :一文看懂UTF-8

Java字节码:一文看懂Java字节码

ASM自动埋点方案实践:ASM自动埋点方案实践

 

 

 

你可能感兴趣的:(个人总结)