AAPT2: Parse coreApp in <manifest> as boolean

Bug:30751662
Change-Id: I283be5725426ee084944c1921df40d1bd6188028
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 1203db7..e7edcc5 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -81,6 +81,22 @@
     return true;
 }
 
+/**
+ * The coreApp attribute in <manifest> is not a regular AAPT attribute, so type checking on it
+ * is manual.
+ */
+static bool fixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) {
+    if (xml::Attribute* attr = el->findAttribute("", "coreApp")) {
+        std::unique_ptr<BinaryPrimitive> result = ResourceUtils::tryParseBool(attr->value);
+        if (!result) {
+            diag->error(DiagMessage(el->lineNumber) << "attribute coreApp must be a boolean");
+            return false;
+        }
+        attr->compiledValue = std::move(result);
+    }
+    return true;
+}
+
 bool ManifestFixer::buildRules(xml::XmlActionExecutor* executor, IDiagnostics* diag) {
     // First verify some options.
     if (mOptions.renameManifestPackage) {
@@ -111,6 +127,7 @@
     // Manifest actions.
     xml::XmlNodeAction& manifestAction = (*executor)["manifest"];
     manifestAction.action(verifyManifest);
+    manifestAction.action(fixCoreAppAttribute);
     manifestAction.action([&](xml::Element* el) -> bool {
         if (mOptions.versionNameDefault) {
             if (el->findAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 1c69a8c..16ab9ab 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -253,4 +253,24 @@
     EXPECT_EQ(std::string("0x10000000"), attr->value);
 }
 
+TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) {
+    EXPECT_EQ(nullptr, verify("<manifest package=\"android\" coreApp=\"hello\" />"));
+    EXPECT_EQ(nullptr, verify("<manifest package=\"android\" coreApp=\"1dp\" />"));
+
+    std::unique_ptr<xml::XmlResource> doc =
+            verify("<manifest package=\"android\" coreApp=\"true\" />");
+    ASSERT_NE(nullptr, doc);
+
+    xml::Element* el = xml::findRootElement(doc.get());
+    ASSERT_NE(nullptr, el);
+
+    EXPECT_EQ("manifest", el->name);
+
+    xml::Attribute* attr = el->findAttribute("", "coreApp");
+    ASSERT_NE(nullptr, attr);
+
+    EXPECT_NE(nullptr, attr->compiledValue);
+    EXPECT_NE(nullptr, valueCast<BinaryPrimitive>(attr->compiledValue.get()));
+}
+
 } // namespace aapt
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index 02af5e3..a29d8dc 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -126,8 +126,9 @@
                     mError = true;
 
                 }
-            } else {
-                // We still encode references.
+            } else if (!attr.compiledValue) {
+                // We still encode references, but only if we haven't manually set this to
+                // another compiled value.
                 attr.compiledValue = ResourceUtils::tryParseReference(attr.value);
             }