AAPT2: ProGuard config for components in main dex.

Create an analogue of "aapt2 --proguard" which outputs a proguard
configuration that keeps only components which need to be in the main
dex.

Bug: 27383099

Change-Id: I61d652bfcdfc18e1614e852bd6f7540efd15f780
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index c610bb0..53ff961 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -140,7 +140,8 @@
 };
 
 struct ManifestVisitor : public BaseVisitor {
-    ManifestVisitor(const Source& source, KeepSet* keepSet) : BaseVisitor(source, keepSet) {
+    ManifestVisitor(const Source& source, KeepSet* keepSet, bool mainDexOnly)
+            : BaseVisitor(source, keepSet), mMainDexOnly(mainDexOnly) {
     }
 
     virtual void visit(xml::Element* node) override {
@@ -161,6 +162,13 @@
                         addClass(node->lineNumber, result.value());
                     }
                 }
+                if (mMainDexOnly) {
+                    xml::Attribute* defaultProcess = node->findAttribute(xml::kSchemaAndroid,
+                                                                         u"process");
+                    if (defaultProcess) {
+                        mDefaultProcess = defaultProcess->value;
+                    }
+                }
             } else if (node->name == u"activity" || node->name == u"service" ||
                     node->name == u"receiver" || node->name == u"provider" ||
                     node->name == u"instrumentation") {
@@ -169,7 +177,18 @@
 
             if (getName) {
                 xml::Attribute* attr = node->findAttribute(xml::kSchemaAndroid, u"name");
-                if (attr) {
+                getName = attr != nullptr;
+
+                if (getName && mMainDexOnly) {
+                    xml::Attribute* componentProcess = node->findAttribute(xml::kSchemaAndroid,
+                                                                           u"process");
+
+                    const std::u16string& process = componentProcess ? componentProcess->value
+                                                                     : mDefaultProcess;
+                    getName = !process.empty() && process[0] != u':';
+                }
+
+                if (getName) {
                     Maybe<std::u16string> result = util::getFullyQualifiedClassName(mPackage,
                                                                                     attr->value);
                     if (result) {
@@ -181,12 +200,15 @@
         BaseVisitor::visit(node);
     }
 
+private:
     std::u16string mPackage;
+    const bool mMainDexOnly;
+    std::u16string mDefaultProcess;
 };
 
 bool collectProguardRulesForManifest(const Source& source, xml::XmlResource* res,
-                                     KeepSet* keepSet) {
-    ManifestVisitor visitor(source, keepSet);
+                                     KeepSet* keepSet, bool mainDexOnly) {
+    ManifestVisitor visitor(source, keepSet, mainDexOnly);
     if (res->root) {
         res->root->accept(&visitor);
         return true;
diff --git a/tools/aapt2/java/ProguardRules.h b/tools/aapt2/java/ProguardRules.h
index aafffd3..744ae5b 100644
--- a/tools/aapt2/java/ProguardRules.h
+++ b/tools/aapt2/java/ProguardRules.h
@@ -46,7 +46,8 @@
     std::map<std::u16string, std::set<Source>> mKeepMethodSet;
 };
 
-bool collectProguardRulesForManifest(const Source& source, xml::XmlResource* res, KeepSet* keepSet);
+bool collectProguardRulesForManifest(const Source& source, xml::XmlResource* res, KeepSet* keepSet,
+                                     bool mainDexOnly = false);
 bool collectProguardRules(const Source& source, xml::XmlResource* res, KeepSet* keepSet);
 
 bool writeKeepSet(std::ostream* out, const KeepSet& keepSet);