Android 编译优化探索2 Hack字节码
Posted 不会写代码的丝丽
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 编译优化探索2 Hack字节码相关的知识,希望对你有一定的参考价值。
前言
承接上文:
Android 编译优化探索
再最初的版本中需要编译kotlin
才能实现Hack
自定义增量,但是还一个任务同样也及其耗时org.gradle.api.tasks.compile.JavaCompile
,但是此任务不在kotlin
插件,难道我们又要自己编译java
插件?就连鄙人导师都觉得编译kotlin插件很麻烦。于是乎最后决定采用动态修改字节码的方式实现。作者使用javassist
作为字节码编辑器。
JavaCompile创建流程
在android
工程中JavaCompile
的创建是由AGP插件创建,其核心创建核心流程如下
//TaskFactoryUtils.kt
fun <T : Task> TaskContainer.registerTask(
creationAction: TaskCreationAction<T>,
secondaryPreConfigAction: PreConfigAction? = null,
secondaryAction: TaskConfigAction<in T>? = null,
secondaryProviderCallback: TaskProviderCallback<T>? = null
): TaskProvider<T>
val actionWrapper = TaskAction(creationAction, secondaryPreConfigAction, secondaryAction, secondaryProviderCallback)
//调用register注册一个task,第一个参数task名字,第二个参数task类型,第三参数注入构造参数
//这里的creationAction是JavaCompileCreationAction
//creationAction.name 任务名字根据变体变化 比如tiya变体就为compileTiyaDebugJavaWithJavac
//creationAction.type返回的一个class类型:JavaCompile::class.java
return this.register(creationAction.name, creationAction.type, actionWrapper)
.also provider ->
actionWrapper.postRegisterHook(provider)
我们最后看看这个
class JavaCompileCreationAction(
private val variantScope: VariantScope,
private val processAnnotationsTaskCreated: Boolean
) : TaskCreationAction<JavaCompile>()
//...略
override val name: String
get() = variantScope.getTaskName("compile", "JavaWithJavac")
override val type: Class<JavaCompile>
get() = JavaCompile::class.java
//...略
知道大致流程我就可以根据如下思想进行操作:
- 将
JavaCompileCreationAction
的type
替换成自己的JavaCompile类即可
class JavaCompileCreationAction(
private val variantScope: VariantScope,
private val processAnnotationsTaskCreated: Boolean
) : TaskCreationAction<JavaCompile>()
//...略
//替换为HackJavaCompile
override val type: Class<JavaCompile>
get() = HackJavaCompile::class.java
//...略
- 抢在gradle的默认的类加载器之前修改类并强行加载(双亲委托知识)
因次插件会在根工程之后直接启用。
- 处理父加载器引用子加载器的类问题
这个问题也是比较头疼的一个地方,在起初使用jdbc那样委托当前线程的类加载器去加载,然后通过反射去调用子类函数,但是最后发现当前线程类加载器居然是一个较为顶层的类加载器。最后采用所有引用的类都交付顶层类加载器加载,并禁使用lambda表达式(编译器会创建一个新的类,并用子类加载器加载)。
最后解决办法
如以下伪代码
以上是关于Android 编译优化探索2 Hack字节码的主要内容,如果未能解决你的问题,请参考以下文章
字节码插桩Android 打包流程 | Android 中的字节码操作方式 | AOP 面向切面编程 | APT 编译时技术