diff options
author | Googler <noreply@google.com> | 2016-05-04 23:15:00 +0000 |
---|---|---|
committer | Kristina Chodorow <kchodorow@google.com> | 2016-05-05 19:10:24 +0000 |
commit | 88ccf0c9f490a5138719c3bb476b17eb1d8384e2 (patch) | |
tree | d5592d85c0f06d941b5f9dac26fccebf0190796f | |
parent | 1f2cb5c56291efab2989e6a342898560ebef3fca (diff) |
[Android] Support aapt-generated main dex specs.
Add bazel support for using the "aapt -D" command to generate a proguard
specification for components which need to be in the main dex.
--
MOS_MIGRATED_REVID=121531584
14 files changed, 152 insertions, 27 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD index 71ca85b3bd..a2848fa67a 100644 --- a/src/main/java/com/google/devtools/build/lib/BUILD +++ b/src/main/java/com/google/devtools/build/lib/BUILD @@ -774,6 +774,7 @@ java_library( "//src/main/java/com/google/devtools/common/options", "//src/main/protobuf:android_deploy_info_java_proto", "//src/main/protobuf:apk_manifest_java_proto", + "//third_party:android_sdklib", "//third_party:jsr305", "//third_party/protobuf", ], diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAaptActionHelper.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAaptActionHelper.java index 51587308b5..8442bbc968 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAaptActionHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAaptActionHelper.java @@ -33,11 +33,13 @@ import com.google.devtools.build.lib.util.Preconditions; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; +import javax.annotation.Nullable; + /** * Helper class to generate Android aapt actions. */ @@ -173,6 +175,12 @@ public final class AndroidAaptActionHelper { private List<String> createAaptCommand(String actionKind, Artifact output, Artifact rTxtOutput, boolean inlineConstants, String... outputArgs) { + return createAaptCommand( + actionKind, output, rTxtOutput, inlineConstants, Arrays.asList(outputArgs)); + } + + private List<String> createAaptCommand(String actionKind, Artifact output, + Artifact rTxtOutput, boolean inlineConstants, Collection<String> outputArgs) { List<String> args = new ArrayList<>(); args.addAll(getArgs(output, actionKind, ResourceType.RESOURCES)); args.addAll(getArgs(output, actionKind, ResourceType.ASSETS)); @@ -181,7 +189,7 @@ public final class AndroidAaptActionHelper { args.add( AndroidSdkProvider.fromRuleContext(ruleContext).getAapt().getExecutable().getExecPathString()); args.add("package"); - Collections.addAll(args, outputArgs); + args.addAll(outputArgs); // Allow overlay in case the same resource appears in more than one target, // giving precedence to the order in which they are found. This is needed // in order to support android library projects. @@ -266,13 +274,25 @@ public final class AndroidAaptActionHelper { "_" + resourceType.getAttribute() + "_" + actionKind)); } - public void createGenerateProguardAction(Artifact outputSpec) { - List<String> aaptCommand = createAaptCommand("proguard", outputSpec, null, true, - "-G", outputSpec.getExecPathString()); + public void createGenerateProguardAction( + Artifact outputSpec, @Nullable Artifact outputMainDexSpec) { + ImmutableList.Builder<Artifact> outputs = ImmutableList.builder(); + ImmutableList.Builder<String> aaptArgs = ImmutableList.builder(); + + outputs.add(outputSpec); + aaptArgs.add("-G").add(outputSpec.getExecPathString()); + + if (outputMainDexSpec != null) { + aaptArgs.add("-D").add(outputMainDexSpec.getExecPathString()); + outputs.add(outputMainDexSpec); + } + + List<String> aaptCommand = + createAaptCommand("proguard", outputSpec, null, true, aaptArgs.build()); ruleContext.registerAction(new SpawnAction.Builder() .addInputs(getInputs()) .addTool(AndroidSdkProvider.fromRuleContext(ruleContext).getAapt()) - .addOutput(outputSpec) + .addOutputs(outputs.build()) .setExecutable( ruleContext.getExecutablePrerequisite("$android_aapt_apk_generator", Mode.HOST)) .setCommandLine(CommandLine.of(aaptCommand, false)) diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java index b8a2a9c828..ad773bcbe1 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java @@ -232,6 +232,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { versionName, false, /* incremental */ ProguardHelper.getProguardConfigArtifact(ruleContext, ""), + createMainDexProguardSpec(ruleContext), null, /* manifestOut */ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP)); if (ruleContext.hasErrors()) { @@ -254,6 +255,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { versionName, true, /* incremental */ ProguardHelper.getProguardConfigArtifact(ruleContext, "incremental"), + null, /* mainDexProguardCfg */ null, /* manifestOut */ null /* mergedResourcesOut */); if (ruleContext.hasErrors()) { @@ -276,6 +278,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { versionName, true, /* incremental */ ProguardHelper.getProguardConfigArtifact(ruleContext, "incremental_split"), + null, /* mainDexProguardCfg */ null, /* manifestOut */ null /* mergedResourcesOut */); if (ruleContext.hasErrors()) { @@ -302,10 +305,12 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ruleContext, resourceDeps, true, - ProguardHelper.getProguardConfigArtifact(ruleContext, "")); + ProguardHelper.getProguardConfigArtifact(ruleContext, ""), + createMainDexProguardSpec(ruleContext)); } else { resourceApk = applicationManifest.useCurrentResources(ruleContext, - ProguardHelper.getProguardConfigArtifact(ruleContext, "")); + ProguardHelper.getProguardConfigArtifact(ruleContext, ""), + createMainDexProguardSpec(ruleContext)); } incrementalResourceApk = applicationManifest .addStubApplication(ruleContext) @@ -315,7 +320,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ruleContext, resourceDeps, false, - ProguardHelper.getProguardConfigArtifact(ruleContext, "incremental")); + ProguardHelper.getProguardConfigArtifact(ruleContext, "incremental"), + null /* mainDexProguardConfig */); if (ruleContext.hasErrors()) { return null; } @@ -326,7 +332,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ruleContext, resourceDeps, false, - ProguardHelper.getProguardConfigArtifact(ruleContext, "incremental_split")); + ProguardHelper.getProguardConfigArtifact(ruleContext, "incremental_split"), + null /* mainDexProguardConfig */); if (ruleContext.hasErrors()) { return null; } @@ -416,6 +423,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { jarToDex, isBinaryJarFiltered, androidCommon, + resourceApk.getMainDexProguardConfig(), resourceClasses); if (dexingOutput == null) { return null; @@ -1056,6 +1064,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { Artifact proguardedJar, boolean isBinaryJarFiltered, AndroidCommon common, + @Nullable Artifact mainDexProguardSpec, JavaTargetAttributes attributes) throws InterruptedException { boolean finalJarIsDerived = isBinaryJarFiltered || binaryJar != proguardedJar; @@ -1114,7 +1123,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { if (multidexMode == MultidexMode.LEGACY) { // For legacy multidex, we need to generate a list for the dexer's --main-dex-list flag. - mainDexList = createMainDexListAction(ruleContext, proguardedJar); + mainDexList = createMainDexListAction(ruleContext, proguardedJar, mainDexProguardSpec); } Artifact classesDex = getDxArtifact(ruleContext, "classes.dex.zip"); @@ -1351,7 +1360,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { * --main-dex-list flag (which specifies the classes that need to be directly in classes.dex). * Returns the file containing the list. */ - static Artifact createMainDexListAction(RuleContext ruleContext, Artifact jar) { + static Artifact createMainDexListAction( + RuleContext ruleContext, Artifact jar, @Nullable Artifact mainDexProguardSpec) { // Process the input jar through Proguard into an intermediate, streamlined jar. Artifact strippedJar = AndroidBinary.getDxArtifact(ruleContext, "main_dex_intermediate.jar"); AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext); @@ -1373,10 +1383,14 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { .addArgument("-dontobfuscate") .addArgument("-dontpreverify"); - List<Artifact> specs = ruleContext.getPrerequisiteArtifacts( - "main_dex_proguard_specs", Mode.TARGET).list(); + List<Artifact> specs = new ArrayList<>(); + specs.addAll( + ruleContext.getPrerequisiteArtifacts("main_dex_proguard_specs", Mode.TARGET).list()); if (specs.isEmpty()) { - specs = ImmutableList.of(sdk.getMainDexClasses()); + specs.add(sdk.getMainDexClasses()); + } + if (mainDexProguardSpec != null) { + specs.add(mainDexProguardSpec); } for (Artifact spec : specs) { @@ -1424,6 +1438,13 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { return splitResources; } + @Nullable + private static Artifact createMainDexProguardSpec(RuleContext ruleContext) { + return AndroidSdkProvider.fromRuleContext(ruleContext).getAaptSupportsMainDexGeneration() + ? ProguardHelper.getProguardConfigArtifact(ruleContext, "main_dex") + : null; + } + /** * Builder class for {@link com.google.devtools.build.lib.analysis.actions.SpawnAction}s that * generate APKs. diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java index 2e4e7756c4..ed5a839a27 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java @@ -96,6 +96,7 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { null /* versionName */, false, null /* proguardCfgOut */, + null, /* mainDexProguardCfg */ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_MANIFEST), null /* mergedResourcesOut */); if (ruleContext.hasErrors()) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java index 2c3606f1e1..7967f92934 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java @@ -58,6 +58,7 @@ public class AndroidResourcesProcessorBuilder { private ResourceContainer primary; private ResourceDependencies dependencies; private Artifact proguardOut; + private Artifact mainDexProguardOut; private Artifact rTxtOut; private Artifact sourceJarOut; private boolean debug = false; @@ -134,6 +135,11 @@ public class AndroidResourcesProcessorBuilder { return this; } + public AndroidResourcesProcessorBuilder setMainDexProguardOut(Artifact mainDexProguardCfg) { + this.mainDexProguardOut = mainDexProguardCfg; + return this; + } + public AndroidResourcesProcessorBuilder setRTxtOut(Artifact rTxtOut) { this.rTxtOut = rTxtOut; return this; @@ -308,6 +314,11 @@ public class AndroidResourcesProcessorBuilder { outs.add(proguardOut); } + if (mainDexProguardOut != null) { + builder.addExecPath("--mainDexProguardOutput", mainDexProguardOut); + outs.add(mainDexProguardOut); + } + if (manifestOut != null) { builder.addExecPath("--manifestOutput", manifestOut); outs.add(manifestOut); diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java index 016fedf990..a4d32e9ec4 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java @@ -13,6 +13,7 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.ConfiguredTarget; @@ -31,6 +32,8 @@ import com.google.devtools.build.lib.rules.java.JavaConfiguration; import com.google.devtools.build.lib.rules.java.JavaToolchainProvider; import com.google.devtools.build.lib.syntax.Type; +import com.android.sdklib.repository.FullRevision; + import java.util.Collection; /** @@ -48,6 +51,18 @@ public class AndroidSdk implements RuleConfiguredTargetFactory { String buildToolsVersion = AggregatingAttributeMapper.of(ruleContext.getRule()) .get("build_tools_version", Type.STRING); + FullRevision parsedBuildToolsVersion = null; + try { + parsedBuildToolsVersion = + Strings.isNullOrEmpty(buildToolsVersion) + ? null + : FullRevision.parseRevision(buildToolsVersion); + } catch (NumberFormatException nfe) { + ruleContext.attributeError("build_tools_version", "Invalid version: " + buildToolsVersion); + } + boolean aaptSupportsMainDexGeneration = + parsedBuildToolsVersion == null + || parsedBuildToolsVersion.compareTo(new FullRevision(24)) >= 0; FilesToRunProvider aidl = ruleContext.getExecutablePrerequisite("aidl", Mode.HOST); FilesToRunProvider aapt = ruleContext.getExecutablePrerequisite("aapt", Mode.HOST); FilesToRunProvider apkBuilder = ruleContext.getExecutablePrerequisite( @@ -91,6 +106,7 @@ public class AndroidSdk implements RuleConfiguredTargetFactory { AndroidSdkProvider.class, new AndroidSdkProvider( buildToolsVersion, + aaptSupportsMainDexGeneration, frameworkAidl, androidJar, shrinkedAndroidJar, diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdkProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdkProvider.java index 2a3065fc42..59efb5505c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdkProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdkProvider.java @@ -29,6 +29,7 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; public final class AndroidSdkProvider implements TransitiveInfoProvider { private final String buildToolsVersion; + private final boolean aaptSupportsMainDexGeneration; private final Artifact frameworkAidl; private final Artifact androidJar; private final Artifact shrinkedAndroidJar; @@ -50,6 +51,7 @@ public final class AndroidSdkProvider implements TransitiveInfoProvider { public AndroidSdkProvider( String buildToolsVersion, + boolean aaptSupportsMainDexGeneration, Artifact frameworkAidl, Artifact androidJar, Artifact shrinkedAndroidJar, @@ -70,6 +72,7 @@ public final class AndroidSdkProvider implements TransitiveInfoProvider { FilesToRunProvider resourceExtractor) { this.buildToolsVersion = buildToolsVersion; + this.aaptSupportsMainDexGeneration = aaptSupportsMainDexGeneration; this.frameworkAidl = frameworkAidl; this.androidJar = androidJar; this.shrinkedAndroidJar = shrinkedAndroidJar; @@ -122,7 +125,11 @@ public final class AndroidSdkProvider implements TransitiveInfoProvider { public String getBuildToolsVersion() { return buildToolsVersion; } - + + public boolean getAaptSupportsMainDexGeneration() { + return aaptSupportsMainDexGeneration; + } + public Artifact getFrameworkAidl() { return frameworkAidl; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java b/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java index c0f1d1ed54..252ed1e8e9 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java @@ -34,6 +34,8 @@ import com.google.devtools.build.lib.vfs.PathFragment; import java.util.List; import java.util.Map; +import javax.annotation.Nullable; + /** Represents a AndroidManifest, that may have been merged from dependencies. */ public final class ApplicationManifest { public static ApplicationManifest fromResourcesRule(RuleContext ruleContext) { @@ -230,6 +232,7 @@ public final class ApplicationManifest { incremental, data, proguardCfg, + null, /* Artifact mainDexProguardCfg */ null, /* Artifact manifestOut */ null /* Artifact mergedResources */); } @@ -253,6 +256,7 @@ public final class ApplicationManifest { String versionName, boolean incremental, Artifact proguardCfg, + @Nullable Artifact mainDexProguardCfg, Artifact manifestOut, Artifact mergedResources) throws InterruptedException { LocalResourceContainer data = new LocalResourceContainer.Builder(ruleContext) @@ -287,6 +291,7 @@ public final class ApplicationManifest { incremental, data, proguardCfg, + mainDexProguardCfg, manifestOut, mergedResources); } @@ -307,6 +312,7 @@ public final class ApplicationManifest { boolean incremental, LocalResourceContainer data, Artifact proguardCfg, + @Nullable Artifact mainDexProguardCfg, Artifact manifestOut, Artifact mergedResources) throws InterruptedException { ResourceContainer resourceContainer = checkForInlinedResources( @@ -340,6 +346,7 @@ public final class ApplicationManifest { .withDependencies(resourceDeps) .setDensities(densities) .setProguardOut(proguardCfg) + .setMainDexProguardOut(mainDexProguardCfg) .setApplicationId(applicationId) .setVersionCode(versionCode) .setVersionName(versionName); @@ -355,7 +362,7 @@ public final class ApplicationManifest { return new ResourceApk( resourceApk, processed.getJavaSourceJar(), resourceDeps, processed, manifest, - proguardCfg, false); + proguardCfg, mainDexProguardCfg, false); } private static ResourceContainer checkForInlinedResources(ResourceContainer resourceContainer, @@ -375,14 +382,16 @@ public final class ApplicationManifest { } /** Uses the resource apk from the resources attribute, as opposed to recompiling. */ - public ResourceApk useCurrentResources(RuleContext ruleContext, Artifact proguardCfg) { + public ResourceApk useCurrentResources( + RuleContext ruleContext, Artifact proguardCfg, @Nullable Artifact mainDexProguardCfg) { ResourceContainer resourceContainer = Iterables.getOnlyElement( AndroidCommon.getAndroidResources(ruleContext).getDirectAndroidResources()); new AndroidAaptActionHelper( ruleContext, resourceContainer.getManifest(), - Lists.newArrayList(resourceContainer)).createGenerateProguardAction(proguardCfg); + Lists.newArrayList(resourceContainer)) + .createGenerateProguardAction(proguardCfg, mainDexProguardCfg); return new ResourceApk( resourceContainer.getApk(), @@ -391,6 +400,7 @@ public final class ApplicationManifest { resourceContainer, manifest, proguardCfg, + mainDexProguardCfg, false); } @@ -406,7 +416,8 @@ public final class ApplicationManifest { RuleContext ruleContext, ResourceDependencies resourceDeps, boolean createSource, - Artifact proguardCfg) throws InterruptedException { + Artifact proguardCfg, + @Nullable Artifact mainDexProguardCfg) throws InterruptedException { TransitiveInfoCollection resourcesPrerequisite = ruleContext.getPrerequisite("resources", Mode.TARGET); @@ -478,10 +489,10 @@ public final class ApplicationManifest { resourceContainer.isManifestExported(), resourceContainer.getRTxt(), null); - aaptActionHelper.createGenerateProguardAction(proguardCfg); + aaptActionHelper.createGenerateProguardAction(proguardCfg, mainDexProguardCfg); return new ResourceApk(resourceApk, updatedResources.getJavaSourceJar(), - resourceDeps, updatedResources, manifest, proguardCfg, true); + resourceDeps, updatedResources, manifest, proguardCfg, mainDexProguardCfg, true); } public Artifact getManifest() { diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java index 0b7bbfc4fc..505be25d3a 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java @@ -26,15 +26,16 @@ import javax.annotation.Nullable; */ @Immutable public final class ResourceApk { - // TODO(bazel-team): The only field that is legitimately nullable is javaSrcJar. The rest is - // marked as such due to .fromTransitiveResources(). It seems like there should be a better way - // to do this. + // TODO(bazel-team): The only fields that are legitimately nullable are javaSrcJar and + // mainDexProguardConfig. The rest are marked as such due to .fromTransitiveResources(). + // It seems like there should be a better way to do this. @Nullable private final Artifact resourceApk; // The .ap_ file @Nullable private final Artifact resourceJavaSrcJar; // Source jar containing R.java and friends private final ResourceDependencies resourceDeps; @Nullable private final ResourceContainer primaryResource; @Nullable private final Artifact manifest; // The non-binary XML version of AndroidManifest.xml @Nullable private final Artifact resourceProguardConfig; + @Nullable private final Artifact mainDexProguardConfig; private final boolean legacy; public ResourceApk( @@ -44,6 +45,7 @@ public final class ResourceApk { @Nullable ResourceContainer primaryResource, @Nullable Artifact manifest, @Nullable Artifact resourceProguardConfig, + @Nullable Artifact mainDexProguardConfig, boolean legacy) { this.resourceApk = resourceApk; this.resourceJavaSrcJar = resourceJavaSrcJar; @@ -51,6 +53,7 @@ public final class ResourceApk { this.primaryResource = primaryResource; this.manifest = manifest; this.resourceProguardConfig = resourceProguardConfig; + this.mainDexProguardConfig = mainDexProguardConfig; this.legacy = legacy; } @@ -76,13 +79,17 @@ public final class ResourceApk { public static ResourceApk fromTransitiveResources( ResourceDependencies resourceDeps) { - return new ResourceApk(null, null, resourceDeps, null, null, null, false); + return new ResourceApk(null, null, resourceDeps, null, null, null, null, false); } public Artifact getResourceProguardConfig() { return resourceProguardConfig; } + public Artifact getMainDexProguardConfig() { + return mainDexProguardConfig; + } + public ResourceDependencies getResourceDependencies() { return resourceDeps; } diff --git a/src/tools/android/java/com/google/devtools/build/android/AaptCommandBuilder.java b/src/tools/android/java/com/google/devtools/build/android/AaptCommandBuilder.java index 83591e73d5..d1f5a54dcb 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AaptCommandBuilder.java +++ b/src/tools/android/java/com/google/devtools/build/android/AaptCommandBuilder.java @@ -83,6 +83,13 @@ class AaptCommandBuilder { return this; } + AaptCommandBuilder maybeAdd(String flag, @Nullable Path path, FullRevision requiredVersion) { + if (buildToolsVersion == null || buildToolsVersion.compareTo(requiredVersion) >= 0) { + add(flag, path); + } + return this; + } + AaptCommandBuilder maybeAdd(String flag, FullRevision requiredVersion) { if (buildToolsVersion == null || buildToolsVersion.compareTo(requiredVersion) >= 0) { add(flag); diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java index ba8e557f62..29112c97ca 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java @@ -141,6 +141,13 @@ public class AndroidResourceProcessingAction { help = "Path for the proguard file.") public Path proguardOutput; + @Option(name = "mainDexProguardOutput", + defaultValue = "null", + converter = PathConverter.class, + category = "output", + help = "Path for the main dex proguard file.") + public Path mainDexProguardOutput; + @Option(name = "manifestOutput", defaultValue = "null", converter = PathConverter.class, @@ -285,6 +292,7 @@ public class AndroidResourceProcessingAction { generatedSources, options.packagePath, options.proguardOutput, + options.mainDexProguardOutput, options.resourcesOutput != null ? processedManifestData.getResourceDir().resolve("values").resolve("public.xml") : null); diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java index 714970b75f..97eedb18d0 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java @@ -329,6 +329,7 @@ public class AndroidResourceProcessor { Path sourceOut, Path packageOut, Path proguardOut, + Path mainDexProguardOut, Path publicResourcesOut) throws IOException, InterruptedException, LoggedErrorException { List<SymbolFileProvider> libraries = new ArrayList<>(); @@ -370,6 +371,7 @@ public class AndroidResourceProcessor { .maybeAdd("--output-text-symbols", prepareOutputPath(sourceOut), sourceOut != null) .add("-F", packageOut) .add("-G", proguardOut) + .maybeAdd("-D", mainDexProguardOut, new FullRevision(24)) .add("-P", publicResourcesOut) .maybeAdd("--debug-mode", debug) .add("--custom-package", customPackageForR) @@ -398,6 +400,9 @@ public class AndroidResourceProcessor { if (proguardOut != null) { Files.setLastModifiedTime(proguardOut, FileTime.fromMillis(0L)); } + if (mainDexProguardOut != null) { + Files.setLastModifiedTime(mainDexProguardOut, FileTime.fromMillis(0L)); + } if (packageOut != null) { Files.setLastModifiedTime(packageOut, FileTime.fromMillis(0L)); } diff --git a/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java b/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java index d5b9774bf3..86ae74d81d 100644 --- a/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java @@ -217,6 +217,7 @@ public class ResourceShrinkerAction { null /* sourceOutputDir */, options.shrunkApk, null /* proguardOutput */, + null /* mainDexProguardOutput */, null /* publicResourcesOut */); if (options.shrunkResources != null) { resourceProcessor.createResourcesZip(shrunkResources, resourceFiles.resolve("assets"), diff --git a/third_party/BUILD b/third_party/BUILD index 7f8f643662..6d7724bda8 100644 --- a/third_party/BUILD +++ b/third_party/BUILD @@ -70,6 +70,13 @@ java_import( ) java_import( + name = "android_sdklib", + jars = [ + "android_common/com.android.tools_sdklib_23.1.3.jar", + ], +) + +java_import( name = "android_common", jars = [ "android_common/com.android.tools.build_builder_0.13.3.jar", @@ -77,9 +84,11 @@ java_import( "android_common/com.android.tools.build_manifest-merger_23.1.3.jar", "android_common/com.android.tools_common_23.1.3.jar", "android_common/com.android.tools_sdk-common_23.1.3.jar", - "android_common/com.android.tools_sdklib_23.1.3.jar", "android_common/com.android.tools.layoutlib_layoutlib_23.1.3.jar", ], + exports = [ + ":android_sdklib", + ], ) java_import( |