blob: 0001a4cd7177c8462b3a58e0f6c7b43c8920d3b2 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.build.gradle.internal;
import static com.android.build.api.transform.QualifiedContent.DefaultContentType.RESOURCES;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.ARTIFACT_TYPE;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactType.APK;
import static com.android.build.gradle.internal.scope.InternalArtifactType.JAVAC;
import android.databinding.tool.DataBindingBuilder;
import com.android.annotations.NonNull;
import com.android.build.api.transform.QualifiedContent;
import com.android.build.api.transform.QualifiedContent.ScopeType;
import com.android.build.gradle.BaseExtension;
import com.android.build.gradle.internal.core.GradleVariantConfiguration;
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension;
import com.android.build.gradle.internal.feature.BundleAllClasses;
import com.android.build.gradle.internal.pipeline.TransformManager;
import com.android.build.gradle.internal.scope.GlobalScope;
import com.android.build.gradle.internal.scope.VariantScope;
import com.android.build.gradle.internal.tasks.AppClasspathCheckTask;
import com.android.build.gradle.internal.tasks.AppPreBuildTask;
import com.android.build.gradle.internal.tasks.ApplicationIdWriterTask;
import com.android.build.gradle.internal.tasks.BundleReportDependenciesTask;
import com.android.build.gradle.internal.tasks.BundleToApkTask;
import com.android.build.gradle.internal.tasks.BundleToStandaloneApkTask;
import com.android.build.gradle.internal.tasks.CheckMultiApkLibrariesTask;
import com.android.build.gradle.internal.tasks.ExportConsumerProguardFilesTask;
import com.android.build.gradle.internal.tasks.ExtractApksTask;
import com.android.build.gradle.internal.tasks.FinalizeBundleTask;
import com.android.build.gradle.internal.tasks.InstallVariantViaBundleTask;
import com.android.build.gradle.internal.tasks.ModuleMetadataWriterTask;
import com.android.build.gradle.internal.tasks.PackageBundleTask;
import com.android.build.gradle.internal.tasks.PerModuleBundleTask;
import com.android.build.gradle.internal.tasks.PerModuleReportDependenciesTask;
import com.android.build.gradle.internal.tasks.SigningConfigWriterTask;
import com.android.build.gradle.internal.tasks.StripDebugSymbolsTask;
import com.android.build.gradle.internal.tasks.TestPreBuildTask;
import com.android.build.gradle.internal.tasks.databinding.DataBindingExportFeatureApplicationIdsTask;
import com.android.build.gradle.internal.tasks.databinding.DataBindingExportFeatureInfoTask;
import com.android.build.gradle.internal.tasks.factory.TaskFactoryUtils;
import com.android.build.gradle.internal.tasks.featuresplit.FeatureSetMetadataWriterTask;
import com.android.build.gradle.internal.tasks.featuresplit.FeatureSplitDeclarationWriterTask;
import com.android.build.gradle.internal.tasks.featuresplit.PackagedDependenciesWriterTask;
import com.android.build.gradle.internal.variant.ApkVariantData;
import com.android.build.gradle.internal.variant.BaseVariantData;
import com.android.build.gradle.internal.variant.MultiOutputPolicy;
import com.android.build.gradle.internal.variant.VariantFactory;
import com.android.build.gradle.options.BooleanOption;
import com.android.build.gradle.options.ProjectOptions;
import com.android.build.gradle.tasks.ExtractDeepLinksTask;
import com.android.build.gradle.tasks.MainApkListPersistence;
import com.android.build.gradle.tasks.MergeResources;
import com.android.builder.core.VariantType;
import com.android.builder.profile.Recorder;
import com.google.common.collect.Sets;
import java.io.File;
import java.util.List;
import java.util.Set;
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.attributes.AttributeContainer;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.Directory;
import org.gradle.api.file.FileCollection;
import org.gradle.api.provider.Provider;
import org.gradle.api.resources.TextResourceFactory;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry;
/**
* TaskManager for creating tasks in an Android application project.
*/
public class ApplicationTaskManager extends TaskManager {
public ApplicationTaskManager(
@NonNull GlobalScope globalScope,
@NonNull Project project,
@NonNull ProjectOptions projectOptions,
@NonNull DataBindingBuilder dataBindingBuilder,
@NonNull BaseExtension extension,
@NonNull VariantFactory variantFactory,
@NonNull ToolingModelBuilderRegistry toolingRegistry,
@NonNull Recorder recorder) {
super(
globalScope,
project,
projectOptions,
dataBindingBuilder,
extension,
variantFactory,
toolingRegistry,
recorder);
}
@Override
public void createTasksForVariantScope(
@NonNull final VariantScope variantScope,
@NonNull List<VariantScope> variantScopesForLint) {
createAnchorTasks(variantScope);
taskFactory.register(new ExtractDeepLinksTask.CreationAction(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);
registerRClassTransformStream(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 ExportConsumerProguardFilesTask.CreationAction(variantScope));
}
// Add data binding tasks if enabled
createDataBindingTasksIfNecessary(variantScope, MergeType.MERGE);
// Add a compile task
createCompileTask(variantScope);
taskFactory.register(new StripDebugSymbolsTask.CreationAction(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 PackagedDependenciesWriterTask.CreationAction(variantScope));
createDynamicBundleTask(variantScope);
}
@Override
protected void createInstallTask(VariantScope variantScope) {
GradleVariantConfiguration variantConfiguration = variantScope.getVariantConfiguration();
final VariantType variantType = variantConfiguration.getType();
// feature split or AIA modules do not have their own install tasks
if (variantType.isFeatureSplit() || variantType.isHybrid()) {
return;
}
// if test app,
// or not a base module (unlikely but better to test),
// or no dynamic features are present,
// then use the default install task
if (variantType.isForTesting()
|| !(extension instanceof BaseAppModuleExtension)
|| ((BaseAppModuleExtension) extension).getDynamicFeatures().isEmpty()) {
super.createInstallTask(variantScope);
} else {
// use the install task that uses the App Bundle
taskFactory.register(new InstallVariantViaBundleTask.CreationAction(variantScope));
}
}
@Override
protected void postJavacCreation(@NonNull VariantScope scope) {
final Provider<Directory> javacOutput = scope.getArtifacts().getFinalProduct(JAVAC);
final FileCollection preJavacGeneratedBytecode =
scope.getVariantData().getAllPreJavacGeneratedBytecode();
final FileCollection postJavacGeneratedBytecode =
scope.getVariantData().getAllPostJavacGeneratedBytecode();
taskFactory.register(new BundleAllClasses.CreationAction(scope));
// create a lighter weight version for usage inside the same module (unit tests basically)
ConfigurableFileCollection files =
scope.getGlobalScope()
.getProject()
.files(javacOutput, preJavacGeneratedBytecode, postJavacGeneratedBytecode);
scope.getArtifacts().appendToAllClasses(files);
}
@Override
protected void createVariantPreBuildTask(@NonNull VariantScope scope) {
final VariantType variantType = scope.getVariantConfiguration().getType();
if (variantType.isApk()) {
boolean useDependencyConstraints =
scope.getGlobalScope()
.getProjectOptions()
.get(BooleanOption.USE_DEPENDENCY_CONSTRAINTS);
TaskProvider<? extends Task> task;
if (variantType.isTestComponent()) {
task = taskFactory.register(new TestPreBuildTask.CreationAction(scope));
if (useDependencyConstraints) {
task.configure(t -> t.setEnabled(false));
}
} else {
//noinspection unchecked
task = taskFactory.register(AppPreBuildTask.getCreationAction(scope));
}
if (!useDependencyConstraints) {
TaskProvider<AppClasspathCheckTask> classpathCheck =
taskFactory.register(new AppClasspathCheckTask.CreationAction(scope));
TaskFactoryUtils.dependsOn(task, classpathCheck);
}
if (variantType.isBaseModule() && globalScope.hasDynamicFeatures()) {
TaskProvider<CheckMultiApkLibrariesTask> checkMultiApkLibrariesTask =
taskFactory.register(new CheckMultiApkLibrariesTask.CreationAction(scope));
TaskFactoryUtils.dependsOn(task, checkMultiApkLibrariesTask);
}
return;
}
super.createVariantPreBuildTask(scope);
}
@NonNull
@Override
protected Set<ScopeType> getJavaResMergingScopes(
@NonNull VariantScope variantScope, @NonNull QualifiedContent.ContentType contentType) {
if (variantScope.consumesFeatureJars() && contentType == RESOURCES) {
return TransformManager.SCOPE_FULL_WITH_FEATURES;
}
return TransformManager.SCOPE_FULL_PROJECT;
}
/** Configure variantData to generate embedded wear application. */
private void handleMicroApp(@NonNull VariantScope scope) {
BaseVariantData variantData = scope.getVariantData();
GradleVariantConfiguration variantConfiguration = variantData.getVariantConfiguration();
final VariantType variantType = variantConfiguration.getType();
if (!variantType.isHybrid() && variantType.isBaseModule()) {
Boolean unbundledWearApp = variantConfiguration.getMergedFlavor().getWearAppUnbundled();
if (!Boolean.TRUE.equals(unbundledWearApp)
&& variantConfiguration.getBuildType().isEmbedMicroApp()) {
Configuration wearApp =
variantData.getVariantDependency().getWearAppConfiguration();
assert wearApp != null : "Wear app with no wearApp configuration";
if (!wearApp.getAllDependencies().isEmpty()) {
Action<AttributeContainer> setApkArtifact =
container -> container.attribute(ARTIFACT_TYPE, APK.getType());
FileCollection files =
wearApp.getIncoming()
.artifactView(config -> config.attributes(setApkArtifact))
.getFiles();
createGenerateMicroApkDataTask(scope, files);
}
} else {
if (Boolean.TRUE.equals(unbundledWearApp)) {
createGenerateMicroApkDataTask(scope, null);
}
}
}
}
private void createApplicationIdWriterTask(@NonNull VariantScope variantScope) {
if (variantScope.getType().isBaseModule()) {
taskFactory.register(new ModuleMetadataWriterTask.CreationAction(variantScope));
}
TaskProvider<? extends Task> applicationIdWriterTask =
taskFactory.register(new ApplicationIdWriterTask.CreationAction(variantScope));
TextResourceFactory resources = project.getResources().getText();
// this builds the dependencies from the task, and its output is the textResource.
variantScope.getVariantData().applicationIdTextResource =
resources.fromFile(applicationIdWriterTask);
}
private static File getIncrementalFolder(VariantScope variantScope, String taskName) {
return new File(variantScope.getIncrementalDir(taskName), variantScope.getDirName());
}
private void createDynamicBundleTask(@NonNull VariantScope scope) {
// If namespaced resources are enabled, LINKED_RES_FOR_BUNDLE is not generated,
// and the bundle can't be created. For now, just don't add the bundle task.
// TODO(b/111168382): Remove this
if (scope.getGlobalScope().getExtension().getAaptOptions().getNamespaced()) {
return;
}
taskFactory.register(
new PerModuleBundleTask.CreationAction(
scope, packagesCustomClassDependencies(scope, projectOptions)));
taskFactory.register(new PerModuleReportDependenciesTask.CreationAction(scope));
if (scope.getType().isBaseModule()) {
taskFactory.register(new PackageBundleTask.CreationAction(scope));
taskFactory.register(new FinalizeBundleTask.CreationAction(scope));
taskFactory.register(new BundleReportDependenciesTask.CreationAction(scope));
taskFactory.register(new BundleToApkTask.CreationAction(scope));
taskFactory.register(new BundleToStandaloneApkTask.CreationAction(scope));
taskFactory.register(new ExtractApksTask.CreationAction(scope));
}
}
}