blob: b49b6d2ab5dfa927ce11f3696b8d9ac8dc0c6051 [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.SdkConstants.FN_PUBLIC_TXT;
import static com.android.build.gradle.internal.cxx.configure.CxxCreateGradleTasksKt.createCxxVariantBuildTask;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.PublishedConfigType.API_PUBLICATION;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.PublishedConfigType.JAVA_DOC_PUBLICATION;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.PublishedConfigType.RUNTIME_PUBLICATION;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.PublishedConfigType.SOURCE_PUBLICATION;
import com.android.annotations.NonNull;
import com.android.build.api.artifact.SingleArtifact;
import com.android.build.api.transform.QualifiedContent.Scope;
import com.android.build.api.transform.QualifiedContent.ScopeType;
import com.android.build.api.transform.Transform;
import com.android.build.api.variant.LibraryVariantBuilder;
import com.android.build.gradle.BaseExtension;
import com.android.build.gradle.internal.component.ComponentCreationConfig;
import com.android.build.gradle.internal.component.LibraryCreationConfig;
import com.android.build.gradle.internal.component.TestComponentCreationConfig;
import com.android.build.gradle.internal.component.TestFixturesCreationConfig;
import com.android.build.gradle.internal.dependency.ConfigurationVariantMapping;
import com.android.build.gradle.internal.dependency.VariantDependencies;
import com.android.build.gradle.internal.pipeline.OriginalStream;
import com.android.build.gradle.internal.pipeline.TransformManager;
import com.android.build.gradle.internal.publishing.AndroidArtifacts;
import com.android.build.gradle.internal.publishing.ComponentPublishingInfo;
import com.android.build.gradle.internal.publishing.PublishedConfigSpec;
import com.android.build.gradle.internal.publishing.VariantPublishingInfo;
import com.android.build.gradle.internal.res.GenerateApiPublicTxtTask;
import com.android.build.gradle.internal.res.GenerateEmptyResourceFilesTask;
import com.android.build.gradle.internal.scope.BuildFeatureValues;
import com.android.build.gradle.internal.scope.InternalArtifactType;
import com.android.build.gradle.internal.services.DokkaParallelBuildService;
import com.android.build.gradle.internal.tasks.AarMetadataTask;
import com.android.build.gradle.internal.tasks.BundleLibraryClassesDir;
import com.android.build.gradle.internal.tasks.BundleLibraryClassesJar;
import com.android.build.gradle.internal.tasks.BundleLibraryJavaRes;
import com.android.build.gradle.internal.tasks.CheckManifest;
import com.android.build.gradle.internal.tasks.ExportConsumerProguardFilesTask;
import com.android.build.gradle.internal.tasks.LibraryAarJarsTask;
import com.android.build.gradle.internal.tasks.LibraryJniLibsTask;
import com.android.build.gradle.internal.tasks.MergeConsumerProguardFilesTask;
import com.android.build.gradle.internal.tasks.MergeGeneratedProguardFilesCreationAction;
import com.android.build.gradle.internal.tasks.PackageRenderscriptTask;
import com.android.build.gradle.internal.tasks.StripDebugSymbolsTask;
import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationConfig;
import com.android.build.gradle.internal.tasks.factory.TaskFactoryUtils;
import com.android.build.gradle.internal.tasks.factory.TaskManagerConfig;
import com.android.build.gradle.internal.tasks.factory.TaskProviderCallback;
import com.android.build.gradle.internal.variant.ComponentInfo;
import com.android.build.gradle.options.BooleanOption;
import com.android.build.gradle.tasks.BundleAar;
import com.android.build.gradle.tasks.CompileLibraryResourcesTask;
import com.android.build.gradle.tasks.ExtractAnnotations;
import com.android.build.gradle.tasks.ExtractDeepLinksTask;
import com.android.build.gradle.tasks.JavaDocGenerationTask;
import com.android.build.gradle.tasks.JavaDocJarTask;
import com.android.build.gradle.tasks.MergeResources;
import com.android.build.gradle.tasks.MergeSourceSetFolders;
import com.android.build.gradle.tasks.ProcessLibraryArtProfileTask;
import com.android.build.gradle.tasks.ProcessLibraryManifest;
import com.android.build.gradle.tasks.SourceJarTask;
import com.android.build.gradle.tasks.ZipMergingTask;
import com.android.build.gradle.tasks.sync.LibraryVariantModelTask;
import com.android.builder.errors.IssueReporter;
import com.android.builder.errors.IssueReporter.Type;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.component.AdhocComponentWithVariants;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.compile.JavaCompile;
import org.jetbrains.annotations.NotNull;
/** TaskManager for creating tasks in an Android library project. */
public class LibraryTaskManager extends TaskManager<LibraryVariantBuilder, LibraryCreationConfig> {
public LibraryTaskManager(
@NonNull Project project,
@NonNull
Collection<
? extends
ComponentInfo<
LibraryVariantBuilder, LibraryCreationConfig>>
variants,
@NonNull Collection<? extends TestComponentCreationConfig> testComponents,
@NonNull Collection<? extends TestFixturesCreationConfig> testFixturesComponents,
@NonNull GlobalTaskCreationConfig globalConfig,
@NonNull TaskManagerConfig localConfig,
@NonNull BaseExtension extension) {
super(
project,
variants,
testComponents,
testFixturesComponents,
globalConfig,
localConfig,
extension);
}
@Override
protected void doCreateTasksForVariant(
@NotNull ComponentInfo<LibraryVariantBuilder, LibraryCreationConfig> variantInfo) {
LibraryCreationConfig libraryVariant = variantInfo.getVariant();
BuildFeatureValues buildFeatures = libraryVariant.getBuildFeatures();
createAnchorTasks(libraryVariant);
taskFactory.register(new LibraryVariantModelTask.CreationAction(libraryVariant));
// Create all current streams (dependencies mostly at this point)
createDependencyStreams(libraryVariant);
if (buildFeatures.getAndroidResources()) {
createGenerateResValuesTask(libraryVariant);
taskFactory.register(new ExtractDeepLinksTask.CreationAction(libraryVariant));
taskFactory.register(new ExtractDeepLinksTask.AarCreationAction(libraryVariant));
} else { // Resource processing is disabled.
// TODO(b/147579629): add a warning for manifests containing resource references.
if (globalConfig.getNamespacedAndroidResources()) {
getLogger()
.error(
"Disabling resource processing in resource namespace aware "
+ "modules is not supported currently.");
}
// Create a task to generate empty/mock required resource artifacts.
taskFactory.register(new GenerateEmptyResourceFilesTask.CreateAction(libraryVariant));
}
// Add a task to check the manifest
taskFactory.register(new CheckManifest.CreationAction(libraryVariant));
taskFactory.register(
new ProcessLibraryManifest.CreationAction(
libraryVariant,
libraryVariant.getTargetSdkVersion(),
libraryVariant.getMaxSdkVersion(),
libraryVariant.getManifestPlaceholders()));
createRenderscriptTask(libraryVariant);
if (buildFeatures.getAndroidResources()) {
createMergeResourcesTasks(libraryVariant);
createCompileLibraryResourcesTask(libraryVariant);
}
createShaderTask(libraryVariant);
// Add tasks to merge the assets folders
createMergeAssetsTask(libraryVariant);
createLibraryAssetsTask(libraryVariant);
// Add a task to create the BuildConfig class
createBuildConfigTask(libraryVariant);
if (buildFeatures.getAndroidResources()) {
// Add a task to generate resource source files, directing the location
// of the r.txt file to be directly in the bundle.
createProcessResTask(
libraryVariant,
null,
// Switch to package where possible so we stop merging resources in
// libraries
MergeType.PACKAGE,
libraryVariant.getServices().getProjectInfo().getProjectBaseName());
// Only verify resources if in Release and not namespaced.
if (!libraryVariant.getDebuggable() && !globalConfig.getNamespacedAndroidResources()) {
createVerifyLibraryResTask(libraryVariant);
}
registerLibraryRClassTransformStream(libraryVariant);
}
// process java resources only, the merge is setup after
// the task to generate intermediate jars for project to project publishing.
createProcessJavaResTask(libraryVariant);
createAidlTask(libraryVariant);
// Add data binding tasks if enabled
createDataBindingTasksIfNecessary(libraryVariant);
// Add a task to auto-generate classes for ML model files.
createMlkitTask(libraryVariant);
// Add a compile task
TaskProvider<? extends JavaCompile> javacTask = createJavacTask(libraryVariant);
addJavacClassesStream(libraryVariant);
TaskManager.setJavaCompilerTask(javacTask, libraryVariant);
taskFactory.register(new MergeGeneratedProguardFilesCreationAction(libraryVariant));
createCxxVariantBuildTask(
taskFactory, variantInfo.getVariant(), project.getProviders(), project.getLayout());
createMergeJniLibFoldersTasks(libraryVariant);
taskFactory.register(new StripDebugSymbolsTask.CreationAction(libraryVariant));
taskFactory.register(new PackageRenderscriptTask.CreationAction(libraryVariant));
// merge consumer proguard files from different build types and flavors
taskFactory.register(new MergeConsumerProguardFilesTask.CreationAction(libraryVariant));
taskFactory.register(new ExportConsumerProguardFilesTask.CreationAction(libraryVariant));
// Some versions of retrolambda remove the actions from the extract annotations task.
// TODO: remove this hack once tests are moved to a version that doesn't do this
// b/37564303
if (libraryVariant
.getServices()
.getProjectOptions()
.get(BooleanOption.ENABLE_EXTRACT_ANNOTATIONS)) {
taskFactory.register(new ExtractAnnotations.CreationAction(libraryVariant));
}
final boolean instrumented = libraryVariant.isAndroidTestCoverageEnabled();
TransformManager transformManager = libraryVariant.getTransformManager();
// ----- Code Coverage first -----
if (instrumented) {
createJacocoTask(libraryVariant);
}
maybeCreateTransformClassesWithAsmTask(libraryVariant);
// ----- External Transforms -----
// apply all the external transforms.
List<Transform> customTransforms = globalConfig.getTransforms();
List<List<Object>> customTransformsDependencies = globalConfig.getTransformsDependencies();
final IssueReporter issueReporter = libraryVariant.getServices().getIssueReporter();
for (int i = 0, count = customTransforms.size(); i < count; i++) {
Transform transform = customTransforms.get(i);
// Check the transform only applies to supported scopes for libraries:
// We cannot transform scopes that are not packaged in the library
// itself.
Sets.SetView<? super Scope> difference =
Sets.difference(transform.getScopes(), TransformManager.PROJECT_ONLY);
if (!difference.isEmpty()) {
String scopes = difference.toString();
issueReporter.reportError(
Type.GENERIC,
String.format(
"Transforms with scopes '%s' cannot be applied to library projects.",
scopes));
}
List<Object> deps = customTransformsDependencies.get(i);
transformManager.addTransform(
taskFactory,
libraryVariant,
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(
libraryVariant.getTaskContainer().getAssembleTask(),
taskProvider);
}
});
}
// Create jar with library classes used for publishing to runtime elements.
taskFactory.register(
new BundleLibraryClassesJar.CreationAction(
libraryVariant, AndroidArtifacts.PublishedConfigType.RUNTIME_ELEMENTS));
// Also create a directory containing the same classes for incremental dexing
taskFactory.register(new BundleLibraryClassesDir.CreationAction(libraryVariant));
taskFactory.register(new BundleLibraryJavaRes.CreationAction(libraryVariant));
// Create a jar with both classes and java resources. This artifact is not
// used by the Android application plugin and the task usually don't need to
// be executed. The artifact is useful for other Gradle users who needs the
// 'jar' artifact as API dependency.
taskFactory.register(new ZipMergingTask.CreationAction(libraryVariant));
// now add a task that will take all the native libs and package
// them into an intermediary folder. This processes only the PROJECT
// scope.
taskFactory.register(
new LibraryJniLibsTask.ProjectOnlyCreationAction(
libraryVariant, InternalArtifactType.LIBRARY_JNI.INSTANCE));
// Now go back to fill the pipeline with transforms used when
// publishing the AAR
// first merge the java resources.
createMergeJavaResTask(libraryVariant);
// ----- Minify next -----
maybeCreateJavaCodeShrinkerTask(libraryVariant);
// now add a task that will take all the classes and java resources and package them
// into the main and secondary jar files that goes in the AAR.
// This is used for building the AAR.
taskFactory.register(
new LibraryAarJarsTask.CreationAction(
libraryVariant, libraryVariant.getMinifiedEnabled()));
// now add a task that will take all the native libs and package
// them into the libs folder of the bundle. This processes both the PROJECT
// and the LOCAL_PROJECT scopes
taskFactory.register(
new LibraryJniLibsTask.ProjectAndLocalJarsCreationAction(
libraryVariant, InternalArtifactType.LIBRARY_AND_LOCAL_JARS_JNI.INSTANCE));
// Add a task to create the AAR metadata file
taskFactory.register(new AarMetadataTask.CreationAction(libraryVariant));
// Add a task to write the local lint AAR file
taskFactory.register(new BundleAar.LibraryLocalLintCreationAction(libraryVariant));
createBundleTask(libraryVariant);
}
private void createBundleTask(@NonNull LibraryCreationConfig variant) {
taskFactory.register(new BundleAar.LibraryCreationAction(variant));
variant.getTaskContainer()
.getAssembleTask()
.configure(
task -> {
task.dependsOn(variant.getArtifacts().get(SingleArtifact.AAR.INSTANCE));
});
VariantPublishingInfo publishInfo = variant.getPublishInfo();
if (publishInfo != null) {
List<ComponentPublishingInfo> components = publishInfo.getComponents();
// Checks all components which the current variant is published to and see if there is
// any component that is configured to publish source or javadoc.
if (components.stream().anyMatch(ComponentPublishingInfo::getWithSourcesJar)) {
taskFactory.register(new SourceJarTask.CreationAction(variant));
}
if (components.stream().anyMatch(ComponentPublishingInfo::getWithJavadocJar)) {
new DokkaParallelBuildService.RegistrationAction(project).execute();
taskFactory.register(new JavaDocGenerationTask.CreationAction(variant));
taskFactory.register(new JavaDocJarTask.CreationAction(variant));
}
for (ComponentPublishingInfo component : components) {
createComponent(
variant, component.getComponentName(), component.isClassifierRequired());
}
}
}
private void createComponent(
@NonNull LibraryCreationConfig variant,
@NonNull String componentName,
boolean isClassifierRequired) {
final VariantDependencies variantDependencies = variant.getVariantDependencies();
AdhocComponentWithVariants component =
(AdhocComponentWithVariants) project.getComponents().findByName(componentName);
if (component == null) {
component = localConfig.getComponentFactory().adhoc(componentName);
project.getComponents().add(component);
}
final Configuration apiPub =
variantDependencies.getElements(
new PublishedConfigSpec(
API_PUBLICATION, componentName, isClassifierRequired));
final Configuration runtimePub =
variantDependencies.getElements(
new PublishedConfigSpec(
RUNTIME_PUBLICATION, componentName, isClassifierRequired));
final Configuration sourcePub =
variantDependencies.getElements(
new PublishedConfigSpec(
SOURCE_PUBLICATION, componentName, isClassifierRequired));
final Configuration javaDocPub =
variantDependencies.getElements(
new PublishedConfigSpec(
JAVA_DOC_PUBLICATION, componentName, isClassifierRequired));
component.addVariantsFromConfiguration(
apiPub, new ConfigurationVariantMapping("compile", isClassifierRequired));
component.addVariantsFromConfiguration(
runtimePub, new ConfigurationVariantMapping("runtime", isClassifierRequired));
if (sourcePub != null) {
component.addVariantsFromConfiguration(
sourcePub, new ConfigurationVariantMapping("runtime", true));
}
if (javaDocPub != null) {
component.addVariantsFromConfiguration(
javaDocPub, new ConfigurationVariantMapping("runtime", true));
}
}
@Override
protected void createDependencyStreams(@NonNull ComponentCreationConfig creationConfig) {
super.createDependencyStreams(creationConfig);
// add the same jars twice in the same stream as the EXTERNAL_LIB in the task manager
// so that filtering of duplicates in proguard can work.
creationConfig
.getTransformManager()
.addStream(
OriginalStream.builder("local-deps-classes")
.addContentTypes(TransformManager.CONTENT_CLASS)
.addScope(InternalScope.LOCAL_DEPS)
.setFileCollection(creationConfig.computeLocalPackagedJars())
.build());
}
private static class MergeResourceCallback implements TaskProviderCallback<MergeResources> {
@NonNull private final LibraryCreationConfig variant;
private MergeResourceCallback(@NonNull LibraryCreationConfig variant) {
this.variant = variant;
}
@Override
public void handleProvider(@NonNull TaskProvider<MergeResources> taskProvider) {
variant.getArtifacts()
.setInitialProvider(taskProvider, MergeResources::getPublicFile)
.withName(FN_PUBLIC_TXT)
.on(InternalArtifactType.PUBLIC_RES.INSTANCE);
}
}
private void createMergeResourcesTasks(@NonNull LibraryCreationConfig variant) {
ImmutableSet<MergeResources.Flag> flags;
if (globalConfig.getNamespacedAndroidResources()) {
flags =
Sets.immutableEnumSet(
MergeResources.Flag.REMOVE_RESOURCE_NAMESPACES,
MergeResources.Flag.PROCESS_VECTOR_DRAWABLES);
} else {
flags = Sets.immutableEnumSet(MergeResources.Flag.PROCESS_VECTOR_DRAWABLES);
}
MergeResourceCallback callback = new MergeResourceCallback(variant);
// Create a merge task to only merge the resources from this library and not
// the dependencies. This is what gets packaged in the aar.
basicCreateMergeResourcesTask(
variant,
MergeType.PACKAGE,
false,
false,
false,
flags,
callback);
// This task merges all the resources, including the dependencies of this library.
// This should be unused, except that external libraries might consume it.
// Also used by the VerifyLibraryResourcesTask (only ran in release builds).
createMergeResourcesTask(variant, false /*processResources*/, ImmutableSet.of());
// Task to generate the public.txt for the API that always exists
// Unlike the internal one which is packaged in the AAR which only exists if the
// developer has explicitly marked resources as public.
taskFactory.register(new GenerateApiPublicTxtTask.CreationAction(variant));
}
private void createCompileLibraryResourcesTask(@NonNull LibraryCreationConfig variant) {
if (variant.getAndroidResourcesCreationConfig() != null
&& variant.getAndroidResourcesCreationConfig()
.isPrecompileDependenciesResourcesEnabled()) {
taskFactory.register(new CompileLibraryResourcesTask.CreationAction(variant));
}
}
@Override
protected void postJavacCreation(@NonNull ComponentCreationConfig creationConfig) {
super.postJavacCreation(creationConfig);
if (creationConfig
.getServices()
.getProjectOptions()
.get(BooleanOption.ENABLE_ART_PROFILES)) {
taskFactory.register(new ProcessLibraryArtProfileTask.CreationAction(creationConfig));
}
// Create jar used for publishing to API elements (for other projects to compile against).
taskFactory.register(
new BundleLibraryClassesJar.CreationAction(
creationConfig, AndroidArtifacts.PublishedConfigType.API_ELEMENTS));
}
public void createLibraryAssetsTask(@NonNull LibraryCreationConfig variant) {
taskFactory.register(new MergeSourceSetFolders.LibraryAssetCreationAction(variant));
}
@NonNull
@Override
protected Set<ScopeType> getJavaResMergingScopes(
@NonNull ComponentCreationConfig creationConfig) {
if (creationConfig.getComponentType().isTestComponent()) {
return TransformManager.SCOPE_FULL_PROJECT_WITH_LOCAL_JARS;
}
return TransformManager.SCOPE_FULL_LIBRARY_WITH_LOCAL_JARS;
}
@Override
protected void createPrepareLintJarForPublishTask() {
super.createPrepareLintJarForPublishTask();
// publish the local lint.jar to all the variants.
// This takes the global jar (output of PrepareLintJar) and publishes to each variants
// as we don't have variant-free publishing at the moment.
for (LibraryCreationConfig variant : variantPropertiesList) {
variant.getArtifacts()
.copy(
InternalArtifactType.LINT_PUBLISH_JAR.INSTANCE,
globalConfig.getGlobalArtifacts());
}
}
}