Add fabricated RRO generation to libidmap2

Fabricated Runtime Resource Overlays are overlays that are generated
at runtime and are stored in the data/ partition.

The system can fabricate RROs at runtime to dynamically theme the
device. Idmaps can now be created from APK RROs and fabricated RROs.

Rather than operating on ApkAssets, libidmap2 now operates on abstract
resource "containers" that supply resource values. Target resource
containers implement methods needed to query overlayable and target
overlay information. Currently only APKs can be loaded as target
resource containers. Overlay resource containers implement methods to
supply the mapping of target resource to overlay value and other
overlay information.

The format of a fabricated RRO is as follows:
0x00 - 0x04 : fabricated overlay magic (always FRRO)
0x04 - 0x08 : file format version
0x08 - 0x0c : crc of version + proto data
0x0c - EOF  : proto fabricated overlay data

The magic is used to quickly detect if the file is a fabricated overlay.
The version is incremented whenever backwards incompatible changes are
made to the proto file format. Idmap must always be able to upgrade
fabricated overlays from previous versions to new versions, so all
previous versions must be checked into the tree.

Bug: 172471315
Test: libidmap2_tests && libandroidfw_tests
Change-Id: I4c9f29da278672e5695fb57d131a44c11a835180
diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
index c163107..3bbe9d9 100644
--- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
+++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
@@ -87,10 +87,6 @@
 }
 
 void BinaryStreamVisitor::visit(const IdmapData::Header& header) {
-  Write8(header.GetTargetPackageId());
-  Write8(header.GetOverlayPackageId());
-  Write8(0U);  // padding
-  Write8(0U);  // padding
   Write32(header.GetTargetEntryCount());
   Write32(header.GetTargetInlineEntryCount());
   Write32(header.GetOverlayEntryCount());
diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
new file mode 100644
index 0000000..4a348ac
--- /dev/null
+++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "idmap2/FabricatedOverlay.h"
+
+#include <androidfw/ResourceUtils.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <utils/ByteOrder.h>
+#include <zlib.h>
+
+#include <fstream>
+
+namespace android::idmap2 {
+
+namespace {
+bool Read32(std::istream& stream, uint32_t* out) {
+  uint32_t value;
+  if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint32_t))) {
+    *out = dtohl(value);
+    return true;
+  }
+  return false;
+}
+
+void Write32(std::ostream& stream, uint32_t value) {
+  uint32_t x = htodl(value);
+  stream.write(reinterpret_cast<char*>(&x), sizeof(uint32_t));
+}
+}  // namespace
+
+FabricatedOverlay::FabricatedOverlay(pb::FabricatedOverlay&& overlay,
+                                     std::optional<uint32_t> crc_from_disk)
+    : overlay_pb_(std::forward<pb::FabricatedOverlay>(overlay)), crc_from_disk_(crc_from_disk) {
+}
+
+FabricatedOverlay::Builder::Builder(const std::string& package_name, const std::string& name,
+                                    const std::string& target_package_name) {
+  package_name_ = package_name;
+  name_ = name;
+  target_package_name_ = target_package_name;
+}
+
+FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetOverlayable(const std::string& name) {
+  target_overlayable_ = name;
+  return *this;
+}
+
+FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
+    const std::string& resource_name, uint8_t data_type, uint32_t data_value) {
+  entries_.emplace_back(Entry{resource_name, data_type, data_value});
+  return *this;
+}
+
+Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
+  std::map<std::string, std::map<std::string, std::map<std::string, TargetValue>>> entries;
+  for (const auto& res_entry : entries_) {
+    StringPiece package_substr;
+    StringPiece type_name;
+    StringPiece entry_name;
+    if (!android::ExtractResourceName(StringPiece(res_entry.resource_name), &package_substr,
+                                      &type_name, &entry_name)) {
+      return Error("failed to parse resource name '%s'", res_entry.resource_name.c_str());
+    }
+
+    std::string package_name =
+        package_substr.empty() ? target_package_name_ : package_substr.to_string();
+    if (type_name.empty()) {
+      return Error("resource name '%s' missing type name", res_entry.resource_name.c_str());
+    }
+
+    if (entry_name.empty()) {
+      return Error("resource name '%s' missing entry name", res_entry.resource_name.c_str());
+    }
+
+    auto package = entries.find(package_name);
+    if (package == entries.end()) {
+      package = entries
+                    .insert(std::make_pair<>(
+                        package_name, std::map<std::string, std::map<std::string, TargetValue>>()))
+                    .first;
+    }
+
+    auto type = package->second.find(type_name.to_string());
+    if (type == package->second.end()) {
+      type =
+          package->second
+              .insert(std::make_pair<>(type_name.to_string(), std::map<std::string, TargetValue>()))
+              .first;
+    }
+
+    auto entry = type->second.find(entry_name.to_string());
+    if (entry == type->second.end()) {
+      entry = type->second.insert(std::make_pair<>(entry_name.to_string(), TargetValue())).first;
+    }
+
+    entry->second = TargetValue{res_entry.data_type, res_entry.data_value};
+  }
+
+  pb::FabricatedOverlay overlay_pb;
+  overlay_pb.set_package_name(package_name_);
+  overlay_pb.set_name(name_);
+  overlay_pb.set_target_package_name(target_package_name_);
+  overlay_pb.set_target_overlayable(target_overlayable_);
+
+  for (const auto& package : entries) {
+    auto package_pb = overlay_pb.add_packages();
+    package_pb->set_name(package.first);
+
+    for (const auto& type : package.second) {
+      auto type_pb = package_pb->add_types();
+      type_pb->set_name(type.first);
+
+      for (const auto& entry : type.second) {
+        auto entry_pb = type_pb->add_entries();
+        entry_pb->set_name(entry.first);
+        pb::ResourceValue* value = entry_pb->mutable_res_value();
+        value->set_data_type(entry.second.data_type);
+        value->set_data_value(entry.second.data_value);
+      }
+    }
+  }
+
+  return FabricatedOverlay(std::move(overlay_pb));
+}
+
+Result<FabricatedOverlay> FabricatedOverlay::FromBinaryStream(std::istream& stream) {
+  uint32_t magic;
+  if (!Read32(stream, &magic)) {
+    return Error("Failed to read fabricated overlay magic.");
+  }
+
+  if (magic != kFabricatedOverlayMagic) {
+    return Error("Not a fabricated overlay file.");
+  }
+
+  uint32_t version;
+  if (!Read32(stream, &version)) {
+    return Error("Failed to read fabricated overlay version.");
+  }
+
+  if (version != 1) {
+    return Error("Invalid fabricated overlay version '%u'.", version);
+  }
+
+  uint32_t crc;
+  if (!Read32(stream, &crc)) {
+    return Error("Failed to read fabricated overlay version.");
+  }
+
+  pb::FabricatedOverlay overlay{};
+  if (!overlay.ParseFromIstream(&stream)) {
+    return Error("Failed read fabricated overlay proto.");
+  }
+
+  // If the proto version is the latest version, then the contents of the proto must be the same
+  // when the proto is re-serialized; otherwise, the crc must be calculated because migrating the
+  // proto to the latest version will likely change the contents of the fabricated overlay.
+  return FabricatedOverlay(std::move(overlay), version == kFabricatedOverlayCurrentVersion
+                                                   ? std::optional<uint32_t>(crc)
+                                                   : std::nullopt);
+}
+
+Result<FabricatedOverlay::SerializedData*> FabricatedOverlay::InitializeData() const {
+  if (!data_.has_value()) {
+    auto size = overlay_pb_.ByteSizeLong();
+    auto data = std::unique_ptr<uint8_t[]>(new uint8_t[size]);
+
+    // Ensure serialization is deterministic
+    google::protobuf::io::ArrayOutputStream array_stream(data.get(), size);
+    google::protobuf::io::CodedOutputStream output_stream(&array_stream);
+    output_stream.SetSerializationDeterministic(true);
+    overlay_pb_.SerializeWithCachedSizes(&output_stream);
+    if (output_stream.HadError() || size != output_stream.ByteCount()) {
+      return Error("Failed to serialize fabricated overlay.");
+    }
+
+    // Calculate the crc using the proto data and the version.
+    uint32_t crc = crc32(0L, Z_NULL, 0);
+    crc = crc32(crc, reinterpret_cast<const uint8_t*>(&kFabricatedOverlayCurrentVersion),
+                sizeof(uint32_t));
+    crc = crc32(crc, data.get(), size);
+    data_ = SerializedData{std::move(data), size, crc};
+  }
+  return &(*data_);
+}
+Result<uint32_t> FabricatedOverlay::GetCrc() const {
+  if (crc_from_disk_.has_value()) {
+    return *crc_from_disk_;
+  }
+  auto data = InitializeData();
+  if (!data) {
+    return data.GetError();
+  }
+  return (*data)->crc;
+}
+
+Result<Unit> FabricatedOverlay::ToBinaryStream(std::ostream& stream) {
+  auto data = InitializeData();
+  if (!data) {
+    return data.GetError();
+  }
+
+  Write32(stream, kFabricatedOverlayMagic);
+  Write32(stream, kFabricatedOverlayCurrentVersion);
+  Write32(stream, (*data)->crc);
+  stream.write(reinterpret_cast<const char*>((*data)->data.get()), (*data)->data_size);
+  if (stream.bad()) {
+    return Error("Failed to write serialized fabricated overlay.");
+  }
+
+  return Unit{};
+}
+
+using FabContainer = FabricatedOverlayContainer;
+FabContainer::FabricatedOverlayContainer(FabricatedOverlay&& overlay, std::string&& path)
+    : overlay_(std::forward<FabricatedOverlay>(overlay)), path_(std::forward<std::string>(path)) {
+}
+
+FabContainer::~FabricatedOverlayContainer() = default;
+
+Result<std::unique_ptr<FabContainer>> FabContainer::FromPath(std::string path) {
+  std::fstream fin(path);
+  auto overlay = FabricatedOverlay::FromBinaryStream(fin);
+  if (!overlay) {
+    return overlay.GetError();
+  }
+  return std::unique_ptr<FabContainer>(
+      new FabricatedOverlayContainer(std::move(*overlay), std::move(path)));
+}
+
+std::unique_ptr<FabricatedOverlayContainer> FabContainer::FromOverlay(FabricatedOverlay&& overlay) {
+  return std::unique_ptr<FabContainer>(
+      new FabricatedOverlayContainer(std::move(overlay), {} /* path */));
+}
+
+Result<OverlayManifestInfo> FabContainer::FindOverlayInfo(const std::string& name) const {
+  const pb::FabricatedOverlay& overlay_pb = overlay_.overlay_pb_;
+  if (name != overlay_pb.name()) {
+    return Error("Failed to find name '%s' in fabricated overlay", name.c_str());
+  }
+
+  return OverlayManifestInfo{
+      .name = overlay_pb.name(),
+      .target_package = overlay_pb.target_package_name(),
+      .target_name = overlay_pb.target_overlayable(),
+  };
+}
+
+Result<OverlayData> FabContainer::GetOverlayData(const OverlayManifestInfo& info) const {
+  const pb::FabricatedOverlay& overlay_pb = overlay_.overlay_pb_;
+  if (info.name != overlay_pb.name()) {
+    return Error("Failed to find name '%s' in fabricated overlay", info.name.c_str());
+  }
+
+  OverlayData result{};
+  for (const auto& package : overlay_pb.packages()) {
+    for (const auto& type : package.types()) {
+      for (const auto& entry : type.entries()) {
+        auto name = base::StringPrintf("%s:%s/%s", package.name().c_str(), type.name().c_str(),
+                                       entry.name().c_str());
+        const auto& res_value = entry.res_value();
+        result.pairs.emplace_back(OverlayData::Value{
+            name, TargetValue{.data_type = static_cast<uint8_t>(res_value.data_type()),
+                              .data_value = res_value.data_value()}});
+      }
+    }
+  }
+  return result;
+}
+
+Result<uint32_t> FabContainer::GetCrc() const {
+  return overlay_.GetCrc();
+}
+
+const std::string& FabContainer::GetPath() const {
+  return path_;
+}
+
+Result<std::string> FabContainer::GetResourceName(ResourceId /* id */) const {
+  return Error("Fabricated overlay does not contain resources.");
+}
+
+}  // namespace android::idmap2
\ No newline at end of file
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index a0cc407..6515d55 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -20,23 +20,16 @@
 #include <iostream>
 #include <iterator>
 #include <limits>
-#include <map>
 #include <memory>
-#include <set>
 #include <string>
 #include <utility>
-#include <vector>
 
 #include "android-base/macros.h"
-#include "android-base/stringprintf.h"
 #include "androidfw/AssetManager2.h"
 #include "idmap2/ResourceMapping.h"
 #include "idmap2/ResourceUtils.h"
 #include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
-#include "idmap2/ZipFile.h"
-#include "utils/String16.h"
-#include "utils/String8.h"
 
 namespace android::idmap2 {
 
@@ -93,22 +86,13 @@
 
 }  // namespace
 
-Result<uint32_t> GetPackageCrc(const ZipFile& zip) {
-  const Result<uint32_t> a = zip.Crc("resources.arsc");
-  const Result<uint32_t> b = zip.Crc("AndroidManifest.xml");
-  return a && b
-             ? Result<uint32_t>(*a ^ *b)
-             : Error("failed to get CRC for \"%s\"", a ? "AndroidManifest.xml" : "resources.arsc");
-}
-
 std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& stream) {
   std::unique_ptr<IdmapHeader> idmap_header(new IdmapHeader());
   if (!Read32(stream, &idmap_header->magic_) || !Read32(stream, &idmap_header->version_)) {
     return nullptr;
   }
 
-  if (idmap_header->magic_ != kIdmapMagic ||
-      idmap_header->version_ != kIdmapCurrentVersion) {
+  if (idmap_header->magic_ != kIdmapMagic || idmap_header->version_ != kIdmapCurrentVersion) {
     // Do not continue parsing if the file is not a current version idmap.
     return nullptr;
   }
@@ -127,32 +111,22 @@
   return std::move(idmap_header);
 }
 
-Result<Unit> IdmapHeader::IsUpToDate(const std::string& target_path,
-                                     const std::string& overlay_path,
+Result<Unit> IdmapHeader::IsUpToDate(const TargetResourceContainer& target,
+                                     const OverlayResourceContainer& overlay,
                                      const std::string& overlay_name,
                                      PolicyBitmask fulfilled_policies,
                                      bool enforce_overlayable) const {
-  const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path);
-  if (!target_zip) {
-    return Error("failed to open target %s", target_path.c_str());
-  }
-
-  const Result<uint32_t> target_crc = GetPackageCrc(*target_zip);
+  const Result<uint32_t> target_crc = target.GetCrc();
   if (!target_crc) {
     return Error("failed to get target crc");
   }
 
-  const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path);
-  if (!overlay_zip) {
-    return Error("failed to overlay target %s", overlay_path.c_str());
-  }
-
-  const Result<uint32_t> overlay_crc = GetPackageCrc(*overlay_zip);
+  const Result<uint32_t> overlay_crc = overlay.GetCrc();
   if (!overlay_crc) {
     return Error("failed to get overlay crc");
   }
 
-  return IsUpToDate(target_path, overlay_path, overlay_name, *target_crc, *overlay_crc,
+  return IsUpToDate(target.GetPath(), overlay.GetPath(), overlay_name, *target_crc, *overlay_crc,
                     fulfilled_policies, enforce_overlayable);
 }
 
@@ -209,11 +183,7 @@
 
 std::unique_ptr<const IdmapData::Header> IdmapData::Header::FromBinaryStream(std::istream& stream) {
   std::unique_ptr<IdmapData::Header> idmap_data_header(new IdmapData::Header());
-
-  uint8_t padding;
-  if (!Read8(stream, &idmap_data_header->target_package_id_) ||
-      !Read8(stream, &idmap_data_header->overlay_package_id_) || !Read8(stream, &padding) ||
-      !Read8(stream, &padding) || !Read32(stream, &idmap_data_header->target_entry_count) ||
+  if (!Read32(stream, &idmap_data_header->target_entry_count) ||
       !Read32(stream, &idmap_data_header->target_entry_inline_count) ||
       !Read32(stream, &idmap_data_header->overlay_entry_count) ||
       !Read32(stream, &idmap_data_header->string_pool_index_offset)) {
@@ -321,8 +291,6 @@
   }
 
   std::unique_ptr<IdmapData::Header> data_header(new IdmapData::Header());
-  data_header->target_package_id_ = resource_mapping.GetTargetPackageId();
-  data_header->overlay_package_id_ = resource_mapping.GetOverlayPackageId();
   data_header->target_entry_count = static_cast<uint32_t>(data->target_entries_.size());
   data_header->target_entry_inline_count =
       static_cast<uint32_t>(data->target_inline_entries_.size());
@@ -332,57 +300,46 @@
   return {std::move(data)};
 }
 
-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) {
+Result<std::unique_ptr<const Idmap>> Idmap::FromContainers(const TargetResourceContainer& target,
+                                                           const OverlayResourceContainer& overlay,
+                                                           const std::string& overlay_name,
+                                                           const PolicyBitmask& fulfilled_policies,
+                                                           bool enforce_overlayable) {
   SYSTRACE << "Idmap::FromApkAssets";
-  const std::string& target_apk_path = target_apk_assets.GetPath();
-  const std::string& overlay_apk_path = overlay_apk_assets.GetPath();
-
-  const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_apk_path);
-  if (!target_zip) {
-    return Error("failed to open target as zip");
-  }
-
-  const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_apk_path);
-  if (!overlay_zip) {
-    return Error("failed to open overlay as zip");
-  }
-
   std::unique_ptr<IdmapHeader> header(new IdmapHeader());
   header->magic_ = kIdmapMagic;
   header->version_ = kIdmapCurrentVersion;
 
-  Result<uint32_t> crc = GetPackageCrc(*target_zip);
-  if (!crc) {
-    return Error(crc.GetError(), "failed to get zip CRC for target");
+  const auto target_crc = target.GetCrc();
+  if (!target_crc) {
+    return Error(target_crc.GetError(), "failed to get zip CRC for '%s'", target.GetPath().data());
   }
-  header->target_crc_ = *crc;
+  header->target_crc_ = *target_crc;
 
-  crc = GetPackageCrc(*overlay_zip);
-  if (!crc) {
-    return Error(crc.GetError(), "failed to get zip CRC for overlay");
+  const auto overlay_crc = overlay.GetCrc();
+  if (!overlay_crc) {
+    return Error(overlay_crc.GetError(), "failed to get zip CRC for '%s'",
+                 overlay.GetPath().data());
   }
-  header->overlay_crc_ = *crc;
+  header->overlay_crc_ = *overlay_crc;
+
   header->fulfilled_policies_ = fulfilled_policies;
   header->enforce_overlayable_ = enforce_overlayable;
-  header->target_path_ = target_apk_path;
-  header->overlay_path_ = overlay_apk_path;
+  header->target_path_ = target.GetPath();
+  header->overlay_path_ = overlay.GetPath();
   header->overlay_name_ = overlay_name;
 
-  auto info = utils::ExtractOverlayManifestInfo(overlay_apk_path, overlay_name);
+  auto info = overlay.FindOverlayInfo(overlay_name);
   if (!info) {
-    return info.GetError();
+    return Error(info.GetError(), "failed to get overlay info for '%s'", overlay.GetPath().data());
   }
 
   LogInfo log_info;
-  auto resource_mapping =
-      ResourceMapping::FromApkAssets(target_apk_assets, overlay_apk_assets, *info,
-                                     fulfilled_policies, enforce_overlayable, log_info);
+  auto resource_mapping = ResourceMapping::FromContainers(
+      target, overlay, *info, fulfilled_policies, enforce_overlayable, log_info);
   if (!resource_mapping) {
-    return resource_mapping.GetError();
+    return Error(resource_mapping.GetError(), "failed to generate resource map for '%s'",
+                 overlay.GetPath().data());
   }
 
   auto idmap_data = IdmapData::FromResourceMapping(*resource_mapping);
diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
index 7e090a9..721612c 100644
--- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
@@ -27,8 +27,6 @@
 
 namespace android::idmap2 {
 
-#define RESID(pkg, type, entry) (((pkg) << 24) | ((type) << 16) | (entry))
-
 #define TAB "    "
 
 void PrettyPrintVisitor::visit(const Idmap& idmap ATTRIBUTE_UNUSED) {
@@ -36,8 +34,8 @@
 
 void PrettyPrintVisitor::visit(const IdmapHeader& header) {
   stream_ << "Paths:" << std::endl
-          << TAB "target apk path  : " << header.GetTargetPath() << std::endl
-          << TAB "overlay apk path : " << header.GetOverlayPath() << std::endl;
+          << TAB "target path  : " << header.GetTargetPath() << std::endl
+          << TAB "overlay path : " << header.GetOverlayPath() << std::endl;
 
   if (!header.GetOverlayName().empty()) {
     stream_ << "Overlay name: " << header.GetOverlayName() << std::endl;
@@ -53,14 +51,11 @@
     }
   }
 
-  if (auto target_apk_ = ApkAssets::Load(header.GetTargetPath())) {
-    target_am_.SetApkAssets({target_apk_.get()});
-    apk_assets_.push_back(std::move(target_apk_));
+  if (auto target = TargetResourceContainer::FromPath(header.GetTargetPath())) {
+    target_ = std::move(*target);
   }
-
-  if (auto overlay_apk = ApkAssets::Load(header.GetOverlayPath())) {
-    overlay_am_.SetApkAssets({overlay_apk.get()});
-    apk_assets_.push_back(std::move(overlay_apk));
+  if (auto overlay = OverlayResourceContainer::FromPath(header.GetOverlayPath())) {
+    overlay_ = std::move(*overlay);
   }
 
   stream_ << "Mapping:" << std::endl;
@@ -72,23 +67,20 @@
 void PrettyPrintVisitor::visit(const IdmapData& data) {
   static constexpr const char* kUnknownResourceName = "???";
 
-  const bool target_package_loaded = !target_am_.GetApkAssets().empty();
-  const bool overlay_package_loaded = !overlay_am_.GetApkAssets().empty();
-
   const ResStringPool string_pool(data.GetStringPoolData().data(), data.GetStringPoolData().size());
   const size_t string_pool_offset = data.GetHeader()->GetStringPoolIndexOffset();
 
   for (const auto& target_entry : data.GetTargetEntries()) {
     std::string target_name = kUnknownResourceName;
-    if (target_package_loaded) {
-      if (auto name = utils::ResToTypeEntryName(target_am_, target_entry.target_id)) {
+    if (target_ != nullptr) {
+      if (auto name = target_->GetResourceName(target_entry.target_id)) {
         target_name = *name;
       }
     }
 
     std::string overlay_name = kUnknownResourceName;
-    if (overlay_package_loaded) {
-      if (auto name = utils::ResToTypeEntryName(overlay_am_, target_entry.overlay_id)) {
+    if (overlay_ != nullptr) {
+      if (auto name = overlay_->GetResourceName(target_entry.overlay_id)) {
         overlay_name = *name;
       }
     }
@@ -112,8 +104,8 @@
     }
 
     std::string target_name = kUnknownResourceName;
-    if (target_package_loaded) {
-      if (auto name = utils::ResToTypeEntryName(target_am_, target_entry.target_id)) {
+    if (target_ != nullptr) {
+      if (auto name = target_->GetResourceName(target_entry.target_id)) {
         target_name = *name;
       }
     }
diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
index b517aa3..a016a36 100644
--- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
@@ -18,16 +18,13 @@
 
 #include <algorithm>
 #include <cstdarg>
-#include <string>
 
 #include "android-base/macros.h"
 #include "android-base/stringprintf.h"
-#include "androidfw/ApkAssets.h"
 #include "idmap2/PolicyUtils.h"
 #include "idmap2/ResourceUtils.h"
 #include "idmap2/Result.h"
 
-using android::ApkAssets;
 using android::idmap2::policy::PoliciesToDebugString;
 
 namespace android::idmap2 {
@@ -48,27 +45,19 @@
   print(header.GetOverlayName(), true /* print_value */, "overlay name");
   print(header.GetDebugInfo(), false /* print_value */, "debug info");
 
-  auto target_apk_ = ApkAssets::Load(header.GetTargetPath());
-  if (target_apk_) {
-    target_am_.SetApkAssets({target_apk_.get()});
-    apk_assets_.push_back(std::move(target_apk_));
+  if (auto target = TargetResourceContainer::FromPath(header.GetTargetPath())) {
+    target_ = std::move(*target);
   }
-
-  auto overlay_apk_ = ApkAssets::Load(header.GetOverlayPath());
-  if (overlay_apk_) {
-    overlay_am_.SetApkAssets({overlay_apk_.get()});
-    apk_assets_.push_back(std::move(overlay_apk_));
+  if (auto overlay = OverlayResourceContainer::FromPath(header.GetOverlayPath())) {
+    overlay_ = std::move(*overlay);
   }
 }
 
 void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
-  const bool target_package_loaded = !target_am_.GetApkAssets().empty();
-  const bool overlay_package_loaded = !overlay_am_.GetApkAssets().empty();
-
   for (auto& target_entry : data.GetTargetEntries()) {
     Result<std::string> target_name(Error(""));
-    if (target_package_loaded) {
-      target_name = utils::ResToTypeEntryName(target_am_, target_entry.target_id);
+    if (target_ != nullptr) {
+      target_name = target_->GetResourceName(target_entry.target_id);
     }
     if (target_name) {
       print(target_entry.target_id, "target id: %s", target_name->c_str());
@@ -77,8 +66,8 @@
     }
 
     Result<std::string> overlay_name(Error(""));
-    if (overlay_package_loaded) {
-      overlay_name = utils::ResToTypeEntryName(overlay_am_, target_entry.overlay_id);
+    if (overlay_ != nullptr) {
+      overlay_name = overlay_->GetResourceName(target_entry.overlay_id);
     }
     if (overlay_name) {
       print(target_entry.overlay_id, "overlay id: %s", overlay_name->c_str());
@@ -89,8 +78,8 @@
 
   for (auto& target_entry : data.GetTargetInlineEntries()) {
     Result<std::string> target_name(Error(""));
-    if (target_package_loaded) {
-      target_name = utils::ResToTypeEntryName(target_am_, target_entry.target_id);
+    if (target_ != nullptr) {
+      target_name = target_->GetResourceName(target_entry.target_id);
     }
     if (target_name) {
       print(target_entry.target_id, "target id: %s", target_name->c_str());
@@ -104,10 +93,10 @@
           utils::DataTypeToString(target_entry.value.data_type).data());
 
     Result<std::string> overlay_name(Error(""));
-    if (overlay_package_loaded &&
+    if (overlay_ != nullptr &&
         (target_entry.value.data_value == Res_value::TYPE_REFERENCE ||
          target_entry.value.data_value == Res_value::TYPE_DYNAMIC_REFERENCE)) {
-      overlay_name = utils::ResToTypeEntryName(overlay_am_, target_entry.value.data_value);
+      overlay_name = overlay_->GetResourceName(target_entry.value.data_value);
     }
 
     if (overlay_name) {
@@ -119,8 +108,8 @@
 
   for (auto& overlay_entry : data.GetOverlayEntries()) {
     Result<std::string> overlay_name(Error(""));
-    if (overlay_package_loaded) {
-      overlay_name = utils::ResToTypeEntryName(overlay_am_, overlay_entry.overlay_id);
+    if (overlay_ != nullptr) {
+      overlay_name = overlay_->GetResourceName(overlay_entry.overlay_id);
     }
 
     if (overlay_name) {
@@ -130,8 +119,8 @@
     }
 
     Result<std::string> target_name(Error(""));
-    if (target_package_loaded) {
-      target_name = utils::ResToTypeEntryName(target_am_, overlay_entry.target_id);
+    if (target_ != nullptr) {
+      target_name = target_->GetResourceName(overlay_entry.target_id);
     }
 
     if (target_name) {
@@ -145,9 +134,6 @@
 }
 
 void RawPrintVisitor::visit(const IdmapData::Header& header) {
-  print(header.GetTargetPackageId(), "target package id");
-  print(header.GetOverlayPackageId(), "overlay package id");
-  align();
   print(header.GetTargetEntryCount(), "target entry count");
   print(header.GetTargetInlineEntryCount(), "target inline entry count");
   print(header.GetOverlayEntryCount(), "overlay entry count");
diff --git a/cmds/idmap2/libidmap2/ResourceContainer.cpp b/cmds/idmap2/libidmap2/ResourceContainer.cpp
new file mode 100644
index 0000000..91cb43c
--- /dev/null
+++ b/cmds/idmap2/libidmap2/ResourceContainer.cpp
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "idmap2/ResourceContainer.h"
+
+#include "androidfw/ApkAssets.h"
+#include "androidfw/AssetManager.h"
+#include "androidfw/Util.h"
+#include "idmap2/FabricatedOverlay.h"
+#include "idmap2/XmlParser.h"
+
+namespace android::idmap2 {
+namespace {
+#define REWRITE_PACKAGE(resid, package_id) \
+  (((resid)&0x00ffffffU) | (((uint32_t)(package_id)) << 24U))
+
+#define EXTRACT_PACKAGE(resid) ((0xff000000 & (resid)) >> 24)
+
+constexpr ResourceId kAttrName = 0x01010003;
+constexpr ResourceId kAttrResourcesMap = 0x01010609;
+constexpr ResourceId kAttrTargetName = 0x0101044d;
+constexpr ResourceId kAttrTargetPackage = 0x01010021;
+
+// idmap version 0x01 naively assumes that the package to use is always the first ResTable_package
+// in the resources.arsc blob. In most cases, there is only a single ResTable_package anyway, so
+// this assumption tends to work out. That said, the correct thing to do is to scan
+// resources.arsc for a package with a given name as read from the package manifest instead of
+// relying on a hard-coded index. This however requires storing the package name in the idmap
+// header, which in turn requires incrementing the idmap version. Because the initial version of
+// idmap2 is compatible with idmap, this will have to wait for now.
+const LoadedPackage* GetPackageAtIndex0(const LoadedArsc* loaded_arsc) {
+  const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+  if (packages.empty()) {
+    return nullptr;
+  }
+  return loaded_arsc->GetPackageById(packages[0]->GetPackageId());
+}
+
+Result<uint32_t> CalculateCrc(const ZipAssetsProvider* zip_assets) {
+  constexpr const char* kResourcesArsc = "resources.arsc";
+  std::optional<uint32_t> res_crc = zip_assets->GetCrc(kResourcesArsc);
+  if (!res_crc) {
+    return Error("failed to get CRC for '%s'", kResourcesArsc);
+  }
+
+  constexpr const char* kManifest = "AndroidManifest.xml";
+  std::optional<uint32_t> man_crc = zip_assets->GetCrc(kManifest);
+  if (!man_crc) {
+    return Error("failed to get CRC for '%s'", kManifest);
+  }
+
+  return *res_crc ^ *man_crc;
+}
+
+Result<XmlParser> OpenXmlParser(const std::string& entry_path, const ZipAssetsProvider* zip) {
+  auto manifest = zip->Open(entry_path);
+  if (manifest == nullptr) {
+    return Error("failed to find %s ", entry_path.c_str());
+  }
+
+  auto size = manifest->getLength();
+  auto buffer = manifest->getIncFsBuffer(true /* aligned */).convert<uint8_t>();
+  if (!buffer.verify(size)) {
+    return Error("failed to read entire %s", entry_path.c_str());
+  }
+
+  return XmlParser::Create(buffer.unsafe_ptr(), size, true /* copyData */);
+}
+
+Result<XmlParser> OpenXmlParser(ResourceId id, const ZipAssetsProvider* zip,
+                                const AssetManager2* am) {
+  const auto ref_table = am->GetDynamicRefTableForCookie(0);
+  if (ref_table == nullptr) {
+    return Error("failed to find dynamic ref table for cookie 0");
+  }
+
+  ref_table->lookupResourceId(&id);
+  auto value = am->GetResource(id);
+  if (!value.has_value()) {
+    return Error("failed to find resource for id 0x%08x", id);
+  }
+
+  if (value->type != Res_value::TYPE_STRING) {
+    return Error("resource for is 0x%08x is not a file", id);
+  }
+
+  auto string_pool = am->GetStringPoolForCookie(value->cookie);
+  auto file = string_pool->string8ObjectAt(value->data);
+  if (!file.has_value()) {
+    return Error("failed to find string for index %d", value->data);
+  }
+
+  return OpenXmlParser(file->c_str(), zip);
+}
+
+Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const ZipAssetsProvider* zip,
+                                                       const std::string& name) {
+  Result<XmlParser> xml = OpenXmlParser("AndroidManifest.xml", zip);
+  if (!xml) {
+    return xml.GetError();
+  }
+
+  auto manifest_it = xml->tree_iterator();
+  if (manifest_it->event() != XmlParser::Event::START_TAG || manifest_it->name() != "manifest") {
+    return Error("root element tag is not <manifest> in AndroidManifest.xml");
+  }
+
+  for (auto&& it : manifest_it) {
+    if (it.event() != XmlParser::Event::START_TAG || it.name() != "overlay") {
+      continue;
+    }
+
+    OverlayManifestInfo info{};
+    if (auto result_str = it.GetAttributeStringValue(kAttrName, "android:name")) {
+      if (*result_str != name) {
+        // A value for android:name was found, but either 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 = it.GetAttributeStringValue(kAttrTargetPackage, "android:targetPackage")) {
+      info.target_package = *result_str;
+    } else {
+      return Error("android:targetPackage missing from <overlay> in AndroidManifest.xml");
+    }
+
+    if (auto result_str = it.GetAttributeStringValue(kAttrTargetName, "android:targetName")) {
+      info.target_name = *result_str;
+    }
+
+    if (auto result_value = it.GetAttributeValue(kAttrResourcesMap, "android:resourcesMap")) {
+      if (utils::IsReference((*result_value).dataType)) {
+        info.resource_mapping = (*result_value).data;
+      } else {
+        return Error("android:resourcesMap is not a reference in AndroidManifest.xml");
+      }
+    }
+    return info;
+  }
+
+  return Error("<overlay> with android:name \"%s\" missing from AndroidManifest.xml", name.c_str());
+}
+
+Result<OverlayData> CreateResourceMapping(ResourceId id, const ZipAssetsProvider* zip,
+                                          const AssetManager2* overlay_am,
+                                          const LoadedArsc* overlay_arsc,
+                                          const LoadedPackage* overlay_package) {
+  auto parser = OpenXmlParser(id, zip, overlay_am);
+  if (!parser) {
+    return parser.GetError();
+  }
+
+  OverlayData overlay_data{};
+  const uint32_t string_pool_offset = overlay_arsc->GetStringPool()->size();
+  const uint8_t package_id = overlay_package->GetPackageId();
+  auto root_it = parser->tree_iterator();
+  if (root_it->event() != XmlParser::Event::START_TAG || root_it->name() != "overlay") {
+    return Error("root element is not <overlay> tag");
+  }
+
+  auto overlay_it_end = root_it.end();
+  for (auto overlay_it = root_it.begin(); overlay_it != overlay_it_end; ++overlay_it) {
+    if (overlay_it->event() == XmlParser::Event::BAD_DOCUMENT) {
+      return Error("failed to parse overlay xml document");
+    }
+
+    if (overlay_it->event() != XmlParser::Event::START_TAG) {
+      continue;
+    }
+
+    if (overlay_it->name() != "item") {
+      return Error("unexpected tag <%s> in <overlay>", overlay_it->name().c_str());
+    }
+
+    Result<std::string> target_resource = overlay_it->GetAttributeStringValue("target");
+    if (!target_resource) {
+      return Error(R"(<item> tag missing expected attribute "target")");
+    }
+
+    Result<android::Res_value> overlay_resource = overlay_it->GetAttributeValue("value");
+    if (!overlay_resource) {
+      return Error(R"(<item> tag missing expected attribute "value")");
+    }
+
+    if (overlay_resource->dataType == Res_value::TYPE_STRING) {
+      overlay_resource->data += string_pool_offset;
+    }
+
+    if (utils::IsReference(overlay_resource->dataType)) {
+      // Only rewrite resources defined within the overlay package to their corresponding target
+      // resource ids at runtime.
+      bool rewrite_id = package_id == EXTRACT_PACKAGE(overlay_resource->data);
+      overlay_data.pairs.emplace_back(OverlayData::Value{
+          *target_resource, OverlayData::ResourceIdValue{overlay_resource->data, rewrite_id}});
+    } else {
+      overlay_data.pairs.emplace_back(
+          OverlayData::Value{*target_resource, TargetValue{.data_type = overlay_resource->dataType,
+                                                           .data_value = overlay_resource->data}});
+    }
+  }
+
+  const auto& string_pool = parser->get_strings();
+  const uint32_t string_pool_data_length = string_pool.bytes();
+  overlay_data.string_pool_data = OverlayData::InlineStringPoolData{
+      .data = std::unique_ptr<uint8_t[]>(new uint8_t[string_pool_data_length]),
+      .data_length = string_pool_data_length,
+      .string_pool_offset = string_pool_offset,
+  };
+
+  // Overlays should not be incrementally installed, so calling unsafe_ptr is fine here.
+  memcpy(overlay_data.string_pool_data->data.get(), string_pool.data().unsafe_ptr(),
+         string_pool_data_length);
+  return overlay_data;
+}
+
+OverlayData CreateResourceMappingLegacy(const AssetManager2* overlay_am,
+                                        const LoadedPackage* overlay_package) {
+  OverlayData overlay_data{};
+  for (const ResourceId overlay_resid : *overlay_package) {
+    if (auto name = utils::ResToTypeEntryName(*overlay_am, overlay_resid)) {
+      // Disable rewriting. Overlays did not support internal references before
+      // android:resourcesMap. Do not introduce new behavior.
+      overlay_data.pairs.emplace_back(OverlayData::Value{
+          *name, OverlayData::ResourceIdValue{overlay_resid, false /* rewrite_id */}});
+    }
+  }
+  return overlay_data;
+}
+
+struct ResState {
+  std::unique_ptr<ApkAssets> apk_assets;
+  const LoadedArsc* arsc;
+  const LoadedPackage* package;
+  std::unique_ptr<AssetManager2> am;
+  ZipAssetsProvider* zip_assets;
+
+  static Result<ResState> Initialize(std::unique_ptr<ZipAssetsProvider> zip) {
+    ResState state;
+    state.zip_assets = zip.get();
+    if ((state.apk_assets = ApkAssets::Load(std::move(zip))) == nullptr) {
+      return Error("failed to load apk asset");
+    }
+
+    if ((state.arsc = state.apk_assets->GetLoadedArsc()) == nullptr) {
+      return Error("failed to retrieve loaded arsc");
+    }
+
+    if ((state.package = GetPackageAtIndex0(state.arsc)) == nullptr) {
+      return Error("failed to retrieve loaded package at index 0");
+    }
+
+    state.am = std::make_unique<AssetManager2>();
+    if (!state.am->SetApkAssets({state.apk_assets.get()})) {
+      return Error("failed to create asset manager");
+    }
+
+    return state;
+  }
+};
+
+}  // namespace
+
+struct ApkResourceContainer : public TargetResourceContainer, public OverlayResourceContainer {
+  static Result<std::unique_ptr<ApkResourceContainer>> FromPath(const std::string& path);
+
+  // inherited from TargetResourceContainer
+  Result<bool> DefinesOverlayable() const override;
+  Result<const android::OverlayableInfo*> GetOverlayableInfo(ResourceId id) const override;
+  Result<ResourceId> GetResourceId(const std::string& name) const override;
+
+  // inherited from OverlayResourceContainer
+  Result<OverlayData> GetOverlayData(const OverlayManifestInfo& info) const override;
+  Result<OverlayManifestInfo> FindOverlayInfo(const std::string& name) const override;
+
+  // inherited from ResourceContainer
+  Result<uint32_t> GetCrc() const override;
+  Result<std::string> GetResourceName(ResourceId id) const override;
+  const std::string& GetPath() const override;
+
+  ~ApkResourceContainer() override = default;
+
+ private:
+  ApkResourceContainer(std::unique_ptr<ZipAssetsProvider> zip_assets, std::string path);
+
+  Result<const ResState*> GetState() const;
+  ZipAssetsProvider* GetZipAssets() const;
+
+  mutable std::variant<std::unique_ptr<ZipAssetsProvider>, ResState> state_;
+  std::string path_;
+};
+
+ApkResourceContainer::ApkResourceContainer(std::unique_ptr<ZipAssetsProvider> zip_assets,
+                                           std::string path)
+    : state_(std::move(zip_assets)), path_(std::move(path)) {
+}
+
+Result<std::unique_ptr<ApkResourceContainer>> ApkResourceContainer::FromPath(
+    const std::string& path) {
+  auto zip_assets = ZipAssetsProvider::Create(path);
+  if (zip_assets == nullptr) {
+    return Error("failed to load zip assets");
+  }
+  return std::unique_ptr<ApkResourceContainer>(
+      new ApkResourceContainer(std::move(zip_assets), path));
+}
+
+Result<const ResState*> ApkResourceContainer::GetState() const {
+  if (auto state = std::get_if<ResState>(&state_); state != nullptr) {
+    return state;
+  }
+
+  auto state =
+      ResState::Initialize(std::move(std::get<std::unique_ptr<ZipAssetsProvider>>(state_)));
+  if (!state) {
+    return state.GetError();
+  }
+
+  state_ = std::move(*state);
+  return &std::get<ResState>(state_);
+}
+
+ZipAssetsProvider* ApkResourceContainer::GetZipAssets() const {
+  if (auto zip = std::get_if<std::unique_ptr<ZipAssetsProvider>>(&state_); zip != nullptr) {
+    return zip->get();
+  }
+  return std::get<ResState>(state_).zip_assets;
+}
+
+Result<bool> ApkResourceContainer::DefinesOverlayable() const {
+  auto state = GetState();
+  if (!state) {
+    return state.GetError();
+  }
+  return (*state)->package->DefinesOverlayable();
+}
+
+Result<const android::OverlayableInfo*> ApkResourceContainer::GetOverlayableInfo(
+    ResourceId id) const {
+  auto state = GetState();
+  if (!state) {
+    return state.GetError();
+  }
+  return (*state)->package->GetOverlayableInfo(id);
+}
+
+Result<OverlayManifestInfo> ApkResourceContainer::FindOverlayInfo(const std::string& name) const {
+  return ExtractOverlayManifestInfo(GetZipAssets(), name);
+}
+
+Result<OverlayData> ApkResourceContainer::GetOverlayData(const OverlayManifestInfo& info) const {
+  const auto state = GetState();
+  if (!state) {
+    return state.GetError();
+  }
+
+  if (info.resource_mapping != 0) {
+    return CreateResourceMapping(info.resource_mapping, GetZipAssets(), (*state)->am.get(),
+                                 (*state)->arsc, (*state)->package);
+  }
+  return CreateResourceMappingLegacy((*state)->am.get(), (*state)->package);
+}
+
+Result<uint32_t> ApkResourceContainer::GetCrc() const {
+  return CalculateCrc(GetZipAssets());
+}
+
+const std::string& ApkResourceContainer::GetPath() const {
+  return path_;
+}
+
+Result<ResourceId> ApkResourceContainer::GetResourceId(const std::string& name) const {
+  auto state = GetState();
+  if (!state) {
+    return state.GetError();
+  }
+  auto id = (*state)->am->GetResourceId(name, "", (*state)->package->GetPackageName());
+  if (!id.has_value()) {
+    return Error("failed to find resource '%s'", name.c_str());
+  }
+
+  // Retrieve the compile-time resource id of the target resource.
+  return REWRITE_PACKAGE(*id, (*state)->package->GetPackageId());
+}
+
+Result<std::string> ApkResourceContainer::GetResourceName(ResourceId id) const {
+  auto state = GetState();
+  if (!state) {
+    return state.GetError();
+  }
+  return utils::ResToTypeEntryName(*(*state)->am, id);
+}
+
+Result<std::unique_ptr<TargetResourceContainer>> TargetResourceContainer::FromPath(
+    std::string path) {
+  auto result = ApkResourceContainer::FromPath(path);
+  if (!result) {
+    return result.GetError();
+  }
+  return std::unique_ptr<TargetResourceContainer>(result->release());
+}
+
+Result<std::unique_ptr<OverlayResourceContainer>> OverlayResourceContainer::FromPath(
+    std::string path) {
+  // Load the path as a fabricated overlay if the file magic indicates this is a fabricated overlay.
+  if (android::IsFabricatedOverlay(path)) {
+    auto result = FabricatedOverlayContainer::FromPath(path);
+    if (!result) {
+      return result.GetError();
+    }
+    return std::unique_ptr<OverlayResourceContainer>(result->release());
+  }
+
+  // Fallback to loading the container as an APK.
+  auto result = ApkResourceContainer::FromPath(path);
+  if (!result) {
+    return result.GetError();
+  }
+  return std::unique_ptr<OverlayResourceContainer>(result->release());
+}
+
+}  // namespace android::idmap2
\ No newline at end of file
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 46eeb8e..3bbbf24 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -30,19 +30,12 @@
 
 using android::base::StringPrintf;
 using android::idmap2::utils::BitmaskToPolicies;
-using android::idmap2::utils::IsReference;
-using android::idmap2::utils::ResToTypeEntryName;
 using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
 
 namespace android::idmap2 {
 
 namespace {
-
-#define REWRITE_PACKAGE(resid, package_id) \
-  (((resid)&0x00ffffffU) | (((uint32_t)(package_id)) << 24U))
-#define EXTRACT_PACKAGE(resid) ((0xff000000 & (resid)) >> 24)
-
 std::string ConcatPolicies(const std::vector<std::string>& policies) {
   std::string message;
   for (const std::string& policy : policies) {
@@ -55,11 +48,11 @@
   return message;
 }
 
-Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
+Result<Unit> CheckOverlayable(const TargetResourceContainer& target,
                               const OverlayManifestInfo& overlay_info,
                               const PolicyBitmask& fulfilled_policies,
                               const ResourceId& target_resource) {
-  static constexpr const PolicyBitmask sDefaultPolicies =
+  constexpr const PolicyBitmask kDefaultPolicies =
       PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION |
       PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE |
       PolicyFlags::CONFIG_SIGNATURE;
@@ -68,8 +61,13 @@
   // the overlay is preinstalled, signed with the same signature as the target or signed with the
   // same signature as reference package defined in SystemConfig under 'overlay-config-signature'
   // tag.
-  if (!target_package.DefinesOverlayable()) {
-    return (sDefaultPolicies & fulfilled_policies) != 0
+  const Result<bool> defines_overlayable = target.DefinesOverlayable();
+  if (!defines_overlayable) {
+    return Error(defines_overlayable.GetError(), "unable to retrieve overlayable info");
+  }
+
+  if (!*defines_overlayable) {
+    return (kDefaultPolicies & fulfilled_policies) != 0
                ? Result<Unit>({})
                : Error(
                      "overlay must be preinstalled, signed with the same signature as the target,"
@@ -77,367 +75,112 @@
                      " <overlay-config-signature>.");
   }
 
-  const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(target_resource);
-  if (overlayable_info == nullptr) {
+  const auto overlayable_info = target.GetOverlayableInfo(target_resource);
+  if (!overlayable_info) {
+    return overlayable_info.GetError();
+  }
+
+  if (*overlayable_info == nullptr) {
     // Do not allow non-overlayable resources to be overlaid.
     return Error("target resource has no overlayable declaration");
   }
 
-  if (overlay_info.target_name != overlayable_info->name) {
+  if (overlay_info.target_name != (*overlayable_info)->name) {
     // If the overlay supplies a target overlayable name, the resource must belong to the
     // overlayable defined with the specified name to be overlaid.
     return Error(R"(<overlay> android:targetName "%s" does not match overlayable name "%s")",
-                 overlay_info.target_name.c_str(), overlayable_info->name.c_str());
+                 overlay_info.target_name.c_str(), (*overlayable_info)->name.c_str());
   }
 
   // Enforce policy restrictions if the resource is declared as overlayable.
-  if ((overlayable_info->policy_flags & fulfilled_policies) == 0) {
+  if (((*overlayable_info)->policy_flags & fulfilled_policies) == 0) {
     return Error(R"(overlay with policies "%s" does not fulfill any overlayable policies "%s")",
                  ConcatPolicies(BitmaskToPolicies(fulfilled_policies)).c_str(),
-                 ConcatPolicies(BitmaskToPolicies(overlayable_info->policy_flags)).c_str());
+                 ConcatPolicies(BitmaskToPolicies((*overlayable_info)->policy_flags)).c_str());
   }
 
   return Result<Unit>({});
 }
 
-// TODO(martenkongstad): scan for package name instead of assuming package at index 0
-//
-// idmap version 0x01 naively assumes that the package to use is always the first ResTable_package
-// in the resources.arsc blob. In most cases, there is only a single ResTable_package anyway, so
-// this assumption tends to work out. That said, the correct thing to do is to scan
-// resources.arsc for a package with a given name as read from the package manifest instead of
-// relying on a hard-coded index. This however requires storing the package name in the idmap
-// header, which in turn requires incrementing the idmap version. Because the initial version of
-// idmap2 is compatible with idmap, this will have to wait for now.
-const LoadedPackage* GetPackageAtIndex0(const LoadedArsc& loaded_arsc) {
-  const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc.GetPackages();
-  if (packages.empty()) {
-    return nullptr;
+std::string GetDebugResourceName(const ResourceContainer& container, ResourceId resid) {
+  auto name = container.GetResourceName(resid);
+  if (name) {
+    return *name;
   }
-  int id = packages[0]->GetPackageId();
-  return loaded_arsc.GetPackageById(id);
+  return StringPrintf("0x%08x", resid);
 }
-
-Result<std::unique_ptr<Asset>> OpenNonAssetFromResource(const ResourceId& resource_id,
-                                                        const AssetManager2& asset_manager) {
-  auto value = asset_manager.GetResource(resource_id);
-  if (!value.has_value()) {
-    return Error("failed to find resource for id 0x%08x", resource_id);
-  }
-
-  if (value->type != Res_value::TYPE_STRING) {
-    return Error("resource for is 0x%08x is not a file", resource_id);
-  }
-
-  auto string_pool = asset_manager.GetStringPoolForCookie(value->cookie);
-  auto file = string_pool->string8ObjectAt(value->data);
-  if (!file.has_value()) {
-    return Error("failed to find string for index %d", value->data);
-  }
-
-  // Load the overlay resource mappings from the file specified using android:resourcesMap.
-  auto asset = asset_manager.OpenNonAsset(file->c_str(), Asset::AccessMode::ACCESS_BUFFER);
-  if (asset == nullptr) {
-    return Error("file \"%s\" not found", file->c_str());
-  }
-
-  return asset;
-}
-
 }  // namespace
 
-Result<ResourceMapping> ResourceMapping::CreateResourceMapping(const AssetManager2* target_am,
-                                                               const LoadedPackage* target_package,
-                                                               const LoadedPackage* overlay_package,
-                                                               size_t string_pool_offset,
-                                                               const XmlParser& overlay_parser,
-                                                               LogInfo& log_info) {
-  ResourceMapping resource_mapping;
-  auto root_it = overlay_parser.tree_iterator();
-  if (root_it->event() != XmlParser::Event::START_TAG || root_it->name() != "overlay") {
-    return Error("root element is not <overlay> tag");
+Result<ResourceMapping> ResourceMapping::FromContainers(const TargetResourceContainer& target,
+                                                        const OverlayResourceContainer& overlay,
+                                                        const OverlayManifestInfo& overlay_info,
+                                                        const PolicyBitmask& fulfilled_policies,
+                                                        bool enforce_overlayable,
+                                                        LogInfo& log_info) {
+  auto overlay_data = overlay.GetOverlayData(overlay_info);
+  if (!overlay_data) {
+    return overlay_data.GetError();
   }
 
-  const uint8_t target_package_id = target_package->GetPackageId();
-  const uint8_t overlay_package_id = overlay_package->GetPackageId();
-  auto overlay_it_end = root_it.end();
-  for (auto overlay_it = root_it.begin(); overlay_it != overlay_it_end; ++overlay_it) {
-    if (overlay_it->event() == XmlParser::Event::BAD_DOCUMENT) {
-      return Error("failed to parse overlay xml document");
-    }
-
-    if (overlay_it->event() != XmlParser::Event::START_TAG) {
+  ResourceMapping mapping;
+  for (const auto& overlay_pair : overlay_data->pairs) {
+    const auto target_resid = target.GetResourceId(overlay_pair.resource_name);
+    if (!target_resid) {
+      log_info.Warning(LogMessage() << target_resid.GetErrorMessage());
       continue;
     }
 
-    if (overlay_it->name() != "item") {
-      return Error("unexpected tag <%s> in <overlay>", overlay_it->name().c_str());
+    if (enforce_overlayable) {
+      // Filter out resources the overlay is not allowed to override.
+      auto overlayable = CheckOverlayable(target, overlay_info, fulfilled_policies, *target_resid);
+      if (!overlayable) {
+        log_info.Warning(LogMessage() << "overlay '" << overlay.GetPath()
+                                      << "' is not allowed to overlay resource '"
+                                      << GetDebugResourceName(target, *target_resid)
+                                      << "' in target: " << overlayable.GetErrorMessage());
+        continue;
+      }
     }
 
-    Result<std::string> target_resource = overlay_it->GetAttributeStringValue("target");
-    if (!target_resource) {
-      return Error(R"(<item> tag missing expected attribute "target")");
-    }
-
-    Result<android::Res_value> overlay_resource = overlay_it->GetAttributeValue("value");
-    if (!overlay_resource) {
-      return Error(R"(<item> tag missing expected attribute "value")");
-    }
-
-    auto target_id_result =
-        target_am->GetResourceId(*target_resource, "", target_package->GetPackageName());
-    if (!target_id_result.has_value()) {
-      log_info.Warning(LogMessage() << "failed to find resource \"" << *target_resource
-                                    << "\" in target resources");
-      continue;
-    }
-
-    // Retrieve the compile-time resource id of the target resource.
-    uint32_t target_id = REWRITE_PACKAGE(*target_id_result, target_package_id);
-
-    if (overlay_resource->dataType == Res_value::TYPE_STRING) {
-      overlay_resource->data += string_pool_offset;
-    }
-
-    if (IsReference(overlay_resource->dataType)) {
-      // Only rewrite resources defined within the overlay package to their corresponding target
-      // resource ids at runtime.
-      bool rewrite_reference = overlay_package_id == EXTRACT_PACKAGE(overlay_resource->data);
-      resource_mapping.AddMapping(target_id, overlay_resource->data, rewrite_reference);
-    } else {
-      resource_mapping.AddMapping(target_id, overlay_resource->dataType, overlay_resource->data);
+    if (auto result = mapping.AddMapping(*target_resid, overlay_pair.value); !result) {
+      return Error(result.GetError(), "failed to add mapping for '%s'",
+                   GetDebugResourceName(target, *target_resid).c_str());
     }
   }
 
-  return resource_mapping;
+  auto& string_pool_data = overlay_data->string_pool_data;
+  if (string_pool_data.has_value()) {
+    mapping.string_pool_offset_ = string_pool_data->string_pool_offset;
+    mapping.string_pool_data_ = std::move(string_pool_data->data);
+    mapping.string_pool_data_length_ = string_pool_data->data_length;
+  }
+
+  return std::move(mapping);
 }
 
-Result<ResourceMapping> ResourceMapping::CreateResourceMappingLegacy(
-    const AssetManager2* target_am, const AssetManager2* overlay_am,
-    const LoadedPackage* target_package, const LoadedPackage* overlay_package, LogInfo& log_info) {
-  ResourceMapping resource_mapping;
-  const uint8_t target_package_id = target_package->GetPackageId();
-  const auto end = overlay_package->end();
-  for (auto iter = overlay_package->begin(); iter != end; ++iter) {
-    const ResourceId overlay_resid = *iter;
-    Result<std::string> name = utils::ResToTypeEntryName(*overlay_am, overlay_resid);
-    if (!name) {
-      continue;
+Result<Unit> ResourceMapping::AddMapping(
+    ResourceId target_resource,
+    const std::variant<OverlayData::ResourceIdValue, TargetValue>& value) {
+  if (target_map_.find(target_resource) != target_map_.end()) {
+    return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
+  }
+
+  // TODO(141485591): Ensure that the overlay type is compatible with the target type. If the
+  // runtime types are not compatible, it could cause runtime crashes when the resource is resolved.
+
+  if (auto overlay_resource = std::get_if<OverlayData::ResourceIdValue>(&value)) {
+    target_map_.insert(std::make_pair(target_resource, overlay_resource->overlay_id));
+    if (overlay_resource->rewrite_id) {
+      // An overlay resource can override multiple target resources at once. Rewrite the overlay
+      // resource as the first target resource it overrides.
+      overlay_map_.insert(std::make_pair(overlay_resource->overlay_id, target_resource));
     }
-
-    // Find the resource with the same type and entry name within the target package.
-    const std::string full_name =
-        base::StringPrintf("%s:%s", target_package->GetPackageName().c_str(), name->c_str());
-    auto target_resource_result = target_am->GetResourceId(full_name);
-    if (!target_resource_result.has_value()) {
-      log_info.Warning(LogMessage()
-                       << "failed to find resource \"" << full_name << "\" in target resources");
-      continue;
-    }
-
-    // Retrieve the compile-time resource id of the target resource.
-    ResourceId target_resource = REWRITE_PACKAGE(*target_resource_result, target_package_id);
-    resource_mapping.AddMapping(target_resource, overlay_resid,
-                                false /* rewrite_overlay_reference */);
-  }
-
-  return resource_mapping;
-}
-
-void ResourceMapping::FilterOverlayableResources(const AssetManager2* target_am,
-                                                 const LoadedPackage* target_package,
-                                                 const LoadedPackage* overlay_package,
-                                                 const OverlayManifestInfo& overlay_info,
-                                                 const PolicyBitmask& fulfilled_policies,
-                                                 LogInfo& log_info) {
-  std::set<ResourceId> remove_ids;
-  for (const auto& target_map : target_map_) {
-    const ResourceId target_resid = target_map.first;
-    Result<Unit> success =
-        CheckOverlayable(*target_package, overlay_info, fulfilled_policies, target_resid);
-    if (success) {
-      continue;
-    }
-
-    // Attempting to overlay a resource that is not allowed to be overlaid is treated as a
-    // warning.
-    Result<std::string> name = utils::ResToTypeEntryName(*target_am, target_resid);
-    if (!name) {
-      name = StringPrintf("0x%08x", target_resid);
-    }
-
-    log_info.Warning(LogMessage() << "overlay \"" << overlay_package->GetPackageName()
-                                  << "\" is not allowed to overlay resource \"" << *name
-                                  << "\" in target: " << success.GetErrorMessage());
-
-    remove_ids.insert(target_resid);
-  }
-
-  for (const ResourceId target_resid : remove_ids) {
-    RemoveMapping(target_resid);
-  }
-}
-
-Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_apk_assets,
-                                                       const ApkAssets& overlay_apk_assets,
-                                                       const OverlayManifestInfo& overlay_info,
-                                                       const PolicyBitmask& fulfilled_policies,
-                                                       bool enforce_overlayable,
-                                                       LogInfo& log_info) {
-  AssetManager2 target_asset_manager;
-  if (!target_asset_manager.SetApkAssets({&target_apk_assets})) {
-    return Error("failed to create target asset manager");
-  }
-
-  AssetManager2 overlay_asset_manager;
-  if (!overlay_asset_manager.SetApkAssets({&overlay_apk_assets})) {
-    return Error("failed to create overlay asset manager");
-  }
-
-  const LoadedArsc* target_arsc = target_apk_assets.GetLoadedArsc();
-  if (target_arsc == nullptr) {
-    return Error("failed to load target resources.arsc");
-  }
-
-  const LoadedArsc* overlay_arsc = overlay_apk_assets.GetLoadedArsc();
-  if (overlay_arsc == nullptr) {
-    return Error("failed to load overlay resources.arsc");
-  }
-
-  const LoadedPackage* target_pkg = GetPackageAtIndex0(*target_arsc);
-  if (target_pkg == nullptr) {
-    return Error("failed to load target package from resources.arsc");
-  }
-
-  const LoadedPackage* overlay_pkg = GetPackageAtIndex0(*overlay_arsc);
-  if (overlay_pkg == nullptr) {
-    return Error("failed to load overlay package from resources.arsc");
-  }
-
-  size_t string_pool_data_length = 0U;
-  size_t string_pool_offset = 0U;
-  std::unique_ptr<uint8_t[]> string_pool_data;
-  Result<ResourceMapping> resource_mapping = {{}};
-  if (overlay_info.resource_mapping != 0U) {
-    // Use the dynamic reference table to find the assigned resource id of the map xml.
-    const auto& ref_table = overlay_asset_manager.GetDynamicRefTableForCookie(0);
-    uint32_t resource_mapping_id = overlay_info.resource_mapping;
-    ref_table->lookupResourceId(&resource_mapping_id);
-
-    // Load the overlay resource mappings from the file specified using android:resourcesMap.
-    auto asset = OpenNonAssetFromResource(resource_mapping_id, overlay_asset_manager);
-    if (!asset) {
-      return Error("failed opening xml for android:resourcesMap: %s",
-                   asset.GetErrorMessage().c_str());
-    }
-
-    auto parser =
-        XmlParser::Create((*asset)->getBuffer(true /* wordAligned*/), (*asset)->getLength());
-    if (!parser) {
-      return Error("failed opening ResXMLTree");
-    }
-
-    // Copy the xml string pool data before the parse goes out of scope.
-    auto& string_pool = (*parser)->get_strings();
-    string_pool_data_length = string_pool.bytes();
-    string_pool_data.reset(new uint8_t[string_pool_data_length]);
-
-    // Overlays should not be incrementally installed, so calling unsafe_ptr is fine here.
-    memcpy(string_pool_data.get(), string_pool.data().unsafe_ptr(), string_pool_data_length);
-
-    // Offset string indices by the size of the overlay resource table string pool.
-    string_pool_offset = overlay_arsc->GetStringPool()->size();
-
-    resource_mapping = CreateResourceMapping(&target_asset_manager, target_pkg, overlay_pkg,
-                                             string_pool_offset, *(*parser), log_info);
   } else {
-    // If no file is specified using android:resourcesMap, it is assumed that the overlay only
-    // defines resources intended to override target resources of the same type and name.
-    resource_mapping = CreateResourceMappingLegacy(&target_asset_manager, &overlay_asset_manager,
-                                                   target_pkg, overlay_pkg, log_info);
+    auto overlay_value = std::get<TargetValue>(value);
+    target_map_.insert(std::make_pair(target_resource, overlay_value));
   }
 
-  if (!resource_mapping) {
-    return resource_mapping.GetError();
-  }
-
-  if (enforce_overlayable) {
-    // Filter out resources the overlay is not allowed to override.
-    (*resource_mapping)
-        .FilterOverlayableResources(&target_asset_manager, target_pkg, overlay_pkg, overlay_info,
-                                    fulfilled_policies, log_info);
-  }
-
-  resource_mapping->target_package_id_ = target_pkg->GetPackageId();
-  resource_mapping->overlay_package_id_ = overlay_pkg->GetPackageId();
-  resource_mapping->string_pool_offset_ = string_pool_offset;
-  resource_mapping->string_pool_data_ = std::move(string_pool_data);
-  resource_mapping->string_pool_data_length_ = string_pool_data_length;
-  return std::move(*resource_mapping);
-}
-
-OverlayResourceMap ResourceMapping::GetOverlayToTargetMap() const {
-  // An overlay resource can override multiple target resources at once. Rewrite the overlay
-  // resource as the first target resource it overrides.
-  OverlayResourceMap map;
-  for (const auto& mappings : overlay_map_) {
-    map.insert(std::make_pair(mappings.first, mappings.second));
-  }
-  return map;
-}
-
-Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource, ResourceId overlay_resource,
-                                         bool rewrite_overlay_reference) {
-  if (target_map_.find(target_resource) != target_map_.end()) {
-    return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
-  }
-
-  // TODO(141485591): Ensure that the overlay type is compatible with the target type. If the
-  // runtime types are not compatible, it could cause runtime crashes when the resource is resolved.
-
-  target_map_.insert(std::make_pair(target_resource, overlay_resource));
-
-  if (rewrite_overlay_reference) {
-    overlay_map_.insert(std::make_pair(overlay_resource, target_resource));
-  }
   return Unit{};
 }
 
-Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource,
-                                         TargetValue::DataType data_type,
-                                         TargetValue::DataValue data_value) {
-  if (target_map_.find(target_resource) != target_map_.end()) {
-    return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
-  }
-
-  // TODO(141485591): Ensure that the overlay type is compatible with the target type. If the
-  // runtime types are not compatible, it could cause runtime crashes when the resource is resolved.
-
-  target_map_.insert(std::make_pair(target_resource, TargetValue{data_type, data_value}));
-  return Unit{};
-}
-
-void ResourceMapping::RemoveMapping(ResourceId target_resource) {
-  auto target_iter = target_map_.find(target_resource);
-  if (target_iter == target_map_.end()) {
-    return;
-  }
-
-  const auto value = target_iter->second;
-  target_map_.erase(target_iter);
-
-  const ResourceId* overlay_resource = std::get_if<ResourceId>(&value);
-  if (overlay_resource == nullptr) {
-    return;
-  }
-
-  auto overlay_iter = overlay_map_.equal_range(*overlay_resource);
-  for (auto i = overlay_iter.first; i != overlay_iter.second; ++i) {
-    if (i->second == target_resource) {
-      overlay_map_.erase(i);
-      return;
-    }
-  }
-}
-
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp
index 4e85e57..e809bf1 100644
--- a/cmds/idmap2/libidmap2/ResourceUtils.cpp
+++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp
@@ -17,27 +17,16 @@
 #include "idmap2/ResourceUtils.h"
 
 #include <memory>
-#include <string>
 
 #include "androidfw/StringPiece.h"
 #include "androidfw/Util.h"
 #include "idmap2/Result.h"
-#include "idmap2/XmlParser.h"
-#include "idmap2/ZipFile.h"
 
 using android::StringPiece16;
 using android::idmap2::Result;
-using android::idmap2::XmlParser;
-using android::idmap2::ZipFile;
 using android::util::Utf16ToUtf8;
 
 namespace android::idmap2::utils {
-namespace {
-constexpr ResourceId kAttrName = 0x01010003;
-constexpr ResourceId kAttrResourcesMap = 0x01010609;
-constexpr ResourceId kAttrTargetName = 0x0101044d;
-constexpr ResourceId kAttrTargetPackage = 0x01010021;
-}  // namespace
 
 bool IsReference(uint8_t data_type) {
   return data_type == Res_value::TYPE_REFERENCE || data_type == Res_value::TYPE_DYNAMIC_REFERENCE;
@@ -97,71 +86,4 @@
   return out;
 }
 
-Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
-                                                       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());
-  }
-
-  std::unique_ptr<const MemoryChunk> entry = zip->Uncompress("AndroidManifest.xml");
-  if (!entry) {
-    return Error("failed to uncompress AndroidManifest.xml from %s", path.c_str());
-  }
-
-  Result<std::unique_ptr<const XmlParser>> xml = XmlParser::Create(entry->buf, entry->size);
-  if (!xml) {
-    return Error("failed to parse AndroidManifest.xml from %s", path.c_str());
-  }
-
-  auto manifest_it = (*xml)->tree_iterator();
-  if (manifest_it->event() != XmlParser::Event::START_TAG || manifest_it->name() != "manifest") {
-    return Error("root element tag is not <manifest> in AndroidManifest.xml of %s", path.c_str());
-  }
-
-  for (auto&& it : manifest_it) {
-    if (it.event() != XmlParser::Event::START_TAG || it.name() != "overlay") {
-      continue;
-    }
-
-    OverlayManifestInfo info{};
-    if (auto result_str = it.GetAttributeStringValue(kAttrName, "android: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 = it.GetAttributeStringValue(kAttrTargetPackage, "android: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());
-    }
-
-    if (auto result_str = it.GetAttributeStringValue(kAttrTargetName, "android:targetName")) {
-      info.target_name = *result_str;
-    }
-
-    if (auto result_value = it.GetAttributeValue(kAttrResourcesMap, "android: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;
-  }
-
-  return Error("<overlay> with android:name \"%s\" missing from AndroidManifest.xml of %s",
-               name.c_str(), path.c_str());
-}
-
 }  // namespace android::idmap2::utils
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
index 00baea4..70822c8 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -151,16 +151,18 @@
   return value ? GetStringValue(parser_, *value, name) : value.GetError();
 }
 
-Result<std::unique_ptr<const XmlParser>> XmlParser::Create(const void* data, size_t size,
-                                                           bool copy_data) {
-  auto parser = std::unique_ptr<const XmlParser>(new XmlParser());
-  if (parser->tree_.setTo(data, size, copy_data) != NO_ERROR) {
+XmlParser::XmlParser(std::unique_ptr<ResXMLTree> tree) : tree_(std::move(tree)) {
+}
+
+Result<XmlParser> XmlParser::Create(const void* data, size_t size, bool copy_data) {
+  auto tree = std::make_unique<ResXMLTree>();
+  if (tree->setTo(data, size, copy_data) != NO_ERROR) {
     return Error("Malformed xml block");
   }
 
   // Find the beginning of the first tag.
   XmlParser::Event event;
-  while ((event = parser->tree_.next()) != XmlParser::Event::BAD_DOCUMENT &&
+  while ((event = tree->next()) != XmlParser::Event::BAD_DOCUMENT &&
          event != XmlParser::Event::END_DOCUMENT && event != XmlParser::Event::START_TAG) {
   }
 
@@ -172,11 +174,7 @@
     return Error("Bad xml document");
   }
 
-  return parser;
-}
-
-XmlParser::~XmlParser() {
-  tree_.uninit();
+  return XmlParser{std::move(tree)};
 }
 
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/libidmap2/ZipFile.cpp b/cmds/idmap2/libidmap2/ZipFile.cpp
deleted file mode 100644
index 1e1a218..0000000
--- a/cmds/idmap2/libidmap2/ZipFile.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "idmap2/ZipFile.h"
-
-#include <memory>
-#include <string>
-
-#include "idmap2/Result.h"
-
-namespace android::idmap2 {
-
-std::unique_ptr<MemoryChunk> MemoryChunk::Allocate(size_t size) {
-  void* ptr = ::operator new(sizeof(MemoryChunk) + size);
-  std::unique_ptr<MemoryChunk> chunk(reinterpret_cast<MemoryChunk*>(ptr));
-  chunk->size = size;
-  return chunk;
-}
-
-std::unique_ptr<const ZipFile> ZipFile::Open(const std::string& path) {
-  ::ZipArchiveHandle handle;
-  int32_t status = ::OpenArchive(path.c_str(), &handle);
-  if (status != 0) {
-    ::CloseArchive(handle);
-    return nullptr;
-  }
-  return std::unique_ptr<ZipFile>(new ZipFile(handle));
-}
-
-ZipFile::~ZipFile() {
-  ::CloseArchive(handle_);
-}
-
-std::unique_ptr<const MemoryChunk> ZipFile::Uncompress(const std::string& entryPath) const {
-  ::ZipEntry entry;
-  int32_t status = ::FindEntry(handle_, entryPath, &entry);
-  if (status != 0) {
-    return nullptr;
-  }
-  std::unique_ptr<MemoryChunk> chunk = MemoryChunk::Allocate(entry.uncompressed_length);
-  status = ::ExtractToMemory(handle_, &entry, chunk->buf, chunk->size);
-  if (status != 0) {
-    return nullptr;
-  }
-  return chunk;
-}
-
-Result<uint32_t> ZipFile::Crc(const std::string& entryPath) const {
-  ::ZipEntry entry;
-  int32_t status = ::FindEntry(handle_, entryPath, &entry);
-  if (status != 0) {
-    return Error("failed to find zip entry %s", entryPath.c_str());
-  }
-  return entry.crc32;
-}
-
-}  // namespace android::idmap2
diff --git a/cmds/idmap2/libidmap2/proto/fabricated_v1.proto b/cmds/idmap2/libidmap2/proto/fabricated_v1.proto
new file mode 100644
index 0000000..a392b2b
--- /dev/null
+++ b/cmds/idmap2/libidmap2/proto/fabricated_v1.proto
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.idmap2.pb;
+
+option optimize_for = LITE_RUNTIME;
+
+// All changes to the proto messages in this file MUST be backwards compatible. Backwards
+// incompatible changes will cause previously fabricated overlays to be considered corrupt by the
+// new proto message specification.
+message FabricatedOverlay {
+  repeated ResourcePackage packages = 1;
+  string name = 2;
+  string package_name = 3;
+  string target_package_name = 4;
+  string target_overlayable = 5;
+}
+
+message ResourcePackage {
+  string name = 1;
+  repeated ResourceType types = 2;
+}
+
+message ResourceType {
+  string name = 1;
+  repeated ResourceEntry entries = 2;
+}
+
+message ResourceEntry {
+  string name = 1;
+  oneof value {
+    ResourceValue res_value = 2;
+  }
+}
+
+message ResourceValue {
+  // Corresponds with android::Res_value::dataType
+  uint32 data_type = 1;
+  // Corresponds with android::Res_value::data
+  uint32 data_value = 2;
+}
\ No newline at end of file