AAPT2: Add support to strip namespaces from XML

The --no-xml-namespaces flag will strip namespace information from
compiled binary XML files in res/* (excluding res/raw/*) and
AndroidManifest.xml. It will also strip URI information from compiled
binary XML files in res/* (excluding res/raw/* and AndroidManifest.xml).

AndroidManifest.xml URI information is retained due to PackageParser, which
requires the Android URI for intent filters.

Bug: 29115919
Change-Id: I90cad6ed39ce02a69776f55314c1d4f38ad1aabe
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 5a2bb6a..ea95dd1 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -74,6 +74,7 @@
     bool generateNonFinalIds = false;
     std::vector<std::string> javadocAnnotations;
     bool outputToDirectory = false;
+    bool noXmlNamespaces = false;
     bool autoAddOverlay = false;
     bool doNotCompressAnything = false;
     std::unordered_set<std::string> extensionsToNotCompress;
@@ -293,6 +294,7 @@
 struct ResourceFileFlattenerOptions {
     bool noAutoVersion = false;
     bool noVersionVectors = false;
+    bool noXmlNamespaces = false;
     bool keepRawValues = false;
     bool doNotCompressAnything = false;
     bool updateProguardSpec = false;
@@ -382,6 +384,13 @@
         return false;
     }
 
+    if (mOptions.noXmlNamespaces) {
+        XmlNamespaceRemover namespaceRemover;
+        if (!namespaceRemover.consume(mContext, outFileOp->xmlToFlatten.get())) {
+            return false;
+        }
+    }
+
     if (!mOptions.noAutoVersion) {
         if (mOptions.noVersionVectors) {
             // Skip this if it is a vector or animated-vector.
@@ -1296,6 +1305,7 @@
         fileFlattenerOptions.extensionsToNotCompress = mOptions.extensionsToNotCompress;
         fileFlattenerOptions.noAutoVersion = mOptions.noAutoVersion;
         fileFlattenerOptions.noVersionVectors = mOptions.noVersionVectors;
+        fileFlattenerOptions.noXmlNamespaces = mOptions.noXmlNamespaces;
         fileFlattenerOptions.updateProguardSpec =
                 static_cast<bool>(mOptions.generateProguardRulesPath);
 
@@ -1594,6 +1604,14 @@
                         error = true;
                     }
                 }
+
+                if (mOptions.noXmlNamespaces) {
+                    // PackageParser will fail if URIs are removed from AndroidManifest.xml.
+                    XmlNamespaceRemover namespaceRemover(true /* keepUris */);
+                    if (!namespaceRemover.consume(mContext, manifestXml.get())) {
+                        error = true;
+                    }
+                }
             } else {
                 error = true;
             }
@@ -1732,6 +1750,9 @@
             .optionalSwitch("--output-to-dir", "Outputs the APK contents to a directory specified "
                             "by -o",
                             &options.outputToDirectory)
+            .optionalSwitch("--no-xml-namespaces", "Removes XML namespace prefix and URI "
+                            "information from AndroidManifest.xml\nand XML binaries in res/*.",
+                            &options.noXmlNamespaces)
             .optionalFlag("--min-sdk-version", "Default minimum SDK version to use for "
                           "AndroidManifest.xml",
                           &options.manifestFixerOptions.minSdkVersionDefault)