Extract `aapt2 optimize` to a new action.
PiperOrigin-RevId: 268106770
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/Aapt2OptimizeActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/Aapt2OptimizeActionBuilder.java
new file mode 100644
index 0000000..77574f1
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/Aapt2OptimizeActionBuilder.java
@@ -0,0 +1,62 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// 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.google.devtools.build.lib.rules.android;
+
+import com.google.auto.value.AutoValue;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
+import javax.annotation.Nullable;
+
+/** Helper for creating an {@code aapt2 optimize} action. */
+@AutoValue
+abstract class Aapt2OptimizeActionBuilder {
+
+ void registerAction(AndroidDataContext dataContext) {
+ BusyBoxActionBuilder builder =
+ BusyBoxActionBuilder.create(dataContext, "AAPT2_OPTIMIZE")
+ .addAapt(AndroidAaptVersion.AAPT2)
+ .addFlag("--");
+ if (resourcePathShorteningMapOut() != null) {
+ builder
+ .addFlag("--enable-resource-path-shortening")
+ .addOutput("--resource-path-shortening-map", resourcePathShorteningMapOut());
+ }
+ builder
+ .addOutput("-o", optimizedApkOut())
+ .addInput(resourceApk())
+ .buildAndRegister("Optimizing Android resources", "Aapt2Optimize");
+ }
+
+ abstract Artifact resourceApk();
+
+ abstract Artifact optimizedApkOut();
+
+ @Nullable
+ abstract Artifact resourcePathShorteningMapOut();
+
+ static Builder builder() {
+ return new AutoValue_Aapt2OptimizeActionBuilder.Builder();
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ abstract Builder setResourceApk(Artifact apk);
+
+ abstract Builder setOptimizedApkOut(Artifact apk);
+
+ abstract Builder setResourcePathShorteningMapOut(Artifact map);
+
+ abstract Aapt2OptimizeActionBuilder build();
+ }
+}
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 c39ea97..03a3666 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
@@ -359,6 +359,10 @@
AndroidBinaryMobileInstall.createMobileInstallResourceApks(
ruleContext, dataContext, manifest);
+ boolean optimizeResources =
+ AndroidAaptVersion.chooseTargetAaptVersion(ruleContext) == AndroidAaptVersion.AAPT2
+ && dataContext.useResourcePathShortening();
+
return createAndroidBinary(
ruleContext,
dataContext,
@@ -373,6 +377,7 @@
resourceApk,
mobileInstallResourceApks,
shrinkResources,
+ optimizeResources,
resourceClasses,
ImmutableList.<Artifact>of(),
ImmutableList.<Artifact>of(),
@@ -395,6 +400,7 @@
ResourceApk resourceApk,
@Nullable MobileInstallResourceApks mobileInstallResourceApks,
boolean shrinkResources,
+ boolean optimizeResources,
JavaTargetAttributes resourceClasses,
ImmutableList<Artifact> apksUnderTest,
ImmutableList<Artifact> additionalMergedManifests,
@@ -430,8 +436,7 @@
// TODO(bazel-team): Verify that proguard spec files don't contain -printmapping directions
// which this -printmapping command line flag will override.
Artifact proguardOutputMap = null;
- if (ProguardHelper.genProguardMapping(ruleContext.attributes())
- || shrinkResources) {
+ if (ProguardHelper.genProguardMapping(ruleContext.attributes()) || shrinkResources) {
proguardOutputMap = androidSemantics.getProguardOutputMap(ruleContext);
}
@@ -457,6 +462,10 @@
filesBuilder);
}
+ if (optimizeResources) {
+ resourceApk = optimizeResources(dataContext, resourceApk);
+ }
+
Artifact jarToDex = proguardOutput.getOutputJar();
DexingOutput dexingOutput =
dex(
@@ -954,6 +963,25 @@
.build(dataContext));
}
+ private static ResourceApk optimizeResources(
+ AndroidDataContext dataContext, ResourceApk resourceApk) throws InterruptedException {
+ Artifact optimizedApk =
+ dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_OPTIMIZED_APK);
+
+ Aapt2OptimizeActionBuilder.Builder builder =
+ Aapt2OptimizeActionBuilder.builder()
+ .setResourceApk(resourceApk.getArtifact())
+ .setOptimizedApkOut(optimizedApk);
+ if (dataContext.useResourcePathShortening()) {
+ builder.setResourcePathShorteningMapOut(
+ dataContext.createOutputArtifact(
+ AndroidRuleClasses.ANDROID_RESOURCE_PATH_SHORTENING_MAP));
+ }
+ builder.build().registerAction(dataContext);
+
+ return resourceApk.withApk(optimizedApk);
+ }
+
@Immutable
static final class DexingOutput {
private final Artifact classesDexZip;
@@ -1255,12 +1283,7 @@
ruleContext, multidex ? "minimal" : "off", dexArchives, classesDex, mainDexList, dexopts);
} else {
SpecialArtifact shardsToMerge =
- createSharderAction(
- ruleContext,
- dexArchives,
- mainDexList,
- dexopts,
- inclusionFilterJar);
+ createSharderAction(ruleContext, dexArchives, mainDexList, dexopts, inclusionFilterJar);
Artifact multidexShards = createTemplatedMergerActions(ruleContext, shardsToMerge, dexopts);
// TODO(b/69431301): avoid this action and give the files to apk build action directly
createZipMergeAction(ruleContext, multidexShards, classesDex);
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 6c0fab1..48db0b2 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
@@ -42,7 +42,6 @@
private Artifact proguardOut;
private Artifact mainDexProguardOut;
- private Artifact resourcePathShorteningMapOut;
private boolean conditionalKeepRules;
private Artifact rTxtOut;
private Artifact sourceJarOut;
@@ -125,12 +124,6 @@
return this;
}
- public AndroidResourcesProcessorBuilder setResourcePathShorteningMapOut(
- Artifact resourcePathShorteningMapOut) {
- this.resourcePathShorteningMapOut = resourcePathShorteningMapOut;
- return this;
- }
-
public AndroidResourcesProcessorBuilder setRTxtOut(Artifact rTxtOut) {
this.rTxtOut = rTxtOut;
return this;
@@ -333,12 +326,6 @@
.addTransitiveInputValues(assetDependencies.getTransitiveCompiledSymbols());
}
- if (resourcePathShorteningMapOut != null) {
- builder
- .addFlag("--resourcePathShortening")
- .maybeAddOutput("--resourcePathShorteningMapOutput", resourcePathShorteningMapOut);
- }
-
builder.maybeAddFlag("--conditionalKeepRules", conditionalKeepRules);
configureCommonFlags(dataContext, primaryResources, primaryAssets, primaryManifest, builder)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
index d0a1f94..cfafdc1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
@@ -108,6 +108,8 @@
fromTemplates("%{name}_files/%{name}_resources_aapt2-src.jar");
public static final SafeImplicitOutputsFunction ANDROID_RESOURCES_SHRUNK_APK =
fromTemplates("%{name}_shrunk.ap_");
+ public static final SafeImplicitOutputsFunction ANDROID_RESOURCES_OPTIMIZED_APK =
+ fromTemplates("%{name}_optimized.ap_");
public static final SafeImplicitOutputsFunction ANDROID_RESOURCES_ZIP =
fromTemplates("%{name}_files/resource_files.zip");
public static final SafeImplicitOutputsFunction ANDROID_ASSETS_ZIP =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java
index d93b9f4..4d6ad92 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java
@@ -71,6 +71,14 @@
}
/** Adds a direct input artifact. */
+ public BusyBoxActionBuilder addInput(Artifact value) {
+ Preconditions.checkNotNull(value);
+ commandLine.addExecPath(value);
+ inputs.add(value);
+ return this;
+ }
+
+ /** Adds a direct input artifact. */
public BusyBoxActionBuilder addInput(@CompileTimeConstant String arg, Artifact value) {
Preconditions.checkNotNull(value);
commandLine.addExecPath(arg, value);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java b/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java
index c33220e..f5a2e44 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java
@@ -73,10 +73,6 @@
throw errorConsumer.throwWithRuleError(
"resource cycle shrinking can only be enabled for builds with aapt2");
}
- if (dataContext.useResourcePathShortening() && aaptVersion != AndroidAaptVersion.AAPT2) {
- throw errorConsumer.throwWithRuleError(
- "resource path shortening can only be enabled for builds with aapt2");
- }
AndroidResourcesProcessorBuilder builder =
builderForNonIncrementalTopLevelTarget(dataContext, manifest, manifestValues, aaptVersion)
@@ -88,11 +84,6 @@
AndroidBinary.createMainDexProguardSpec(
dataContext.getLabel(), dataContext.getActionConstructionContext()))
.conditionalKeepRules(conditionalKeepRules);
- if (dataContext.useResourcePathShortening()) {
- builder.setResourcePathShorteningMapOut(
- dataContext.createOutputArtifact(
- AndroidRuleClasses.ANDROID_RESOURCE_PATH_SHORTENING_MAP));
- }
dataBindingContext.supplyLayoutInfo(builder::setDataBindingInfoZip);
return buildActionForBinary(
dataContext,
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
index 34097a8..f4468df 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.getArtifactsEndingWith;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.getFirstArtifactEndingWith;
+import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.hasInput;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.prettyArtifactNames;
import static com.google.devtools.build.lib.rules.java.JavaCompileActionTestHelper.getJavacArguments;
import static com.google.devtools.build.lib.rules.java.JavaCompileActionTestHelper.getProcessorpath;
@@ -937,7 +938,7 @@
}
@Test
- public void testResourcePathShortening_flagEnabledAndCOpt_flagsGetPassedToAction()
+ public void testResourcePathShortening_flagEnabledAndCOpt_optimizedApkIsInputToApkBuilderAction()
throws Exception {
useConfiguration("--experimental_android_resource_path_shortening", "-c", "opt");
@@ -945,23 +946,26 @@
Set<Artifact> artifacts = actionsTestUtil().artifactClosureOf(getFilesToBuild(binary));
- Artifact resourcePathShorteningMapArtifact =
- getFirstArtifactEndingWith(artifacts, "app_resource_paths.map");
- assertThat(resourcePathShorteningMapArtifact).isNotNull();
- assertThat(getGeneratingAction(resourcePathShorteningMapArtifact).getMnemonic())
- .isEqualTo("AndroidAapt2");
+ SpawnAction optimizeAction =
+ getGeneratingSpawnAction(getFirstArtifactEndingWith(artifacts, "app_optimized.ap_"));
+ assertThat(optimizeAction.getMnemonic()).isEqualTo("Aapt2Optimize");
+ assertThat(getGeneratingAction(getFirstArtifactEndingWith(artifacts, "app_resource_paths.map")))
+ .isEqualTo(optimizeAction);
- Artifact androidResourcesApk = getFirstArtifactEndingWith(artifacts, ".ap_");
- assertThat(getGeneratingAction(androidResourcesApk).getMnemonic()).isEqualTo("AndroidAapt2");
-
- List<String> processingArgs = getGeneratingSpawnActionArgs(androidResourcesApk);
- assertThat(processingArgs).contains("--resourcePathShortening");
- assertThat(flagValue("--resourcePathShorteningMapOutput", processingArgs))
+ List<String> processingArgs = optimizeAction.getArguments();
+ assertThat(processingArgs).contains("--enable-resource-path-shortening");
+ assertThat(flagValue("--resource-path-shortening-map", processingArgs))
.endsWith("app_resource_paths.map");
+
+ // Verify that the optimized APK is an input to build the unsigned APK.
+ SpawnAction apkAction =
+ getGeneratingSpawnAction(getFirstArtifactEndingWith(artifacts, "app_unsigned.apk"));
+ assertThat(apkAction.getMnemonic()).isEqualTo("ApkBuilder");
+ assertThat(hasInput(apkAction, "app_optimized.ap_")).isTrue();
}
@Test
- public void testResourcePathShortening_flagEnabledAndCDefault_flagsNotPassedToAction()
+ public void testResourcePathShortening_flagEnabledAndCDefault_optimizeArtifactsAbsent()
throws Exception {
useConfiguration("--experimental_android_resource_path_shortening");
@@ -973,16 +977,18 @@
getFirstArtifactEndingWith(artifacts, "app_resource_paths.map");
assertThat(resourcePathShorteningMapArtifact).isNull();
- Artifact androidResourcesApk = getFirstArtifactEndingWith(artifacts, ".ap_");
- assertThat(getGeneratingAction(androidResourcesApk).getMnemonic()).isEqualTo("AndroidAapt2");
+ Artifact optimizedResourceApk = getFirstArtifactEndingWith(artifacts, "app_optimized.ap_");
+ assertThat(optimizedResourceApk).isNull();
- List<String> processingArgs = getGeneratingSpawnActionArgs(androidResourcesApk);
- assertThat(processingArgs).doesNotContain("--resourcePathShortening");
- assertThat(processingArgs).doesNotContain("--resourcePathShorteningMapOutput");
+ // Verify that the optimized APK is not an input to build the unsigned APK.
+ SpawnAction apkAction =
+ getGeneratingSpawnAction(getFirstArtifactEndingWith(artifacts, "app_unsigned.apk"));
+ assertThat(apkAction.getMnemonic()).isEqualTo("ApkBuilder");
+ assertThat(hasInput(apkAction, "app_optimized.ap_")).isFalse();
}
@Test
- public void testResourcePathShorteningMap_flagNotEnabledAndCOpt_flagsNotPassedToAction()
+ public void testResourcePathShorteningMap_flagNotEnabledAndCOpt_optimizeArtifactsAbsent()
throws Exception {
useConfiguration("-c", "opt");
@@ -994,12 +1000,14 @@
getFirstArtifactEndingWith(artifacts, "app_resource_paths.map");
assertThat(resourcePathShorteningMapArtifact).isNull();
- Artifact androidResourcesApk = getFirstArtifactEndingWith(artifacts, ".ap_");
- assertThat(getGeneratingAction(androidResourcesApk).getMnemonic()).isEqualTo("AndroidAapt2");
+ Artifact optimizedResourceApk = getFirstArtifactEndingWith(artifacts, "app_optimized.ap_");
+ assertThat(optimizedResourceApk).isNull();
- List<String> processingArgs = getGeneratingSpawnActionArgs(androidResourcesApk);
- assertThat(processingArgs).doesNotContain("--resourcePathShortening");
- assertThat(processingArgs).doesNotContain("--resourcePathShorteningMapOutput");
+ // Verify that the optimized APK is not an input to build the unsigned APK.
+ SpawnAction apkAction =
+ getGeneratingSpawnAction(getFirstArtifactEndingWith(artifacts, "app_unsigned.apk"));
+ assertThat(apkAction.getMnemonic()).isEqualTo("ApkBuilder");
+ assertThat(hasInput(apkAction, "app_optimized.ap_")).isFalse();
}
@Test