Android Gradle Plugin 源码解析(上)
一、源码依赖
本文基于:
android gradle plugin版本:
com.android.tools.build:gradle:2.3.0
gradle 版本:4.1
Gradle源码总共30个G,为简单起见,方便大家看源码,此处通过gradle依赖的形式来查看源码,依赖源码姿势:
创建一个新工程,app 项目目录中删除所有文件,仅留下gradle文件,依赖
apply plugin: 'java' sourceCompatibility = 1.8 dependencies { compile gradleApi() compile 'com.android.tools.build:gradle:2.3.0' }
将跟目录下的gradle文件,删除掉gradle依赖
buildscript { repositories { google() jcenter() } dependencies { // compile 'com.android.tools.build:gradle:2.3.0' } }
然后rebuild一下,就可以在External Libraries中查看到android gradle的源码已经依赖了
二、Android Gradle Plugin简介
我们知道Android gradle plugin是用来构建Android工程的gradle插件,在Android gradle 插件中,可以看到app工程和library工程所依赖的plugin是不一样的
// app 工程 apply plugin: 'com.android.application' // library 工程 apply plugin: 'com.android.library'
而对应填写andorid块中所填写的配置也不同,这就是区分Application和Library的插件的extension块
分别为:
app工程 -> AppPlugin -> AppExtension librar工程 -> LibraryPlugin -> LibraryExtension
对应的是AppPlugin和AppExtension,这两个插件构建的流程大抵是相同的,只是各自插件生成的任务不同,接下来我们着重分析Application插件是如何构建我们的Android应用的
三、AppPlugin的构建流程
我们先看下app工程中gradle的文件格式
apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion '26.0.2' defaultConfig { applicationId "com.zengshaoyi.gradledemo" minSdkVersion 15 targetSdkVersion 25 versionCode project.ext.versionCode versionName project.ext.versionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } lintOptions { abortOnError false } }
跟踪apply方法,其实是进入到
AppPlugin的apply的方法,我们可以看到内部实现是直接调用父类BasePlugin的apply方法
protected void apply(@NonNull Project project) { checkPluginVersion(); this.project = project; ExecutionConfigurationUtil.setThreadPoolSize(project); checkPathForErrors(); checkModulesForErrors(); ProfilerInitializer.init(project); threadRecorder = ThreadRecorder.get(); ProcessProfileWriter.getProject(project.getPath()) .setAndroidPluginVersion(Version.ANDROID_GRADLE_PLUGIN_VERSION) .setAndroidPlugin(getAnalyticsPluginType()) .setPluginGeneration(GradleBuildProject.PluginGeneration.FIRST); threadRecorder.record( ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE, project.getPath(), null, this::configureProject); threadRecorder.record( ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION, project.getPath(), null, this::configureExtension); threadRecorder.record( ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION, project.getPath(), null, this::createTasks); // Apply additional plugins for (String plugin : AndroidGradleOptions.getAdditionalPlugins(project)) { project.apply(ImmutableMap.of("plugin", plugin)); } }
threadRecoirder.recode()是记录最后一个参数的路径和执行的时间点,前面做了一些必要性的信息检测之前,其实主要做了以下几件事情:
// 配置项目,设置构建回调 this::configureProject // 配置Extension this::configureExtension // 创建任务 this::createTasks
::是java 8引入的特性,详情可以查看java8特性 ,这里就是方法的调用
configureProject
直接来看源码
private void configureProject() { extraModelInfo = new ExtraModelInfo(project); checkGradleVersion(); AndroidGradleOptions.validate(project); // Android SDK处理类 sdkHandler = new SdkHandler(project, getLogger()); // 设置项目评估阶段回调 project.afterEvaluate(p -> { // TODO: Read flag from extension. if (!p.getGradle().getStartParameter().isOffline() && AndroidGradleOptions.getUseSdkDownload(p)) { // 相关配置依赖的下载处理 SdkLibData sdkLibData = SdkLibData.download(getDownloader(), getSettingsController()); dependencyManager.setSdkLibData(sdkLibData); sdkHandler.setSdkLibData(sdkLibData); } }); // 创建AndroidBuilder androidBuilder = new AndroidBuilder( project == project.getRootProject() ? project.getName() : project.getPath(), creator, new GradleProcessExecutor(project), new GradleJavaProcessExecutor(project), extraModelInfo, getLogger(), isVerbose()); // dataBinding的相关处理 dataBindingBuilder = new DataBindingBuilder(); dataBindingBuilder.setPrintMachineReadableOutput( extraModelInfo.getErrorFormatMode() == ExtraModelInfo.ErrorFormatMode.MACHINE_PARSABLE); // Apply the Java and Jacoco plugins. project.getPlugins().apply(JavaBasePlugin.class); project.getPlugins().apply(JacocoPlugin.class); // 给assemble任务添加描述 project.getTasks() .getByName("assemble") .setDescription( "Assembles all variants of all applications and secondary packages."); ...
可以看到 configureProject 方法中在 project.afterEvaluate 设置了回调,当项目评估结束时,根据项目配置情况,设置 dependece 依赖;创建了 AndroidBuilder 对象,这个对象是用来合并manifest 和创建 dex 等作用,后面在创建任务的过程中会使用到,结下来继续看 configureProject 的源码
// call back on execution. This is called after the whole build is done (not // after the current project is done). // This is will be called for each (android) projects though, so this should support // being called 2+ times. // 设置构建回调 project.getGradle() .addBuildListener( new BuildListener() { private final LibraryCache libraryCache = LibraryCache.getCache(); @Override public void buildStarted(Gradle gradle) {} @Override public void settingsEvaluated(Settings settings) {} @Override public void projectsLoaded(Gradle gradle) {} @Override public void projectsEvaluated(Gradle gradle) {} @Override public void buildFinished(BuildResult buildResult) { ExecutorSingleton.shutdown(); sdkHandler.unload(); threadRecorder.record( ExecutionType.BASE_PLUGIN_BUILD_FINISHED, project.getPath(), null, () -> { // 当任务执行完成时,清楚dex缓存 PreDexCache.getCache() .clear( FileUtils.join( project.getRootProject() .getBuildDir(), FD_INTERMEDIATES, "dex-cache", "cache.xml"), getLogger()); JackConversionCache.getCache() .clear( FileUtils.join( project.getRootProject() .getBuildDir(), FD_INTERMEDIATES, "jack-cache", "cache.xml"), getLogger()); libraryCache.unload(); Main.clearInternTables(); }); } }); // 设置创建有向图任务回调 project.getGradle() .getTaskGraph() .addTaskExecutionGraphListener( taskGraph -> { for (Task task : taskGraph.getAllTasks()) { // TransformTask是class编译成dex的重要任务 if (task instanceof TransformTask) { Transform transform = ((TransformTask) task).getTransform(); if (transform instanceof DexTransform) { PreDexCache.getCache() .load( FileUtils.join( project.getRootProject() .getBuildDir(), FD_INTERMEDIATES, "dex-cache", "cache.xml")); break; } else if (transform instanceof JackPreDexTransform) { JackConversionCache.getCache() .load( FileUtils.join( project.getRootProject() .getBuildDir(), FD_INTERMEDIATES, "jack-cache", "cache.xml")); break; } } } });
这里在添加了 BuildListener,在 buildFinished 的时候清楚了dex缓存,而在任务有向图创建的回调中,判断是否是 DexTransfrom,从而从缓存中加载dex。
总结一下 configureProject 做的事情,主要是进行版本有效性的判断,创建了 AndroidBuilder 对象,并设置了构建流程的回调来处理依赖和dex的加载和缓存清理。
configureExtension
这个阶段就是配置 extension 的阶段,就是创建我们 android 块中的可配置的对象
private void configureExtension() { final NamedDomainObjectContainer<BuildType> buildTypeContainer = project.container( BuildType.class, new BuildTypeFactory(instantiator, project, project.getLogger())); final NamedDomainObjectContainer<ProductFlavor> productFlavorContainer = project.container( ProductFlavor.class, new ProductFlavorFactory( instantiator, project, project.getLogger(), extraModelInfo)); final NamedDomainObjectContainer<SigningConfig> signingConfigContainer = project.container(SigningConfig.class, new SigningConfigFactory(instantiator)); extension = createExtension( project, instantiator, androidBuilder, sdkHandler, buildTypeContainer, productFlavorContainer, signingConfigContainer, extraModelInfo); ...
首先创建了 BuildType、ProductFlavor、SigningConfig 三个类型的Container,接着传入到了createExtension方法中,点入查看是个抽象的方法,各自的实现在子类中,这里也就是我们的AppPlugin 中
@NonNull @Override protected BaseExtension createExtension( @NonNull Project project, @NonNull Instantiator instantiator, @NonNull AndroidBuilder androidBuilder, @NonNull SdkHandler sdkHandler, @NonNull NamedDomainObjectContainer<BuildType> buildTypeContainer, @NonNull NamedDomainObjectContainer<ProductFlavor> productFlavorContainer, @NonNull NamedDomainObjectContainer<SigningConfig> signingConfigContainer, @NonNull ExtraModelInfo extraModelInfo) { return project.getExtensions() .create( "android", AppExtension.class, project, instantiator, androidBuilder, sdkHandler, buildTypeContainer, productFlavorContainer, signingConfigContainer, extraModelInfo); }
这里也就是可以看到我们android块配置是如何来的了,对应的Extension也确实是AppExtension,继续查看 configureExtension 的源码
dependencyManager = new DependencyManager( project, extraModelInfo, sdkHandler); ndkHandler = new NdkHandler( project.getRootDir(), null, /* compileSkdVersion, this will be set in afterEvaluate */ "gcc", "" /*toolchainVersion*/); taskManager = createTaskManager( project, androidBuilder, dataBindingBuilder, extension, sdkHandler, ndkHandler, dependencyManager, registry, threadRecorder); variantFactory = createVariantFactory(instantiator, androidBuilder, extension); variantManager = new VariantManager( project, androidBuilder, extension, variantFactory, taskManager, instantiator, threadRecorder); // Register a builder for the custom tooling model ModelBuilder modelBuilder = new ModelBuilder( androidBuilder, variantManager, taskManager, extension, extraModelInfo, ndkHandler, new NativeLibraryFactoryImpl(ndkHandler), getProjectType(), AndroidProject.GENERATION_ORIGINAL); registry.register(modelBuilder); // Register a builder for the native tooling model NativeModelBuilder nativeModelBuilder = new NativeModelBuilder(variantManager); registry.register(nativeModelBuilder);
这一部分主要是创建一些管理类,其中 createTaskManager、createVariantFactory 都是抽象方法,对应的实现类
createTaskManager AppPlugin -> ApplicationTaskManager LibraryPlugin -> LibraryTaskManager createVariantFactory AppPlugin -> ApplicationVariantFactory LibraryPlugin -> LibraryVariantFactory
这里简单介绍一下 TaskManager 就是创建具体任务的管理类,app 工程和库 library 工程所需的构建任务是不同的,后面我们会介绍 app 工程创建的构建任务;VariantFactory 就是我们常说的构建变体的工厂类,主要是生成Variant(构建变体)的对象。我们回到 createExtension 的源码中
// map the whenObjectAdded callbacks on the containers. signingConfigContainer.whenObjectAdded(variantManager::addSigningConfig); buildTypeContainer.whenObjectAdded( buildType -> { SigningConfig signingConfig = signingConfigContainer.findByName(BuilderConstants.DEBUG); buildType.init(signingConfig); variantManager.addBuildType(buildType); }); productFlavorContainer.whenObjectAdded(variantManager::addProductFlavor); ... // create default Objects, signingConfig first as its used by the BuildTypes. variantFactory.createDefaultComponents( buildTypeContainer, productFlavorContainer, signingConfigContainer);
这一部分做得事情,配置了 BuildTypeContainer、ProductFlavorContainer、SigningConfigContainer 这三个配置项的 whenObjectAdded 的回调,每个配置的添加都会加入到 variantManager 中;创建默认配置,下面是 ApplicationVariantFactory 的 createDefaultComponents 代码
@Override public void createDefaultComponents( @NonNull NamedDomainObjectContainer<BuildType> buildTypes, @NonNull NamedDomainObjectContainer<ProductFlavor> productFlavors, @NonNull NamedDomainObjectContainer<SigningConfig> signingConfigs) { // must create signing config first so that build type 'debug' can be initialized // with the debug signing config. signingConfigs.create(DEBUG); buildTypes.create(DEBUG); buildTypes.create(RELEASE); }
总结一下 configureExtension 方法的作用,主要是创建 Android 插件的扩展对象,对配置项 BuildType、ProductFlavor、SigningConfig 做了统一的创建和回调处理, 创建taskManager、variantFactory、variantManager。
createTasks
private void createTasks() { threadRecorder.record( ExecutionType.TASK_MANAGER_CREATE_TASKS, project.getPath(), null, () -> // 在项目评估之前创建任务 taskManager.createTasksBeforeEvaluate( new TaskContainerAdaptor(project.getTasks()))); project.afterEvaluate( project -> threadRecorder.record( ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS, project.getPath(), null, // 在项目评估完成之后创建 androidTask () -> createAndroidTasks(false))); }
这里主要是分两块,一个是在 beforeEvaluate 创建任务;一个是在 afterEvaluate 创建任务。这里的区别是 AndroidTask 是依赖配置项的配置才能生成相应任务,所以是需要在 afterEvaluate 之后创建,如果对项目评估回调不理解的话,可以查阅Project文档。beforeEvaluate 创建的任务跟我们编译没有太大关系,我们重点查看一下 afterEvaluate 创建的任务 createAndroidTasks
@VisibleForTesting final void createAndroidTasks(boolean force) { ... threadRecorder.record( ExecutionType.VARIANT_MANAGER_CREATE_ANDROID_TASKS, project.getPath(), null, () -> { // 创建AndroidTasks variantManager.createAndroidTasks(); ApiObjectFactory apiObjectFactory = new ApiObjectFactory( androidBuilder, extension, variantFactory, instantiator); for (BaseVariantData variantData : variantManager.getVariantDataList()) { apiObjectFactory.create(variantData); } }); ... }
我们主要看下variantManager的createAndroidTasks的方法
/** * Variant/Task creation entry point. * * Not used by gradle-experimental. */ public void createAndroidTasks() { variantFactory.validateModel(this); variantFactory.preVariantWork(project); final TaskFactory tasks = new TaskContainerAdaptor(project.getTasks()); if (variantDataList.isEmpty()) { recorder.record( ExecutionType.VARIANT_MANAGER_CREATE_VARIANTS, project.getPath(), null /*variantName*/, this::populateVariantDataList); } // Create top level test tasks. recorder.record( ExecutionType.VARIANT_MANAGER_CREATE_TESTS_TASKS, project.getPath(), null /*variantName*/, () -> taskManager.createTopLevelTestTasks(tasks, !productFlavors.isEmpty())); for (final BaseVariantData<? extends BaseVariantOutputData> variantData : variantDataList) { recorder.record( ExecutionType.VARIANT_MANAGER_CREATE_TASKS_FOR_VARIANT, project.getPath(), variantData.getName(), () -> createTasksForVariantData(tasks, variantData)); } taskManager.createReportTasks(tasks, variantDataList); }
首先判断 variantDataList 是否是空,如果是空的就会进入到 populateVariantDataList 方法中
/** * Create all variants. */ public void populateVariantDataList() { if (productFlavors.isEmpty()) { createVariantDataForProductFlavors(Collections.emptyList()); } else { List<String> flavorDimensionList = extension.getFlavorDimensionList(); // Create iterable to get GradleProductFlavor from ProductFlavorData. Iterable<CoreProductFlavor> flavorDsl = Iterables.transform( productFlavors.values(), ProductFlavorData::getProductFlavor); // Get a list of all combinations of product flavors. List<ProductFlavorCombo<CoreProductFlavor>> flavorComboList = ProductFlavorCombo.createCombinations( flavorDimensionList, flavorDsl); for (ProductFlavorCombo<CoreProductFlavor> flavorCombo : flavorComboList) { //noinspection unchecked createVariantDataForProductFlavors( (List<ProductFlavor>) (List) flavorCombo.getFlavorList()); } } }
从方法注释可以看到,这个方法主要的作用就是创建所有的 variants,试想一下该段代码会做哪些事情,是否是解析 buildType、productFlavor 配置?
创建构建变体(BuildVariant)
继续观察上面的代码,可以看到无论是否有配置productFlavor 子项,都会进入到 createVariantDataForProductFlavors 方法。如果有配置的话,通过获取配置的 flavorDimension 和 productFlavor 数组,调用 ProductFlavorCombo.createCombinations 组合出最后的产品风味数组 flavorComboList ,最后通过遍历调用 createVariantDataForProductFlavors 方法
/** * Creates VariantData for a specified list of product flavor. * * This will create VariantData for all build types of the given flavors. * * @param productFlavorList the flavor(s) to build. */ private void createVariantDataForProductFlavors( @NonNull List<ProductFlavor> productFlavorList) { ... for (BuildTypeData buildTypeData : buildTypes.values()) { boolean ignore = false; ... if (!ignore) { BaseVariantData<?> variantData = createVariantData( buildTypeData.getBuildType(), productFlavorList); variantDataList.add(variantData); ... } } ... }
看上述代码,通过 creatVariantData 方法,将 buildType 和 productFlavor 的作为参数传入,创建了 variantData,并且加入到了 variantDataList 集合中,这里我们就是将所有的构建变体集合到了 variantDataList 中。
接着我们返回继续看 createAndroidTasks 方法
/** * Variant/Task creation entry point. * * Not used by gradle-experimental. */ public void createAndroidTasks() { ... for (final BaseVariantData<? extends BaseVariantOutputData> variantData : variantDataList) { recorder.record( ExecutionType.VARIANT_MANAGER_CREATE_TASKS_FOR_VARIANT, project.getPath(), variantData.getName(), () -> createTasksForVariantData(tasks, variantData)); } ... }
通过上面拿到的variantDataList,遍历该集合来创建任务
/** * Create tasks for the specified variantData. */ public void createTasksForVariantData( final TaskFactory tasks, final BaseVariantData<? extends BaseVariantOutputData> variantData) { final BuildTypeData buildTypeData = buildTypes.get( variantData.getVariantConfiguration().getBuildType().getName()); if (buildTypeData.getAssembleTask() == null) { // 创建assemble + buildType任务 buildTypeData.setAssembleTask(taskManager.createAssembleTask(tasks, buildTypeData)); } // Add dependency of assemble task on assemble build type task. tasks.named("assemble", new Action<Task>() { @Override public void execute(Task task) { assert buildTypeData.getAssembleTask() != null; // 将 assemble 任务依赖于我们的 assemble + buildType 任务 task.dependsOn(buildTypeData.getAssembleTask().getName()); } }); VariantType variantType = variantData.getType(); // 根据 variantData 创建 assemble + flavor + buildType 任务 createAssembleTaskForVariantData(tasks, variantData); if (variantType.isForTesting()) { ... } else { // 根据 variantData 创建一系列任务 taskManager.createTasksForVariantData(tasks, variantData); } }
首先会先根据 buildType 信息创建 assemble + buildType 的任务,可以看下taskManager. createAssembleTask里的代码
@NonNull public AndroidTask<DefaultTask> createAssembleTask( @NonNull TaskFactory tasks, @NonNull VariantDimensionData dimensionData) { final String sourceSetName = StringHelper.capitalize(dimensionData.getSourceSet().getName()); return androidTasks.create( tasks, // 设置任务名字为 assembleXXX "assemble" + sourceSetName, assembleTask -> { // 设置描述和任务组 assembleTask.setDescription("Assembles all " + sourceSetName + " builds."); assembleTask.setGroup(BasePlugin.BUILD_GROUP); }); }
创建完任务之后,将assemble任务依赖于我们的assembleXXX任务,随后调用 createAssembleTaskForVariantData 方法,此方法是创建 assemble + flavor + buildType 任务,流程多了 productFlavor 任务的创建,这里就不赘述了。后面会执 createTasksForVariantData,这个方法就是根据 variant 生成一系列 Android 构建所需任务(后面会详细介绍),回到 createAndroidTasks 方法中
threadRecorder.record( ExecutionType.VARIANT_MANAGER_CREATE_ANDROID_TASKS, project.getPath(), null, () -> { variantManager.createAndroidTasks(); ApiObjectFactory apiObjectFactory = new ApiObjectFactory( androidBuilder, extension, variantFactory, instantiator); for (BaseVariantData variantData : variantManager.getVariantDataList()) { // 创建variantApi,添加到extensions中 apiObjectFactory.create(variantData); } });
最后就遍历 variantDataList 通过 ApiObjectFactory 创建 variantApi,添加到 extensions 中。至此,我们就已经将配置的构建变种任务已经添加到我们的任务列表中,并形成了相关依赖。
一篇文太长,还有一半下一章发出来。
最后
感谢你到这里,喜欢的话请帮忙点个赞让更多需要的人看到哦。更多Android进阶技术,面试资料整理分享,职业生涯规划,产品,思维,行业观察,谈天说地。可以加Android架构师群;701740775。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Android O 中的 seccomp 过滤器
在 Android 的设备中,强制执行 Android 安全模式的重任交由内核承担。由于安全团队已努力加强 Android 的用户空间,并隔离和削弱进程的权限。因此内核已成为更多安全攻击的焦点。系统调用是攻击者攻击内核的常用方式。 所有 Android 软件都使用系统调用(简写为 syscall)与 Linux 内核通信。内核提供许多基于设备和 SOC 的系统调用,让用户空间的进程(包括应用程序)直接与内核交互。所有应用都依赖此机制,通过唯一的系统调用来检索访问对应的行为,例如打开文件或发送一条 binder 消息。但是许多系统调用没有被 Android 使用或官方支持。 Android O 利用被称为 seccomp 的 Linux 功能,使得未使用的系统调用无法被应用程序访问。由于应用无法访问这些系统调用,因此无法被潜在的有害应用程序利用。 seccomp 过滤器 Android O 包含一个已被安装到 zygote (所有 Android 应用均派生自该进程) 中的 seccomp 过滤器。由于过滤器已安装到 zygote,对所有应用程序生效,Android 安全团队采取了额外的...
- 下一篇
Android Gradle Plugin 源码解析(下)
上半部分请看上一篇文章。 下面是下半部分: Application 的编译任务 我们继续查看createTasksForVariantData的最后一行,taskManager.createTasksForVariantData,发现 createTasksForVariantData 是抽象方法,这里的 taskManager 具体实现是 ApplicationTaskManager,查看 ApplicationTaskManager 的 createTasksForVariantData 方法 /** * Creates the tasks for a given BaseVariantData. */ @Override public void createTasksForVariantData( @NonNull final TaskFactory tasks, @NonNull final BaseVariantData<? extends BaseVariantOutputData> variantData) { assert variantData insta...
相关文章
文章评论
共有0条评论来说两句吧...