Android 编译优化探索2 Hack字节码

Android 编译优化探索2 Hack字节码,第1张

Android 编译优化探索2 Hack字节码 前言

承接上文:
Android 编译优化探索

再最初的版本中需要编译kotlin才能实现Hack自定义增量,但是还一个任务同样也及其耗时org.gradle.api.tasks.compile.JavaCompile,但是此任务不在kotlin插件,难道我们又要自己编译java插件?就连鄙人导师都觉得编译kotlin插件很麻烦。于是乎最后决定采用动态修改字节码的方式实现。作者使用javassist作为字节码编辑器。

JavaCompile创建流程

在android工程中JavaCompile的创建是由AGP插件创建,其核心创建核心流程如下

//TaskFactoryUtils.kt

fun  TaskContainer.registerTask(
    creationAction: TaskCreationAction,
    secondaryPreConfigAction: PreConfigAction? = null,
    secondaryAction: TaskConfigAction? = null,
    secondaryProviderCallback: TaskProviderCallback? = null
): TaskProvider {
    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() {
	//...略
	  override val name: String
        get() = variantScope.getTaskName("compile", "JavaWithJavac")

    override val type: Class
        get() = JavaCompile::class.java
	//...略
}

知道大致流程我就可以根据如下思想进行 *** 作:

    将JavaCompileCreationAction的type替换成自己的JavaCompile类即可
class JavaCompileCreationAction(
    private val variantScope: VariantScope,
    private val processAnnotationsTaskCreated: Boolean
) : TaskCreationAction() {
	//...略
	//替换为HackJavaCompile 
    override val type: Class
        get() = HackJavaCompile::class.java
	//...略
}
    抢在gradle的默认的类加载器之前修改类并强行加载(双亲委托知识)

因次插件会在根工程之后直接启用。

    处理父加载器引用子加载器的类问题
    这个问题也是比较头疼的一个地方,在起初使用jdbc那样委托当前线程的类加载器去加载,然后通过反射去调用子类函数,但是最后发现当前线程类加载器居然是一个较为顶层的类加载器。最后采用所有引用的类都交付顶层类加载器加载,并禁使用lambda表达式(编译器会创建一个新的类,并用子类加载器加载)。

最后解决办法

如以下伪代码

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5719268.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存