Switch all dummy manifest writing to the AndroidManifest class. This ensures that the minSdk will be propagated to the dummy manifests.

RELNOTES: None
PiperOrigin-RevId: 210085414
diff --git a/src/test/java/com/google/devtools/build/android/ManifestMergerActionTest.java b/src/test/java/com/google/devtools/build/android/ManifestMergerActionTest.java
index 75857ae..fda1cd8 100644
--- a/src/test/java/com/google/devtools/build/android/ManifestMergerActionTest.java
+++ b/src/test/java/com/google/devtools/build/android/ManifestMergerActionTest.java
@@ -108,14 +108,17 @@
         });
 
     assertThat(
-        Joiner.on(" ")
-            .join(Files.readAllLines(mergedManifest, UTF_8))
-            .replaceAll("\\s+", " ")
-            .trim())
+            Joiner.on(" ")
+                .join(Files.readAllLines(mergedManifest, UTF_8))
+                .replaceAll("\\s+", " ")
+                .trim())
         .isEqualTo(
             "<?xml version=\"1.0\" encoding=\"utf-8\"?> "
                 + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" "
-                + "package=\"foo.bar.baz\" />");
+                + "package=\"foo.bar.baz\" > "
+                + "<uses-sdk android:minSdkVersion=\"1\" /> "
+                + "<application /> "
+                + "</manifest>");
   }
 
   @Test public void testMerge() throws Exception {
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidManifestProcessor.java b/src/tools/android/java/com/google/devtools/build/android/AndroidManifestProcessor.java
index 70cbf74..1e93036 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidManifestProcessor.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidManifestProcessor.java
@@ -400,21 +400,4 @@
       throw new ManifestProcessingException(e);
     }
   }
-
-  public static Path writeDummyManifestForAapt(Path dummyManifest, String packageForR) {
-    try {
-      Files.createDirectories(dummyManifest.getParent());
-      return Files.write(
-          dummyManifest,
-          String.format(
-                  "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
-                      + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\""
-                      + " package=\"%s\">"
-                      + "</manifest>",
-                  packageForR)
-              .getBytes(UTF_8));
-    } catch (IOException e) {
-      throw new ManifestProcessingException(e);
-    }
-  }
 }
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 940bdd0..2eade05 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
@@ -95,288 +95,264 @@
   /** Flag specifications for this action. */
   public static final class Options extends OptionsBase {
     @Option(
-      name = "primaryData",
-      defaultValue = "null",
-      converter = UnvalidatedAndroidDataConverter.class,
-      category = "input",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help =
-          "The directory containing the primary resource directory. The contents will override "
-              + "the contents of any other resource directories during merging. The expected "
-              + "format is "
-              + UnvalidatedAndroidData.EXPECTED_FORMAT
-    )
+        name = "primaryData",
+        defaultValue = "null",
+        converter = UnvalidatedAndroidDataConverter.class,
+        category = "input",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help =
+            "The directory containing the primary resource directory. The contents will override "
+                + "the contents of any other resource directories during merging. The expected "
+                + "format is "
+                + UnvalidatedAndroidData.EXPECTED_FORMAT)
     public UnvalidatedAndroidData primaryData;
 
     @Option(
-      name = "data",
-      defaultValue = "",
-      converter = DependencyAndroidDataListConverter.class,
-      category = "input",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help =
-          "Transitive Data dependencies. These values will be used if not defined in the "
-              + "primary resources. The expected format is "
-              + DependencyAndroidData.EXPECTED_FORMAT
-              + "[,...]"
-    )
+        name = "data",
+        defaultValue = "",
+        converter = DependencyAndroidDataListConverter.class,
+        category = "input",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help =
+            "Transitive Data dependencies. These values will be used if not defined in the "
+                + "primary resources. The expected format is "
+                + DependencyAndroidData.EXPECTED_FORMAT
+                + "[,...]")
     public List<DependencyAndroidData> transitiveData;
 
     @Option(
-      name = "directData",
-      defaultValue = "",
-      converter = DependencyAndroidDataListConverter.class,
-      category = "input",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help =
-          "Direct Data dependencies. These values will be used if not defined in the "
-              + "primary resources. The expected format is "
-              + DependencyAndroidData.EXPECTED_FORMAT
-              + "[,...]"
-    )
+        name = "directData",
+        defaultValue = "",
+        converter = DependencyAndroidDataListConverter.class,
+        category = "input",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help =
+            "Direct Data dependencies. These values will be used if not defined in the "
+                + "primary resources. The expected format is "
+                + DependencyAndroidData.EXPECTED_FORMAT
+                + "[,...]")
     public List<DependencyAndroidData> directData;
 
     @Option(
-      name = "assets",
-      defaultValue = "",
-      converter = SerializedAndroidDataListConverter.class,
-      category = "input",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help =
-          "Transitive asset dependencies. These can also be specified together with resources"
-              + " using --data. Expected format: "
-              + SerializedAndroidData.EXPECTED_FORMAT
-              + "[,...]"
-    )
+        name = "assets",
+        defaultValue = "",
+        converter = SerializedAndroidDataListConverter.class,
+        category = "input",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help =
+            "Transitive asset dependencies. These can also be specified together with resources"
+                + " using --data. Expected format: "
+                + SerializedAndroidData.EXPECTED_FORMAT
+                + "[,...]")
     public List<SerializedAndroidData> transitiveAssets;
 
     @Option(
-      name = "directAssets",
-      defaultValue = "",
-      converter = SerializedAndroidDataListConverter.class,
-      category = "input",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help =
-          "Direct asset dependencies. These can also be specified together with resources using "
-              + "--directData. Expected format: "
-              + SerializedAndroidData.EXPECTED_FORMAT
-              + "[,...]"
-    )
+        name = "directAssets",
+        defaultValue = "",
+        converter = SerializedAndroidDataListConverter.class,
+        category = "input",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help =
+            "Direct asset dependencies. These can also be specified together with resources using "
+                + "--directData. Expected format: "
+                + SerializedAndroidData.EXPECTED_FORMAT
+                + "[,...]")
     public List<SerializedAndroidData> directAssets;
 
     @Option(
-      name = "rOutput",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path to where the R.txt should be written."
-    )
+        name = "rOutput",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path to where the R.txt should be written.")
     public Path rOutput;
 
     @Option(
-      name = "symbolsOut",
-      oldName = "symbolsTxtOut",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path to where the symbols should be written."
-    )
+        name = "symbolsOut",
+        oldName = "symbolsTxtOut",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path to where the symbols should be written.")
     public Path symbolsOut;
 
     @Option(
-      name = "dataBindingInfoOut",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path to where data binding's layout info output should be written."
-    )
+        name = "dataBindingInfoOut",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path to where data binding's layout info output should be written.")
     public Path dataBindingInfoOut;
 
     @Option(
-      name = "packagePath",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path to the write the archive."
-    )
+        name = "packagePath",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path to the write the archive.")
     public Path packagePath;
 
     @Option(
-      name = "resourcesOutput",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path to the write merged resources archive."
-    )
+        name = "resourcesOutput",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path to the write merged resources archive.")
     public Path resourcesOutput;
 
     @Option(
-      name = "proguardOutput",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path for the proguard file."
-    )
+        name = "proguardOutput",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path for the proguard file.")
     public Path proguardOutput;
 
     @Option(
-      name = "mainDexProguardOutput",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path for the main dex proguard file."
-    )
+        name = "mainDexProguardOutput",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path for the main dex proguard file.")
     public Path mainDexProguardOutput;
 
     @Option(
-      name = "manifestOutput",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path for the modified manifest."
-    )
+        name = "manifestOutput",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path for the modified manifest.")
     public Path manifestOutput;
 
     @Option(
-      name = "srcJarOutput",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path for the generated java source jar."
-    )
+        name = "srcJarOutput",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path for the generated java source jar.")
     public Path srcJarOutput;
 
     @Option(
-      name = "packageType",
-      defaultValue = "DEFAULT",
-      converter = VariantTypeConverter.class,
-      category = "config",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help =
-          "Variant configuration type for packaging the resources."
-              + " Acceptible values DEFAULT, LIBRARY, ANDROID_TEST, UNIT_TEST"
-    )
+        name = "packageType",
+        defaultValue = "DEFAULT",
+        converter = VariantTypeConverter.class,
+        category = "config",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help =
+            "Variant configuration type for packaging the resources."
+                + " Acceptible values DEFAULT, LIBRARY, ANDROID_TEST, UNIT_TEST")
     public VariantType packageType;
 
     @Option(
-      name = "densities",
-      defaultValue = "",
-      converter = CommaSeparatedOptionListConverter.class,
-      category = "config",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "A list of densities to filter the resource drawables by."
-    )
+        name = "densities",
+        defaultValue = "",
+        converter = CommaSeparatedOptionListConverter.class,
+        category = "config",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "A list of densities to filter the resource drawables by.")
     public List<String> densities;
 
     @Option(
-      name = "packageForR",
-      defaultValue = "null",
-      category = "config",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Custom java package to generate the R symbols files."
-    )
+        name = "packageForR",
+        defaultValue = "null",
+        category = "config",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Custom java package to generate the R symbols files.")
     public String packageForR;
 
     @Option(
-      name = "applicationId",
-      defaultValue = "null",
-      category = "config",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Custom application id (package manifest) for the packaged manifest."
-    )
+        name = "applicationId",
+        defaultValue = "null",
+        category = "config",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Custom application id (package manifest) for the packaged manifest.")
     public String applicationId;
 
     @Option(
-      name = "versionName",
-      defaultValue = "null",
-      category = "config",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Version name to stamp into the packaged manifest."
-    )
+        name = "versionName",
+        defaultValue = "null",
+        category = "config",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Version name to stamp into the packaged manifest.")
     public String versionName;
 
     @Option(
-      name = "versionCode",
-      defaultValue = "-1",
-      category = "config",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Version code to stamp into the packaged manifest."
-    )
+        name = "versionCode",
+        defaultValue = "-1",
+        category = "config",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Version code to stamp into the packaged manifest.")
     public int versionCode;
 
     @Option(
-      name = "prefilteredResources",
-      defaultValue = "",
-      converter = Converters.CommaSeparatedOptionListConverter.class,
-      category = "config",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "A list of resources that were filtered out in analysis."
-    )
+        name = "prefilteredResources",
+        defaultValue = "",
+        converter = Converters.CommaSeparatedOptionListConverter.class,
+        category = "config",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "A list of resources that were filtered out in analysis.")
     public List<String> prefilteredResources;
 
     @Option(
-      name = "throwOnResourceConflict",
-      defaultValue = "false",
-      category = "config",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "If passed, resource merge conflicts will be treated as errors instead of warnings"
-    )
+        name = "throwOnResourceConflict",
+        defaultValue = "false",
+        category = "config",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "If passed, resource merge conflicts will be treated as errors instead of warnings")
     public boolean throwOnResourceConflict;
 
     @Option(
-      name = "packageUnderTest",
-      defaultValue = "null",
-      category = "config",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help =
-          "When building a test APK, the package of the binary being tested. Android resources can"
-              + " only be provided if there is no package under test or if the test instrumentation"
-              + " is in a different package."
-    )
+        name = "packageUnderTest",
+        defaultValue = "null",
+        category = "config",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help =
+            "When building a test APK, the package of the binary being tested. Android resources"
+                + " can only be provided if there is no package under test or if the test"
+                + " instrumentation is in a different package.")
     public String packageUnderTest;
 
     @Option(
-      name = "isTestWithResources",
-      defaultValue = "false",
-      category = "config",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help =
-          "Indicates that these resources are being processed for a test APK. Tests can only have"
-              + "resources if they are not instrumented or they instrument only themselves."
-    )
+        name = "isTestWithResources",
+        defaultValue = "false",
+        category = "config",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help =
+            "Indicates that these resources are being processed for a test APK. Tests can only have"
+                + "resources if they are not instrumented or they instrument only themselves.")
     public boolean isTestWithResources;
   }
 
@@ -402,7 +378,7 @@
       final Path filteredResources = tmp.resolve("resources-filtered");
       final Path densityManifest = tmp.resolve("manifest-filtered/AndroidManifest.xml");
       final Path processedManifest = tmp.resolve("manifest-processed/AndroidManifest.xml");
-      final Path dummyManifest = tmp.resolve("manifest-aapt-dummy/AndroidManifest.xml");
+      final Path dummyManifestDirectory = tmp.resolve("manifest-aapt-dummy");
       final Path publicXmlOut = tmp.resolve("public-resources/public.xml");
 
       Path generatedSources = null;
@@ -469,10 +445,12 @@
       }
 
       if (options.packageType == VariantType.LIBRARY) {
-        AndroidResourceProcessor.writeDummyManifestForAapt(dummyManifest, options.packageForR);
         processedData =
             new MergedAndroidData(
-                processedData.getResourceDir(), processedData.getAssetDir(), dummyManifest);
+                processedData.getResourceDir(),
+                processedData.getAssetDir(),
+                AndroidManifest.parseFrom(processedData.getManifest())
+                    .writeDummyManifestForAapt(dummyManifestDirectory, options.packageForR));
       }
 
       if (hasConflictWithPackageUnderTest(
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 1e20492..be6ad68 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
@@ -640,10 +640,6 @@
     }
   }
 
-  public static void writeDummyManifestForAapt(Path dummyManifest, String packageForR) {
-    AndroidManifestProcessor.writeDummyManifestForAapt(dummyManifest, packageForR);
-  }
-
   /** Shutdown AOSP utilized thread-pool. */
   public void shutdown() {
     FullyQualifiedName.logCacheUsage(logger);
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceValidatorAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceValidatorAction.java
index b960c8c..2e1fd8e 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceValidatorAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceValidatorAction.java
@@ -55,68 +55,62 @@
   public static final class Options extends OptionsBase {
 
     @Option(
-      name = "mergedResources",
-      defaultValue = "null",
-      converter = ExistingPathConverter.class,
-      category = "input",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path to the read merged resources archive."
-    )
+        name = "mergedResources",
+        defaultValue = "null",
+        converter = ExistingPathConverter.class,
+        category = "input",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path to the read merged resources archive.")
     public Path mergedResources;
 
     @Option(
-      name = "manifest",
-      defaultValue = "null",
-      converter = ExistingPathConverter.class,
-      category = "input",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path for the AndroidManifest.xml."
-    )
+        name = "manifest",
+        defaultValue = "null",
+        converter = ExistingPathConverter.class,
+        category = "input",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path for the AndroidManifest.xml.")
     public Path manifest;
 
     @Option(
-      name = "packageForR",
-      defaultValue = "null",
-      category = "config",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Custom java package to generate the R symbols files."
-    )
+        name = "packageForR",
+        defaultValue = "null",
+        category = "config",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Custom java package to generate the R symbols files.")
     public String packageForR;
 
     @Option(
-      name = "srcJarOutput",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path for the generated java source jar."
-    )
+        name = "srcJarOutput",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path for the generated java source jar.")
     public Path srcJarOutput;
 
     @Option(
-      name = "rOutput",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path to where the R.txt should be written."
-    )
+        name = "rOutput",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path to where the R.txt should be written.")
     public Path rOutput;
 
     @Option(
-      name = "packagePath",
-      defaultValue = "null",
-      converter = PathConverter.class,
-      category = "output",
-      documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
-      effectTags = {OptionEffectTag.UNKNOWN},
-      help = "Path to the write the archive."
-    )
+        name = "packagePath",
+        defaultValue = "null",
+        converter = PathConverter.class,
+        category = "output",
+        documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+        effectTags = {OptionEffectTag.UNKNOWN},
+        help = "Path to the write the archive.")
     // TODO(b/30307842): Remove this once it is no longer needed for resources migration.
     public Path packagePath;
   }
@@ -144,13 +138,12 @@
       Path resources = expandedOut.resolve("res");
       Path assets = expandedOut.resolve("assets");
       Path generatedSources = tmp.resolve("generated_resources");
-      Path dummyManifest = tmp.resolve("manifest-aapt-dummy/AndroidManifest.xml");
+      Path dummyManifestDirectory = tmp.resolve("manifest-aapt-dummy");
 
       unpackZip(options.mergedResources, expandedOut);
       logger.fine(String.format("unpacked zip at %sms", timer.elapsed(TimeUnit.MILLISECONDS)));
 
       // We need to make the manifest aapt safe (w.r.t., placeholders). For now, just stub it out.
-      AndroidResourceProcessor.writeDummyManifestForAapt(dummyManifest, options.packageForR);
 
       resourceProcessor.runAapt(
           tmp,
@@ -163,7 +156,8 @@
           new FlagAaptOptions(aaptConfigOptions),
           aaptConfigOptions.resourceConfigs,
           ImmutableList.<String>of(),
-          dummyManifest,
+          AndroidManifest.parseFrom(options.manifest)
+              .writeDummyManifestForAapt(dummyManifestDirectory, options.packageForR),
           resources,
           assets,
           generatedSources,
diff --git a/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java b/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java
index 18040ea..211070d 100644
--- a/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java
@@ -207,8 +207,8 @@
       Path manifest = options.manifest;
       if (manifest == null) {
         // No primary manifest was passed. Generate a dummy primary.
-        manifest = tmp.resolve("dummy_AndroidManifest.xml");
-        AndroidResourceProcessor.writeDummyManifestForAapt(manifest, options.customPackage);
+
+        manifest = AndroidManifest.asEmpty().writeDummyManifestForAapt(tmp, options.customPackage);
       }
 
       mergedManifest =
diff --git a/src/tools/android/java/com/google/devtools/build/android/ValidateAndLinkResourcesAction.java b/src/tools/android/java/com/google/devtools/build/android/ValidateAndLinkResourcesAction.java
index 18b5cf3..4257f5e 100644
--- a/src/tools/android/java/com/google/devtools/build/android/ValidateAndLinkResourcesAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/ValidateAndLinkResourcesAction.java
@@ -14,9 +14,7 @@
 // Copyright 2017 The Bazel Authors. All rights reserved.
 package com.google.devtools.build.android;
 
-import com.android.builder.core.VariantConfiguration;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
 import com.google.devtools.build.android.aapt2.Aapt2ConfigOptions;
 import com.google.devtools.build.android.aapt2.CompiledResources;
 import com.google.devtools.build.android.aapt2.ResourceLinker;
@@ -172,23 +170,17 @@
               // We need to make the manifest aapt safe (w.r.t., placeholders). For now, just stub
               // it out.
               .processManifest(
-                  manifest -> {
-                    final String packageForR =
-                        Strings.isNullOrEmpty(options.packageForR)
-                            ? VariantConfiguration.getManifestPackage(manifest.toFile())
-                            : options.packageForR;
-                    return AndroidManifestProcessor.writeDummyManifestForAapt(
-                        scopedTmp.getPath().resolve("manifest-aapt-dummy/AndroidManifest.xml"),
-                        packageForR);
-                  });
+                  manifest ->
+                      AndroidManifest.parseFrom(manifest)
+                          .writeDummyManifestForAapt(
+                              scopedTmp.getPath().resolve("manifest-aapt-dummy"),
+                              options.packageForR));
       profiler.recordEndOf("manifest").startTask("link");
       ResourceLinker.create(aapt2Options.aapt2, executorService, scopedTmp.getPath())
           .profileUsing(profiler)
           .dependencies(Optional.ofNullable(options.deprecatedLibraries).orElse(options.libraries))
           .include(
-              options
-                  .compiledDeps
-                  .stream()
+              options.compiledDeps.stream()
                   .map(CompiledResources::from)
                   .collect(Collectors.toList()))
           .buildVersion(aapt2Options.buildToolsVersion)