Accept --overlay-name flag in idmap2

To support allowing for multiple <overlay> tags in one package, idmap2
must be able to generate an idmap for an individual <overlay> tag.

`idmap2 create` now accepts a --overlay-name flag that specifies which
tag to use to generate the idmap. The value of --overlay-name should be
set to the value of the android:name attribute on the <overlay> tag to
use.

If the flag is not present, idmap2 will look for an <overlay> tag with
no value for android:name.

Bug: 162841629
Test: libandroidfw_tests
Test: libidmap2_tests
Change-Id: I02316d0b88773f02c04a5d462be9825016fa496d
diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
index 5db09ba..c163107 100644
--- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
+++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
@@ -59,6 +59,7 @@
   Write32(static_cast<uint8_t>(header.GetEnforceOverlayable()));
   WriteString(header.GetTargetPath());
   WriteString(header.GetOverlayPath());
+  WriteString(header.GetOverlayName());
   WriteString(header.GetDebugInfo());
 }
 
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 4745cc6..5af84b0 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -109,6 +109,7 @@
       !Read32(stream, &idmap_header->fulfilled_policies_) ||
       !Read32(stream, &enforce_overlayable) || !ReadString(stream, &idmap_header->target_path_) ||
       !ReadString(stream, &idmap_header->overlay_path_) ||
+      !ReadString(stream, &idmap_header->overlay_name_) ||
       !ReadString(stream, &idmap_header->debug_info_)) {
     return nullptr;
   }
@@ -119,6 +120,7 @@
 
 Result<Unit> IdmapHeader::IsUpToDate(const std::string& target_path,
                                      const std::string& overlay_path,
+                                     const std::string& overlay_name,
                                      PolicyBitmask fulfilled_policies,
                                      bool enforce_overlayable) const {
   const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path);
@@ -141,12 +143,13 @@
     return Error("failed to get overlay crc");
   }
 
-  return IsUpToDate(target_path, overlay_path, *target_crc, *overlay_crc, fulfilled_policies,
-                    enforce_overlayable);
+  return IsUpToDate(target_path, overlay_path, overlay_name, *target_crc, *overlay_crc,
+                    fulfilled_policies, enforce_overlayable);
 }
 
 Result<Unit> IdmapHeader::IsUpToDate(const std::string& target_path,
-                                     const std::string& overlay_path, uint32_t target_crc,
+                                     const std::string& overlay_path,
+                                     const std::string& overlay_name, uint32_t target_crc,
                                      uint32_t overlay_crc, PolicyBitmask fulfilled_policies,
                                      bool enforce_overlayable) const {
   if (magic_ != kIdmapMagic) {
@@ -187,6 +190,11 @@
                  overlay_path_.c_str());
   }
 
+  if (overlay_name != overlay_name_) {
+    return Error("bad overlay name: idmap version %s, file system version %s", overlay_name.c_str(),
+                 overlay_name_.c_str());
+  }
+
   return Unit{};
 }
 
@@ -317,6 +325,7 @@
 
 Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const ApkAssets& target_apk_assets,
                                                           const ApkAssets& overlay_apk_assets,
+                                                          const std::string& overlay_name,
                                                           const PolicyBitmask& fulfilled_policies,
                                                           bool enforce_overlayable) {
   SYSTRACE << "Idmap::FromApkAssets";
@@ -352,15 +361,16 @@
   header->enforce_overlayable_ = enforce_overlayable;
   header->target_path_ = target_apk_path;
   header->overlay_path_ = overlay_apk_path;
+  header->overlay_name_ = overlay_name;
 
-  auto overlay_info = utils::ExtractOverlayManifestInfo(overlay_apk_path);
-  if (!overlay_info) {
-    return overlay_info.GetError();
+  auto info = utils::ExtractOverlayManifestInfo(overlay_apk_path, overlay_name);
+  if (!info) {
+    return info.GetError();
   }
 
   LogInfo log_info;
   auto resource_mapping =
-      ResourceMapping::FromApkAssets(target_apk_assets, overlay_apk_assets, *overlay_info,
+      ResourceMapping::FromApkAssets(target_apk_assets, overlay_apk_assets, *info,
                                      fulfilled_policies, enforce_overlayable, log_info);
   if (!resource_mapping) {
     return resource_mapping.GetError();
diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
index f56d3d2..7e090a9 100644
--- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
@@ -39,6 +39,10 @@
           << TAB "target apk path  : " << header.GetTargetPath() << std::endl
           << TAB "overlay apk path : " << header.GetOverlayPath() << std::endl;
 
+  if (!header.GetOverlayName().empty()) {
+    stream_ << "Overlay name: " << header.GetOverlayName() << std::endl;
+  }
+
   const std::string& debug = header.GetDebugInfo();
   if (!debug.empty()) {
     std::istringstream debug_stream(debug);
diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
index d7f0739..b517aa3 100644
--- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
@@ -45,6 +45,7 @@
   print(static_cast<uint32_t>(header.GetEnforceOverlayable()), "enforce overlayable");
   print(header.GetTargetPath(), true /* print_value */, "target path");
   print(header.GetOverlayPath(), true /* print_value */, "overlay path");
+  print(header.GetOverlayName(), true /* print_value */, "overlay name");
   print(header.GetDebugInfo(), false /* print_value */, "debug info");
 
   auto target_apk_ = ApkAssets::Load(header.GetTargetPath());
diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp
index e817140..5283741 100644
--- a/cmds/idmap2/libidmap2/ResourceUtils.cpp
+++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp
@@ -92,7 +92,7 @@
 }
 
 Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
-                                                       bool assert_overlay) {
+                                                       const std::string& name) {
   std::unique_ptr<const ZipFile> zip = ZipFile::Open(path);
   if (!zip) {
     return Error("failed to open %s as a zip file", path.c_str());
@@ -113,65 +113,49 @@
     return Error("root element tag is not <manifest> in AndroidManifest.xml of %s", path.c_str());
   }
 
-  auto overlay_it = std::find_if(manifest_it.begin(), manifest_it.end(), [](const auto& it) {
-    return it.event() == XmlParser::Event::START_TAG && it.name() == "overlay";
-  });
-
-  OverlayManifestInfo info{};
-  if (overlay_it == manifest_it.end()) {
-    if (!assert_overlay) {
-      return info;
+  for (auto&& it : manifest_it) {
+    if (it.event() != XmlParser::Event::START_TAG || it.name() != "overlay") {
+      continue;
     }
-    return Error("<overlay> missing from AndroidManifest.xml of %s", path.c_str());
-  }
 
-  if (auto result_str = overlay_it->GetAttributeStringValue("targetPackage")) {
-    info.target_package = *result_str;
-  } else {
-    return Error("android:targetPackage missing from <overlay> of %s: %s", path.c_str(),
-                 result_str.GetErrorMessage().c_str());
-  }
+    OverlayManifestInfo info{};
+    if (auto result_str = it.GetAttributeStringValue("name")) {
+      if (*result_str != name) {
+        // A value for android:name was found, but either a the name does not match the requested
+        // name, or an <overlay> tag with no name was requested.
+        continue;
+      }
+      info.name = *result_str;
+    } else if (!name.empty()) {
+      // This tag does not have a value for android:name, but an <overlay> tag with a specific name
+      // has been requested.
+      continue;
+    }
 
-  if (auto result_str = overlay_it->GetAttributeStringValue("targetName")) {
-    info.target_name = *result_str;
-  }
-
-  if (auto result_value = overlay_it->GetAttributeValue("resourcesMap")) {
-    if (IsReference((*result_value).dataType)) {
-      info.resource_mapping = (*result_value).data;
+    if (auto result_str = it.GetAttributeStringValue("targetPackage")) {
+      info.target_package = *result_str;
     } else {
-      return Error("android:resourcesMap is not a reference in AndroidManifest.xml of %s",
-                   path.c_str());
+      return Error("android:targetPackage missing from <overlay> of %s: %s", path.c_str(),
+                   result_str.GetErrorMessage().c_str());
     }
-  }
 
-  if (auto result_value = overlay_it->GetAttributeValue("isStatic")) {
-    if ((*result_value).dataType >= Res_value::TYPE_FIRST_INT &&
-        (*result_value).dataType <= Res_value::TYPE_LAST_INT) {
-      info.is_static = (*result_value).data != 0U;
-    } else {
-      return Error("android:isStatic is not a boolean in AndroidManifest.xml of %s", path.c_str());
+    if (auto result_str = it.GetAttributeStringValue("targetName")) {
+      info.target_name = *result_str;
     }
-  }
 
-  if (auto result_value = overlay_it->GetAttributeValue("priority")) {
-    if ((*result_value).dataType >= Res_value::TYPE_FIRST_INT &&
-        (*result_value).dataType <= Res_value::TYPE_LAST_INT) {
-      info.priority = (*result_value).data;
-    } else {
-      return Error("android:priority is not an integer in AndroidManifest.xml of %s", path.c_str());
+    if (auto result_value = it.GetAttributeValue("resourcesMap")) {
+      if (IsReference((*result_value).dataType)) {
+        info.resource_mapping = (*result_value).data;
+      } else {
+        return Error("android:resourcesMap is not a reference in AndroidManifest.xml of %s",
+                     path.c_str());
+      }
     }
+    return info;
   }
 
-  if (auto result_str = overlay_it->GetAttributeStringValue("requiredSystemPropertyName")) {
-    info.requiredSystemPropertyName = *result_str;
-  }
-
-  if (auto result_str = overlay_it->GetAttributeStringValue("requiredSystemPropertyValue")) {
-    info.requiredSystemPropertyValue = *result_str;
-  }
-
-  return info;
+  return Error("<overlay> with android:name \"%s\" missing from AndroidManifest.xml of %s",
+               name.c_str(), path.c_str());
 }
 
 }  // namespace android::idmap2::utils