AAPT2: Proguard rules generation added.

Change-Id: Ifbe79516cd9a1ade471e211a259301c63b62ac67
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index de2dafc..41c229d 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -28,6 +28,7 @@
 #include "ManifestValidator.h"
 #include "NameMangler.h"
 #include "Png.h"
+#include "ProguardRules.h"
 #include "ResourceParser.h"
 #include "ResourceTable.h"
 #include "ResourceTableResolver.h"
@@ -300,6 +301,9 @@
     // Directory to in which to generate R.java.
     Maybe<Source> generateJavaClass;
 
+    // File in which to produce proguard rules.
+    Maybe<Source> generateProguardRules;
+
     // Whether to output verbose details about
     // compilation.
     bool verbose = false;
@@ -417,7 +421,8 @@
 
 bool linkXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>& table,
              const std::shared_ptr<IResolver>& resolver, const LinkItem& item,
-             const void* data, size_t dataLen, ZipFile* outApk, std::queue<LinkItem>* outQueue) {
+             const void* data, size_t dataLen, ZipFile* outApk, std::queue<LinkItem>* outQueue,
+             proguard::KeepSet* keepSet) {
     SourceLogger logger(item.source);
     std::unique_ptr<xml::Node> root = xml::inflate(data, dataLen, &logger);
     if (!root) {
@@ -435,6 +440,10 @@
         xmlOptions.maxSdkAttribute = item.config.sdkVersion ? item.config.sdkVersion : 1;
     }
 
+    if (options.generateProguardRules) {
+        proguard::collectProguardRules(item.name.type, item.source, root.get(), keepSet);
+    }
+
     BigBuffer outBuffer(1024);
     Maybe<size_t> minStrippedSdk = xml::flattenAndLink(item.source, root.get(),
                                                        item.originalPackage, resolver,
@@ -509,7 +518,7 @@
 
 bool compileManifest(const AaptOptions& options, const std::shared_ptr<IResolver>& resolver,
                      const std::map<std::shared_ptr<ResourceTable>, StaticLibraryData>& libApks,
-                     const android::ResTable& table, ZipFile* outApk) {
+                     const android::ResTable& table, ZipFile* outApk, proguard::KeepSet* keepSet) {
     if (options.verbose) {
         Logger::note(options.manifest) << "compiling AndroidManifest.xml." << std::endl;
     }
@@ -557,6 +566,11 @@
         }
     }
 
+    if (options.generateProguardRules) {
+        proguard::collectProguardRulesForManifest(options.manifest, merger.getMergedXml(),
+                                                  keepSet);
+    }
+
     BigBuffer outBuffer(1024);
     if (!xml::flattenAndLink(options.manifest, merger.getMergedXml(), options.appInfo.package,
                 resolver, {}, &outBuffer)) {
@@ -805,8 +819,10 @@
         return false;
     }
 
+    proguard::KeepSet keepSet;
+
     android::ResTable binTable;
-    if (!compileManifest(options, resolver, apkFiles, binTable, &outApk)) {
+    if (!compileManifest(options, resolver, apkFiles, binTable, &outApk, &keepSet)) {
         return false;
     }
 
@@ -826,7 +842,7 @@
             assert(uncompressedData);
 
             if (!linkXml(options, outTable, resolver, item, uncompressedData,
-                        entry->getUncompressedLen(), &outApk, &linkQueue)) {
+                        entry->getUncompressedLen(), &outApk, &linkQueue, &keepSet)) {
                 Logger::error(options.output) << "failed to link '" << item.originalPath << "'."
                                               << std::endl;
                 return false;
@@ -883,6 +899,26 @@
         }
     }
 
+    // Generate the Proguard rules file.
+    if (options.generateProguardRules) {
+        const Source& outPath = options.generateProguardRules.value();
+
+        if (options.verbose) {
+            Logger::note(outPath) << "writing proguard rules." << std::endl;
+        }
+
+        std::ofstream fout(outPath.path);
+        if (!fout) {
+            Logger::error(outPath) << strerror(errno) << std::endl;
+            return false;
+        }
+
+        if (!proguard::writeKeepSet(&fout, keepSet)) {
+            Logger::error(outPath) << "failed to write proguard rules." << std::endl;
+            return false;
+        }
+    }
+
     outTable->getValueStringPool().prune();
     outTable->getValueStringPool().sort(
             [](const StringPool::Entry& a, const StringPool::Entry& b) -> bool {
@@ -1072,6 +1108,11 @@
                         options.generateJavaClass = Source{ arg.toString() };
                     });
 
+            flag::optionalFlag("--proguard", "file in which to output proguard rules",
+                    [&options](const StringPiece& arg) {
+                        options.generateProguardRules = Source{ arg.toString() };
+                    });
+
             flag::optionalSwitch("--static-lib", "generate a static Android library", true,
                                  &isStaticLib);