| /* |
| * Copyright 2013-present Facebook, Inc. |
| * |
| * 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.facebook.buck.android; |
| |
| import com.facebook.buck.android.AndroidBinary.ExopackageMode; |
| import com.facebook.buck.android.AndroidBinary.PackageType; |
| import com.facebook.buck.android.AndroidBinary.TargetCpuType; |
| import com.facebook.buck.android.FilterResourcesStep.ResourceFilter; |
| import com.facebook.buck.android.ResourcesFilter.ResourceCompressionMode; |
| import com.facebook.buck.cxx.CxxPlatform; |
| import com.facebook.buck.java.JavaLibrary; |
| import com.facebook.buck.java.JavaNativeLinkable; |
| import com.facebook.buck.java.JavacOptions; |
| import com.facebook.buck.java.Keystore; |
| import com.facebook.buck.model.BuildTarget; |
| import com.facebook.buck.model.Flavor; |
| import com.facebook.buck.model.HasBuildTarget; |
| import com.facebook.buck.model.ImmutableFlavor; |
| import com.facebook.buck.model.Pair; |
| import com.facebook.buck.rules.BuildRule; |
| import com.facebook.buck.rules.BuildRuleParams; |
| import com.facebook.buck.rules.BuildRuleResolver; |
| import com.facebook.buck.rules.BuildRuleType; |
| import com.facebook.buck.rules.BuildRules; |
| import com.facebook.buck.rules.PathSourcePath; |
| import com.facebook.buck.rules.SourcePath; |
| import com.facebook.buck.rules.SourcePathResolver; |
| import com.facebook.buck.rules.coercer.BuildConfigFields; |
| import com.facebook.buck.rules.coercer.ImmutableBuildConfigFields; |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.common.base.Function; |
| import com.google.common.base.Optional; |
| import com.google.common.base.Preconditions; |
| import com.google.common.base.Suppliers; |
| import com.google.common.collect.FluentIterable; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.ImmutableSortedSet; |
| |
| import java.nio.file.Path; |
| import java.util.Collection; |
| import java.util.EnumSet; |
| import java.util.Map; |
| |
| public class AndroidBinaryGraphEnhancer { |
| |
| private static final Flavor COPY_NATIVE_LIBS_FLAVOR = ImmutableFlavor.of("copy_native_libs"); |
| private static final Flavor DEX_FLAVOR = ImmutableFlavor.of("dex"); |
| private static final Flavor DEX_MERGE_FLAVOR = ImmutableFlavor.of("dex_merge"); |
| private static final Flavor RESOURCES_FILTER_FLAVOR = ImmutableFlavor.of("resources_filter"); |
| private static final Flavor AAPT_PACKAGE_FLAVOR = ImmutableFlavor.of("aapt_package"); |
| private static final Flavor CALCULATE_ABI_FLAVOR = ImmutableFlavor.of("calculate_exopackage_abi"); |
| private static final Flavor PACKAGE_STRING_ASSETS_FLAVOR = |
| ImmutableFlavor.of("package_string_assets"); |
| |
| private final BuildTarget originalBuildTarget; |
| private final ImmutableSortedSet<BuildRule> originalDeps; |
| private final BuildRuleParams buildRuleParams; |
| private final BuildRuleResolver ruleResolver; |
| private final SourcePathResolver pathResolver; |
| private final ResourceCompressionMode resourceCompressionMode; |
| private final ResourceFilter resourceFilter; |
| private final ImmutableSet<String> locales; |
| private final SourcePath manifest; |
| private final PackageType packageType; |
| private final ImmutableSet<TargetCpuType> cpuFilters; |
| private final boolean shouldBuildStringSourceMap; |
| private final boolean shouldPreDex; |
| private final Path primaryDexPath; |
| private final DexSplitMode dexSplitMode; |
| private final ImmutableSet<BuildTarget> buildTargetsToExcludeFromDex; |
| private final ImmutableSet<BuildTarget> resourcesToExclude; |
| private final boolean skipCrunchPngs; |
| private final JavacOptions javacOptions; |
| private final EnumSet<ExopackageMode> exopackageModes; |
| private final Keystore keystore; |
| private final BuildConfigFields buildConfigValues; |
| private final Optional<SourcePath> buildConfigValuesFile; |
| |
| /** |
| * Maps a {@link TargetCpuType} to the {@link CxxPlatform} we need to use to build C/C++ |
| * libraries for it. |
| */ |
| private final ImmutableMap<TargetCpuType, NdkCxxPlatform> nativePlatforms; |
| |
| AndroidBinaryGraphEnhancer( |
| BuildRuleParams originalParams, |
| BuildRuleResolver ruleResolver, |
| ResourceCompressionMode resourceCompressionMode, |
| ResourceFilter resourcesFilter, |
| ImmutableSet<String> locales, |
| SourcePath manifest, |
| PackageType packageType, |
| ImmutableSet<TargetCpuType> cpuFilters, |
| boolean shouldBuildStringSourceMap, |
| boolean shouldPreDex, |
| Path primaryDexPath, |
| DexSplitMode dexSplitMode, |
| ImmutableSet<BuildTarget> buildTargetsToExcludeFromDex, |
| ImmutableSet<BuildTarget> resourcesToExclude, |
| boolean skipCrunchPngs, |
| JavacOptions javacOptions, |
| EnumSet<ExopackageMode> exopackageModes, |
| Keystore keystore, |
| BuildConfigFields buildConfigValues, |
| Optional<SourcePath> buildConfigValuesFile, |
| ImmutableMap<TargetCpuType, NdkCxxPlatform> nativePlatforms) { |
| this.buildRuleParams = originalParams; |
| this.originalBuildTarget = originalParams.getBuildTarget(); |
| this.originalDeps = originalParams.getDeps(); |
| this.ruleResolver = ruleResolver; |
| this.pathResolver = new SourcePathResolver(ruleResolver); |
| this.resourceCompressionMode = resourceCompressionMode; |
| this.resourceFilter = resourcesFilter; |
| this.locales = locales; |
| this.manifest = manifest; |
| this.packageType = packageType; |
| this.cpuFilters = cpuFilters; |
| this.shouldBuildStringSourceMap = shouldBuildStringSourceMap; |
| this.shouldPreDex = shouldPreDex; |
| this.primaryDexPath = primaryDexPath; |
| this.dexSplitMode = dexSplitMode; |
| this.buildTargetsToExcludeFromDex = buildTargetsToExcludeFromDex; |
| this.resourcesToExclude = resourcesToExclude; |
| this.skipCrunchPngs = skipCrunchPngs; |
| this.javacOptions = javacOptions; |
| this.exopackageModes = exopackageModes; |
| this.keystore = keystore; |
| this.buildConfigValues = buildConfigValues; |
| this.buildConfigValuesFile = buildConfigValuesFile; |
| this.nativePlatforms = nativePlatforms; |
| } |
| |
| AndroidGraphEnhancementResult createAdditionalBuildables() { |
| ImmutableSortedSet.Builder<BuildRule> enhancedDeps = ImmutableSortedSet.naturalOrder(); |
| enhancedDeps.addAll(originalDeps); |
| |
| AndroidPackageableCollector collector = |
| new AndroidPackageableCollector( |
| originalBuildTarget, |
| buildTargetsToExcludeFromDex, |
| resourcesToExclude); |
| collector.addPackageables(AndroidPackageableCollector.getPackageableRules(originalDeps)); |
| ImmutableAndroidPackageableCollection packageableCollection = collector.build(); |
| AndroidPackageableCollection.ResourceDetails resourceDetails = |
| packageableCollection.getResourceDetails(); |
| |
| ImmutableSortedSet<BuildRule> resourceRules = |
| getTargetsAsRules(resourceDetails.getResourcesWithNonEmptyResDir()); |
| |
| FilteredResourcesProvider filteredResourcesProvider; |
| boolean needsResourceFiltering = resourceFilter.isEnabled() || |
| resourceCompressionMode.isStoreStringsAsAssets() || |
| !locales.isEmpty(); |
| |
| if (needsResourceFiltering) { |
| BuildRuleParams paramsForResourcesFilter = buildRuleParams.copyWithChanges( |
| BuildRuleType.RESOURCES_FILTER, |
| createBuildTargetWithFlavor(RESOURCES_FILTER_FLAVOR), |
| Suppliers.ofInstance(resourceRules), |
| /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())); |
| ResourcesFilter resourcesFilter = new ResourcesFilter( |
| paramsForResourcesFilter, |
| pathResolver, |
| resourceDetails.getResourceDirectories(), |
| ImmutableSet.copyOf(resourceDetails.getWhitelistedStringDirectories()), |
| locales, |
| resourceCompressionMode, |
| resourceFilter); |
| ruleResolver.addToIndex(resourcesFilter); |
| |
| filteredResourcesProvider = resourcesFilter; |
| enhancedDeps.add(resourcesFilter); |
| resourceRules = ImmutableSortedSet.<BuildRule>of(resourcesFilter); |
| } else { |
| filteredResourcesProvider = |
| new IdentityResourcesProvider(resourceDetails.getResourceDirectories()); |
| } |
| |
| // Create the AaptPackageResourcesBuildable. |
| BuildTarget buildTargetForAapt = createBuildTargetWithFlavor(AAPT_PACKAGE_FLAVOR); |
| BuildRuleParams paramsForAaptPackageResources = buildRuleParams.copyWithChanges( |
| BuildRuleType.AAPT_PACKAGE, |
| buildTargetForAapt, |
| Suppliers.ofInstance( |
| getAdditionalAaptDeps(pathResolver, resourceRules, packageableCollection)), |
| /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())); |
| AaptPackageResources aaptPackageResources = new AaptPackageResources( |
| paramsForAaptPackageResources, |
| pathResolver, |
| manifest, |
| filteredResourcesProvider, |
| getTargetsAsResourceDeps(resourceDetails.getResourcesWithNonEmptyResDir()), |
| packageableCollection.getAssetsDirectories(), |
| packageType, |
| cpuFilters, |
| javacOptions, |
| shouldPreDex, |
| shouldBuildStringSourceMap, |
| locales.isEmpty(), |
| skipCrunchPngs); |
| ruleResolver.addToIndex(aaptPackageResources); |
| enhancedDeps.add(aaptPackageResources); |
| |
| Optional<PackageStringAssets> packageStringAssets = Optional.absent(); |
| if (resourceCompressionMode.isStoreStringsAsAssets()) { |
| BuildTarget buildTargetForPackageStringAssets = |
| createBuildTargetWithFlavor(PACKAGE_STRING_ASSETS_FLAVOR); |
| BuildRuleParams paramsForPackageStringAssets = buildRuleParams.copyWithChanges( |
| BuildRuleType.PACKAGE_STRING_ASSETS, |
| buildTargetForPackageStringAssets, |
| Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of(aaptPackageResources)), |
| /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())); |
| packageStringAssets = Optional.of( |
| new PackageStringAssets( |
| paramsForPackageStringAssets, |
| pathResolver, |
| filteredResourcesProvider, |
| aaptPackageResources)); |
| ruleResolver.addToIndex(packageStringAssets.get()); |
| enhancedDeps.add(packageStringAssets.get()); |
| } |
| |
| // TODO(natthu): Try to avoid re-building the collection by passing UberRDotJava directly. |
| if (packageableCollection.getResourceDetails().hasResources()) { |
| collector.addClasspathEntry( |
| aaptPackageResources, |
| aaptPackageResources.getPathToCompiledRDotJavaFiles()); |
| } |
| |
| // BuildConfig deps should not be added for instrumented APKs because BuildConfig.class has |
| // already been added to the APK under test. |
| ImmutableList<DexProducedFromJavaLibrary> preDexBuildConfigs; |
| ImmutableList<Path> buildConfigJarFiles; |
| if (packageType == PackageType.INSTRUMENTED) { |
| preDexBuildConfigs = ImmutableList.of(); |
| buildConfigJarFiles = ImmutableList.of(); |
| } else { |
| ImmutableList.Builder<DexProducedFromJavaLibrary> preDexBuildConfigsBuilder = |
| ImmutableList.builder(); |
| ImmutableList.Builder<Path> buildConfigJarFilesBuilder = ImmutableList.builder(); |
| addBuildConfigDeps( |
| shouldPreDex, |
| packageableCollection, |
| enhancedDeps, |
| preDexBuildConfigsBuilder, |
| buildConfigJarFilesBuilder); |
| preDexBuildConfigs = preDexBuildConfigsBuilder.build(); |
| buildConfigJarFiles = buildConfigJarFilesBuilder.build(); |
| } |
| |
| packageableCollection = collector.build(); |
| |
| Optional<PreDexMerge> preDexMerge = Optional.absent(); |
| if (shouldPreDex) { |
| preDexMerge = Optional.of(createPreDexMergeRule( |
| aaptPackageResources, |
| preDexBuildConfigs, |
| packageableCollection)); |
| enhancedDeps.add(preDexMerge.get()); |
| } else { |
| enhancedDeps.addAll(getTargetsAsRules(packageableCollection.getJavaLibrariesToDex())); |
| } |
| |
| // Iterate over all the {@link AndroidNativeLinkable}s from the collector and grab the shared |
| // libraries for all the {@link TargetCpuType}s that we care about. We deposit them into a map |
| // of CPU type and SONAME to the shared library path, which the {@link CopyNativeLibraries} |
| // rule will use to compose the destination name. |
| ImmutableMap.Builder<Pair<TargetCpuType, String>, SourcePath> nativeLinkableLibsBuilder = |
| ImmutableMap.builder(); |
| |
| // TODO(agallagher): We currently treat an empty set of filters to mean to allow everything. |
| // We should fix this by assigning a default list of CPU filters in the descriptions, but |
| // until we doIf the set of filters is empty, just build for all available platforms. |
| ImmutableSet<TargetCpuType> filters = |
| cpuFilters.isEmpty() ? nativePlatforms.keySet() : cpuFilters; |
| for (TargetCpuType targetCpuType : filters) { |
| NdkCxxPlatform platform = Preconditions.checkNotNull(nativePlatforms.get(targetCpuType)); |
| |
| for (JavaNativeLinkable nativeLinkable : packageableCollection.getNativeLinkables()) { |
| ImmutableMap<String, SourcePath> solibs = nativeLinkable.getSharedLibraries( |
| platform.getCxxPlatform()); |
| for (Map.Entry<String, SourcePath> entry : solibs.entrySet()) { |
| nativeLinkableLibsBuilder.put( |
| new Pair<>(targetCpuType, entry.getKey()), |
| entry.getValue()); |
| } |
| } |
| |
| // If we're using a C/C++ runtime other than the system one, add it to the APK. |
| NdkCxxPlatforms.CxxRuntime cxxRuntime = platform.getCxxRuntime(); |
| if (!packageableCollection.getNativeLinkables().isEmpty() && |
| !cxxRuntime.equals(NdkCxxPlatforms.CxxRuntime.SYSTEM)) { |
| nativeLinkableLibsBuilder.put( |
| new Pair<>( |
| targetCpuType, |
| cxxRuntime.getSoname()), |
| new PathSourcePath( |
| buildRuleParams.getProjectFilesystem(), |
| platform.getCxxSharedRuntimePath())); |
| } |
| } |
| ImmutableMap<Pair<TargetCpuType, String>, SourcePath> nativeLinkableLibs = |
| nativeLinkableLibsBuilder.build(); |
| |
| Optional<CopyNativeLibraries> copyNativeLibraries = Optional.absent(); |
| if (!packageableCollection.getNativeLibsDirectories().isEmpty() || |
| !nativeLinkableLibs.isEmpty()) { |
| BuildRuleParams paramsForCopyNativeLibraries = buildRuleParams.copyWithChanges( |
| BuildRuleType.COPY_NATIVE_LIBS, |
| createBuildTargetWithFlavor(COPY_NATIVE_LIBS_FLAVOR), |
| Suppliers.ofInstance( |
| ImmutableSortedSet.<BuildRule>naturalOrder() |
| .addAll(getTargetsAsRules(packageableCollection.getNativeLibsTargets())) |
| .addAll(pathResolver.filterBuildRuleInputs(nativeLinkableLibs.values())) |
| .build()), |
| /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())); |
| copyNativeLibraries = Optional.of( |
| new CopyNativeLibraries( |
| paramsForCopyNativeLibraries, |
| pathResolver, |
| packageableCollection.getNativeLibsDirectories(), |
| cpuFilters, |
| nativePlatforms, |
| nativeLinkableLibs)); |
| ruleResolver.addToIndex(copyNativeLibraries.get()); |
| enhancedDeps.add(copyNativeLibraries.get()); |
| } |
| |
| ImmutableSortedSet<BuildRule> finalDeps; |
| Optional<ComputeExopackageDepsAbi> computeExopackageDepsAbi = Optional.absent(); |
| if (!exopackageModes.isEmpty()) { |
| BuildRuleParams paramsForComputeExopackageAbi = buildRuleParams.copyWithChanges( |
| BuildRuleType.EXOPACKAGE_DEPS_ABI, |
| createBuildTargetWithFlavor(CALCULATE_ABI_FLAVOR), |
| Suppliers.ofInstance(enhancedDeps.build()), |
| /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())); |
| computeExopackageDepsAbi = Optional.of( |
| new ComputeExopackageDepsAbi( |
| paramsForComputeExopackageAbi, |
| pathResolver, |
| exopackageModes, |
| packageableCollection, |
| aaptPackageResources, |
| copyNativeLibraries, |
| packageStringAssets, |
| preDexMerge, |
| keystore)); |
| ruleResolver.addToIndex(computeExopackageDepsAbi.get()); |
| finalDeps = ImmutableSortedSet.<BuildRule>of(computeExopackageDepsAbi.get()); |
| } else { |
| finalDeps = enhancedDeps.build(); |
| } |
| |
| return ImmutableAndroidGraphEnhancementResult.builder() |
| .setPackageableCollection(packageableCollection) |
| .setAaptPackageResources(aaptPackageResources) |
| .setCopyNativeLibraries(copyNativeLibraries) |
| .setPackageStringAssets(packageStringAssets) |
| .setPreDexMerge(preDexMerge) |
| .setComputeExopackageDepsAbi(computeExopackageDepsAbi) |
| .setClasspathEntriesToDex(ImmutableSet.<Path>builder() |
| .addAll(packageableCollection.getClasspathEntriesToDex()) |
| .addAll(buildConfigJarFiles) |
| .build()) |
| .setFinalDeps(finalDeps) |
| .build(); |
| } |
| |
| /** |
| * If the user specified any android_build_config() rules, then we must add some build rules to |
| * generate the production {@code BuildConfig.class} files and ensure that they are included in |
| * the list of {@link AndroidPackageableCollection#getClasspathEntriesToDex}. |
| */ |
| private void addBuildConfigDeps( |
| boolean shouldPreDex, |
| AndroidPackageableCollection packageableCollection, |
| ImmutableSortedSet.Builder<BuildRule> enhancedDeps, |
| ImmutableList.Builder<DexProducedFromJavaLibrary> preDexRules, |
| ImmutableList.Builder<Path> buildConfigJarFilesBuilder) { |
| BuildConfigFields buildConfigConstants = BuildConfigFields.fromFields( |
| ImmutableList.<BuildConfigFields.Field>of( |
| ImmutableBuildConfigFields.Field.of( |
| "boolean", |
| BuildConfigs.DEBUG_CONSTANT, |
| String.valueOf(packageType != AndroidBinary.PackageType.RELEASE)), |
| ImmutableBuildConfigFields.Field.of( |
| "boolean", |
| BuildConfigs.IS_EXO_CONSTANT, |
| String.valueOf(!exopackageModes.isEmpty())), |
| ImmutableBuildConfigFields.Field.of( |
| "int", |
| BuildConfigs.EXOPACKAGE_FLAGS, |
| String.valueOf(ExopackageMode.toBitmask(exopackageModes))))); |
| for (Map.Entry<String, BuildConfigFields> entry : |
| packageableCollection.getBuildConfigs().entrySet()) { |
| // Merge the user-defined constants with the APK-specific overrides. |
| BuildConfigFields totalBuildConfigValues = BuildConfigFields.empty() |
| .putAll(entry.getValue()) |
| .putAll(buildConfigValues) |
| .putAll(buildConfigConstants); |
| |
| // Each enhanced dep needs a unique build target, so we parameterize the build target by the |
| // Java package. |
| String javaPackage = entry.getKey(); |
| Flavor flavor = ImmutableFlavor.of("buildconfig_" + javaPackage.replace('.', '_')); |
| BuildRuleParams buildConfigParams = new BuildRuleParams( |
| createBuildTargetWithFlavor(flavor), |
| /* declaredDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()), |
| /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()), |
| buildRuleParams.getProjectFilesystem(), |
| buildRuleParams.getRuleKeyBuilderFactory(), |
| AndroidBuildConfigDescription.TYPE, |
| buildRuleParams.getTargetGraph()); |
| JavaLibrary buildConfigJavaLibrary = AndroidBuildConfigDescription.createBuildRule( |
| buildConfigParams, |
| javaPackage, |
| totalBuildConfigValues, |
| buildConfigValuesFile, |
| /* useConstantExpressions */ true, |
| javacOptions, |
| ruleResolver); |
| ruleResolver.addToIndex(buildConfigJavaLibrary); |
| |
| enhancedDeps.add(buildConfigJavaLibrary); |
| Path buildConfigJar = buildConfigJavaLibrary.getPathToOutputFile(); |
| Preconditions.checkNotNull( |
| buildConfigJar, |
| "%s must have an output file.", |
| buildConfigJavaLibrary); |
| buildConfigJarFilesBuilder.add(buildConfigJar); |
| |
| if (shouldPreDex) { |
| DexProducedFromJavaLibrary buildConfigDex = new DexProducedFromJavaLibrary( |
| buildConfigParams.copyWithChanges( |
| BuildRuleType.PRE_DEX, |
| createBuildTargetWithFlavor(ImmutableFlavor.of("dex_" + flavor.getName())), |
| Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of(buildConfigJavaLibrary)), |
| /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())), |
| pathResolver, |
| buildConfigJavaLibrary); |
| ruleResolver.addToIndex(buildConfigDex); |
| enhancedDeps.add(buildConfigDex); |
| preDexRules.add(buildConfigDex); |
| } |
| } |
| } |
| |
| /** |
| * Creates/finds the set of build rules that correspond to pre-dex'd artifacts that should be |
| * merged to create the final classes.dex for the APK. |
| * <p> |
| * This method may modify {@code ruleResolver}, inserting new rules into its index. |
| */ |
| @VisibleForTesting |
| PreDexMerge createPreDexMergeRule( |
| AaptPackageResources aaptPackageResources, |
| Iterable<DexProducedFromJavaLibrary> preDexRulesNotInThePackageableCollection, |
| AndroidPackageableCollection packageableCollection) { |
| ImmutableSet.Builder<DexProducedFromJavaLibrary> preDexDeps = ImmutableSet.builder(); |
| preDexDeps.addAll(preDexRulesNotInThePackageableCollection); |
| for (BuildTarget buildTarget : packageableCollection.getJavaLibrariesToDex()) { |
| Preconditions.checkState( |
| !buildTargetsToExcludeFromDex.contains(buildTarget), |
| "JavaLibrary should have been excluded from target to dex: %s", buildTarget); |
| |
| BuildRule libraryRule = ruleResolver.getRule(buildTarget); |
| |
| // Skip uber R.java since AaptPackageResources takes care of dexing. |
| if (libraryRule.equals(aaptPackageResources)) { |
| continue; |
| } |
| |
| Preconditions.checkState(libraryRule instanceof JavaLibrary); |
| JavaLibrary javaLibrary = (JavaLibrary) libraryRule; |
| |
| // If the rule has no output file (which happens when a java_library has no srcs or |
| // resources, but export_deps is true), then there will not be anything to dx. |
| if (javaLibrary.getPathToOutputFile() == null) { |
| continue; |
| } |
| |
| // See whether the corresponding IntermediateDexRule has already been added to the |
| // ruleResolver. |
| BuildTarget originalTarget = javaLibrary.getBuildTarget(); |
| BuildTarget preDexTarget = BuildTarget.builder(originalTarget) |
| .addFlavors(DEX_FLAVOR) |
| .build(); |
| Optional<BuildRule> preDexRule = ruleResolver.getRuleOptional(preDexTarget); |
| if (preDexRule.isPresent()) { |
| preDexDeps.add((DexProducedFromJavaLibrary) preDexRule.get()); |
| continue; |
| } |
| |
| // Create the IntermediateDexRule and add it to both the ruleResolver and preDexDeps. |
| BuildRuleParams paramsForPreDex = buildRuleParams.copyWithChanges( |
| BuildRuleType.PRE_DEX, |
| preDexTarget, |
| Suppliers.ofInstance( |
| ImmutableSortedSet.of(ruleResolver.getRule(javaLibrary.getBuildTarget()))), |
| /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())); |
| DexProducedFromJavaLibrary preDex = |
| new DexProducedFromJavaLibrary(paramsForPreDex, pathResolver, javaLibrary); |
| ruleResolver.addToIndex(preDex); |
| preDexDeps.add(preDex); |
| } |
| |
| ImmutableSet<DexProducedFromJavaLibrary> allPreDexDeps = preDexDeps.build(); |
| |
| BuildRuleParams paramsForPreDexMerge = buildRuleParams.copyWithChanges( |
| BuildRuleType.DEX_MERGE, |
| createBuildTargetWithFlavor(DEX_MERGE_FLAVOR), |
| Suppliers.ofInstance(getDexMergeDeps(aaptPackageResources, allPreDexDeps)), |
| /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())); |
| PreDexMerge preDexMerge = new PreDexMerge( |
| paramsForPreDexMerge, |
| pathResolver, |
| primaryDexPath, |
| dexSplitMode, |
| allPreDexDeps, |
| aaptPackageResources); |
| ruleResolver.addToIndex(preDexMerge); |
| |
| return preDexMerge; |
| } |
| |
| private BuildTarget createBuildTargetWithFlavor(Flavor flavor) { |
| return BuildTarget.builder(originalBuildTarget) |
| .addFlavors(flavor) |
| .build(); |
| } |
| |
| private ImmutableSortedSet<BuildRule> getAdditionalAaptDeps( |
| SourcePathResolver resolver, |
| ImmutableSortedSet<BuildRule> resourceRules, |
| AndroidPackageableCollection packageableCollection) { |
| ImmutableSortedSet.Builder<BuildRule> builder = ImmutableSortedSet.<BuildRule>naturalOrder() |
| .addAll(resourceRules) |
| .addAll( |
| getTargetsAsRules( |
| FluentIterable.from( |
| packageableCollection.getResourceDetails() |
| .getResourcesWithEmptyResButNonEmptyAssetsDir()) |
| .transform(HasBuildTarget.TO_TARGET) |
| .toList())); |
| Optional<BuildRule> manifestRule = resolver.getRule(manifest); |
| if (manifestRule.isPresent()) { |
| builder.add(manifestRule.get()); |
| } |
| return builder.build(); |
| } |
| |
| private ImmutableSortedSet<BuildRule> getDexMergeDeps( |
| AaptPackageResources aaptPackageResources, |
| ImmutableSet<DexProducedFromJavaLibrary> preDexDeps) { |
| ImmutableSet.Builder<BuildTarget> targets = ImmutableSet.builder(); |
| targets.add(aaptPackageResources.getBuildTarget()); |
| for (DexProducedFromJavaLibrary preDex : preDexDeps) { |
| targets.add(preDex.getBuildTarget()); |
| } |
| return getTargetsAsRules(targets.build()); |
| } |
| |
| private ImmutableSortedSet<BuildRule> getTargetsAsRules(Collection<BuildTarget> buildTargets) { |
| return BuildRules.toBuildRulesFor( |
| originalBuildTarget, |
| ruleResolver, |
| buildTargets, |
| /* allowNonExistentRules */ false); |
| } |
| |
| private ImmutableList<HasAndroidResourceDeps> getTargetsAsResourceDeps( |
| Collection<BuildTarget> targets) { |
| return FluentIterable.from(getTargetsAsRules(targets)) |
| .transform(new Function<BuildRule, HasAndroidResourceDeps>() { |
| @Override |
| public HasAndroidResourceDeps apply(BuildRule input) { |
| Preconditions.checkState(input instanceof HasAndroidResourceDeps); |
| return (HasAndroidResourceDeps) input; |
| } |
| }) |
| .toList(); |
| } |
| } |