AGP working principle of Android Android advanced technology sharing

1. Basic preparation

Before analyzing the source code, I think you should have a basic understanding of the Android packaging process, at least understand the packaging process in the following figure:

Otherwise, you may not understand the terminology below.

2. How to open AGP source code

When I was looking at the AGP code, I was always struggling to download the source code of AGP. Later, I listened to the suggestion of a colleague and directly used the code that the project depends on for analysis.

There are two main reasons:

1. The source code of AGP is too big, there are 30g, and the version is very old.

2. Using the AGP code that the project depends on is easy.

Just add it to the project

implementation "com.android.tools.build:gradle:4.1.1"  

复制代码

to view.


3. Code Analysis

By the way, the version of AGP is 4.1.1.

The first step is to find the AppPlugin

In AS, if a project is created, it is added under the main module by default:

apply plugin: 'com.android.application'  

复制代码

Anyone who has customized Plugin knows that there must be a com.android.application.properties file corresponding to it in the source code, which is the entrance of our Plugin.

Search com.android.application globally, open com.android.application.properties, the content is:

implementation-class=com.android.build.gradle.AppPlugin  

复制代码

Press the "Command" button to click the source code, and find that there is another Plugin declared in the AppPlugin, and finally jump to:

implementation-class=com.android.build.gradle.internal.plugins.AppPlugin
复制代码

The package name is different from the previous one, and this is our final entry.

Do you have such doubts, I added apply plugin: com.android.application, when will this code be called?

I don't know if you have noticed that every time you change the build.gradle file, AS will let us click the "Sync Now" button. After clicking, the configuration process in Gradle will be triggered, and finally the Plugin#apply method will be run. Everyone Verify it when you can customize the Plugin.

The second step AppPlugin

The parent class of AppPlugin is AbstractAppPlugin, and the parent class of AbstractAppPlugin is BasePlugin. The beginning of the plugin is in the BasePlugin#apply method:

@Override  
public final void apply(@NonNull Project project) {  
    CrashReporting.runAction(  
            () -> {  
                basePluginApply(project);  
                pluginSpecificApply(project);  
            });  
}  

复制代码

这里我们只需要关注方法块里面的两个方法 basePluginApply 和 pluginSpecificApply。

进入重点方法 basePluginApply 方法,这个方法的前期做了很多的检查工作,包括路径、版本和 AGP 版本等等,之后又做了很多监听工作,看一下源码:

private void basePluginApply(@NonNull Project project) {  
    // ... 代码省略  
    // 依赖检查  
    DependencyResolutionChecks.registerDependencyCheck(project, projectOptions);  
    // ... 省略路径检查、模块检查等、构建参数监听器  
    // AGP版本检查  
    AgpVersionChecker.enforceTheSamePluginVersions(project);  
    // 构建流程Task执行的监听器  
    RecordingBuildListener buildListener = ProfilerInitializer.init(project, projectOptions);  
    ProfileAgent.INSTANCE.register(project.getName(), buildListener);  
    threadRecorder = ThreadRecorder.get();  
    //... 代码省略  
    // 重点  
    // 1. 配置项目  
    threadRecorder.record(  
            ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE,  
            project.getPath(),  
            null,  
            this::configureProject);  
    // 2. 配置扩展  
    threadRecorder.record(  
            ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION,  
            project.getPath(),  
            null,  
            this::configureExtension);  
    // 3. 创建Task  
    threadRecorder.record(  
            ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION,  
            project.getPath(),  
            null,  
            this::createTasks);  
}  

复制代码

其中的重点方法我已经标注出来了,分别是配置项目、配置扩展和创建Task。

第三步 配置Project

需要注意的是,此配置并不是对应 Gradle 生命周期的配置,而是针对当前 Project 做一些配置工作。

private void configureProject() {  
    // ... 执行大量的Service  
    // 依赖版本相关  
    Provider<ConstraintHandler.CachedStringBuildService> cachedStringBuildServiceProvider =  
            new ConstraintHandler.CachedStringBuildService.RegistrationAction(project)  
                    .execute();  
    // maven缓存相关  
    Provider<MavenCoordinatesCacheBuildService> mavenCoordinatesCacheBuildService =  
            new MavenCoordinatesCacheBuildService.RegistrationAction(  
                    project, cachedStringBuildServiceProvider)  
                    .execute();  
    // 依赖库相关  
    new LibraryDependencyCacheBuildService.RegistrationAction(project).execute();  
    // aapt准备工作  
    new Aapt2WorkersBuildService.RegistrationAction(project, projectOptions).execute();  
    new Aapt2DaemonBuildService.RegistrationAction(project).execute();  
    new SyncIssueReporterImpl.GlobalSyncIssueService.RegistrationAction(  
            project, SyncOptions.getModelQueryMode(projectOptions))  
            .execute();  
    // SDK相关  
    Provider<SdkComponentsBuildService> sdkComponentsBuildService =  
            new SdkComponentsBuildService.RegistrationAction(  
                    project,  
                    projectOptions,  
                    project.getProviders()  
                            .provider(() -> extension.getCompileSdkVersion()),  
                    project.getProviders()  
                            .provider(() -> extension.getBuildToolsRevision()),  
                    project.getProviders().provider(() -> extension.getNdkVersion()),  
                    project.getProviders().provider(() -> extension.getNdkPath()))  
                    .execute();  
    // Enforce minimum versions of certain plugins  
    GradlePluginUtils.enforceMinimumVersionsOfPlugins(project, issueReporter);  
    // Apply the Java plugin  
    project.getPlugins().apply(JavaBasePlugin.class);  
    dslServices =  
            new DslServicesImpl(  
                    projectServices,  
                    new DslVariableFactory(syncIssueReporter),  
                    sdkComponentsBuildService);  
    // 消息打印服务注册  
    MessageReceiverImpl messageReceiver =  
            new MessageReceiverImpl(  
                    SyncOptions.getErrorFormatMode(projectOptions),  
                    projectServices.getLogger());  
    // ... 省略  
    createLintClasspathConfiguration(project);  
}  

复制代码

我对上述代码的理解是创建Task前的准备工作,并且,上面代码中描述的 xxxAction 也很容易让人迷惑,也并不是对应 Task 中的 Action。

第四步 确认扩展

确认扩展对应的方法就是 configureExtension。

通常在 app 模块下的 build.gradle 文件中,常常会有诸如此类的配置:

android {  
    compileSdk 32  
  
    defaultConfig {  
        applicationId "com.qidian.test"  
        minSdk 21  
        targetSdk 32  
        versionCode 1  
        versionName "1.0"  
  
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"  
    }  
  
    buildTypes {  
        release {  
            minifyEnabled false  
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'  
        }  
        debug {  
            minifyEnabled false  
        }  
    }  
    compileOptions {  
        sourceCompatibility JavaVersion.VERSION_1_8  
        targetCompatibility JavaVersion.VERSION_1_8  
    }  
    kotlinOptions {  
        jvmTarget = '1.8'  
    }  
}
复制代码

configureExtension 的目的就是为了将此类的脚本信息转化成代码可以识别的信息:

private void configureExtension() {  
    // Gradle DSL的帮助类  
    DslServices dslServices = globalScope.getDslServices();  
    final NamedDomainObjectContainer<BaseVariantOutput> buildOutputs =  
            project.container(BaseVariantOutput.class);  
    // ... 代码省略  
    // ... variant 的工厂类以及管理等等  
    variantFactory = createVariantFactory(projectServices, globalScope);  
    variantInputModel =  
            new LegacyVariantInputManager(  
                    dslServices,  
                    variantFactory.getVariantType(),  
                    new SourceSetManager(  
                            project,  
                            isPackagePublished(),  
                            dslServices,  
                            new DelayedActionsExecutor()));  
    // 创建扩展  
    extension =  
            createExtension(  
                    dslServices, globalScope, variantInputModel, buildOutputs, extraModelInfo);  
    globalScope.setExtension(extension);  
    variantManager =  
            new VariantManager<>(  
                    globalScope,  
                    project,  
                    projectServices.getProjectOptions(),  
                    extension,  
                    variantFactory,  
                    variantInputModel,  
                    projectServices,  
                    threadRecorder);  
    registerModels(  
            registry,  
            globalScope,  
            variantInputModel,  
            extension,  
            extraModelInfo);  
    // create default Objects, signingConfig first as its used by the BuildTypes.  
    variantFactory.createDefaultComponents(variantInputModel);  
    // ...   
}  

复制代码

简单看一下代码即可,发现大部分的代码都跟 variant 和扩展相关。

再关注一下生成的扩展,BasePlugin#createExtension 是个抽象方法,最终交给了 AppPlugin#createExtension 方法:

protected AppExtension createExtension(  
        @NonNull DslServices dslServices,  
        @NonNull GlobalScope globalScope,  
        @NonNull  
                DslContainerProvider<DefaultConfig, BuildType, ProductFlavor, SigningConfig>  
                dslContainers,  
        @NonNull NamedDomainObjectContainer<BaseVariantOutput> buildOutputs,  
        @NonNull ExtraModelInfo extraModelInfo) {  
    return project.getExtensions()  
            .create(  
                    "android",  
                    getExtensionClass(),  
                    dslServices,  
                    globalScope,  
                    buildOutputs,  
                    dslContainers.getSourceSetManager(),  
                    extraModelInfo,  
                    new ApplicationExtensionImpl(dslServices, dslContainers));  
}  

复制代码

乍看似乎还是不太熟悉,但是如果开发过插件,你一定知道 AppExtension,它可以获取到上面提及的 build.gradle 下的 android {} 中的任何信息。

第五步 创建Task

这应该是最重要的一步了,创建 Task 就在 BasePlugin#createTasks 方法:

private void createTasks() {  
    // 注册跟Variant不相关的任务  
    threadRecorder.record(  
            ExecutionType.TASK_MANAGER_CREATE_TASKS,  
            project.getPath(),  
            null,  
            () ->  
                    TaskManager.createTasksBeforeEvaluate(  
                            globalScope,  
                            variantFactory.getVariantType(),  
                            extension.getSourceSets()));  
    // 等到Gradle配置阶段完成后,注册跟Variant相关的任务  
    project.afterEvaluate(  
            CrashReporting.afterEvaluate(  
                    p -> {  
                        variantInputModel.getSourceSetManager().runBuildableArtifactsActions();  
                        threadRecorder.record(  
                                ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,  
                                project.getPath(),  
                                null,  
                                this::createAndroidTasks);  
                    }));  
}  

复制代码

这个方法里面主要有两个方法:

1. TaskManager#createTasksBeforeEvaluate:静态方法表示在 Project 配置前,会创建一批 Task。

2. createAndroidTasks:注册了一个配置生命周期完成后的回调,等到 Project 配置完成后,Variant 已经确定完毕,又会创建一批 Task。

TaskManager#createTasksBeforeEvaluate 里面是一大段注册 Task 的代码,感兴趣可以自己查看源码。

第六步 配置完成后创建Task

等 Project 进入配置生命周期的回调,进入方法 createAndroidTasks:

final void createAndroidTasks() {  
    if (extension.getCompileSdkVersion() == null) {  
        // ... compileSdkVersion 相关  
    }  
    // ...  
    // get current plugins and look for the default Java plugin.  
    if (project.getPlugins().hasPlugin(JavaPlugin.class)) {  
        throw new BadPluginException(  
                "The 'java' plugin has been applied, but it is not compatible with the Android plugins.");  
    }  
    // ...  
  
    // 设置一些配置  
    ProcessProfileWriter.getProject(project.getPath())  
            .setCompileSdk(extension.getCompileSdkVersion())  
            .setBuildToolsVersion(extension.getBuildToolsRevision().toString())  
            .setSplits(AnalyticsUtil.toProto(extension.getSplits()));  
  
    String kotlinPluginVersion = getKotlinPluginVersion();  
    if (kotlinPluginVersion != null) {  
        ProcessProfileWriter.getProject(project.getPath())  
                .setKotlinPluginVersion(kotlinPluginVersion);  
    }  
    AnalyticsUtil.recordFirebasePerformancePluginVersion(project);  
    // 注释一 创建Variant  
    variantManager.createVariants();  
    List<ComponentInfo<VariantT, VariantPropertiesT>> variants =  
            variantManager.getMainComponents();  
    TaskManager<VariantT, VariantPropertiesT> taskManager =  
            createTaskManager(  
                    variants,  
                    variantManager.getTestComponents(),  
                    !variantInputModel.getProductFlavors().isEmpty(),  
                    globalScope,  
                    extension,  
                    threadRecorder);  
    // 注释二 创建Task  
    taskManager.createTasks();  
  
    // ...  
  
    // 注释三 创建 Task configure compose related tasks.  
    taskManager.createPostApiTasks();  
  
    // now publish all variant artifacts for non test variants since  
    // tests don't publish anything.  
    for (ComponentInfo<VariantT, VariantPropertiesT> component : variants) {  
        component.getProperties().publishBuildArtifacts();  
    }  
  
    // ...  
    variantManager.setHasCreatedTasks(true);  
    // notify our properties that configuration is over for us.  
    GradleProperty.Companion.endOfEvaluation();  
}  

复制代码

首先,从注释一中可以看出,所有的 Variant 在这一步已经创建完成了。

接着,从注释二和注释三我们可以看出,createAndroidTasks 先后两次使用 taskManager 创建 Task。

**第七步 TaskManager第一次创建多个Task

**

第一次创建 Task 使用的 TaskManager#createTasks 方法,点进这个方法:

public void createTasks() {  
    // lint相关的Task  
    taskFactory.register(new PrepareLintJarForPublish.CreationAction(globalScope));  
    // create a lifecycle task to build the lintChecks dependencies  
    taskFactory.register(  
            COMPILE_LINT_CHECKS_TASK,  
            task -> task.dependsOn(globalScope.getLocalCustomLintChecks()));  
    // Create top level test tasks.  
    createTopLevelTestTasks();  
    // 重点,遍历VariantCreate tasks for all variants (main and tests)  
    for (ComponentInfo<VariantT, VariantPropertiesT> variant : variants) {  
        createTasksForVariant(variant, variants);  
    }  
    // Test相关的Task  
    for (ComponentInfo<  
            TestComponentImpl<? extends TestComponentPropertiesImpl>,  
            TestComponentPropertiesImpl>  
            testComponent : testComponents) {  
        createTasksForTest(testComponent);  
    }  
    // 信息记录相关的Task  
    createReportTasks();  
}  

复制代码

里面依然注册了很多 Task,Lint、测试和信息记录相关的 Task等。

其中最重要的还是获取在上面创建好的的 Variant,遍历执行 createTasksForVariant 方法,我们看看它为每一个 Variant 注册了哪些方法:

private void createTasksForVariant(  
        @NonNull ComponentInfo<VariantT, VariantPropertiesT> variant,  
        @NonNull List<ComponentInfo<VariantT, VariantPropertiesT>> variants) {  
    // ... 省略  
    createAssembleTask(variantProperties);  
    if (variantType.isBaseModule()) {  
        createBundleTask(variantProperties);  
    }  
    doCreateTasksForVariant(variant, variants);  
}  

复制代码

大家对 createAssembleTask 这个方法肯定很熟悉,因为我们每次打包都是使用的 assembleDebug 或者 assembleRelease 这样的命令,这个方法就是创建 Assemble 对应的 Task。

doCreateTasksForVariant 方法就是创建跟 Variant 相关 Task 的方法,不过在 TaskManager 中,它是一个抽象方法,交给了 ApplicationTaskManager 去实现。

那么它里面到底创建了哪些 Task 呢?往后面翻,后面的图片会告诉你!

第八步 TaskManager第二次创建多个Task

第二次创建多个 Task 调用的是 TaskManager#createPostApiTasks 方法,主要跟 ViewBinding、DataBinding 和 Kotlin 编译相关的 Task,感兴趣的可以看一下。

这里就不一一和同学们分析了,直接看图:

Task过程

简单的解释一下:

蓝色的:Gradle 配置阶段前 createTasksBeforeEvaluate注册的 Task。

橙色:Gradle 配置阶段完成后创建的 Task。

红色:重要的 Task。

箭头:依赖关系(并不是所有)。

当然,我并没有把所有的 Task 都列出来,依赖关系也只把我看见的列出来(代码太多,并没有都阅读)。

如果我们将上面的图片和之前官方的打包流程图结合起来,发现很多都是可以对应起来的:

1. 前面有 AIDL、Source Code、Resource资源文件这类的处理 Task。

2. 中期有 Class 编译相关、代码混淆相关的 Task。

3. 后期又有创建合并 Dex以及打包 Apk 相关的 Task。

而且,Task 之间都有依赖关系(图中并没有展现),比如我通过命令:

./gradlew assembleDebug  

复制代码

这个命令会调用 assembleDebug 对应的 Task,在此之前,它会执行完前面依赖的 Task,比如资源处理、编译相关、打包生成我们想要的APK等等。

到这儿,这个源码就分析的差不多了,回到第二步,BasePlugin 在 apply 方法里面,还执行了 pluginSpecificApply 方法,不过这个方法是一个空方法。


3.总结

这篇文章的目的是希望大家对 AGP 有一个轮廓,AGP 主要做了什么?

可以发现,AGP 中注册的大部分 Task 都是为了打包服务的,每个小的 Task 都是打包这个流水线的螺丝钉。

如果觉得本文不错,「点赞」是最好的肯定!

Guess you like

Origin juejin.im/post/7086361034096803853