aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Andrew Pellegrini <apell@google.com>2016-03-07 20:02:36 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2016-03-08 03:45:14 +0000
commit52048e36215a70028ca355808f9ee36e2a9ca986 (patch)
treefb301a69cd414b06d56a03b4cb641832f1514ffb /src
parent4b1999792537270b46d0750ff8b4155b10b0320c (diff)
Adds ResourceShrinkerAction to android_binary targets if they use Proguard and specify --experimental_android_resource_shrinking on the command line.
RELNOTES: Specifying --experimental_android_resource_shrinking on the command line will enable a resource shrinking pass on android_binary targets that already use Proguard. -- MOS_MIGRATED_REVID=116572863
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java92
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java28
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java31
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java26
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ResourceShrinkerActionBuilder.java208
-rw-r--r--src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java1
-rw-r--r--src/test/shell/bazel/android/BUILD1
-rwxr-xr-xsrc/test/shell/bazel/test-setup.sh7
-rwxr-xr-xsrc/test/shell/bazel/testenv.sh1
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java2
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java9
13 files changed, 393 insertions, 37 deletions
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 7fa4575bc9..42ddaf11be 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
@@ -193,8 +193,9 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
resourceApk = applicationManifest.packWithDataAndResources(
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK),
ruleContext,
+ false, /* isLibrary */
resourceDeps,
- null, /* Artifact rTxt */
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT),
null, /* Artifact symbolsTxt */
ruleContext.getTokenizedStringListAttr("resource_configuration_filters"),
ruleContext.getTokenizedStringListAttr("nocompress_extensions"),
@@ -204,7 +205,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
getExpandedMakeVarsForAttr(ruleContext, "version_name"),
false, /* incremental */
ProguardHelper.getProguardConfigArtifact(ruleContext, ""),
- null /* manifestOut */);
+ null, /* manifestOut */
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP));
if (ruleContext.hasErrors()) {
return null;
}
@@ -212,6 +214,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
.packWithDataAndResources(ruleContext
.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_INCREMENTAL_RESOURCES_APK),
ruleContext,
+ false, /* isLibrary */
resourceDeps,
null, /* Artifact rTxt */
null, /* Artifact symbolsTxt */
@@ -223,7 +226,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
getExpandedMakeVarsForAttr(ruleContext, "version_name"),
true, /* incremental */
ProguardHelper.getProguardConfigArtifact(ruleContext, "incremental"),
- null /* manifestOut */);
+ null, /* manifestOut */
+ null /* mergedResourcesOut */);
if (ruleContext.hasErrors()) {
return null;
}
@@ -231,6 +235,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
.createSplitManifest(ruleContext, "android_resources", false)
.packWithDataAndResources(getDxArtifact(ruleContext, "android_resources.ap_"),
ruleContext,
+ false, /* isLibrary */
resourceDeps,
null, /* Artifact rTxt */
null, /* Artifact symbolsTxt */
@@ -242,7 +247,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
getExpandedMakeVarsForAttr(ruleContext, "version_name"),
true,
ProguardHelper.getProguardConfigArtifact(ruleContext, "incremental_split"),
- null /* manifestOut */);
+ null, /* manifestOut */
+ null /* mergedResourcesOut */);
if (ruleContext.hasErrors()) {
return null;
}
@@ -347,6 +353,12 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
ImmutableList<Artifact> proguardSpecs = ProguardHelper.collectTransitiveProguardSpecs(
ruleContext, ImmutableList.of(resourceApk.getResourceProguardConfig()));
+ Artifact resourceApkArtifact = shrinkResources(
+ ruleContext,
+ androidCommon,
+ resourceApk,
+ deployJar,
+ proguardSpecs);
ProguardOutput proguardOutput =
applyProguard(
ruleContext,
@@ -378,7 +390,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
ApkActionBuilder apkBuilder = new ApkActionBuilder(ruleContext, androidSemantics)
.classesDex(dexingOutput.classesDexZip)
- .resourceApk(resourceApk.getArtifact())
+ .resourceApk(resourceApkArtifact)
.javaResourceZip(dexingOutput.javaResourceJar)
.nativeLibs(nativeLibs);
@@ -840,6 +852,76 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
return new ProguardOutput(deployJarArtifact, null);
}
+ private static Artifact shrinkResources(
+ RuleContext ruleContext,
+ AndroidCommon androidCommon,
+ ResourceApk resourceApk,
+ Artifact deployJar,
+ ImmutableList<Artifact> proguardSpecs) throws InterruptedException {
+
+ if (ruleContext.getFragment(AndroidConfiguration.class).useAndroidResourceShrinking()
+ && LocalResourceContainer.definesAndroidResources(ruleContext.attributes())
+ && !proguardSpecs.isEmpty()) {
+
+ // TODO(apell): Once ProGuard is split into multiple runs, use the Artifact from the shrinking
+ // pass here instead.
+ Artifact shrunkJar = ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.ANDROID_BINARY_SHRUNK_JAR);
+ AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
+
+ Iterable<Artifact> libraryJars = NestedSetBuilder.<Artifact>naiveLinkOrder()
+ .add(sdk.getAndroidJar())
+ .addTransitive(androidCommon.getTransitiveNeverLinkLibraries())
+ .build();
+ Builder builder = new SpawnAction.Builder()
+ .addInput(deployJar)
+ .addInputs(libraryJars)
+ .addInputs(proguardSpecs)
+ .setExecutable(sdk.getProguard())
+ .setProgressMessage("Finding Resource References With Proguard")
+ .setMnemonic("ProguardResourceMapping")
+ .addArgument("-injars")
+ .addArgument(deployJar.getExecPathString());
+
+ for (Artifact libraryJar : libraryJars) {
+ builder.addArgument("-libraryjars")
+ .addArgument(libraryJar.getExecPathString());
+ }
+
+ for (Artifact proguardSpec : proguardSpecs) {
+ builder.addArgument("@" + proguardSpec.getExecPathString());
+ }
+
+ builder.addArgument("-ignorewarnings")
+ .addArgument("-dontnote")
+ .addArgument("-forceprocessing")
+ .addArgument("-dontoptimize")
+ .addArgument("-dontobfuscate")
+ .addArgument("-dontpreverify")
+ .addArgument("-outjars")
+ .addOutputArgument(shrunkJar);
+
+ ruleContext.registerAction(builder.build(ruleContext));
+
+ return new ResourceShrinkerActionBuilder(ruleContext)
+ .setResourceApkOut(ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.ANDROID_RESOURCES_SHRUNK_APK))
+ .setShrunkResourcesOut(ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.ANDROID_RESOURCES_SHRUNK_ZIP))
+ .withResourceFiles(ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.ANDROID_RESOURCES_ZIP))
+ .withShrunkJar(shrunkJar)
+ .withPrimary(resourceApk.getPrimaryResource())
+ .withDependencies(resourceApk.getResourceDependencies())
+ .setConfigurationFilters(
+ ruleContext.getTokenizedStringListAttr("resource_configuration_filters"))
+ .setUncompressedExtensions(
+ ruleContext.getTokenizedStringListAttr("nocompress_extensions"))
+ .build();
+ }
+ return resourceApk.getArtifact();
+ }
+
@Immutable
private static final class DexingOutput {
private final Artifact classesDexZip;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
index d3755b32cd..83ac2aa738 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
@@ -180,6 +180,12 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
+ " rules with deps. The depot needs to be cleaned up to roll this out by default.")
public boolean allowAndroidLibraryDepsWithoutSrcs;
+ @Option(name = "experimental_android_resource_shrinking",
+ defaultValue = "false",
+ category = "undocumented",
+ help = "Enables resource shrinking for android_binary APKs that use proguard.")
+ public boolean useAndroidResourceShrinking;
+
@Override
public void addAllLabels(Multimap<String, Label> labelMap) {
if (androidCrosstoolTop != null) {
@@ -249,6 +255,7 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
private final boolean useJackForDexing;
private final boolean jackSanityChecks;
private final boolean allowAndroidLibraryDepsWithoutSrcs;
+ private final boolean useAndroidResourceShrinking;
AndroidConfiguration(Options options) {
this.sdk = options.sdk;
@@ -261,6 +268,7 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
this.useJackForDexing = options.useJackForDexing;
this.jackSanityChecks = options.jackSanityChecks;
this.allowAndroidLibraryDepsWithoutSrcs = options.allowAndroidLibraryDepsWithoutSrcs;
+ this.useAndroidResourceShrinking = options.useAndroidResourceShrinking;
}
public String getCpu() {
@@ -306,6 +314,10 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
return allowAndroidLibraryDepsWithoutSrcs;
}
+ public boolean useAndroidResourceShrinking() {
+ return useAndroidResourceShrinking;
+ }
+
@Override
public void addGlobalMakeVariables(ImmutableMap.Builder<String, String> globalMakeEnvBuilder) {
globalMakeEnvBuilder.put("ANDROID_CPU", cpu);
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 8b3927459b..189c3fd793 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
@@ -81,6 +81,7 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
resourceApk = applicationManifest.packWithDataAndResources(
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK),
ruleContext,
+ true, /* isLibrary */
ResourceDependencies.fromRuleDeps(ruleContext, JavaCommon.isNeverLink(ruleContext)),
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT),
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_SYMBOLS_TXT),
@@ -92,8 +93,8 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
null /* versionName */,
false,
null /* proguardCfgOut */,
- ruleContext.getImplicitOutputArtifact(
- AndroidRuleClasses.ANDROID_LIBRARY_MANIFEST));
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_MANIFEST),
+ null /* mergedResourcesOut */);
if (ruleContext.hasErrors()) {
return null;
}
@@ -150,18 +151,17 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT), null);
primaryResources = new AndroidResourcesProcessorBuilder(ruleContext)
- .setApkOut(apk)
- .setRTxtOut(resourceContainer.getRTxt())
- .setManifestOut(
- ruleContext.getImplicitOutputArtifact(
- AndroidRuleClasses.ANDROID_LIBRARY_MANIFEST))
- .setSourceJarOut(resourceContainer.getJavaSourceJar())
- .setJavaPackage(resourceContainer.getJavaPackage())
- .withPrimary(resourceContainer)
- .withDependencies(resourceApk.getResourceDependencies())
- .setDebug(
- ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT)
- .build(ruleContext);
+ .setLibrary(true)
+ .setApkOut(apk)
+ .setRTxtOut(resourceContainer.getRTxt())
+ .setManifestOut(ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.ANDROID_LIBRARY_MANIFEST))
+ .setSourceJarOut(resourceContainer.getJavaSourceJar())
+ .setJavaPackage(resourceContainer.getJavaPackage())
+ .withPrimary(resourceContainer)
+ .withDependencies(resourceApk.getResourceDependencies())
+ .setDebug(ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT)
+ .build(ruleContext);
}
new AarGeneratorBuilder(ruleContext)
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 465d2bfcfd..8b0b314ffc 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
@@ -76,6 +76,8 @@ public class AndroidResourcesProcessorBuilder {
private Artifact symbolsTxt;
private Artifact manifestOut;
+ private Artifact mergedResourcesOut;
+ private boolean isLibrary;
/**
* @param ruleContext The RuleContext that was used to create the SpawnAction.Builder.
@@ -156,6 +158,16 @@ public class AndroidResourcesProcessorBuilder {
return this;
}
+ public AndroidResourcesProcessorBuilder setMergedResourcesOut(Artifact mergedResourcesOut) {
+ this.mergedResourcesOut = mergedResourcesOut;
+ return this;
+ }
+
+ public AndroidResourcesProcessorBuilder setLibrary(boolean isLibrary) {
+ this.isLibrary = isLibrary;
+ return this;
+ }
+
private static class ResourceContainerToArg implements Function<ResourceContainer, String> {
private boolean includeSymbols;
@@ -257,7 +269,7 @@ public class AndroidResourcesProcessorBuilder {
Iterables.unmodifiableIterable(
Iterables.transform(dependencies.getDirectResources(), RESOURCE_DEP_TO_ARG)));
}
- // This flattens the nested set. Since each ResourceContainer needs to be transformed into
+ // This flattens the nested set. Since each ResourceContainer needs to be transformed into
// Artifacts, and the NestedSetBuilder.wrap doesn't support lazy Iterator evaluation
// and SpawnActionBuilder.addInputs evaluates Iterables, it becomes necessary to make the
// best effort and let it get flattened.
@@ -268,13 +280,13 @@ public class AndroidResourcesProcessorBuilder {
.transformAndConcat(RESOURCE_DEP_TO_ARTIFACTS)));
}
+ if (isLibrary) {
+ builder.add("--packageType").add("LIBRARY");
+ }
+
if (rTxtOut != null) {
builder.addExecPath("--rOutput", rTxtOut);
outs.add(rTxtOut);
- // If R.txt is not null, dependency R.javas will not be regenerated from the R.txt found in
- // the deps, which means the resource processor needs to be told it is creating a library so
- // that it will generate the R.txt.
- builder.add("--packageType").add("LIBRARY");
}
if (symbolsTxt != null) {
@@ -289,12 +301,17 @@ public class AndroidResourcesProcessorBuilder {
builder.addExecPath("--proguardOutput", proguardOut);
outs.add(proguardOut);
}
-
+
if (manifestOut != null) {
builder.addExecPath("--manifestOutput", manifestOut);
outs.add(manifestOut);
}
-
+
+ if (mergedResourcesOut != null) {
+ builder.addExecPath("--resourcesOutput", mergedResourcesOut);
+ outs.add(mergedResourcesOut);
+ }
+
if (apkOut != null) {
builder.addExecPath("--packagePath", apkOut);
outs.add(apkOut);
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 8a7cc46643..96315719a9 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
@@ -80,6 +80,14 @@ public final class AndroidRuleClasses {
fromTemplates("%{name}_resources.jar");
public static final SafeImplicitOutputsFunction ANDROID_RESOURCES_APK =
fromTemplates("%{name}.ap_");
+ public static final SafeImplicitOutputsFunction ANDROID_BINARY_SHRUNK_JAR =
+ fromTemplates("%{name}_shrunk.jar");
+ public static final SafeImplicitOutputsFunction ANDROID_RESOURCES_SHRUNK_APK =
+ fromTemplates("%{name}_shrunk.ap_");
+ public static final SafeImplicitOutputsFunction ANDROID_RESOURCES_ZIP =
+ fromTemplates("%{name}_files/resource_files.zip");
+ public static final SafeImplicitOutputsFunction ANDROID_RESOURCES_SHRUNK_ZIP =
+ fromTemplates("%{name}_files/resource_files_shrunk.zip");
public static final SafeImplicitOutputsFunction ANDROID_INCREMENTAL_RESOURCES_APK =
fromTemplates("%{name}_files/incremental.ap_");
public static final SafeImplicitOutputsFunction ANDROID_BINARY_APK =
@@ -141,6 +149,8 @@ public final class AndroidRuleClasses {
"//tools/android:incremental_split_stub_application";
public static final String DEFAULT_RESOURCES_PROCESSOR =
"//tools/android:resources_processor";
+ public static final String DEFAULT_RESOURCE_SHRINKER =
+ "//tools/android:resource_shrinker";
public static final String DEFAULT_AAR_GENERATOR = "//tools/android:aar_generator";
public static final Label DEFAULT_ANDROID_SDK =
@@ -369,6 +379,8 @@ public final class AndroidRuleClasses {
return builder
.add(attr("$android_resources_processor", LABEL).cfg(HOST).exec().value(
env.getToolsLabel(DEFAULT_RESOURCES_PROCESSOR)))
+ .add(attr("$android_resource_shrinker", LABEL).cfg(HOST).exec().value(
+ env.getToolsLabel(DEFAULT_RESOURCE_SHRINKER)))
.add(attr("$android_aar_generator", LABEL).cfg(HOST).exec().value(
env.getToolsLabel(DEFAULT_AAR_GENERATOR)))
.build();
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 b20c8c2403..05df106d88 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
@@ -163,7 +163,7 @@ public final class ApplicationManifest {
public ApplicationManifest mergeWith(RuleContext ruleContext,
ResourceDependencies resourceDeps) {
- Iterable<Artifact> mergeeManifests = getMergeeManifests(resourceDeps.getResources());
+ Iterable<Artifact> mergeeManifests = getMergeeManifests(resourceDeps.getResources());
if (!Iterables.isEmpty(mergeeManifests)) {
Iterable<Artifact> exportedManifests = mergeeManifests;
Artifact outputManifest = ruleContext.getUniqueDirectoryArtifact(
@@ -188,7 +188,7 @@ public final class ApplicationManifest {
return builder.build();
}
- /** Packages up the manifest with assets from the rule and dependent resources.
+ /** Packages up the manifest with assets from the rule and dependent resources.
* @throws InterruptedException */
public ResourceApk packWithAssets(
Artifact resourceApk,
@@ -208,6 +208,7 @@ public final class ApplicationManifest {
return createApk(resourceApk,
ruleContext,
+ false, /* isLibrary */
resourceDeps,
rTxt,
null, /* configurationFilters */
@@ -220,15 +221,17 @@ public final class ApplicationManifest {
incremental,
data,
proguardCfg,
- null);
+ null, /* Artifact manifestOut */
+ null /* Artifact mergedResources */);
}
- /** Packages up the manifest with resource and assets from the rule and dependent resources.
+ /** Packages up the manifest with resource and assets from the rule and dependent resources.
* @param manifestOut TODO(corysmith):
* @throws InterruptedException */
public ResourceApk packWithDataAndResources(
Artifact resourceApk,
RuleContext ruleContext,
+ boolean isLibrary,
ResourceDependencies resourceDeps,
Artifact rTxt,
Artifact symbolsTxt,
@@ -240,7 +243,8 @@ public final class ApplicationManifest {
String versionName,
boolean incremental,
Artifact proguardCfg,
- Artifact manifestOut) throws InterruptedException {
+ Artifact manifestOut,
+ Artifact mergedResources) throws InterruptedException {
LocalResourceContainer data = new LocalResourceContainer.Builder(ruleContext)
.withAssets(
AndroidCommon.getAssetDir(ruleContext),
@@ -259,6 +263,7 @@ public final class ApplicationManifest {
}
return createApk(resourceApk,
ruleContext,
+ isLibrary,
resourceDeps,
rTxt,
symbolsTxt,
@@ -271,11 +276,13 @@ public final class ApplicationManifest {
incremental,
data,
proguardCfg,
- manifestOut);
+ manifestOut,
+ mergedResources);
}
private ResourceApk createApk(Artifact resourceApk,
RuleContext ruleContext,
+ boolean isLibrary,
ResourceDependencies resourceDeps,
Artifact rTxt,
Artifact symbolsTxt,
@@ -288,7 +295,8 @@ public final class ApplicationManifest {
boolean incremental,
LocalResourceContainer data,
Artifact proguardCfg,
- Artifact manifestOut) throws InterruptedException {
+ Artifact manifestOut,
+ Artifact mergedResources) throws InterruptedException {
ResourceContainer resourceContainer = checkForInlinedResources(
new AndroidResourceContainerBuilder()
.withData(data)
@@ -307,12 +315,14 @@ public final class ApplicationManifest {
AndroidResourcesProcessorBuilder builder =
new AndroidResourcesProcessorBuilder(ruleContext)
+ .setLibrary(isLibrary)
.setApkOut(resourceContainer.getApk())
.setConfigurationFilters(configurationFilters)
.setUncompressedExtensions(uncompressedExtensions)
.setJavaPackage(resourceContainer.getJavaPackage())
.setDebug(ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT)
.setManifestOut(manifestOut)
+ .setMergedResourcesOut(mergedResources)
.withPrimary(resourceContainer)
.withDependencies(resourceDeps)
.setDensities(densities)
@@ -373,7 +383,7 @@ public final class ApplicationManifest {
/**
* Packages up the manifest with resources, and generates the R.java.
- * @throws InterruptedException
+ * @throws InterruptedException
*
* @deprecated in favor of {@link ApplicationManifest#packWithDataAndResources}.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceShrinkerActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceShrinkerActionBuilder.java
new file mode 100644
index 0000000000..d51bad31be
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceShrinkerActionBuilder.java
@@ -0,0 +1,208 @@
+// Copyright 2016 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 static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.analysis.config.CompilationMode;
+import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceContainer;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Builder for creating resource shrinker actions.
+ */
+public class ResourceShrinkerActionBuilder {
+ private Artifact resourceFilesZip;
+ private Artifact shrunkJar;
+ private ResourceContainer primaryResources;
+ private ResourceDependencies dependencyResources;
+ private Artifact resourceApkOut;
+ private Artifact shrunkResourcesOut;
+
+ private final RuleContext ruleContext;
+ private final SpawnAction.Builder spawnActionBuilder;
+ private final AndroidSdkProvider sdk;
+
+ private List<String> uncompressedExtensions = Collections.emptyList();
+ private List<String> assetsToIgnore = Collections.emptyList();
+ private List<String> resourceConfigs = Collections.emptyList();
+
+ /**
+ * @param ruleContext The RuleContext of the owning rule.
+ */
+ public ResourceShrinkerActionBuilder(RuleContext ruleContext) {
+ this.ruleContext = ruleContext;
+ this.spawnActionBuilder = new SpawnAction.Builder();
+ this.sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
+ }
+
+ public ResourceShrinkerActionBuilder setUncompressedExtensions(
+ List<String> uncompressedExtensions) {
+ this.uncompressedExtensions = uncompressedExtensions;
+ return this;
+ }
+
+ public ResourceShrinkerActionBuilder setAssetsToIgnore(List<String> assetsToIgnore) {
+ this.assetsToIgnore = assetsToIgnore;
+ return this;
+ }
+
+ public ResourceShrinkerActionBuilder setConfigurationFilters(List<String> resourceConfigs) {
+ this.resourceConfigs = resourceConfigs;
+ return this;
+ }
+
+ /**
+ * @param resourceFilesZip A zip file containing the merged assets and resources to be shrunk.
+ */
+ public ResourceShrinkerActionBuilder withResourceFiles(Artifact resourceFilesZip) {
+ this.resourceFilesZip = resourceFilesZip;
+ return this;
+ }
+
+ /**
+ * @param shrunkJar The deploy jar of the rule after a dead code removal Proguard pass.
+ */
+ public ResourceShrinkerActionBuilder withShrunkJar(Artifact shrunkJar) {
+ this.shrunkJar = shrunkJar;
+ return this;
+ }
+
+ /**
+ * @param primary The fully processed {@link ResourceContainer} of the resources to be shrunk.
+ * Must contain both an R.txt and merged manifest.
+ */
+ public ResourceShrinkerActionBuilder withPrimary(ResourceContainer primary) {
+ checkNotNull(primary);
+ checkNotNull(primary.getManifest());
+ checkNotNull(primary.getRTxt());
+ this.primaryResources = primary;
+ return this;
+ }
+
+ /**
+ * @param resourceDeps The full dependency tree of {@link ResourceContainer}s.
+ */
+ public ResourceShrinkerActionBuilder withDependencies(ResourceDependencies resourceDeps) {
+ this.dependencyResources = resourceDeps;
+ return this;
+ }
+
+ /**
+ * @param resourceApkOut The location to write the shrunk resource ap_ package.
+ */
+ public ResourceShrinkerActionBuilder setResourceApkOut(Artifact resourceApkOut) {
+ this.resourceApkOut = resourceApkOut;
+ return this;
+ }
+
+ /**
+ * @param shrunkResourcesOut The location to write the shrunk resource files zip.
+ */
+ public ResourceShrinkerActionBuilder setShrunkResourcesOut(Artifact shrunkResourcesOut) {
+ this.shrunkResourcesOut = shrunkResourcesOut;
+ return this;
+ }
+
+ public Artifact build() {
+ ImmutableList.Builder<Artifact> inputs = ImmutableList.builder();
+ ImmutableList.Builder<Artifact> outputs = ImmutableList.builder();
+
+ CustomCommandLine.Builder commandLine = new CustomCommandLine.Builder();
+
+ inputs.addAll(ruleContext.getExecutablePrerequisite("$android_resource_shrinker", Mode.HOST)
+ .getRunfilesSupport()
+ .getRunfilesArtifactsWithoutMiddlemen());
+
+ commandLine.addExecPath("--aapt", sdk.getAapt().getExecutable());
+
+ commandLine.addExecPath("--annotationJar", sdk.getAnnotationsJar());
+ inputs.add(sdk.getAnnotationsJar());
+
+ commandLine.addExecPath("--androidJar", sdk.getAndroidJar());
+ inputs.add(sdk.getAndroidJar());
+
+ if (!uncompressedExtensions.isEmpty()) {
+ commandLine.addJoinStrings("--uncompressedExtensions", ",", uncompressedExtensions);
+ }
+ if (!assetsToIgnore.isEmpty()) {
+ commandLine.addJoinStrings("--assetsToIgnore", ",", assetsToIgnore);
+ }
+ if (ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT) {
+ commandLine.add("--debug");
+ }
+ if (!resourceConfigs.isEmpty()) {
+ commandLine.addJoinStrings("--resourceConfigs", ",", resourceConfigs);
+ }
+
+ checkNotNull(resourceFilesZip);
+ checkNotNull(shrunkJar);
+ checkNotNull(primaryResources);
+ checkNotNull(resourceApkOut);
+
+ commandLine.addExecPath("--resources", resourceFilesZip);
+ inputs.add(resourceFilesZip);
+
+ commandLine.addExecPath("--shrunkJar", shrunkJar);
+ inputs.add(shrunkJar);
+
+ commandLine.addExecPath("--rTxt", primaryResources.getRTxt());
+ inputs.add(primaryResources.getRTxt());
+
+ commandLine.addExecPath("--primaryManifest", primaryResources.getManifest());
+ inputs.add(primaryResources.getManifest());
+
+ List<Artifact> dependencyManifests = getManifests(dependencyResources);
+ commandLine.addJoinExecPaths("--dependencyManifests", ":", dependencyManifests);
+ inputs.addAll(dependencyManifests);
+
+ commandLine.addExecPath("--shrunkResourceApk", resourceApkOut);
+ outputs.add(resourceApkOut);
+
+ commandLine.addExecPath("--shrunkResources", shrunkResourcesOut);
+ outputs.add(shrunkResourcesOut);
+
+ ruleContext.registerAction(spawnActionBuilder
+ .addTool(sdk.getAapt())
+ .addInputs(inputs.build())
+ .addOutputs(outputs.build())
+ .setCommandLine(commandLine.build())
+ .setExecutable(ruleContext.getExecutablePrerequisite(
+ "$android_resource_shrinker", Mode.HOST))
+ .setProgressMessage("Shrinking resources")
+ .setMnemonic("ResourceShrinker")
+ .build(ruleContext));
+
+ return resourceApkOut;
+ }
+
+ private List<Artifact> getManifests(ResourceDependencies resourceDependencies) {
+ ImmutableList.Builder<Artifact> manifests = ImmutableList.builder();
+ for (ResourceContainer resources : resourceDependencies.getResources()) {
+ if (resources.getManifest() != null) {
+ manifests.add(resources.getManifest());
+ }
+ }
+ return manifests.build();
+ }
+}
+
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
index 6304712c6c..5c0d4119ee 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
@@ -148,6 +148,7 @@ public final class BazelAnalysisMock extends AnalysisMock {
.add(")")
.add("sh_binary(name = 'aar_generator', srcs = ['empty.sh'])")
.add("sh_binary(name = 'resources_processor', srcs = ['empty.sh'])")
+ .add("sh_binary(name = 'resource_shrinker', srcs = ['empty.sh'])")
.add("android_library(name = 'incremental_stub_application')")
.add("android_library(name = 'incremental_split_stub_application')")
.add("sh_binary(name = 'stubify_manifest', srcs = ['empty.sh'])")
diff --git a/src/test/shell/bazel/android/BUILD b/src/test/shell/bazel/android/BUILD
index 9fa75cd11a..16243889ff 100644
--- a/src/test/shell/bazel/android/BUILD
+++ b/src/test/shell/bazel/android/BUILD
@@ -12,6 +12,7 @@ sh_test(
"//external:android_sdk_for_testing",
"//src/tools/android/java/com/google/devtools/build/android:AarGeneratorAction_deploy.jar",
"//src/tools/android/java/com/google/devtools/build/android:AndroidResourceProcessingAction_deploy.jar",
+ "//src/tools/android/java/com/google/devtools/build/android:ResourceShrinkerAction_deploy.jar",
"//src/tools/android/java/com/google/devtools/build/android/incrementaldeployment:srcs",
"//src/tools/android/java/com/google/devtools/build/android/ziputils:mapper_deploy.jar",
"//src/tools/android/java/com/google/devtools/build/android/ziputils:reducer_deploy.jar",
diff --git a/src/test/shell/bazel/test-setup.sh b/src/test/shell/bazel/test-setup.sh
index bcccc84209..15b1bb9645 100755
--- a/src/test/shell/bazel/test-setup.sh
+++ b/src/test/shell/bazel/test-setup.sh
@@ -51,6 +51,7 @@ function setup_android_support() {
ln -s "${aargenerator_path}" ${ANDROID_TOOLS}/tools/android/aargenerator.jar
ln -s "${androidresourceprocessor_path}" ${ANDROID_TOOLS}/tools/android/androidresourceprocessor.jar
+ ln -s "${resourceshrinker_path}" ${ANDROID_TOOLS}/tools/android/resourceshrinker.jar
ln -s "${dexmapper_path}" ${ANDROID_TOOLS}/tools/android/dexmapper.jar
ln -s "${dexreducer_path}" ${ANDROID_TOOLS}/tools/android/dexreducer.jar
ln -s "${TEST_SRCDIR}/tools/android/bazel_debug.keystore" ${ANDROID_TOOLS}/tools/android/bazel_debug.keystore
@@ -103,6 +104,12 @@ java_binary(
)
java_binary(
+ name = "resource_shrinker",
+ srcs = ["resourceshrinker.jar"],
+ main_class = "com.google.devtools.build.android.ResourceShrinkerAction",
+)
+
+java_binary(
name = "merge_dexzips",
srcs = ["dexreducer.jar"],
main_class = "com.google.devtools.build.android.ziputils.DexReducer",
diff --git a/src/test/shell/bazel/testenv.sh b/src/test/shell/bazel/testenv.sh
index 4cb5fef8bf..19d0729ea7 100755
--- a/src/test/shell/bazel/testenv.sh
+++ b/src/test/shell/bazel/testenv.sh
@@ -52,6 +52,7 @@ namespace_sandbox="${TEST_SRCDIR}/src/main/tools/namespace-sandbox"
# Android tooling
aargenerator_path="${TEST_SRCDIR}/src/tools/android/java/com/google/devtools/build/android/AarGeneratorAction_deploy.jar"
androidresourceprocessor_path="${TEST_SRCDIR}/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction_deploy.jar"
+resourceshrinker_path="${TEST_SRCDIR}/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction_deploy.jar"
dexmapper_path="${TEST_SRCDIR}/src/tools/android/java/com/google/devtools/build/android/ziputils/mapper_deploy.jar"
dexreducer_path="${TEST_SRCDIR}/src/tools/android/java/com/google/devtools/build/android/ziputils/reducer_deploy.jar"
incrementaldeployment_path="${TEST_SRCDIR}/src/tools/android/java/com/google/devtools/build/android/incrementaldeployment"
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 daf553ed90..0e233743d6 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
@@ -286,7 +286,7 @@ public class AndroidResourceProcessingAction {
options.packagePath,
options.proguardOutput,
options.resourcesOutput != null
- ? filteredData.getResourceDir().resolve("values").resolve("public.xml")
+ ? processedManifestData.getResourceDir().resolve("values").resolve("public.xml")
: null);
LOGGER.fine(String.format("appt finished at %sms", timer.elapsed(TimeUnit.MILLISECONDS)));
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 51a7262f74..bca53a7761 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
@@ -272,7 +272,9 @@ public class AndroidResourceProcessor {
public void createResourcesZip(Path resourcesRoot, Path assetsRoot, Path output)
throws IOException {
try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(output.toFile()))) {
- Files.walkFileTree(resourcesRoot, new ZipBuilderVisitor(zout, resourcesRoot, "res"));
+ if (Files.exists(resourcesRoot)) {
+ Files.walkFileTree(resourcesRoot, new ZipBuilderVisitor(zout, resourcesRoot, "res"));
+ }
if (Files.exists(assetsRoot)) {
Files.walkFileTree(assetsRoot, new ZipBuilderVisitor(zout, assetsRoot, "assets"));
}
@@ -310,6 +312,9 @@ public class AndroidResourceProcessor {
Path androidManifest = primaryData.getManifest();
Path resourceDir = primaryData.getResourceDir();
Path assetsDir = primaryData.getAssetDir();
+ if (publicResourcesOut != null) {
+ prepareOutputPath(publicResourcesOut.getParent());
+ }
AaptCommandBuilder commandBuilder =
new AaptCommandBuilder(aapt, buildToolsVersion, variantType, "package")
@@ -366,7 +371,7 @@ public class AndroidResourceProcessor {
if (packageOut != null) {
Files.setLastModifiedTime(packageOut, FileTime.fromMillis(0L));
}
- if (publicResourcesOut != null) {
+ if (publicResourcesOut != null && Files.exists(publicResourcesOut)) {
Files.setLastModifiedTime(publicResourcesOut, FileTime.fromMillis(0L));
}
}