Implement issue #112113117: Ad library dependency declaration in manifest

You can now do a new form of <uses-package> that allows you to
specify a type of package along with required cert digests (like
uses-static-library).

This defines the new attribute needed for this and XML tag, and
updates aapt2 to actually allow uses-library in the manifest and
output this data with "dump badging".

While doing this I realized that "dump badging" was not printing
the data for uses-static-library or uses-library, so do those too.

Bug: 112113117
Test: manual
Change-Id: I5d02010aad9cb44675504a317df9cced421be8a1
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 2c356d1..c685f0d 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -16,6 +16,8 @@
 
 #include "DumpManifest.h"
 
+#include <algorithm>
+
 #include "LoadedApk.h"
 #include "SdkConstants.h"
 #include "ValueVisitor.h"
@@ -70,10 +72,14 @@
   CATEGORY_ATTR = 0x010103e8,
   BANNER_ATTR = 0x10103f2,
   ISGAME_ATTR = 0x10103f4,
+  VERSION_ATTR = 0x01010519,
+  CERT_DIGEST_ATTR = 0x01010548,
   REQUIRED_FEATURE_ATTR = 0x1010557,
   REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
   COMPILE_SDK_VERSION_ATTR = 0x01010572,
   COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573,
+  VERSION_MAJOR_ATTR = 0x01010577,
+  PACKAGE_TYPE_ATTR = 0x01010587,
 };
 
 const std::string& kAndroidNamespace = "http://schemas.android.com/apk/res/android";
@@ -1318,6 +1324,70 @@
   }
 };
 
+/** Represents <static-library> elements. **/
+class StaticLibrary : public ManifestExtractor::Element {
+ public:
+  StaticLibrary() = default;
+  std::string name;
+  int version;
+  int versionMajor;
+
+  void Extract(xml::Element* element) override {
+    auto parent_stack = extractor()->parent_stack();
+    if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
+      name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+      version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+      versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+    }
+  }
+
+  void Print(text::Printer& printer) override {
+    printer.Print(StringPrintf(
+      "static-library: name='%s' version='%d' versionMajor='%d'\n",
+      name.data(), version, versionMajor));
+  }
+};
+
+/** Represents <uses-static-library> elements. **/
+class UsesStaticLibrary : public ManifestExtractor::Element {
+ public:
+  UsesStaticLibrary() = default;
+  std::string name;
+  int version;
+  int versionMajor;
+  std::vector<std::string> certDigests;
+
+  void Extract(xml::Element* element) override {
+    auto parent_stack = extractor()->parent_stack();
+    if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
+      name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+      version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+      versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+      AddCertDigest(element);
+    }
+  }
+
+  void AddCertDigest(xml::Element* element) {
+    std::string digest = GetAttributeStringDefault(FindAttribute(element, CERT_DIGEST_ATTR), "");
+    // We allow ":" delimiters in the SHA declaration as this is the format
+    // emitted by the certtool making it easy for developers to copy/paste.
+    digest.erase(std::remove(digest.begin(), digest.end(), ':'), digest.end());
+    if (!digest.empty()) {
+      certDigests.push_back(digest);
+    }
+  }
+
+  void Print(text::Printer& printer) override {
+    printer.Print(StringPrintf(
+      "uses-static-library: name='%s' version='%d' versionMajor='%d'",
+      name.data(), version, versionMajor));
+    for (size_t i = 0; i < certDigests.size(); i++) {
+      printer.Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
+    }
+    printer.Print("\n");
+  }
+};
+
 /**
  * Represents <meta-data> elements. These tags are only printed when a flag is passed in to
  * explicitly enable meta data printing.
@@ -1544,15 +1614,65 @@
 class UsesPackage : public ManifestExtractor::Element {
  public:
   UsesPackage() = default;
+  const std::string* packageType = nullptr;
   const std::string* name = nullptr;
+  int version;
+  int versionMajor;
+  std::vector<std::string> certDigests;
 
   void Extract(xml::Element* element) override {
-    name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+    auto parent_stack = extractor()->parent_stack();
+    if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
+      packageType = GetAttributeString(FindAttribute(element, PACKAGE_TYPE_ATTR));
+      name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+      version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+      versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+      AddCertDigest(element);
+    }
+  }
+
+  void AddCertDigest(xml::Element* element) {
+    std::string digest = GetAttributeStringDefault(FindAttribute(element, CERT_DIGEST_ATTR), "");
+    // We allow ":" delimiters in the SHA declaration as this is the format
+    // emitted by the certtool making it easy for developers to copy/paste.
+    digest.erase(std::remove(digest.begin(), digest.end(), ':'), digest.end());
+    if (!digest.empty()) {
+      certDigests.push_back(digest);
+    }
   }
 
   void Print(text::Printer& printer) override {
     if (name) {
-      printer.Print(StringPrintf("uses-package:'%s'\n", name->data()));
+      if (packageType) {
+        printer.Print(StringPrintf(
+          "uses-typed-package: type='%s' name='%s' version='%d' versionMajor='%d'",
+          packageType->data(), name->data(), version, versionMajor));
+        for (size_t i = 0; i < certDigests.size(); i++) {
+          printer.Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
+        }
+        printer.Print("\n");
+      } else {
+        printer.Print(StringPrintf("uses-package:'%s'\n", name->data()));
+      }
+    }
+  }
+};
+
+/** Represents <additional-certificate> elements. **/
+class AdditionalCertificate : public ManifestExtractor::Element {
+ public:
+  AdditionalCertificate() = default;
+
+  void Extract(xml::Element* element) override {
+    auto parent_stack = extractor()->parent_stack();
+    if (parent_stack.size() > 0) {
+      if (ElementCast<UsesPackage>(parent_stack[0])) {
+        UsesPackage* uses = ElementCast<UsesPackage>(parent_stack[0]);
+        uses->AddCertDigest(element);
+      } else if (ElementCast<UsesStaticLibrary>(parent_stack[0])) {
+        UsesStaticLibrary* uses = ElementCast<UsesStaticLibrary>(parent_stack[0]);
+        uses->AddCertDigest(element);
+      }
     }
   }
 };
@@ -2065,6 +2185,9 @@
     {"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
     {"uses-library", std::is_base_of<UsesLibrary, T>::value},
     {"uses-package", std::is_base_of<UsesPackage, T>::value},
+    {"static-library", std::is_base_of<StaticLibrary, T>::value},
+    {"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
+    {"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
     {"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
   };
 
@@ -2110,7 +2233,10 @@
     {"uses-permission", &CreateType<UsesPermission>},
     {"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
     {"uses-library", &CreateType<UsesLibrary>},
+    {"static-library", &CreateType<StaticLibrary>},
+    {"uses-static-library", &CreateType<UsesStaticLibrary>},
     {"uses-package", &CreateType<UsesPackage>},
+    {"additional-certificate", &CreateType<AdditionalCertificate>},
     {"uses-sdk", &CreateType<UsesSdkBadging>},
   };