美文网首页
gradle 如何生成 _Decoreted 包装类的

gradle 如何生成 _Decoreted 包装类的

作者: moasm | 来源:发表于2021-11-18 20:09 被阅读0次

    how and where gradle generate _Decorated classes like DefaultProject_Decorated.

    0. 背景

    xxxTask --> xxxxTask_Decorated ??
    经常调试gradle的小伙伴, 一定有遇到 一些 以_Decorated 结尾的类.
    比如 org.gradle.api.Project的实现类 org.gradle.api.internal.project.DefaultProject, 我们在下断点调试他的时候, 看到的是
    org.gradle.api.internal.project.DefaultProject_Decorated 类.
    这里面有什么故事呢?

    ps: _Decorated, 网上资料真的非常稀少:


    image.png

    一个简略的介绍:
    stackoverflow.com/.../how-to-get-projects-implementation-in-gradle

    DefaultProject_Decorated
    • 大多数人是网络信息的获取者. 这次我们来做网络信息的生成者:)
    • 现在我们开始调查 _Decorated 包装类的'前世今生'

    1. 从终点开始, 生成的_Decorated类的地方

    通过扫描源码关键字, 结合一些推理分析, 找到疑似生成X_Decorated类的地方


    image.png

    2> 向下跟进, gradle如何利用ASM生成类X_Decorated类的,

    -- 以及想办法dump出 X_Decorated字节码, 观察其的一些特殊实现.

    继续'向下' X_Decorated类如何从ASM生成 并注册到classLoader 并实例化的

    defineDecorator:81, ClassLoaderUtils (org.gradle.internal.classloader)
    define:58, AsmClassGenerator (org.gradle.model.internal.asm)
    define:54, AsmClassGenerator (org.gradle.model.internal.asm)
    generate:1764, AsmBackedClassGenerator$ClassBuilderImpl (org.gradle.internal.instantiation.generator)
    generateUnderLock:227, AbstractClassGenerator (org.gradle.internal.instantiation.generator)
    lambda$new$0:119, AbstractClassGenerator (org.gradle.internal.instantiation.generator)
    transform:-1, 1964650551 (org.gradle.internal.instantiation.generator.AbstractClassGenerator$$Lambda$18)
    get:124, DefaultCrossBuildInMemoryCacheFactory$AbstractCrossBuildInMemoryCache (org.gradle.cache.internal)
    generate:167, AbstractClassGenerator (org.gradle.internal.instantiation.generator)
    generate:130, AsmBackedClassGenerator (org.gradle.internal.instantiation.generator)
    
    image.png

    参数clazzBytes即为生成的类的字节码, 将其导出成文件, 可观察生成类的具体实现
    直接在调试器的Evaluate窗口写如下代码:


    image.png image.png

    使用javap观察字节码:

    $ javap -p -v /home/moasm/xx.class
    
    image.png

    如此, 我们就学会了gradle研究的一个利器: dump X_Decorated类的字节码, 观察gradle运行时的 _Decorated class的实现.

    - 另外提一下, 如上可以看到, X_Decorated类的生成方式是:
    -   使用ASM在X的基础上补一些字节码后生成的字节码, 得到数组byte[] classBytes. 
    -   然后通过反射调用ClassLoader.defineClass()传入名字,字节码byte数组等信息, 生成的运行时所需的类.
    

    从ASM获取字节码数组:


    image.png

    通过生成类的字节码数组等信息, 生成运行时类:


    image.png
    • 小结: 如上 我们就基本搞清楚了一个 X_Decorated类是如何生成了了.

    3. 向上,栈回溯: 往发起调用, 请求生成X_Decorated类的方向看

    -- 以AGP的一个task的创建为例跟进 (com.android.build.gradle.internal.tasks.MergeNativeLibsTask)

    下断点


    image.png

    取得调用栈,精简栈, 观察栈:

    generate:163, AbstractClassGenerator (org.gradle.internal.instantiation.generator)
    generate:130, AsmBackedClassGenerator (org.gradle.internal.instantiation.generator)
    transform:59, Jsr330ConstructorSelector$1 (org.gradle.internal.instantiation.generator)
    transform:54, Jsr330ConstructorSelector$1 (org.gradle.internal.instantiation.generator)
    get:124, DefaultCrossBuildInMemoryCacheFactory$AbstractCrossBuildInMemoryCache (org.gradle.cache.internal)
    forType:54, Jsr330ConstructorSelector (org.gradle.internal.instantiation.generator)
    forParams:49, Jsr330ConstructorSelector (org.gradle.internal.instantiation.generator)
    doCreate:61, DependencyInjectingInstantiator (org.gradle.internal.instantiation.generator)
    newInstanceWithDisplayName:50, DependencyInjectingInstantiator (org.gradle.internal.instantiation.generator)
    call:90, TaskFactory$1 (org.gradle.api.internal.project.taskfactory)
    call:84, TaskFactory$1 (org.gradle.api.internal.project.taskfactory)
    uncheckedCall:442, GUtil (org.gradle.util)
    injectIntoNewInstance:201, AbstractTask (org.gradle.api.internal)
    create:84, TaskFactory (org.gradle.api.internal.project.taskfactory)
    create:48, AnnotationProcessingTaskFactory (org.gradle.api.internal.project.taskfactory)
    createTask:326, DefaultTaskContainer (org.gradle.api.internal.tasks)
    access$200:77, DefaultTaskContainer (org.gradle.api.internal.tasks)
    createDomainObject:701, DefaultTaskContainer$TaskCreatingProvider (org.gradle.api.internal.tasks)
    createDomainObject:658, DefaultTaskContainer$TaskCreatingProvider (org.gradle.api.internal.tasks)
    tryCreate:941, DefaultNamedDomainObjectCollection$AbstractDomainObjectCreatingProvider (org.gradle.api.internal)
    access$1401:658, DefaultTaskContainer$TaskCreatingProvider (org.gradle.api.internal.tasks)
    run:684, DefaultTaskContainer$TaskCreatingProvider$1 (org.gradle.api.internal.tasks)
    ...
    
    tryCreate:680, DefaultTaskContainer$TaskCreatingProvider (org.gradle.api.internal.tasks)
    ...
    addLaterInternal:765, DefaultTaskContainer (org.gradle.api.internal.tasks)
    access$900:77, DefaultTaskContainer (org.gradle.api.internal.tasks)
    call:420, DefaultTaskContainer$3 (org.gradle.api.internal.tasks)
    call:407, DefaultTaskContainer$3 (org.gradle.api.internal.tasks)
    ...
    registerTask:407, DefaultTaskContainer (org.gradle.api.internal.tasks)
    register:379, DefaultTaskContainer (org.gradle.api.internal.tasks)
    // -------------↑ gradle如何创建task ↑ --------------------------------------------------------------------------
    
    registerTask:37, TaskFactoryUtils (com.android.build.gradle.internal.tasks.factory)
    register:45, TaskFactoryImpl (com.android.build.gradle.internal.tasks.factory)
    createMergeJniLibFoldersTasks:956, TaskManager (com.android.build.gradle.internal)
    createTasksForVariantScope:187, ApplicationTaskManager (com.android.build.gradle.internal)
    createTasksForVariant:331, VariantManager (com.android.build.gradle.internal)
    createVariantsAndTasks:207, VariantManager (com.android.build.gradle.internal)
    createAndroidTasks:671, BasePlugin (com.android.build.gradle.internal.plugins)
    call:-1, 1828560501 (com.android.build.gradle.internal.plugins.BasePlugin$$Lambda$552)
    record:82, ThreadRecorder (com.android.builder.profile)
    lambda$createTasks$4:582, BasePlugin (com.android.build.gradle.internal.plugins)
    accept:-1, 1056623483 (com.android.build.gradle.internal.plugins.BasePlugin$$Lambda$546)
    execute:37, CrashReporting$afterEvaluate$1 (com.android.build.gradle.internal.crash)
    execute:-1, CrashReporting$afterEvaluate$1 (com.android.build.gradle.internal.crash)
    // -------------↑ android AGP插件开始 ↑ -------------------------------------------------------------------------
    ....
    afterEvaluate:-1, $Proxy36 (com.sun.proxy)  // *********某个Project的afterEvaluate()回调
    ...
    call:94, DefaultBuildOperationExecutor (org.gradle.internal.operations)
    ...
    execute:75, ForwardClientInput (org.gradle.launcher.daemon.server.exec)
    ...
    proceed:104, DaemonCommandExecution (org.gradle.launcher.daemon.server.api)
    run:52, StartBuildOrRespondWithBusy$1 (org.gradle.launcher.daemon.server.exec)
    run:297, DaemonStateCoordinator$1 (org.gradle.launcher.daemon.server)
    onExecute:64, ExecutorPolicy$CatchAndRecordFailures (org.gradle.internal.concurrent)
    run:48, ManagedExecutorImpl$1 (org.gradle.internal.concurrent)
    runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
    run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
    run:56, ThreadFactoryImpl$ManagedThreadRunnable (org.gradle.internal.concurrent)
    run:748, Thread (java.lang)
    
    • 画外音: 如上精简栈, 容易理解AGP的task创建流程.
      经常会有这样, 从终点栈回溯研究一个流程, 比正向阅读代码跟进流程容易的多. 尤其在gradle这种大量设计模式应用的地方, 一些地方, 静态阅读很难说清楚走向.
    简单来说, AGP创建一个XXTask 是通过事先已经从Project拿到的taskContiner去创建. 
      而taskContainer将创建task的工作交给TaskFactor.
        TaskFactory会调用到AsmBackedClassGenerator 将实际生成的类变成XXTask_Decorated
           (从TaskFactory 到 AsmBackedClassGenerator 这段不管是动态调试 还是静态阅读代码 
             都是很难看清流程的, 通过这么一次栈回溯 不仅突破当前问题, 并且可以学习gradle的
            一些封装套路, 为以后更好更快研究gradle打下基础)
    
          如上我说的很'轻巧' 但若不亲身实践下 看了也几乎没有什么意义  -- 除非带着跟我一样的问题 直接拿走答案. 
    

    4. dump X_Decorated类的字节码, 有什么用呢?

    • 比如我们看gradle源码 DefaultProject 有的地方写了"Decoration takes care of the implementation"
      大意思就是 这个方法在装饰类实现.


      image.png

    此时我们就能使用上面第二节提到的办法, 拿到 DefaultProject_Decorated 的字节码, 直接观察getProviders的实现


    image.png

    剩下的问题, 就是继续看grade源码去研究该研究的问题了.
    如此我们就成功越过一个 _Decorated 关于的, 阻碍我们研究gradle的障碍点了.

    小结, 研究gradle的装饰类 X_Decorated 的相关流程, 我们不仅了解了问题本身,
    并且使用的 '站在栈终点回溯' 等一些研究方法, 也是重要经验.

    5. 实际案例

    研究 _Decorated 类的实现, 只是我们调查/解决问题, 必要路径中的一步.
    在接管AGP的 class翻译dex后, 我们遇到了只在部分windows电脑上游的 MergeNativeLibsTask 耗时过长问题.
    通过我们的自有日志可以观察到:


    image.png

    该例, 构建耗时263秒. 其中mergeXXXNativeLibs 耗时198秒.
    虽然不科学 但是估算范围基本是准的: 这个一行代码都没改的增量编译 因为 mergeXXXNativeLibs 而拖慢了月200秒.
    即若修复他的问题, 则此次热编译耗时应该在60秒左右.

    前面我们做了AGP的class翻译dex的接管. dex翻译的task参数相对来说, 清晰一些, 所以我们实现起来不难.
    但是 mergeXXXNativeLibs 的输入参数稍复杂一些. 既为了避免硬编码, 也为了只是调查清楚问题点, 并做出优化,
    我们都需要调查清楚 mergeXXXNativeLibs task的创建, 运行, inputs参数填充等流程.
    有得深入, 方能浅出.

     // TODO ....待续....

    相关文章

      网友评论

          本文标题:gradle 如何生成 _Decoreted 包装类的

          本文链接:https://www.haomeiwen.com/subject/qkdjtrtx.html