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
- 大多数人是网络信息的获取者. 这次我们来做网络信息的生成者:)
- 现在我们开始调查 _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 ....待续....
网友评论