Move all the resource processing tools into a "busybox".
This makes the code simpler as well as reducing the number of targets to build.
It also makes testing and profiling different action strategies vastly easier.

--
PiperOrigin-RevId: 146812659
MOS_MIGRATED_REVID=146812659
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AarGeneratorBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AarGeneratorBuilder.java
index 4a42915..41c5ab7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AarGeneratorBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AarGeneratorBuilder.java
@@ -83,6 +83,12 @@
     List<Artifact> outs = new ArrayList<>();
     List<Artifact> ins = new ArrayList<>();
     List<String> args = new ArrayList<>();
+    
+    // Set the busybox tool
+    args.add("--tool");
+    args.add("GENERATE_AAR");
+    // Deliminate between the tool and the tool arguments.
+    args.add("--");
 
     args.add("--mainData");
     addPrimaryResourceContainer(ins, args, primary);
@@ -109,15 +115,16 @@
     args.add(aarOut.getExecPathString());
     outs.add(aarOut);
 
-    ruleContext.registerAction(this.builder
-        .addInputs(ImmutableList.<Artifact>copyOf(ins))
-        .addOutputs(ImmutableList.<Artifact>copyOf(outs))
-        .setCommandLine(CommandLine.of(args, false))
-        .setExecutable(
-            ruleContext.getExecutablePrerequisite("$android_aar_generator", Mode.HOST))
-        .setProgressMessage("Building AAR package for " + ruleContext.getLabel())
-        .setMnemonic("AARGenerator")
-        .build(context));
+    ruleContext.registerAction(
+        this.builder
+            .addInputs(ImmutableList.<Artifact>copyOf(ins))
+            .addOutputs(ImmutableList.<Artifact>copyOf(outs))
+            .setCommandLine(CommandLine.of(args, false))
+            .setExecutable(
+                ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST))
+            .setProgressMessage("Building AAR package for " + ruleContext.getLabel())
+            .setMnemonic("AARGenerator")
+            .build(context));
   }
 
   private void addPrimaryResourceContainer(List<Artifact> inputs, List<String> args,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java
index 56ab7bf..1e3ae9c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java
@@ -35,7 +35,7 @@
  * $android_resource_validator action. For android_binary, see {@link
  * AndroidResourcesProcessorBuilder}.
  */
-class AndroidResourceMergingActionBuilder {
+public class AndroidResourceMergingActionBuilder {
 
   private static final ResourceContainerConverter.ToArtifacts RESOURCE_CONTAINER_TO_ARTIFACTS =
       ResourceContainerConverter.builder()
@@ -107,12 +107,15 @@
 
   public ResourceContainer build(ActionConstructionContext context) {
     CustomCommandLine.Builder builder = new CustomCommandLine.Builder();
+    
+    // Set the busybox tool.
+    builder.add("--tool").add("MERGE").add("--");
 
     // Use a FluentIterable to avoid flattening the NestedSets
     NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder();
     inputs.addAll(
         ruleContext
-            .getExecutablePrerequisite("$android_resource_merger", Mode.HOST)
+            .getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)
             .getRunfilesSupport()
             .getRunfilesArtifactsWithoutMiddlemen());
 
@@ -162,7 +165,7 @@
             .addOutputs(ImmutableList.copyOf(outs))
             .setCommandLine(builder.build())
             .setExecutable(
-                ruleContext.getExecutablePrerequisite("$android_resource_merger", Mode.HOST))
+                ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST))
             .setProgressMessage("Merging Android resources for " + ruleContext.getLabel())
             .setMnemonic("AndroidResourceMerger")
             .build(context));
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java
index 0d86acf..4a926fd 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java
@@ -112,11 +112,16 @@
 
   public ResourceContainer build(ActionConstructionContext context) {
     CustomCommandLine.Builder builder = new CustomCommandLine.Builder();
+    
+    // Set the busybox tool.
+    builder.add("--tool").add("PARSE").add("--");
 
     NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder();
-    inputs.addAll(ruleContext.getExecutablePrerequisite("$android_resource_parser", Mode.HOST)
-        .getRunfilesSupport()
-        .getRunfilesArtifactsWithoutMiddlemen());
+    inputs.addAll(
+        ruleContext
+            .getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)
+            .getRunfilesSupport()
+            .getRunfilesArtifactsWithoutMiddlemen());
 
     Preconditions.checkNotNull(primary);
     builder.add("--primaryData").add(RESOURCE_CONTAINER_TO_ARG.apply(primary));
@@ -136,7 +141,7 @@
             .addOutputs(ImmutableList.copyOf(outs))
             .setCommandLine(builder.build())
             .setExecutable(
-                ruleContext.getExecutablePrerequisite("$android_resource_parser", Mode.HOST))
+                ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST))
             .setProgressMessage("Parsing Android resources for " + ruleContext.getLabel())
             .setMnemonic("AndroidResourceParser")
             .build(context));
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceValidatorActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceValidatorActionBuilder.java
index ce8df5f..66e8b8b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceValidatorActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceValidatorActionBuilder.java
@@ -91,6 +91,9 @@
   public ResourceContainer build(ActionConstructionContext context) {
     CustomCommandLine.Builder builder = new CustomCommandLine.Builder();
 
+    // Set the busybox tool.
+    builder.add("--tool").add("VALIDATE").add("--");
+
     if (!Strings.isNullOrEmpty(sdk.getBuildToolsVersion())) {
       builder.add("--buildToolsVersion").add(sdk.getBuildToolsVersion());
     }
@@ -101,7 +104,7 @@
     NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder();
     inputs.addAll(
         ruleContext
-            .getExecutablePrerequisite("$android_resource_validator", Mode.HOST)
+            .getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)
             .getRunfilesSupport()
             .getRunfilesArtifactsWithoutMiddlemen());
 
@@ -146,7 +149,7 @@
             .addOutputs(ImmutableList.copyOf(outs))
             .setCommandLine(builder.build())
             .setExecutable(
-                ruleContext.getExecutablePrerequisite("$android_resource_validator", Mode.HOST))
+                ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST))
             .setProgressMessage("Validating Android resources for " + ruleContext.getLabel())
             .setMnemonic("AndroidResourceValidator")
             .build(context));
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 81cec62..c10228c 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
@@ -201,6 +201,9 @@
   public ResourceContainer build(ActionConstructionContext context) {
     List<Artifact> outs = new ArrayList<>();
     CustomCommandLine.Builder builder = new CustomCommandLine.Builder();
+    
+    // Set the busybox tool.
+    builder.add("--tool").add("PACKAGE").add("--");
 
     if (!Strings.isNullOrEmpty(sdk.getBuildToolsVersion())) {
       builder.add("--buildToolsVersion").add(sdk.getBuildToolsVersion());
@@ -209,7 +212,9 @@
     builder.addExecPath("--aapt", sdk.getAapt().getExecutable());
     // Use a FluentIterable to avoid flattening the NestedSets
     NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder();
-    inputs.addAll(ruleContext.getExecutablePrerequisite("$android_resources_processor", Mode.HOST)
+    inputs.addAll(
+        ruleContext
+            .getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)
             .getRunfilesSupport()
             .getRunfilesArtifactsWithoutMiddlemen());
 
@@ -317,7 +322,7 @@
             .addOutputs(ImmutableList.<Artifact>copyOf(outs))
             .setCommandLine(builder.build())
             .setExecutable(
-                ruleContext.getExecutablePrerequisite("$android_resources_processor", Mode.HOST))
+                ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST))
             .setProgressMessage("Processing Android resources for " + ruleContext.getLabel())
             .setMnemonic("AndroidAapt")
             .build(context));
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 3ec2bb4..ba55207 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
@@ -163,14 +163,7 @@
       "//tools/android:incremental_stub_application";
   public static final String DEFAULT_INCREMENTAL_SPLIT_STUB_APPLICATION =
       "//tools/android:incremental_split_stub_application";
-  public static final String DEFAULT_AAR_GENERATOR = "//tools/android:aar_generator";
-  public static final String DEFAULT_MANIFEST_MERGER = "//tools/android:manifest_merger";
-  public static final String DEFAULT_RCLASS_GENERATOR = "//tools/android:rclass_generator";
-  public static final String DEFAULT_RESOURCES_PROCESSOR = "//tools/android:resources_processor";
-  public static final String DEFAULT_RESOURCE_MERGER = "//tools/android:resource_merger";
-  public static final String DEFAULT_RESOURCE_PARSER = "//tools/android:resource_parser";
-  public static final String DEFAULT_RESOURCE_SHRINKER = "//tools/android:resource_shrinker";
-  public static final String DEFAULT_RESOURCE_VALIDATOR = "//tools/android:resource_validator";
+  public static final String DEFAULT_RESOURCES_BUSYBOX = "//tools/android:busybox";
   public static final String DEFAULT_SDK = "//tools/android:sdk";
 
   /**
@@ -423,22 +416,11 @@
     @Override
     public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
       return builder
-          .add(attr("$android_aar_generator", LABEL).cfg(HOST).exec().value(
-              env.getToolsLabel(DEFAULT_AAR_GENERATOR)))
-          .add(attr("$android_manifest_merger", LABEL).cfg(HOST).exec().value(
-              env.getToolsLabel(DEFAULT_MANIFEST_MERGER)))
-          .add(attr("$android_rclass_generator", LABEL).cfg(HOST).exec().value(
-              env.getToolsLabel(DEFAULT_RCLASS_GENERATOR)))
-          .add(attr("$android_resources_processor", LABEL).cfg(HOST).exec().value(
-              env.getToolsLabel(DEFAULT_RESOURCES_PROCESSOR)))
-          .add(attr("$android_resource_merger", LABEL).cfg(HOST).exec().value(
-              env.getToolsLabel(DEFAULT_RESOURCE_MERGER)))
-          .add(attr("$android_resource_parser", LABEL).cfg(HOST).exec().value(
-              env.getToolsLabel(DEFAULT_RESOURCE_PARSER)))
-          .add(attr("$android_resource_validator", LABEL).cfg(HOST).exec().value(
-              env.getToolsLabel(DEFAULT_RESOURCE_VALIDATOR)))
-          .add(attr("$android_resource_shrinker", LABEL).cfg(HOST).exec().value(
-              env.getToolsLabel(DEFAULT_RESOURCE_SHRINKER)))
+          .add(
+              attr("$android_resources_busybox", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel(DEFAULT_RESOURCES_BUSYBOX)))
           .build();
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ManifestMergerActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/ManifestMergerActionBuilder.java
index af679f0..c84e3fd 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ManifestMergerActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ManifestMergerActionBuilder.java
@@ -25,7 +25,6 @@
 import com.google.devtools.build.lib.analysis.actions.SpawnAction;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
-
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -89,10 +88,15 @@
     NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder();
     ImmutableList.Builder<Artifact> outputs = ImmutableList.builder();
     CustomCommandLine.Builder builder = new CustomCommandLine.Builder();
+    
+    // Set the busybox tool.
+    builder.add("--tool").add("MERGE_MANIFEST").add("--");
 
-    inputs.addAll(ruleContext.getExecutablePrerequisite("$android_manifest_merger", Mode.HOST)
-        .getRunfilesSupport()
-        .getRunfilesArtifactsWithoutMiddlemen());
+    inputs.addAll(
+        ruleContext
+            .getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)
+            .getRunfilesSupport()
+            .getRunfilesArtifactsWithoutMiddlemen());
 
     builder.addExecPath("--manifest", manifest);
     inputs.add(manifest);
@@ -135,7 +139,7 @@
             .addOutputs(outputs.build())
             .setCommandLine(builder.build())
             .setExecutable(
-                ruleContext.getExecutablePrerequisite("$android_manifest_merger", Mode.HOST))
+                ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST))
             .setProgressMessage("Merging manifest for " + ruleContext.getLabel())
             .setMnemonic("ManifestMerger")
             .build(context));
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/RClassGeneratorActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/RClassGeneratorActionBuilder.java
index f9597c4..aec1682 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/RClassGeneratorActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/RClassGeneratorActionBuilder.java
@@ -98,10 +98,16 @@
 
   public void build() {
     CustomCommandLine.Builder builder = new CustomCommandLine.Builder();
+    
+    // Set the busybox tool.
+    builder.add("--tool").add("GENERATE_BINARY_R").add("--");
+
     NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder();
-    inputs.addAll(ruleContext.getExecutablePrerequisite("$android_rclass_generator", Mode.HOST)
-        .getRunfilesSupport()
-        .getRunfilesArtifactsWithoutMiddlemen());
+    inputs.addAll(
+        ruleContext
+            .getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)
+            .getRunfilesSupport()
+            .getRunfilesArtifactsWithoutMiddlemen());
 
     List<Artifact> outs = new ArrayList<>();
     if (primary.getRTxt() != null) {
@@ -138,7 +144,7 @@
             .useParameterFile(ParameterFileType.SHELL_QUOTED)
             .setCommandLine(builder.build())
             .setExecutable(
-                ruleContext.getExecutablePrerequisite("$android_rclass_generator", Mode.HOST))
+                ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST))
             .setProgressMessage("Generating R Classes: " + ruleContext.getLabel())
             .setMnemonic("RClassGenerator")
             .build(ruleContext));
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
index beb7370..4d23429 100644
--- 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
@@ -144,10 +144,15 @@
     ImmutableList.Builder<Artifact> outputs = ImmutableList.builder();
 
     CustomCommandLine.Builder commandLine = new CustomCommandLine.Builder();
+    
+    // Set the busybox tool.
+    commandLine.add("--tool").add("SHRINK").add("--");
 
-    inputs.addAll(ruleContext.getExecutablePrerequisite("$android_resource_shrinker", Mode.HOST)
-        .getRunfilesSupport()
-        .getRunfilesArtifactsWithoutMiddlemen());
+    inputs.addAll(
+        ruleContext
+            .getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)
+            .getRunfilesSupport()
+            .getRunfilesArtifactsWithoutMiddlemen());
 
     commandLine.addExecPath("--aapt", sdk.getAapt().getExecutable());
 
@@ -208,16 +213,17 @@
     commandLine.addExecPath("--log", logOut);
     outputs.add(logOut);
 
-    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 for " + ruleContext.getLabel())
-        .setMnemonic("ResourceShrinker")
-        .build(ruleContext));
+    ruleContext.registerAction(
+        spawnActionBuilder
+            .addTool(sdk.getAapt())
+            .addInputs(inputs.build())
+            .addOutputs(outputs.build())
+            .setCommandLine(commandLine.build())
+            .setExecutable(
+                ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST))
+            .setProgressMessage("Shrinking resources for " + ruleContext.getLabel())
+            .setMnemonic("ResourceShrinker")
+            .build(ruleContext));
 
     return resourceApkOut;
   }
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 c22249b..aff2791 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
@@ -166,13 +166,7 @@
         .add("sh_binary(name = 'aar_native_libs_zip_creator', srcs = ['empty.sh'])")
         .add("sh_binary(name = 'dexbuilder', srcs = ['empty.sh'])")
         .add("sh_binary(name = 'dexmerger', srcs = ['empty.sh'])")
-        .add("sh_binary(name = 'manifest_merger', srcs = ['empty.sh'])")
-        .add("sh_binary(name = 'rclass_generator', srcs = ['empty.sh'])")
-        .add("sh_binary(name = 'resources_processor', srcs = ['empty.sh'])")
-        .add("sh_binary(name = 'resource_merger', srcs = ['empty.sh'])")
-        .add("sh_binary(name = 'resource_parser', srcs = ['empty.sh'])")
-        .add("sh_binary(name = 'resource_shrinker', srcs = ['empty.sh'])")
-        .add("sh_binary(name = 'resource_validator', srcs = ['empty.sh'])")
+        .add("sh_binary(name = 'busybox', srcs = ['empty.sh'])")
         .add("sh_binary(name = 'rex_wrapper', srcs = ['empty.sh'])")
         .add("android_library(name = 'incremental_stub_application')")
         .add("android_library(name = 'incremental_split_stub_application')")
diff --git a/src/test/shell/bazel/android/BUILD b/src/test/shell/bazel/android/BUILD
index 0bd8a35..758ddd6 100644
--- a/src/test/shell/bazel/android/BUILD
+++ b/src/test/shell/bazel/android/BUILD
@@ -16,15 +16,6 @@
         # labels, there isn't really a better option.
         "//external:android_ndk_for_testing",
         "//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:AndroidResourceMergingAction_deploy.jar",
-        "//src/tools/android/java/com/google/devtools/build/android:AndroidResourceParsingAction_deploy.jar",
-        "//src/tools/android/java/com/google/devtools/build/android:AndroidResourceProcessingAction_deploy.jar",
-        "//src/tools/android/java/com/google/devtools/build/android:AndroidResourceValidatorAction_deploy.jar",
-        "//src/tools/android/java/com/google/devtools/build/android:RClassGeneratorAction_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",
+        "//src/tools/android/java/com/google/devtools/build/android:ResourceProcessorBusyBox_deploy.jar",
     ],
 )
diff --git a/src/tools/android/java/com/google/devtools/build/android/BUILD b/src/tools/android/java/com/google/devtools/build/android/BUILD
index a132eea..a4b1ca1 100644
--- a/src/tools/android/java/com/google/devtools/build/android/BUILD
+++ b/src/tools/android/java/com/google/devtools/build/android/BUILD
@@ -17,73 +17,10 @@
     runtime_deps = [":android_builder_lib"],
 )
 
+# Used by //src/test/shell/bazel/android:android_integration_test
 java_binary(
-    name = "AarGeneratorAction",
-    main_class = "com.google.devtools.build.android.AarGeneratorAction",
-    runtime_deps = [
-        ":android_builder_lib",
-    ],
-)
-
-java_binary(
-    name = "AndroidResourceMergingAction",
-    main_class = "com.google.devtools.build.android.AndroidResourceMergingAction",
-    runtime_deps = [
-        ":android_builder_lib",
-    ],
-)
-
-java_binary(
-    name = "AndroidResourceParsingAction",
-    main_class = "com.google.devtools.build.android.AndroidResourceParsingAction",
-    runtime_deps = [
-        ":android_builder_lib",
-    ],
-)
-
-java_binary(
-    name = "AndroidResourceProcessingAction",
-    main_class = "com.google.devtools.build.android.AndroidResourceProcessingAction",
-    runtime_deps = [
-        ":android_builder_lib",
-    ],
-)
-
-java_binary(
-    name = "AndroidResourceValidatorAction",
-    main_class = "com.google.devtools.build.android.AndroidResourceValidatorAction",
-    runtime_deps = [
-        ":android_builder_lib",
-    ],
-)
-
-java_binary(
-    name = "ManifestMergerAction",
-    main_class = "com.google.devtools.build.android.ManifestMergerAction",
-    runtime_deps = [
-        ":android_builder_lib",
-    ],
-)
-
-java_binary(
-    name = "RClassGeneratorAction",
-    main_class = "com.google.devtools.build.android.RClassGeneratorAction",
-    runtime_deps = [
-        ":android_builder_lib",
-    ],
-)
-
-java_binary(
-    name = "LibraryRClassGeneratorAction",
-    main_class = "com.google.devtools.build.android.LibraryRClassGeneratorAction",
-    runtime_deps = [
-        ":android_builder_lib",
-    ],
-)
-
-java_binary(
-    name = "ResourceShrinkerAction",
-    main_class = "com.google.devtools.build.android.ResourceShinkerAction",
+    name = "ResourceProcessorBusyBox",
+    main_class = "com.google.devtools.build.android.ResourceProcessorBusyBox",
     runtime_deps = [
         ":android_builder_lib",
     ],
diff --git a/src/tools/android/java/com/google/devtools/build/android/BUILD.tools b/src/tools/android/java/com/google/devtools/build/android/BUILD.tools
index ab09887..c50dbf3 100644
--- a/src/tools/android/java/com/google/devtools/build/android/BUILD.tools
+++ b/src/tools/android/java/com/google/devtools/build/android/BUILD.tools
@@ -76,3 +76,11 @@
         ":classes",
     ],
 )
+
+java_binary(
+    name = "ResourceProcessorBusyBox",
+    main_class = "com.google.devtools.build.android.ResourceProcessorBusyBox",
+    runtime_deps = [
+        ":classes",
+    ],
+)
diff --git a/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java b/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java
new file mode 100644
index 0000000..553fe7c
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java
@@ -0,0 +1,139 @@
+// Copyright 2017 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.android;
+
+import com.google.devtools.common.options.EnumConverter;
+import com.google.devtools.common.options.Option;
+import com.google.devtools.common.options.OptionsBase;
+import com.google.devtools.common.options.OptionsParser;
+import java.nio.file.FileSystems;
+
+/**
+ * Provides an entry point for the resource processing stages.
+ *
+ * <p>A single entry point simplifies the build tool binary configuration and keeps the size of tool
+ * jar small, as opposed to multiple tools for each prosess step. It also makes it easy to prototype
+ * changes in the resource processing system.
+ *
+ * <pre>
+ * Example Usage:
+ *   java/com/google/build/android/ResourceProcessorBusyBox\
+ *      --tool PACKAGE\
+ *      --sdkRoot path/to/sdk\
+ *      --aapt path/to/sdk/aapt\
+ *      --annotationJar path/to/sdk/annotationJar\
+ *      --adb path/to/sdk/adb\
+ *      --zipAlign path/to/sdk/zipAlign\
+ *      --androidJar path/to/sdk/androidJar\
+ *      --manifestOutput path/to/manifest\
+ *      --primaryData path/to/resources:path/to/assets:path/to/manifest\
+ *      --data p/t/res1:p/t/assets1:p/t/1/AndroidManifest.xml:p/t/1/R.txt:symbols,\
+ *             p/t/res2:p/t/assets2:p/t/2/AndroidManifest.xml:p/t/2/R.txt:symbols\
+ *      --packagePath path/to/write/archive.ap_\
+ *      --srcJarOutput path/to/write/archive.srcjar
+ * </pre>
+ */
+public class ResourceProcessorBusyBox {
+  static enum Tool {
+    PACKAGE() {
+      @Override
+      void call(String[] args) throws Exception {
+        AndroidResourceProcessingAction.main(args);
+      }
+    },
+    VALIDATE() {
+      @Override
+      void call(String[] args) throws Exception {
+        AndroidResourceValidatorAction.main(args);
+      }
+    },
+    GENERATE_BINARY_R() {
+      @Override
+      void call(String[] args) throws Exception {
+        RClassGeneratorAction.main(args);
+      }
+    },
+    GENERATE_LIBRARY_R() {
+      @Override
+      void call(String[] args) throws Exception {
+        LibraryRClassGeneratorAction.main(args);
+      }
+    },
+    PARSE() {
+      @Override
+      void call(String[] args) throws Exception {
+        AndroidResourceParsingAction.main(args);
+      }
+    },
+    MERGE() {
+      @Override
+      void call(String[] args) throws Exception {
+        AndroidResourceMergingAction.main(args);
+      }
+    },
+    GENERATE_AAR() {
+      @Override
+      void call(String[] args) throws Exception {
+        AarGeneratorAction.main(args);
+      }
+    },
+    SHRINK() {
+      @Override
+      void call(String[] args) throws Exception {
+        ResourceShrinkerAction.main(args);
+      }
+    },
+    MERGE_MANIFEST() {
+      @Override
+      void call(String[] args) throws Exception {
+        ManifestMergerAction.main(args);
+      }
+    };
+
+    abstract void call(String[] args) throws Exception;
+  }
+
+  /** Converter for the Tool enum. */
+  public static final class ToolConverter extends EnumConverter<Tool> {
+
+    public ToolConverter() {
+      super(Tool.class, "resource tool");
+    }
+  }
+
+  /** Flag specifications for this action. */
+  public static final class Options extends OptionsBase {
+    @Option(
+      name = "tool",
+      defaultValue = "null",
+      converter = ToolConverter.class,
+      category = "input",
+      help =
+          "The processing tool to execute. "
+              + "Valid tools: PACKAGE, VALIDATE, GENERATE_BINARY_R, GENERATE_LIBRARY_R, PARSE, "
+              + "MERGE, GENERATE_AAR, SHRINK, MERGE_MANIFEST."
+    )
+    public Tool tool;
+  }
+
+  public static void main(String[] args) throws Exception {
+    OptionsParser optionsParser = OptionsParser.newOptionsParser(Options.class);
+    optionsParser.setAllowResidue(true);
+    optionsParser.enableParamsFileSupport(FileSystems.getDefault());
+    optionsParser.parse(args);
+    Options options = optionsParser.getOptions(Options.class);
+    options.tool.call(optionsParser.getResidue().toArray(new String[0]));
+  }
+}
diff --git a/tools/android/BUILD.tools b/tools/android/BUILD.tools
index d6c8456..a7035b3 100644
--- a/tools/android/BUILD.tools
+++ b/tools/android/BUILD.tools
@@ -16,43 +16,8 @@
 )
 
 alias(
-    name = "aar_generator",
-    actual = "//src/tools/android/java/com/google/devtools/build/android:AarGeneratorAction",
-)
-
-alias(
-    name = "manifest_merger",
-    actual = "//src/tools/android/java/com/google/devtools/build/android:ManifestMergerAction",
-)
-
-alias(
-    name = "rclass_generator",
-    actual = "//src/tools/android/java/com/google/devtools/build/android:RClassGeneratorAction",
-)
-
-alias(
-    name = "resources_processor",
-    actual = "//src/tools/android/java/com/google/devtools/build/android:AndroidResourceProcessingAction",
-)
-
-alias(
-    name = "resource_merger",
-    actual = "//src/tools/android/java/com/google/devtools/build/android:AndroidResourceMergingAction",
-)
-
-alias(
-    name = "resource_parser",
-    actual = "//src/tools/android/java/com/google/devtools/build/android:AndroidResourceParsingAction",
-)
-
-alias(
-    name = "resource_shrinker",
-    actual = "//src/tools/android/java/com/google/devtools/build/android:ResourceShrinkerAction",
-)
-
-alias(
-    name = "resource_validator",
-    actual = "//src/tools/android/java/com/google/devtools/build/android:AndroidResourceValidatorAction",
+    name = "busybox",
+    actual = "//src/tools/android/java/com/google/devtools/build/android:ResourceBusyBox",
 )
 
 alias(