./gradlew installDebug 命令行启动*

创建项目的时候 IDE 在项目的根目录会生成 gradlew 可执行文件,gradlew
中很多逻辑是判断系统类型的,gradlew.bat 是
windows下的实现思路一样的。这里的主要的逻辑:

  1. 先定义了 java 程序执行需要的 CLASSPATH 目录
  2. 然后把 JAVACMD 设置为 java 的入口文件
  3. 最后把开发者定义的 JAVA_OPTS、DEFAULT_JVM_OPTS、进程名都拼接为一串参数执行
  4. 文件最后一行的 exec 开始打包,可以替换为 echo 看具体执行的命令是啥

gradle-wrapper.jar 是 gradle 的入口引导

上文中提到的 CLASSPATH 是 gradle 的入口 jar 实际目录在项目根目录
./gradle/wrapper/ 下,并不是 gradle 的编译主逻辑,根据 gradlew
可执行文件指定的入口类 org.gradle.wrapper.GradleWrapperMain

在里面找到了 main 函数,主要逻辑是:

  1. 加载项目目录下的 gradle.properties 到环境变量
  2. 解析同目录下的 gradle-wrapper.properties 用 Install 下载指定的url 到本地
  3. BootstrapMainStarter 加载真正的 org.gradle.launcher.GradleMain
    进行打包,如果看源码去目录
    ~/.gradle/wrapper/dists/gradle-6.7.1-bin/bwlcbys1h7rz3272sye1xwiv6/gradle-6.7.1/lib

这样设计的好处应该是把 gradle 版本和项目解耦,方便替换 gradle
的版本,如果想自定义 gradle 版本或者因为国内访问 url
超时,可以直接替换配置文件的 distributionUrl

GradleUserHomeLookup 里主要声明了默认目录 ~/.gradle

WrapperExecutor 并不是线程池,gradle 代码特色是只要切换一层逻辑就会有
xxxExecutor,Install 和 BootstrapMainStarter 实际是串行的

这里使用 org.gradle.debug=true 打断点不生效,因为这里是纯 java 进程没有处理任何
gradle 参数,应该使用 java
-agentlib:jdwp=transport=dt_socket,server=y,address=5006 -classpath
./gradle/wrapper/gradle-wrapper.jar org.gradle.wrapper.GradleWrapperMain
installdebug 和 jdb -attach
localhost:5006

两个命令行进行断点调试

启动 Daemon 进程

  1. GradleMain.main-> ProcessBootstrap.run 这是一个通用的替换类加载器的反射
  2. org.gradle.launcher.Main.run-> .doAction
  3. DefaultCommandLineActionFactory.convert->WithLogging.execute
  4. ExceptionReportingAction.execute
  5. NativeServicesInitializingAction.execute
  6. DefaultCommandLineActionFactory.ParseAndBuildAction.execute
  1. DefaultCommandLineActionFactory.BuiltInActions.createAction
  2. BuildActionsFactory.createAction 区分是否要使用守护进程执行
  3. RunBuildAction.run 使用的 BuildActionExecuter 是上一步提供的
  4. DaemonClient.execute通过 DefaultDaemonConnector 连接 ExecutorFactory
    执行池,只管 dispatch 发送参数,DefaultDaemonStarter 才开始处理 gradle
    任务,这里判断 org.gradle.daemon.debug 添加了调试功能,端口固定 5005
  1. DefaultExecActionFactory.newExec->DefaultExecHandleBuilder
  2. DefaultExecHandle.start
  3. ProcessBuilder.start 开启了新的线程
  4. GradleDaemon.main > ProcessBootstrap.run 是新进程的入口,这里可以用
    org.gradle.debug=true 打断点调试了
  5. DaemonMain.doAction 创建 Daemon 和 DaemonServices,同时在 DaemonServices
    的构造方法初始化 GlobalScopeServices 内部使用 DefaultServiceLocator 加载
    META-INF/services/”配置的所有 PluginServiceRegistry,确定了 gradle
    能处理哪些任务
  6. DaemonServerConnector
    的实现类DaemonTcpServerConnector(TcpIncomingConnector).start()
    当每次执行./gradlew installDebug 的时候 TcpIncomingConnector 会收到
    ConnectCompletion 再包装成 SynchronizedDispatchConnection(SocketConnection)
    分发给 DefaultIncomingConnectionHandler.handle 切换线程转到
    ConnectionWorker.run ,经过DefaultDaemonConnection.receive 读取到Command
    实际类型为
    org.gradle.launcher.daemon.protocol.Build(ExecuteBuildAction(StartParameterInternal(DefaultTaskExecutionRequest(args))))
    里面包含里命令的字符串,然后handleCommand
    处理数据。这是一个死循环,这个进程前面的逻辑只执行一次
  7. DaemonCommandExecuter.executeCommand-> DaemonCommandExecution. proceed
  8. 顺序执行下面的 action,都是在 DaemonServices.createDaemonCommandActions 创建
    Daemon的时候准备好的,实例创建一次执行多次。前面都是验证是否可以执行的,最后一个
    ExecuteBuild 触发 BuildExecuter。这种一层套一层的设计思路在 gradle
    源码中十分普遍
  1. HandleStop
  2. HandleInvalidateVirtualFileSystem
  3. HandleCancel
  4. HandleReportStatus
  5. ReturnResult
  6. StartBuildOrRespondWithBusy
  7. EstablishBuildEnvironment
  8. LogToClient
  9. LogAndCheckHealth
  10. ForwardClientInput
  11. RequestStopIfSingleUsedDaemon
  12. ResetDeprecationLogger
  13. WatchForDisconnection
  14. ExecuteBuild
  1. 继续往下走主流程,又是一层套一层的执行逻辑,代码风格上 16
    点像装饰,这条像代理。我猜不是同一个开发写的,经过同一个老板 review
    的,代码风格不一样但是执行逻辑完全一样
  1. SetupLoggingActionExecuter
  2. SessionFailureReportingActionExecuter
  3. StartParamsValidatingActionExecuter
  4. GradleThreadBuildActionExecuter
  5. SessionScopeLifecycleBuildActionExecuter
    这前面的都只创建一个实例,在LauncherServices$ToolingGlobalScopeServices.createBuildExecuter
    创建,所有的参数保存在BuildSessionState 中
  6. SubscribableBuildActionExecuter
    后面的每次执行到任务创建LauncherServices$ToolingBuildSessionScopeServices.
    createBuildExecuter
  7. ContinuousBuildActionExecuter
  8. BuildTreeScopeLifecycleBuildActionExecuter ,所有的参数保存在 BuildTreeState
  9. InProcessBuildActionExecuter 由 DefaultIncludedBuildRegistry.createRootBuild
    方法把前面收到的 ExecuteBuildAction 转换为
    GradleBuildController(DefaultGradleLauncher(BuildScopeServices(DefaultServiceRegistry.OwnServices(BuildDefinition(StartParameter)))))
  1. LauncherServices.createActionExecuter 创建了下面这些Runner
  1. RunAsBuildOperationBuildActionRunner
  2. BuildCompletionNotifyingBuildActionRunner
  3. FileSystemWatchingBuildActionRunner
  4. ValidatingBuildActionRunner
  5. BuildOutcomeReportingBuildActionRunner
  6. ChainingBuildActionRunner
  7. ExecuteBuildActionRunner

ServiceRegistry 和 PluginServiceRegistry 所有逻辑的起始

  1. ServiceRegistry 的主要实现类有
    DaemonServices、DaemonClientServices、ConnectorServiceRegistry
    都是随进程存活
  1. findProviderMethods 把当前实现类的所有方法转成 FactoryMethodService 存到
    allServices.providersByType<返回类型,FactoryMethodService > 里。
  2. get(Class) 直接拿到上面的 FactoryMethodService extends SingletonService
    如果第一次调用 create 一个实例,再次调用返回缓存。因为这个 Daemon
    进程不销毁,无论多少次构建任务都只创建一次实例
  3. getFactory(Class) 和上面一点很像,支持创建出来的是个池子,比如
    ConnectorServiceRegistry
  1. PluginServiceRegistry 的主要实现类有
    DependencyServices、LauncherServices、ExecutionServices、MavenPublishServices、XcodeServices
    分别对应了 gradle
    的不同能力,每种能力对不同的生命周期可以添加不同的处理方式,生命周期从长到短依次为:
  1. registerGlobalServices 全局进程内唯一 GlobalScopeServices.configure 执行
  2. registerGradleUserHomeServices 不是安卓项目目录, 是 gradle 的目录,和
    Global 基本一样,正常不会搞多个 gradle 目录,在
    BuildSessionState(GradleUserHomeScopeServiceRegistry) 根据传入的传入的 file
    目录缓存在 map 里,GradleUserHomeScopeServices.configure 执行
  3. registerBuildSessionServices 每一次执行命令 ,在 BuildSessionState
    构造方法同时初始化 BuildSessionScopeServices.configure 执行,相比
    GradleUserHome 不会缓存
  4. registerBuildTreeServices 每个命令的任务树 在 BuildTreeState
    构造方法同时初始化 BuildTreeScopeServices.configure 执行
  5. registerBuildServices 任务树的 build 阶段,随 DefaultGradleLauncher
    初始化执行 BuildScopeServices 并注册 ServiceRegistration
  6. registerGradleServices 随 GradleScopeServices 初始化执行
  7. registerSettingsServices 随 DefaultSettings 初始化的 SettingsScopeServices
    内部执行,DefaultGradleLauncher.prepareSettings 阶段执行
  8. registerProjectServices 随 DefaultProject 初始化的 ProjectScopeServices
    内部执行,DefaultGradleLauncher.prepareProjects 阶段执行,需要注意每个
    android 项目下的 module 和 DefaultProject 一一对应,每个 build.gradle
    都对应不同的 DefaultProject,根据层级有父子关系

gradle 里的 execute 大部分不是创建线程执行,只是因为当前逻辑需要分层。可能是要加 log,可能是为了抓
Exception 不让进程崩溃,也可能是为了统计执行时间等等

gradle 里的接口定义的十分多,为有能力的开发者提供了足够的扩展性,现有的实现类一般都以
Default+接口名

GradleBuildController.execute -> DefaultGradleLauncher.doClassicBuildStages 分为 4 个主要步骤

  1. 初始化 setting.gradle 根据 include 的目录层级创建树状关系的
    DefaultProjectDescriptor
  1. prepareSettings
  2. BuildOperationFiringSettingsPreparer$LoadBuild.run
  3. DefaultSettingsPreparer.prepareSettings
  4. DefaultSettingsLoader.findAndLoadSettings
  5. BuildOperationSettingsProcessor.process
  6. RootBuildCacheControllerSettingsProcessor.process
  7. SettingsEvaluatedCallbackFiringSettingsProcessor.process
  8. ScriptEvaluatingSettingsProcessor.process
  1. 创建 setting.gradle 对应的 DefaultSettings :SettingsFactory.createSettings
    -> DependencyInjectingInstantiator.newInstance ->
    ClassBuilderImpl.generate
  2. 为 DefaultSettings 赋值 :applySettingsScript ->
    BuildOperationScriptPlugin.apply ->
    DefaultScriptPluginFactory$ScriptPluginImpl.apply 解析 gradle
    文件,主要是赋值 rootProjectDescriptor
  1. 每一个 build.gradle 初始化一个 DefaultProject
  1. prepareProjects
  2. BuildOperationFiringProjectsPreparer$ConfigureBuild.run
  3. BuildTreePreparingProjectsPreparer.prepareProjects -> 这里初始化了 buildSrc 自定义插件
  1. 创建 build.gradle 对应的 DefaultProject :NotifyingBuildLoader.load ->
    ProjectPropertySettingBuildLoader.load ->
    InstantiatingBuildLoader.createProjects -> ProjectFactory.createProject ->
    DependencyInjectingInstantiator.newInstance -> ClassBuilderImpl.generate 和
    settings.gradle 同级目录的 build.gradle 是 rootProject,在
    InstantiatingBuildLoader.createProjects -> createChildProjectsRecursively
    每一个 module 都会创建一个 childProject
  2. 解析 build.gradle 为 DefaultProject 赋值:prepareProjects ->
    DefaultProjectsPreparer.prepareProjects ->
    TaskPathProjectEvaluator.configureHierarchy -> DefaultProject.evaluate ->
    LifecycleProjectEvaluator$EvaluateProject.run ->
    这里解析plugin,包含安卓的和自定义的,所有的需要的 task 都在这里添加到
    project 里,ConfigureActionsProjectEvaluator.evaluate 包含三个步骤
  1. PluginsProjectConfigureActions.execute
  1. HelpTasksAutoApplyAction.execute
  2. KotlinScriptingModelBuildersRegistrationAction.execute
  3. BuildInitAutoApplyAction.execute
  4. WrapperPluginAutoApplyAction.execute
  1. BuildScriptProcessor.execute -> BuildOperationScriptPlugin.apply ->
    DefaultScriptPluginFactory$ScriptPluginImpl.apply
  2. DelayedConfigurationActions
  1. 构建任务树生成 TaskGraph
  1. prepareTaskExecution
  2. BuildOperationFiringTaskExecutionPreparer.prepareForTaskExecution
  3. BuildOperationFiringTaskExecutionPreparer$CalculateTaskGraph.run ->
    populateTaskGraph
  4. DefaultTaskExecutionPreparer.prepareForTaskExecution ->
    DefaultBuildConfigurationActionExecuter.select
  1. ExcludedTaskFilteringBuildConfigurationAction.configure
    过滤配置的不需要执行的 task
  2. DefaultTasksBuildExecutionAction.configure 如果没带任何参数执行默认的 task
  3. TaskNameResolvingBuildConfigurationAction.configure ->
    DefaultTaskExecutionGraph(DefaultExecutionPlan).addEntryTasks -> doAddNodes
    -> LocalTaskNode.resolveDependencies -> getDependencies ->
    TaskDependencyResolver.resolveDependenciesFor ->
    CompositeResolvedArtifactSet.visitDependencies ->
    FailureCollectingTaskDependencyResolveContext.add 判断是否为
    TaskDependencyContainer 递归添加所有依赖的 task
  4. DefaultTaskExecutionGraph.populate
  5. DefaultExecutionPlan.determineExecutionPlan
    根据依赖关系生成任务先后执行的队列,可以说是 gradle 的核心
  1. 执行构建任务
  1. runWork
  2. BuildOperationFiringBuildWorkerExecutor.execute
  3. BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.run
  4. DeprecateUndefinedBuildWorkExecutor.execute
  5. IncludedBuildLifecycleBuildWorkExecutor.execute
  6. DefaultBuildWorkExecutor.execute
  1. DryRunBuildExecutionAction.execute 使用 --dry-run 参数调过所有 task
    的执行(调试用)
  2. SelectedTaskExecutionAction.execute 执行 DefaultTaskExecutionGraph
  1. DefaultTaskExecutionGraph.execute -> executeWithServices
  2. DefaultPlanExecutor.process
  3. DefaultPlanExecutor.startAdditionalWorkers
    开启多线程后面的方法都是多线程执行的
  4. DefaultPlanExecutor$ExecutorWorker.run -> executeNextNode 拆分每一个 Node
  5. DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute
  6. DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute
  1. WorkNodeExecutor.execute 如果需要同步执行 实现接口 SelfExecutingNode
  2. LocalTaskNodeExecutor.execute
  1. EventFiringTaskExecuter.execute 返回值 TaskExecuterResult 放到 context 里
  2. CatchExceptionTaskExecuter
  3. SkipOnlyIfTaskExecuter.execute 跳过 enable=false 的任务
  4. SkipTaskWithNoActionsExecuter.execute 跳过不包含任何 action 的任务
  5. ResolveTaskExecutionModeExecuter.execute
  6. FinalizePropertiesTaskExecuter.execute
  7. CleanupStaleOutputsExecuter.execute
  8. ExecuteActionsTaskExecuter.execute -> executeIfValid
  9. DefaultWorkExecutor.execute 返回值 return new TaskExecuterResult 参数放到 context 里,下面的这堆都从 ExecutionGradleServices.createWorkExecutor 里创建
  1. LoadExecutionStateStep.execute 这里开始切换了代码风格,Task 不放参数里
  2. MarkSnapshottingInputsStartedStep.execute
  3. SkipEmptyWorkStep.execute 调过没有输入的 task
  4. ValidateStep.execute
  5. CaptureStateBeforeExecutionStep.execute
  6. ResolveCachingStateStep.execute
  7. MarkSnapshottingInputsFinishedStep.execute
  8. ResolveChangesStep.execute
  9. SkipUpToDateStep.execute 检查是否有变化的文件,调过没有变化的task
  10. RecordOutputsStep.execute
  11. StoreExecutionStateStep.execute
  12. CacheStep.execute -> executeWithoutCache
  13. BroadcastChangingOutputsStep.execute
  14. SnapshotOutputsStep.execute
  15. CreateOutputsStep.execute
  16. TimeoutStep.execute -> executeWithoutTimeout 检查是否配置了这个任务的超时时间
  17. CancelExecutionStep.execute
  18. ResolveInputChangesStep.execute
  19. CleanupOutputsStep.execute
  20. ExecuteStep.execute -> executeWithPreviousOutputFiles
  21. ExecuteActionsTaskExecuter$TaskExecution.execute -> executeWithPreviousOutputFiles -> executeActions 反射到 task 的实现类执行

下载 dependencies 依赖库

  1. prepareProjects 解析 build.gradle 阶段
    DefaultScriptPluginFactory$ScriptPluginImpl.apply 继续往下看
  2. DefaultPluginRequestApplicator.applyPlugins ->
    defineScriptHandlerClassScope
  3. DefaultScriptHandler.getScriptClassPath
  4. DefaultScriptClassPathResolver.resolveClassPath
  5. CompositeBuildClassPathInitializer.execute
  6. DefaultConfiguration$ConfigurationArtifactCollection.getArtifacts ->
    ensureResolved
  1. DefaultConfiguration$ConfigurationFileCollection.getSelectedArtifacts ->
    resolveToStateOrLater -> resolveExclusively -> resolveGraphIfRequired ->
    ErrorHandlingConfigurationResolver((ShortCircuitEmptyConfigurationResolver(DefaultConfigurationResolver(DefaultArtifactDependencyResolver)))).resolveGraph
    -> DependencyGraphBuilder.attachToTargetRevisionsSerially ->
    EdgeState.attachToTargetConfigurations -> calculateTargetConfigurations ->
    ComponentState.getMetadata -> resolve -> ClientModuleResolver. resolve ->
    RepositoryChainComponentMetaDataResolver.resolveModule -> findBestMatch
    配置了多个仓库会挨个遍历找到第一个 Resolved 的
  2. DefaultLenientConfiguration.select
  3. DefaultVisitedArtifactResults.select
  4. CompositeResolvedArtifactSet.of
  1. DefaultLenientConfiguration.visitArtifacts
  2. ParallelResolveArtifactSet$VisitingSet.visit
  3. ParallelResolveArtifactSet$VisitingSet$StartVisitAction.execute
  4. CompositeResolvedArtifactSet.startVisit
  5. ArtifactBackedResolvedVariant$SingleArtifactSet.startVisit
    如果需要下载到本地
  6. DefaultBuildOperationQueue.add 内部有线程池 下面的调用都为异步执行
  7. DownloadArtifactFile.run
  8. DefaultResolvedArtifact.getFile
  9. DefaultArtifactSet$LazyArtifactSource.create
  10. RepositoryChainArtifactResolver.resolveArtifact ->
  11. getLocalAccess() 加载本地缓存
  1. CachingModuleComponentRepository$LocateInCacheRepositoryAccess.resolveArtifact -> resolveArtifactFromCache 返回值 cache 是 null 或 isMissing
    都会走到下载依赖
  2. InMemoryModuleArtifactCache.lookup
  3. DefaultModuleArtifactCache.lookup -> super.lookup ->
    getPersistentCache().get(key);
  4. WritableArtifactCacheLockingManager$CacheLockingPersistentCache.useCache
  5. DefaultCacheFactory$ReferenceTrackingCache($DirCacheReference(DefaultPersistentDirectoryStore(DefaultCacheAccess))).useCache
  6. DefaultMultiProcessSafePersistentIndexedCache(BTreePersistentIndexedCache($HeaderBlock.getRoot().load().StateCheckBlockStore(StateCheckBlockStore(FreeListBlockStore(CachingBlockStore(FileBackedBlockStore(FileBackedBlockStore$BlockImpl))))).read())).get
    主要逻辑是读 module-artifact.bin 缓存找到确切的缓存文
  1. getRemoteAccess() 如果本地缓存没读到 下载依赖并缓存
  1. CachingModuleComponentRepository$ResolveAndCacheRepositoryAccess.resolveArtifact
  2. ExternalResourceResolver$RemoteRepositoryAccess.resolveArtifact
  3. DefaultExternalResourceArtifactResolver.resolveArtifact ->
    downloadStaticResource -> downloadByUrl
  4. DefaultCacheAwareExternalResourceAccessor.getResource ->
    ProducerGuard$AdaptiveProducerGuard.guardByKey
  5. BuildOperationFiringExternalResourceDecorator.getMetaData
  6. AccessorBackedExternalResource(DefaultExternalResourceConnector(HttpResourceAccessor)).getMetaData
  7. HttpClientHelper.performHead -> performRawHead -> performRequest ->
    executeGetOrHead -> performHttpRequest -> getClient().execute
    这里使用了HttpClient 开启了同步下载流程

安卓编译流程-是 gradle 的一种插件

  1. JavaCompile 只编译改过的类
  1. IncrementalInputsTaskAction.doExecute
  2. JavaCompile.performIncrementalCompilation -> performCompilation
  3. CompileJavaBuildOperationReportingCompiler.execute
  4. IncrementalResultStoringCompiler.execute
  5. SelectiveCompiler.execute ->
    JavaRecompilationSpecProvider.provideRecompilationSpec ->
    JavaRecompilationSpecProvider.processOtherChanges ->
    SourceFileChangeProcessor.processChange ->
    PreviousCompilation.getDependents -> ClassSetAnalysis.getRelevantDependents
    根据上次编译结果有依赖关系的类都会重新编译
  6. ModuleApplicationNameWritingCompiler.execute
  7. AnnotationProcessorDiscoveringCompiler.execute
  8. NormalizingJavaCompiler.execute -> delegateAndHandleErrors
  9. JdkJavaCompiler.execute
  10. ResourceCleaningCompilationTask.call
  11. AnnotationProcessingCompileTask.call
  12. IncrementalCompileTask.call
  13. JavacTaskImpl. call 这里就是 jdk 的 javac
  1. 执行自定义插件
    ………… 后面还有很多 Android build tools 流程,未完待续

编译流程的运用

  1. 自定义插件
  1. AnnoationProcessor 是 javac 的一种代码注入技术,在 JavaCompile 期间处理。比如ButterKnife
  1. 定义 javax.annotation.processing.AbstractProcessor 的实现类
  2. 添加 src/main/resources/META-INF/services/javax.annotation.processing.Processor
  3. 添加 src/main/resources/META-INF/gradle/incremental.annotation.processors
  4. 引用 annotationProcessor project(path: ‘:compiler’)
  5. 简单的Demo https://github.com/dingshaoran/WMRouter
  1. GradlePlugin 安卓编译流程的一部分 后面也会讲一下具体实现流程
  1. 提高编译速度
  1. gradle.properties 里添加配置
    org.gradle.unsafe.configuration-cache=true。DefaultGradleLauncher.doBuildStages
    里判断了 DefaultConfigurationCache.canLoad -> isConfigurationCacheEnabled
    -> startParameter.isEnabled -> isConfigurationCache
  2. 用 nexus 搭建自己的 maven 仓库,把 repositories
    所有的地址都配进去,不直接使用多个 repo 防止
    RepositoryChainComponentMetaDataResolver.findBestMatch 遍历多个 repo
  3. gradle.properties 里添加配置 org.gradle.caching=true
  4. 遵循 Gradle 的编码原则,相比普通的 javac gradle 实现了增量编译,如果不按照 gradle 规则会影响打包速度 ⁣https://docs.gradle.org/7.1/userguide/java_plugin.html#sec:incremental_compile