一.如何调试Android Gradle源码
最简单的方式如下: 1.配置 gradle.properties 比较方便的做法是配置全局的 gradle.properties,这样对所有 Gradle 工具都适用,配置文件位于 ~/.gradle/gradle.properties,在 gradle.properties 文件中加上 org.gradle.jvmargs 属性:
代码语言:javascript复制org.gradle.jvmargs=-XX:MaxPermSize=4g -XX: HeapDumpOnOutOfMemoryError -Xmx4g -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006
2.启动 Gradle Daemon 进程
代码语言:javascript复制$ ./gradlew --stop # 先停掉 daemon 进程
$ ./gradlew --daemon # 启动 daemon 进程
3.Attach daemon 进程
然后,选择 Gradle Daemon 进程,如下图所示:
4.新建一个空的module 删除所有其他文件,只留如下2个文件
gradle文件配置如下
代码语言:javascript复制apply plugin: 'groovy'
dependencies {
implementation gradleApi()
implementation localGroovy()
implementation 'com.android.tools.build:gradle:3.5.0'
}
这样就引入了源码,想看对应版本的源码,改变相应的引用即可 保持和classpath声明的一致
代码语言:javascript复制 classpath 'com.android.tools.build:gradle:3.5.0'
5.放断点 在相应的代码行放上断点
6.运行构建,开始调试
在命令行中执行相应的 Task,例如:
代码语言:javascript复制$ ./gradlew assembleDebug
二.Gralde Plugin源码分析
平时我们使用plugin都是通过apply方法,例如:
代码语言:javascript复制apply plugin: 'com.android.application'
所以我们就从apply方法入手
1.AppPlugin#apply
从上面得知 ‘com.android.application’ 对应com.android.build.gradle.AppPlugin
AppPlugin继承自AbstractAppPlugin,AbstractAppPlugin继承自BasePlugin
2.BasePlugin#apply
代码语言:javascript复制 @Override
public final void apply(@NonNull Project project) {
CrashReporting.runAction(
() -> {
basePluginApply(project);
pluginSpecificApply(project);
});
}
3.BasePlugin#basePluginApply
代码语言:javascript复制private void basePluginApply(@NonNull Project project) {
// We run by default in headless mode, so the JVM doesn't steal focus.
System.setProperty("java.awt.headless", "true");
this.project = project;
this.projectOptions = new ProjectOptions(project);
checkGradleVersion(project, getLogger(), projectOptions);
DependencyResolutionChecks.registerDependencyCheck(project, projectOptions);
project.getPluginManager().apply(AndroidBasePlugin.class);
checkPathForErrors();
checkModulesForErrors();
PluginInitializer.initialize(project);
RecordingBuildListener buildListener = ProfilerInitializer.init(project, projectOptions);
ProfileAgent.INSTANCE.register(project.getName(), buildListener);
threadRecorder = ThreadRecorder.get();
Workers.INSTANCE.initFromProject(
projectOptions,
// possibly, in the future, consider using a pool with a dedicated size
// using the gradle parallelism settings.
ForkJoinPool.commonPool());
ProcessProfileWriter.getProject(project.getPath())
.setAndroidPluginVersion(Version.ANDROID_GRADLE_PLUGIN_VERSION)
.setAndroidPlugin(getAnalyticsPluginType())
.setPluginGeneration(GradleBuildProject.PluginGeneration.FIRST)
.setOptions(AnalyticsUtil.toProto(projectOptions));
if (!projectOptions.get(BooleanOption.ENABLE_NEW_DSL_AND_API)) {
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);
} else {
// Apply the Java plugin
project.getPlugins().apply(JavaBasePlugin.class);
// create the delegate
ProjectWrapper projectWrapper = new ProjectWrapper(project);
PluginDelegate<E> delegate =
new PluginDelegate<>(
project.getPath(),
project.getObjects(),
project.getExtensions(),
project.getConfigurations(),
projectWrapper,
projectWrapper,
project.getLogger(),
projectOptions,
getTypedDelegate());
delegate.prepareForEvaluation();
// after evaluate callbacks
project.afterEvaluate(
CrashReporting.afterEvaluate(
p -> {
threadRecorder.record(
ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
p.getPath(),
null,
delegate::afterEvaluate);
}));
}
}
threadRecoirder.recode()是记录最后一个参数的路径和执行的时间点,前面做了一些必要性的信息检测之前,其实主要做了以下几件事情:
代码语言:javascript复制// 配置项目,设置构建回调
this::configureProject
// 配置Extension
this::configureExtension
// 创建任务
this::createTasks
4.configureProject
代码语言:javascript复制 private void configureProject() {
final Gradle gradle = project.getGradle();
ObjectFactory objectFactory = project.getObjects();
extraModelInfo = new ExtraModelInfo(project.getPath(), projectOptions, project.getLogger());
final SyncIssueHandler syncIssueHandler = extraModelInfo.getSyncIssueHandler();
SdkComponents sdkComponents =
SdkComponents.Companion.createSdkComponents(
project,
projectOptions,
// We pass a supplier here because extension will only be set later.
this::getExtension,
getLogger(),
syncIssueHandler);
dataBindingBuilder = new DataBindingBuilder();
dataBindingBuilder.setPrintMachineReadableOutput(
SyncOptions.getErrorFormatMode(projectOptions) == ErrorFormatMode.MACHINE_PARSABLE);
if (projectOptions.hasRemovedOptions()) {
syncIssueHandler.reportWarning(
Type.GENERIC, projectOptions.getRemovedOptionsErrorMessage());
}
if (projectOptions.hasDeprecatedOptions()) {
extraModelInfo
.getDeprecationReporter()
.reportDeprecatedOptions(projectOptions.getDeprecatedOptions());
}
if (!projectOptions.getExperimentalOptions().isEmpty()) {
projectOptions
.getExperimentalOptions()
.forEach(extraModelInfo.getDeprecationReporter()::reportExperimentalOption);
}
// Enforce minimum versions of certain plugins
GradlePluginUtils.enforceMinimumVersionsOfPlugins(project, syncIssueHandler);
// Apply the Java plugin
project.getPlugins().apply(JavaBasePlugin.class);
DslScopeImpl dslScope =
new DslScopeImpl(
syncIssueHandler, extraModelInfo.getDeprecationReporter(), objectFactory);
@Nullable
FileCache buildCache = BuildCacheUtils.createBuildCacheIfEnabled(project, projectOptions);
globalScope =
new GlobalScope(
project,
creator,
new ProjectWrapper(project),
projectOptions,
dslScope,
sdkComponents,
registry,
buildCache,
extraModelInfo.getMessageReceiver());
project.getTasks()
.named("assemble")
.configure(
task ->
task.setDescription(
"Assembles all variants of all applications and secondary packages."));
// 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.
gradle.addBuildListener(
new BuildListener() {
@Override
public void buildStarted(@NonNull Gradle gradle) {}
@Override
public void settingsEvaluated(@NonNull Settings settings) {}
@Override
public void projectsLoaded(@NonNull Gradle gradle) {}
@Override
public void projectsEvaluated(@NonNull Gradle gradle) {}
@Override
public void buildFinished(@NonNull BuildResult buildResult) {
// Do not run buildFinished for included project in composite build.
if (buildResult.getGradle().getParent() != null) {
return;
}
ModelBuilder.clearCaches();
Workers.INSTANCE.shutdown();
sdkComponents.unload();
SdkLocator.resetCache();
threadRecorder.record(
ExecutionType.BASE_PLUGIN_BUILD_FINISHED,
project.getPath(),
null,
() -> {
if (!projectOptions.get(
BooleanOption.KEEP_SERVICES_BETWEEN_BUILDS)) {
WorkerActionServiceRegistry.INSTANCE
.shutdownAllRegisteredServices(
ForkJoinPool.commonPool());
}
Main.clearInternTables();
});
DeprecationReporterImpl.Companion.clean();
}
});
createLintClasspathConfiguration(project);
}
这里在添加了 BuildListener,在 buildFinished 的时候清楚了dex缓存 总结一下 configureProject 做的事情,主要是进行版本有效性的判断,并设置了构建流程的回调来处理依赖和dex的加载和缓存清理。
5.configureExtension 这个阶段就是配置 extension 的阶段,就是创建我们 android 块中的可配置的对象
代码语言:javascript复制ObjectFactory objectFactory = project.getObjects();
final NamedDomainObjectContainer<BuildType> buildTypeContainer =
project.container(
BuildType.class,
new BuildTypeFactory(
objectFactory,
project,
extraModelInfo.getSyncIssueHandler(),
extraModelInfo.getDeprecationReporter()));
final NamedDomainObjectContainer<ProductFlavor> productFlavorContainer =
project.container(
ProductFlavor.class,
new ProductFlavorFactory(
objectFactory,
project,
extraModelInfo.getDeprecationReporter(),
project.getLogger()));
final NamedDomainObjectContainer<SigningConfig> signingConfigContainer =
project.container(
SigningConfig.class,
new SigningConfigFactory(
objectFactory,
GradleKeystoreHelper.getDefaultDebugKeystoreLocation()));
final NamedDomainObjectContainer<BaseVariantOutput> buildOutputs =
project.container(BaseVariantOutput.class);
project.getExtensions().add("buildOutputs", buildOutputs);
sourceSetManager =
new SourceSetManager(
project,
isPackagePublished(),
globalScope.getDslScope(),
new DelayedActionsExecutor());
extension =
createExtension(
project,
projectOptions,
globalScope,
buildTypeContainer,
productFlavorContainer,
signingConfigContainer,
buildOutputs,
sourceSetManager,
extraModelInfo);
globalScope.setExtension(extension);
首先创建了 BuildType、ProductFlavor、SigningConfig 三个类型的Container,接着传入到了createExtension方法中,点入查看是个抽象的方法,各自的实现在子类中,这里也就是我们的AppPlugin 中
6.AbstractAppPlugin#createExtension
代码语言:javascript复制@NonNull
@Override
protected BaseExtension createExtension(
@NonNull Project project,
@NonNull ProjectOptions projectOptions,
@NonNull GlobalScope globalScope,
@NonNull NamedDomainObjectContainer<BuildType> buildTypeContainer,
@NonNull NamedDomainObjectContainer<ProductFlavor> productFlavorContainer,
@NonNull NamedDomainObjectContainer<SigningConfig> signingConfigContainer,
@NonNull NamedDomainObjectContainer<BaseVariantOutput> buildOutputs,
@NonNull SourceSetManager sourceSetManager,
@NonNull ExtraModelInfo extraModelInfo) {
return project.getExtensions()
.create(
"android",
getExtensionClass(),
project,
projectOptions,
globalScope,
buildTypeContainer,
productFlavorContainer,
signingConfigContainer,
buildOutputs,
sourceSetManager,
extraModelInfo,
isBaseApplication);
}
这里也就是可以看到我们android块配置是如何来的了,对应的Extension也确实是AppExtension,继续查看 configureExtension 的源码
代码语言:javascript复制 variantFactory = createVariantFactory(globalScope, extension);
taskManager =
createTaskManager(
globalScope,
project,
projectOptions,
dataBindingBuilder,
extension,
variantFactory,
registry,
threadRecorder);
variantManager =
new VariantManager(
globalScope,
project,
projectOptions,
extension,
variantFactory,
taskManager,
sourceSetManager,
threadRecorder);
registerModels(registry, globalScope, variantManager, extension, extraModelInfo);
这一部分主要是创建一些管理类,其中 createTaskManager、createVariantFactory 都是抽象方法,对应的实现类
代码语言:javascript复制createTaskManager
AppPlugin -> ApplicationTaskManager
LibraryPlugin -> LibraryTaskManager
createVariantFactory
AppPlugin -> ApplicationVariantFactory
LibraryPlugin -> LibraryVariantFactory
这里简单介绍一下 TaskManager 就是创建具体任务的管理类,app 工程和库 library 工程所需的构建任务是不同的,后面我们会介绍 app 工程创建的构建任务;VariantFactory 就是我们常说的构建变体的工厂类,主要是生成Variant(构建变体)的对象。我们回到 createExtension 的源码中
代码语言:javascript复制 buildTypeContainer.whenObjectAdded(
buildType -> {
if (!this.getClass().isAssignableFrom(DynamicFeaturePlugin.class)) {
SigningConfig signingConfig =
signingConfigContainer.findByName(BuilderConstants.DEBUG);
buildType.init(signingConfig);
} else {
// initialize it without the signingConfig for dynamic-features.
buildType.init();
}
variantManager.addBuildType(buildType);
});
productFlavorContainer.whenObjectAdded(variantManager::addProductFlavor);
// map whenObjectRemoved on the containers to throw an exception.
signingConfigContainer.whenObjectRemoved(
new UnsupportedAction("Removing signingConfigs is not supported."));
buildTypeContainer.whenObjectRemoved(
new UnsupportedAction("Removing build types is not supported."));
productFlavorContainer.whenObjectRemoved(
new UnsupportedAction("Removing product flavors is not supported."));
// create default Objects, signingConfig first as its used by the BuildTypes.
variantFactory.createDefaultComponents(
buildTypeContainer, productFlavorContainer, signingConfigContainer);
这一部分做得事情,配置了 BuildTypeContainer、ProductFlavorContainer、SigningConfigContainer 这三个配置项的 whenObjectAdded 的回调,每个配置的添加都会加入到 variantManager 中;创建默认配置,下面是 ApplicationVariantFactory 的 createDefaultComponents 代码
7.ApplicationVariantFactory#createDefaultComponents
代码语言:javascript复制 @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。
8.BasePlugin#createTasks
代码语言:javascript复制private void createTasks() {
threadRecorder.record(
ExecutionType.TASK_MANAGER_CREATE_TASKS,
project.getPath(),
null,
() -> taskManager.createTasksBeforeEvaluate());
project.afterEvaluate(
CrashReporting.afterEvaluate(
p -> {
sourceSetManager.runBuildableArtifactsActions();
threadRecorder.record(
ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
project.getPath(),
null,
this::createAndroidTasks);
}));
}
这里主要是分两块,一个是在 beforeEvaluate 创建任务;一个是在 afterEvaluate 创建任务。这里的区别是 AndroidTask 是依赖配置项的配置才能生成相应任务,所以是需要在 afterEvaluate 之后创建,如果对项目评估回调不理解的话,可以查阅Project文档。beforeEvaluate 创建的任务跟我们编译没有太大关系,我们重点查看一下 afterEvaluate 创建的任务 createAndroidTasks
代码语言:javascript复制List<VariantScope> variantScopes = variantManager.createAndroidTasks();
ApiObjectFactory apiObjectFactory =
new ApiObjectFactory(
extension,
variantFactory,
project.getObjects());
for (VariantScope variantScope : variantScopes) {
BaseVariantData variantData = variantScope.getVariantData();
apiObjectFactory.create(variantData);
}
// Make sure no SourceSets were added through the DSL without being properly configured
// Only do it if we are not restricting to a single variant (with Instant
// Run or we can find extra source set
if (projectOptions.get(StringOption.IDE_RESTRICT_VARIANT_NAME) == null) {
sourceSetManager.checkForUnconfiguredSourceSets();
}
// must run this after scopes are created so that we can configure kotlin
// kapt tasks
taskManager.addDataBindingDependenciesIfNecessary(
extension.getDataBinding(), variantManager.getVariantScopes());
// create the global lint task that depends on all the variants
taskManager.configureGlobalLintTask(variantManager.getVariantScopes());
int flavorDimensionCount = 0;
if (extension.getFlavorDimensionList() != null) {
flavorDimensionCount = extension.getFlavorDimensionList().size();
}
taskManager.createAnchorAssembleTasks(
variantScopes,
extension.getProductFlavors().size(),
flavorDimensionCount,
variantFactory.getVariantConfigurationTypes().size());
// now publish all variant artifacts.
for (VariantScope variantScope : variantManager.getVariantScopes()) {
variantManager.publishBuildArtifacts(variantScope);
}
checkSplitConfiguration();
variantManager.setHasCreatedTasks(true);
我们主要看下variantManager的createAndroidTasks的方法
9.VariantManager#createAndroidTasks
代码语言:javascript复制public List<VariantScope> createAndroidTasks() {
variantFactory.validateModel(this);
variantFactory.preVariantWork(project);
if (variantScopes.isEmpty()) {
populateVariantDataList();
}
// Create top level test tasks.
taskManager.createTopLevelTestTasks(!productFlavors.isEmpty());
for (final VariantScope variantScope : variantScopes) {
createTasksForVariantData(variantScope);
}
taskManager.createSourceSetArtifactReportTask(globalScope);
taskManager.createReportTasks(variantScopes);
return variantScopes;
}
首先判断 variantDataList 是否是空,如果是空的就会进入到 populateVariantDataList 方法中
10.VariantManager#populateVariantDataList
代码语言:javascript复制public void populateVariantDataList() {
List<String> flavorDimensionList = extension.getFlavorDimensionList();
if (productFlavors.isEmpty()) {
configureDependencies();
createVariantDataForProductFlavors(Collections.emptyList());
} else {
// ensure that there is always a dimension
if (flavorDimensionList == null || flavorDimensionList.isEmpty()) {
globalScope
.getErrorHandler()
.reportError(
EvalIssueReporter.Type.UNNAMED_FLAVOR_DIMENSION,
new EvalIssueException(
"All flavors must now belong to a named flavor dimension. "
"Learn more at "
"https://d.android.com/r/tools/flavorDimensions-missing-error-message.html"));
} else if (flavorDimensionList.size() == 1) {
// if there's only one dimension, auto-assign the dimension to all the flavors.
String dimensionName = flavorDimensionList.get(0);
for (ProductFlavorData<CoreProductFlavor> flavorData : productFlavors.values()) {
CoreProductFlavor flavor = flavorData.getProductFlavor();
if (flavor.getDimension() == null && flavor instanceof DefaultProductFlavor) {
((DefaultProductFlavor) flavor).setDimension(dimensionName);
}
}
}
// can only call this after we ensure all flavors have a dimension.
configureDependencies();
// 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());
}
}
configureVariantArtifactTransforms(variantScopes);
}
从方法注释可以看到,这个方法主要的作用就是创建所有的 variants
创建构建变体(BuildVariant) 继续观察上面的代码,可以看到无论是否有配置productFlavor 子项,都会进入到 createVariantDataForProductFlavors 方法。如果有配置的话,通过获取配置的 flavorDimension 和 productFlavor 数组,调用 ProductFlavorCombo.createCombinations 组合出最后的产品风味数组 flavorComboList ,最后通过遍历调用 createVariantDataForProductFlavors 方法
11.VariantManager#createVariantDataForProductFlavors
代码语言:javascript复制/**
* 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 (VariantType variantType : variantFactory.getVariantConfigurationTypes()) {
createVariantDataForProductFlavorsAndVariantType(productFlavorList, variantType);
}
}
12.VariantManager#createVariantDataForProductFlavorsAndVariantType
代码语言:javascript复制......
if (!ignore) {
BaseVariantData variantData =
createVariantDataForVariantType(
buildTypeData.getBuildType(), productFlavorList, variantType);
addVariant(variantData);
........
}
看上述代码,通过 creatVariantData 方法,将 buildType 和 productFlavor 的作为参数传入,创建了 variantData,并且加入到了 variantScopes 集合中,这里我们就是将所有的构建变体VariantScope集合到了 variantScopes 中。
接着我们返回继续看 createAndroidTasks 方法
- VariantManager#createAndroidTasks
/** Variant/Task creation entry point. */
public List<VariantScope> createAndroidTasks() {
variantFactory.validateModel(this);
variantFactory.preVariantWork(project);
if (variantScopes.isEmpty()) {
populateVariantDataList();
}
// Create top level test tasks.
taskManager.createTopLevelTestTasks(!productFlavors.isEmpty());
for (final VariantScope variantScope : variantScopes) {
createTasksForVariantData(variantScope);
}
taskManager.createSourceSetArtifactReportTask(globalScope);
taskManager.createReportTasks(variantScopes);
return variantScopes;
}
继续看如下关键代码:
代码语言:javascript复制 for (final VariantScope variantScope : variantScopes) {
createTasksForVariantData(variantScope);
}
14.VariantManager#createTasksForVariantData
代码语言:javascript复制/** Create tasks for the specified variant. */
public void createTasksForVariantData(final VariantScope variantScope) {
final BaseVariantData variantData = variantScope.getVariantData();
final VariantType variantType = variantData.getType();
final GradleVariantConfiguration variantConfig = variantScope.getVariantConfiguration();
taskManager.createAssembleTask(variantData);
if (variantType.isBaseModule()) {
taskManager.createBundleTask(variantData);
}
if (variantType.isTestComponent()) {
...........
} else {
taskManager.createTasksForVariantScope(
variantScope,
variantScopes
.stream()
.filter(TaskManager::isLintVariant)
.collect(Collectors.toList()));
}
}
首先会先根据 variantData 信息创建 assemble 任务,可以看下taskManager. createAssembleTask里的代码,然后这里最后是if else判断, if (variantType.isTestComponent())这里明显是测试会走,所以打包时候我们直接看else
代码语言:javascript复制taskManager.createTasksForVariantScope(
variantScope,
variantScopes
.stream()
.filter(TaskManager::isLintVariant)
.collect(Collectors.toList()));
15.TaskManager#createAssembleTask
代码语言:javascript复制 public void createAssembleTask(@NonNull final BaseVariantData variantData) {
final VariantScope scope = variantData.getScope();
taskFactory.register(
//注册任务名字为 assembleXXX的任务
getAssembleTaskName(scope, "assemble"),
null /*preConfigAction*/,
task -> {
task.setDescription(
"Assembles main output for variant "
scope.getVariantConfiguration().getFullName());
},
taskProvider -> scope.getTaskContainer().setAssembleTask(taskProvider));
}
回到 createAndroidTasks 方法中
16.BasePlugin#createAndroidTasks
代码语言:javascript复制.......
ApiObjectFactory apiObjectFactory =
new ApiObjectFactory(
extension,
variantFactory,
project.getObjects());
for (VariantScope variantScope : variantScopes) {
BaseVariantData variantData = variantScope.getVariantData();
apiObjectFactory.create(variantData);
}
.......
最后就遍历 VariantScope 通过 ApiObjectFactory 创建 variantApi,添加到 extensions 中; 至此,我们就已经将配置的构建变种任务已经添加到我们的任务列表中,并形成了相关依赖。
代码语言:javascript复制public BaseVariantImpl create(BaseVariantData variantData) {
if (variantData.getType().isTestComponent()) {
// Testing variants are handled together with their "owners".
createVariantOutput(variantData, null);
return null;
}
BaseVariantImpl variantApi =
variantFactory.createVariantApi(
objectFactory,
variantData,
readOnlyObjectProvider);
if (variantApi == null) {
return null;
}
............
createVariantOutput(variantData, variantApi);
try {
// Only add the variant API object to the domain object set once it's been fully
// initialized.
extension.addVariant(variantApi);
} catch (Throwable t) {
// Adding variant to the collection will trigger user-supplied callbacks
throw new ExternalApiUsageException(t);
}
return variantApi;
}
Application 的编译任务 17. ApplicationTaskManager#createTasksForVariantScope taskManager.createTasksForVariantData,发现 createTasksForVariantData 是抽象方法,这里的 taskManager 具体实现是 ApplicationTaskManager,查看 ApplicationTaskManager 的 createTasksForVariantData 方法
代码语言:javascript复制@Override
public void createTasksForVariantScope(
@NonNull final VariantScope variantScope,
@NonNull List<VariantScope> variantScopesForLint) {
createAnchorTasks(variantScope);
createCheckManifestTask(variantScope);
handleMicroApp(variantScope);
// Create all current streams (dependencies mostly at this point)
createDependencyStreams(variantScope);
// Add a task to publish the applicationId.
createApplicationIdWriterTask(variantScope);
taskFactory.register(new MainApkListPersistence.CreationAction(variantScope));
createBuildArtifactReportTask(variantScope);
// Add a task to process the manifest(s)
createMergeApkManifestsTask(variantScope);
// Add a task to create the res values
createGenerateResValuesTask(variantScope);
// Add a task to compile renderscript files.
createRenderscriptTask(variantScope);
// Add a task to merge the resource folders
createMergeResourcesTask(
variantScope,
true,
Sets.immutableEnumSet(MergeResources.Flag.PROCESS_VECTOR_DRAWABLES));
// Add tasks to compile shader
createShaderTask(variantScope);
// Add a task to merge the asset folders
createMergeAssetsTask(variantScope);
// Add a task to create the BuildConfig class
createBuildConfigTask(variantScope);
// Add a task to process the Android Resources and generate source files
createApkProcessResTask(variantScope);
// Add a task to process the java resources
createProcessJavaResTask(variantScope);
createAidlTask(variantScope);
// Add external native build tasks
createExternalNativeBuildJsonGenerators(variantScope);
createExternalNativeBuildTasks(variantScope);
// Add a task to merge the jni libs folders
createMergeJniLibFoldersTasks(variantScope);
// Add feature related tasks if necessary
if (variantScope.getType().isBaseModule()) {
// Base feature specific tasks.
taskFactory.register(new FeatureSetMetadataWriterTask.CreationAction(variantScope));
createValidateSigningTask(variantScope);
// Add a task to produce the signing config file.
taskFactory.register(new SigningConfigWriterTask.CreationAction(variantScope));
if (extension.getDataBinding().isEnabled()) {
// Create a task that will package the manifest ids(the R file packages) of all
// features into a file. This file's path is passed into the Data Binding annotation
// processor which uses it to known about all available features.
//
// <p>see: {@link TaskManager#setDataBindingAnnotationProcessorParams(VariantScope)}
taskFactory.register(
new DataBindingExportFeatureApplicationIdsTask.CreationAction(
variantScope));
}
} else {
// Non-base feature specific task.
// Task will produce artifacts consumed by the base feature
taskFactory.register(
new FeatureSplitDeclarationWriterTask.CreationAction(variantScope));
if (extension.getDataBinding().isEnabled()) {
// Create a task that will package necessary information about the feature into a
// file which is passed into the Data Binding annotation processor.
taskFactory.register(
new DataBindingExportFeatureInfoTask.CreationAction(variantScope));
}
taskFactory.register(new MergeConsumerProguardFilesTask.CreationAction(variantScope));
}
// Add data binding tasks if enabled
createDataBindingTasksIfNecessary(variantScope, MergeType.MERGE);
// Add a compile task
createCompileTask(variantScope);
createStripNativeLibraryTask(taskFactory, variantScope);
if (variantScope.getVariantData().getMultiOutputPolicy().equals(MultiOutputPolicy.SPLITS)) {
if (extension.getBuildToolsRevision().getMajor() < 21) {
throw new RuntimeException(
"Pure splits can only be used with buildtools 21 and later");
}
createSplitTasks(variantScope);
}
createPackagingTask(variantScope);
maybeCreateLintVitalTask(
(ApkVariantData) variantScope.getVariantData(), variantScopesForLint);
// Create the lint tasks, if enabled
createLintTasks(variantScope, variantScopesForLint);
taskFactory.register(new FeatureSplitTransitiveDepsWriterTask.CreationAction(variantScope));
createDynamicBundleTask(variantScope);
}
这个主要就是生成 variantData 的一系列像 compileXXX、generateXXX、processXXX、mergeXXX的任务,这一系列 task 就是构建一个可运行的完整APK的所需的所有task。
Dex的编译过程 我们查看重点方法,createCompileTask 1.ApplicationTaskManager#createCompileTask
代码语言:javascript复制protected void createCompileTask(@NonNull VariantScope variantScope) {
TaskProvider<? extends JavaCompile> javacTask = createJavacTask(variantScope);
addJavacClassesStream(variantScope);
setJavaCompilerTask(javacTask, variantScope);
createPostCompilationTasks(variantScope);
}
创建Javac任务,将java文件编译为class文件
2.TaskManager#createJavacTask
代码语言:javascript复制public TaskProvider<? extends JavaCompile> createJavacTask(@NonNull final VariantScope scope) {
taskFactory.register(new JavaPreCompileTask.CreationAction(scope));
boolean processAnnotationsTaskCreated = ProcessAnnotationsTask.taskShouldBeCreated(scope);
if (processAnnotationsTaskCreated) {
taskFactory.register(new ProcessAnnotationsTask.CreationAction(scope));
}
final TaskProvider<? extends JavaCompile> javacTask =
taskFactory.register(
new AndroidJavaCompile.CreationAction(
scope, processAnnotationsTaskCreated));
postJavacCreation(scope);
return javacTask;
}
在执行 createPostCompilationTasks 之前,先创建了 javac 任务,任务名称为 compileXXXJavaWithJavac ,该任务是将 java 源文件编译成 class 文件,
代码语言:javascript复制/** Makes the given task the one used by top-level "compile" task. */
public static void setJavaCompilerTask(
@NonNull TaskProvider<? extends JavaCompile> javaCompilerTask,
@NonNull VariantScope scope) {
TaskFactoryUtils.dependsOn(scope.getTaskContainer().getCompileTask(), javaCompilerTask);
}
使compileXXXXSources依赖compileXXXXJavaWithJavac
紧接着我们来看一下 createPostCompilationTasks 的方法 3.TaskManager#createPostCompilationTasks
代码语言:javascript复制/**
* Creates the post-compilation tasks for the given Variant.
*
* These tasks create the dex file from the .class files, plus optional intermediary steps like
* proguard and jacoco
*/
public void createPostCompilationTasks(
@NonNull final VariantScope variantScope) {
final BaseVariantData variantData = variantScope.getVariantData();
final GradleVariantConfiguration config = variantData.getVariantConfiguration();
TransformManager transformManager = variantScope.getTransformManager();
//注册合并混淆文件的任务
taskFactory.register(new MergeGeneratedProguardFilesCreationAction(variantScope));
........
maybeCreateDesugarTask(
variantScope, config.getMinSdkVersion(), transformManager, isTestCoverageEnabled);
AndroidConfig extension = variantScope.getGlobalScope().getExtension();
// Merge Java Resources.
createMergeJavaResTask(variantScope);
// ----- External Transforms -----
// apply all the external transforms.
List<Transform> customTransforms = extension.getTransforms();
List<List<Object>> customTransformsDependencies = extension.getTransformsDependencies();
for (int i = 0, count = customTransforms.size(); i < count; i ) {
Transform transform = customTransforms.get(i);
List<Object> deps = customTransformsDependencies.get(i);
transformManager.addTransform(
taskFactory,
variantScope,
transform,
null,
task -> {
if (!deps.isEmpty()) {
task.dependsOn(deps);
}
},
taskProvider -> {
// if the task is a no-op then we make assemble task depend on it.
if (transform.getScopes().isEmpty()) {
TaskFactoryUtils.dependsOn(
variantScope.getTaskContainer().getAssembleTask(),
taskProvider);
}
});
}
// Add transform to create merged runtime classes if this is a feature, a dynamic-feature,
// or a base module consuming feature jars. Merged runtime classes are needed if code
// minification is enabled in a project with features or dynamic-features.
if (variantData.getType().isFeatureSplit() || variantScope.consumesFeatureJars()) {
createMergeClassesTransform(variantScope);
}
// ----- Android studio profiling transforms
if (appliesCustomClassTransforms(variantScope, projectOptions)) {
for (String jar : getAdvancedProfilingTransforms(projectOptions)) {
if (jar != null) {
transformManager.addTransform(
taskFactory,
variantScope,
new CustomClassTransform(
jar,
packagesCustomClassDependencies(variantScope, projectOptions)));
}
}
}
// ----- Minify next -----
//只有开启混淆这里才会shrinker不为null
CodeShrinker shrinker = maybeCreateJavaCodeShrinkerTransform(variantScope);
if (shrinker == CodeShrinker.R8) {
maybeCreateResourcesShrinkerTransform(variantScope);
maybeCreateDexSplitterTransform(variantScope);
// TODO: create JavaResSplitterTransform and call it here (http://b/77546738)
return;
}
// ----- Multi-Dex support
DexingType dexingType = variantScope.getDexingType();
// Upgrade from legacy multi-dex to native multi-dex if possible when using with a device
if (dexingType == DexingType.LEGACY_MULTIDEX) {
if (variantScope.getVariantConfiguration().isMultiDexEnabled()
&& variantScope
.getVariantConfiguration()
.getMinSdkVersionWithTargetDeviceApi()
.getFeatureLevel()
>= 21) {
dexingType = DexingType.NATIVE_MULTIDEX;
}
}
if (variantScope.getNeedsMainDexList()) {
taskFactory.register(new D8MainDexListTask.CreationAction(variantScope, false));
}
if (variantScope.getNeedsMainDexListForBundle()) {
taskFactory.register(new D8MainDexListTask.CreationAction(variantScope, true));
}
createDexTasks(variantScope, dexingType);
maybeCreateResourcesShrinkerTransform(variantScope);
// TODO: support DexSplitterTransform when IR enabled (http://b/77585545)
maybeCreateDexSplitterTransform(variantScope);
// TODO: create JavaResSplitterTransform and call it here (http://b/77546738)
}
4.TaskManager#maybeCreateResourcesShrinkerTransform
代码语言:javascript复制/**
* Checks if {@link ShrinkResourcesTransform} should be added to the build pipeline and either
* adds it or registers a {@link SyncIssue} with the reason why it was skipped.
*/
protected void maybeCreateResourcesShrinkerTransform(@NonNull VariantScope scope) {
if (!scope.useResourceShrinker()) {
return;
}
// if resources are shrink, insert a no-op transform per variant output
// to transform the res package into a stripped res package
File shrinkerOutput =
FileUtils.join(
globalScope.getIntermediatesDir(),
"res_stripped",
scope.getVariantConfiguration().getDirName());
ShrinkResourcesTransform shrinkResTransform =
new ShrinkResourcesTransform(
scope.getVariantData(),
scope.getArtifacts()
.getFinalArtifactFiles(InternalArtifactType.PROCESSED_RES),
shrinkerOutput,
logger);
Optional<TaskProvider<TransformTask>> shrinkTask =
scope.getTransformManager()
.addTransform(
taskFactory,
scope,
shrinkResTransform,
taskName ->
scope.getArtifacts()
.appendArtifact(
InternalArtifactType.SHRUNK_PROCESSED_RES,
ImmutableList.of(shrinkerOutput),
taskName),
null,
null);
if (!shrinkTask.isPresent()) {
globalScope
.getErrorHandler()
.reportError(
Type.GENERIC,
new EvalIssueException(
"Internal error, could not add the ShrinkResourcesTransform"));
}
// And for the bundle
taskFactory.register(new ShrinkBundleResourcesTask.CreationAction(scope));
}
这里代码执行之后会生成build/intermediates/res_stripped/release/resources-release-stripped.ap_
重点在于createDexTasks方法
代码语言:javascript复制/**
* Creates tasks used for DEX generation. This will use an incremental pipeline that uses dex
* archives in order to enable incremental dexing support.
*/
private void createDexTasks(
@NonNull VariantScope variantScope, @NonNull DexingType dexingType) {
TransformManager transformManager = variantScope.getTransformManager();
DefaultDexOptions dexOptions;
if (variantScope.getVariantData().getType().isTestComponent()) {
// Don't use custom dx flags when compiling the test FULL_APK. They can break the test FULL_APK,
// like --minimal-main-dex.
dexOptions = DefaultDexOptions.copyOf(extension.getDexOptions());
dexOptions.setAdditionalParameters(ImmutableList.of());
} else {
dexOptions = extension.getDexOptions();
}
Java8LangSupport java8SLangSupport = variantScope.getJava8LangSupportType();
boolean minified = variantScope.getCodeShrinker() != null;
boolean supportsDesugaring =
java8SLangSupport == Java8LangSupport.UNUSED
|| (java8SLangSupport == Java8LangSupport.D8
&& projectOptions.get(
BooleanOption.ENABLE_DEXING_DESUGARING_ARTIFACT_TRANSFORM));
boolean enableDexingArtifactTransform =
globalScope.getProjectOptions().get(BooleanOption.ENABLE_DEXING_ARTIFACT_TRANSFORM)
&& extension.getTransforms().isEmpty()
&& !minified
&& supportsDesugaring
&& !appliesCustomClassTransforms(variantScope, projectOptions);
FileCache userLevelCache = getUserDexCache(minified, dexOptions.getPreDexLibraries());
DexArchiveBuilderTransform preDexTransform =
new DexArchiveBuilderTransformBuilder()
.setAndroidJarClasspath(globalScope.getFilteredBootClasspath())
.setDexOptions(dexOptions)
.setMessageReceiver(variantScope.getGlobalScope().getMessageReceiver())
.setErrorFormatMode(
SyncOptions.getErrorFormatMode(
variantScope.getGlobalScope().getProjectOptions()))
.setUserLevelCache(userLevelCache)
.setMinSdkVersion(
variantScope
.getVariantConfiguration()
.getMinSdkVersionWithTargetDeviceApi()
.getFeatureLevel())
.setDexer(variantScope.getDexer())
.setUseGradleWorkers(
projectOptions.get(BooleanOption.ENABLE_GRADLE_WORKERS))
.setInBufferSize(projectOptions.get(IntegerOption.DEXING_READ_BUFFER_SIZE))
.setOutBufferSize(
projectOptions.get(IntegerOption.DEXING_WRITE_BUFFER_SIZE))
.setIsDebuggable(
variantScope
.getVariantConfiguration()
.getBuildType()
.isDebuggable())
.setJava8LangSupportType(java8SLangSupport)
.setProjectVariant(getProjectVariantId(variantScope))
.setNumberOfBuckets(
projectOptions.get(IntegerOption.DEXING_NUMBER_OF_BUCKETS))
.setIncludeFeaturesInScope(variantScope.consumesFeatureJars())
.setEnableDexingArtifactTransform(enableDexingArtifactTransform)
.createDexArchiveBuilderTransform();
transformManager.addTransform(taskFactory, variantScope, preDexTransform);
if (projectOptions.get(BooleanOption.ENABLE_DUPLICATE_CLASSES_CHECK)) {
taskFactory.register(new CheckDuplicateClassesTask.CreationAction(variantScope));
}
createDexMergingTasks(variantScope, dexingType, enableDexingArtifactTransform);
}
5.TaskManager#maybeCreateDexSplitterTransform 这里是只有使用了Multidex 才会走到这里
代码语言:javascript复制private void maybeCreateDexSplitterTransform(@NonNull VariantScope variantScope) {
if (!variantScope.consumesFeatureJars()) {
return;
}
File dexSplitterOutput =
FileUtils.join(
globalScope.getIntermediatesDir(),
"dex-splitter",
variantScope.getVariantConfiguration().getDirName());
FileCollection featureJars =
variantScope.getArtifactFileCollection(METADATA_VALUES, PROJECT, METADATA_CLASSES);
BuildableArtifact baseJars =
variantScope
.getArtifacts()
.getFinalArtifactFiles(
InternalArtifactType.MODULE_AND_RUNTIME_DEPS_CLASSES);
BuildableArtifact mappingFileSrc =
variantScope.getArtifacts().hasArtifact(InternalArtifactType.APK_MAPPING)
? variantScope
.getArtifacts()
.getFinalArtifactFiles(InternalArtifactType.APK_MAPPING)
: null;
BuildableArtifact mainDexList =
variantScope
.getArtifacts()
.getFinalArtifactFilesIfPresent(
InternalArtifactType.MAIN_DEX_LIST_FOR_BUNDLE);
DexSplitterTransform transform =
new DexSplitterTransform(
dexSplitterOutput, featureJars, baseJars, mappingFileSrc, mainDexList);
Optional<TaskProvider<TransformTask>> transformTask =
variantScope
.getTransformManager()
.addTransform(
taskFactory,
variantScope,
transform,
taskName ->
variantScope
.getArtifacts()
.appendArtifact(
InternalArtifactType.FEATURE_DEX,
ImmutableList.of(dexSplitterOutput),
taskName),
null,
null);
if (transformTask.isPresent()) {
publishFeatureDex(variantScope);
} else {
globalScope
.getErrorHandler()
.reportError(
Type.GENERIC,
new EvalIssueException(
"Internal error, could not add the DexSplitterTransform"));
}
}