diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 50f400122fe1b3d01d4e89e64a2c2aab11a5d2ae..34d38d2b1b04cadeca4e2267c22c9011e8896da0 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -51,13 +51,18 @@ cc_library {
             static: {
                 enabled: false,
             },
+            static_libs: [
+                "libidmap2_protos",
+            ],
             shared_libs: [
                 "libandroidfw",
                 "libbase",
                 "libcutils",
+                "libidmap2_policies",
+                "libprotobuf-cpp-lite",
                 "libutils",
+                "libz",
                 "libziparchive",
-                "libidmap2_policies",
             ],
         },
         host: {
@@ -68,14 +73,29 @@ cc_library {
                 "libandroidfw",
                 "libbase",
                 "libcutils",
+                "libidmap2_policies",
+                "libidmap2_protos",
+                "libprotobuf-cpp-lite",
                 "libutils",
+                "libz",
                 "libziparchive",
-                "libidmap2_policies",
             ],
         },
     },
 }
 
+cc_library {
+    name: "libidmap2_protos",
+    srcs: [
+        "libidmap2/proto/*.proto",
+    ],
+    host_supported: true,
+    proto: {
+        type: "lite",
+        export_proto_headers: true,
+    },
+}
+
 cc_library {
     name: "libidmap2_policies",
     defaults: [
@@ -88,9 +108,6 @@ cc_library {
             enabled: true,
         },
         android: {
-            static: {
-                enabled: false,
-            },
             shared_libs: [
                 "libandroidfw",
             ],
@@ -119,6 +136,7 @@ cc_test {
     srcs: [
         "tests/BinaryStreamVisitorTests.cpp",
         "tests/CommandLineOptionsTests.cpp",
+        "tests/FabricatedOverlayTests.cpp",
         "tests/FileUtilsTests.cpp",
         "tests/Idmap2BinaryTests.cpp",
         "tests/IdmapTests.cpp",
@@ -130,20 +148,27 @@ cc_test {
         "tests/ResourceUtilsTests.cpp",
         "tests/ResultTests.cpp",
         "tests/XmlParserTests.cpp",
-        "tests/ZipFileTests.cpp",
     ],
-    static_libs: ["libgmock"],
+    required: [
+        "idmap2",
+    ],
+    static_libs: [
+        "libgmock",
+        "libidmap2_protos",
+    ],
     target: {
         android: {
             shared_libs: [
                 "libandroidfw",
                 "libbase",
                 "libidmap2",
+                "libidmap2_policies",
                 "liblog",
+                "libprotobuf-cpp-lite",
                 "libutils",
                 "libz",
+                "libz",
                 "libziparchive",
-                "libidmap2_policies",
             ],
         },
         host: {
@@ -152,10 +177,11 @@ cc_test {
                 "libbase",
                 "libcutils",
                 "libidmap2",
+                "libidmap2_policies",
                 "liblog",
+                "libprotobuf-cpp-lite",
                 "libutils",
                 "libziparchive",
-                "libidmap2_policies",
             ],
             shared_libs: [
                 "libz",
@@ -189,6 +215,9 @@ cc_binary {
         "idmap2/Lookup.cpp",
         "idmap2/Main.cpp",
     ],
+    static_libs: [
+        "libidmap2_protos",
+    ],
     target: {
         android: {
             shared_libs: [
@@ -196,9 +225,11 @@ cc_binary {
                 "libbase",
                 "libcutils",
                 "libidmap2",
+                "libidmap2_policies",
+                "libprotobuf-cpp-lite",
                 "libutils",
+                "libz",
                 "libziparchive",
-                "libidmap2_policies",
             ],
         },
         host: {
@@ -207,10 +238,11 @@ cc_binary {
                 "libbase",
                 "libcutils",
                 "libidmap2",
+                "libidmap2_policies",
                 "liblog",
+                "libprotobuf-cpp-lite",
                 "libutils",
                 "libziparchive",
-                "libidmap2_policies",
             ],
             shared_libs: [
                 "libz",
@@ -236,11 +268,13 @@ cc_binary {
         "libbinder",
         "libcutils",
         "libidmap2",
+        "libidmap2_policies",
+        "libprotobuf-cpp-lite",
         "libutils",
         "libziparchive",
-        "libidmap2_policies",
     ],
     static_libs: [
+        "libidmap2_protos",
         "libidmap2daidl",
     ],
     init_rc: ["idmap2d/idmap2d.rc"],
diff --git a/cmds/idmap2/idmap2/CommandUtils.cpp b/cmds/idmap2/idmap2/CommandUtils.cpp
index 09867f3a9c202fd89b81fd21899109f6390e7eab..bf30a76d581ae73984c15c00c146f7ea7fed2e87 100644
--- a/cmds/idmap2/idmap2/CommandUtils.cpp
+++ b/cmds/idmap2/idmap2/CommandUtils.cpp
@@ -25,7 +25,9 @@
 
 using android::idmap2::Error;
 using android::idmap2::IdmapHeader;
+using android::idmap2::OverlayResourceContainer;
 using android::idmap2::Result;
+using android::idmap2::TargetResourceContainer;
 using android::idmap2::Unit;
 
 Result<Unit> Verify(const std::string& idmap_path, const std::string& target_path,
@@ -39,11 +41,20 @@ Result<Unit> Verify(const std::string& idmap_path, const std::string& target_pat
     return Error("failed to parse idmap header");
   }
 
-  const auto header_ok = header->IsUpToDate(target_path, overlay_path, overlay_name,
-                                            fulfilled_policies, enforce_overlayable);
+  auto target = TargetResourceContainer::FromPath(target_path);
+  if (!target) {
+    return Error("failed to load target '%s'", target_path.c_str());
+  }
+
+  auto overlay = OverlayResourceContainer::FromPath(overlay_path);
+  if (!overlay) {
+    return Error("failed to load overlay '%s'", overlay_path.c_str());
+  }
+
+  const auto header_ok = header->IsUpToDate(**target, **overlay, overlay_name, fulfilled_policies,
+                                            enforce_overlayable);
   if (!header_ok) {
     return Error(header_ok.GetError(), "idmap not up to date");
   }
-
   return Unit{};
 }
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index c93c717a15d29886d0e9f43868694f1458145a59..977a0bbadafb86ce11ec99d2d461cf458d687703 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -20,7 +20,6 @@
 #include <fstream>
 #include <memory>
 #include <ostream>
-#include <string>
 #include <vector>
 
 #include "androidfw/ResourceTypes.h"
@@ -31,12 +30,13 @@
 #include "idmap2/PolicyUtils.h"
 #include "idmap2/SysTrace.h"
 
-using android::ApkAssets;
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Error;
 using android::idmap2::Idmap;
+using android::idmap2::OverlayResourceContainer;
 using android::idmap2::Result;
+using android::idmap2::TargetResourceContainer;
 using android::idmap2::Unit;
 using android::idmap2::utils::kIdmapFilePermissionMask;
 using android::idmap2::utils::PoliciesToBitmaskResult;
@@ -93,18 +93,18 @@ Result<Unit> Create(const std::vector<std::string>& args) {
     fulfilled_policies |= PolicyFlags::PUBLIC;
   }
 
-  const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  if (!target_apk) {
-    return Error("failed to load apk %s", target_apk_path.c_str());
+  const auto target = TargetResourceContainer::FromPath(target_apk_path);
+  if (!target) {
+    return Error("failed to load target '%s'", target_apk_path.c_str());
   }
 
-  const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  if (!overlay_apk) {
-    return Error("failed to load apk %s", overlay_apk_path.c_str());
+  const auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+  if (!overlay) {
+    return Error("failed to load apk overlay '%s'", overlay_apk_path.c_str());
   }
 
-  const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, overlay_name,
-                                          fulfilled_policies, !ignore_overlayable);
+  const auto idmap = Idmap::FromContainers(**target, **overlay, overlay_name, fulfilled_policies,
+                                           !ignore_overlayable);
   if (!idmap) {
     return Error(idmap.GetError(), "failed to create idmap");
   }
@@ -112,13 +112,14 @@ Result<Unit> Create(const std::vector<std::string>& args) {
   umask(kIdmapFilePermissionMask);
   std::ofstream fout(idmap_path);
   if (fout.fail()) {
-    return Error("failed to open idmap path %s", idmap_path.c_str());
+    return Error("failed to open idmap path '%s'", idmap_path.c_str());
   }
+
   BinaryStreamVisitor visitor(fout);
   (*idmap)->accept(&visitor);
   fout.close();
   if (fout.fail()) {
-    return Error("failed to write to idmap path %s", idmap_path.c_str());
+    return Error("failed to write to idmap path '%s'", idmap_path.c_str());
   }
 
   return Unit{};
diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp
index 5db391caac309989cb01f6dc31e0905f5c6fbad7..953d99f8dcfb15e2ba5bb7d11126ccef7b0350ea 100644
--- a/cmds/idmap2/idmap2/CreateMultiple.cpp
+++ b/cmds/idmap2/idmap2/CreateMultiple.cpp
@@ -34,13 +34,14 @@
 #include "idmap2/PolicyUtils.h"
 #include "idmap2/SysTrace.h"
 
-using android::ApkAssets;
 using android::base::StringPrintf;
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Error;
 using android::idmap2::Idmap;
+using android::idmap2::OverlayResourceContainer;
 using android::idmap2::Result;
+using android::idmap2::TargetResourceContainer;
 using android::idmap2::Unit;
 using android::idmap2::utils::kIdmapCacheDir;
 using android::idmap2::utils::kIdmapFilePermissionMask;
@@ -91,9 +92,9 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
     fulfilled_policies |= PolicyFlags::PUBLIC;
   }
 
-  const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  if (!target_apk) {
-    return Error("failed to load apk %s", target_apk_path.c_str());
+  const auto target = TargetResourceContainer::FromPath(target_apk_path);
+  if (!target) {
+    return Error("failed to load target '%s'", target_apk_path.c_str());
   }
 
   std::vector<std::string> idmap_paths;
@@ -108,14 +109,14 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
     // TODO(b/175014391): Support multiple overlay tags in OverlayConfig
     if (!Verify(idmap_path, target_apk_path, overlay_apk_path, "", fulfilled_policies,
                 !ignore_overlayable)) {
-      const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-      if (!overlay_apk) {
+      const auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+      if (!overlay) {
         LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str();
         continue;
       }
 
-      const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, "", fulfilled_policies,
-                                              !ignore_overlayable);
+      const auto idmap =
+          Idmap::FromContainers(**target, **overlay, "", fulfilled_policies, !ignore_overlayable);
       if (!idmap) {
         LOG(WARNING) << "failed to create idmap";
         continue;
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index 43a1951a5ba96add505c82de5d77954e1ad52141..f41e57cc66d603f41fadf314a3580e55e1c40253 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -37,7 +37,6 @@
 #include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
 #include "idmap2/XmlParser.h"
-#include "idmap2/ZipFile.h"
 #include "utils/String16.h"
 #include "utils/String8.h"
 
@@ -52,10 +51,10 @@ using android::base::StringPrintf;
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Error;
 using android::idmap2::IdmapHeader;
+using android::idmap2::OverlayResourceContainer;
 using android::idmap2::ResourceId;
 using android::idmap2::Result;
 using android::idmap2::Unit;
-using android::idmap2::utils::ExtractOverlayManifestInfo;
 
 namespace {
 
@@ -195,12 +194,17 @@ Result<Unit> Lookup(const std::vector<std::string>& args) {
       }
       apk_assets.push_back(std::move(target_apk));
 
-      auto manifest_info = ExtractOverlayManifestInfo(idmap_header->GetOverlayPath(),
-                                                      idmap_header->GetOverlayName());
+      auto overlay = OverlayResourceContainer::FromPath(idmap_header->GetOverlayPath());
+      if (!overlay) {
+        return overlay.GetError();
+      }
+
+      auto manifest_info = (*overlay)->FindOverlayInfo(idmap_header->GetOverlayName());
       if (!manifest_info) {
         return manifest_info.GetError();
       }
-      target_package_name = manifest_info->target_package;
+
+      target_package_name = (*manifest_info).target_package;
     } else if (target_path != idmap_header->GetTargetPath()) {
       return Error("different target APKs (expected target APK %s but %s has target APK %s)",
                    target_path.c_str(), idmap_path.c_str(), idmap_header->GetTargetPath().c_str());
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index 93537d32299b71d4993383e7bf327b183b5e9437..f62630e702d41188ac3f56c80eb824c7171b1096 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -35,17 +35,16 @@
 #include "idmap2/Idmap.h"
 #include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
-#include "idmap2/ZipFile.h"
 #include "utils/String8.h"
 
 using android::IPCThreadState;
 using android::base::StringPrintf;
 using android::binder::Status;
 using android::idmap2::BinaryStreamVisitor;
-using android::idmap2::GetPackageCrc;
 using android::idmap2::Idmap;
 using android::idmap2::IdmapHeader;
-using android::idmap2::ZipFile;
+using android::idmap2::OverlayResourceContainer;
+using android::idmap2::TargetResourceContainer;
 using android::idmap2::utils::kIdmapCacheDir;
 using android::idmap2::utils::kIdmapFilePermissionMask;
 using android::idmap2::utils::UidHasWriteAccessToPath;
@@ -68,40 +67,24 @@ Status error(const std::string& msg) {
 PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
   return static_cast<PolicyBitmask>(arg);
 }
-
-Status GetCrc(const std::string& apk_path, uint32_t* out_crc) {
-  const auto zip = ZipFile::Open(apk_path);
-  if (!zip) {
-    return error(StringPrintf("failed to open apk %s", apk_path.c_str()));
-  }
-
-  const auto crc = GetPackageCrc(*zip);
-  if (!crc) {
-    return error(crc.GetErrorMessage());
-  }
-
-  *out_crc = *crc;
-  return ok();
-}
-
 }  // namespace
 
 namespace android::os {
 
-Status Idmap2Service::getIdmapPath(const std::string& overlay_apk_path,
+Status Idmap2Service::getIdmapPath(const std::string& overlay_path,
                                    int32_t user_id ATTRIBUTE_UNUSED, std::string* _aidl_return) {
   assert(_aidl_return);
-  SYSTRACE << "Idmap2Service::getIdmapPath " << overlay_apk_path;
-  *_aidl_return = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+  SYSTRACE << "Idmap2Service::getIdmapPath " << overlay_path;
+  *_aidl_return = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
   return ok();
 }
 
-Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
-                                  int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
+Status Idmap2Service::removeIdmap(const std::string& overlay_path, int32_t user_id ATTRIBUTE_UNUSED,
+                                  bool* _aidl_return) {
   assert(_aidl_return);
-  SYSTRACE << "Idmap2Service::removeIdmap " << overlay_apk_path;
+  SYSTRACE << "Idmap2Service::removeIdmap " << overlay_path;
   const uid_t uid = IPCThreadState::self()->getCallingUid();
-  const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+  const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
   if (!UidHasWriteAccessToPath(uid, idmap_path)) {
     *_aidl_return = false;
     return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
@@ -115,85 +98,79 @@ Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
   return ok();
 }
 
-Status Idmap2Service::verifyIdmap(const std::string& target_apk_path,
-                                  const std::string& overlay_apk_path, int32_t fulfilled_policies,
-                                  bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
-                                  bool* _aidl_return) {
-  SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_apk_path;
+Status Idmap2Service::verifyIdmap(const std::string& target_path, const std::string& overlay_path,
+                                  int32_t fulfilled_policies, bool enforce_overlayable,
+                                  int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
+  SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_path;
   assert(_aidl_return);
 
-  const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+  const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
   std::ifstream fin(idmap_path);
   const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
   fin.close();
   if (!header) {
     *_aidl_return = false;
-    return error("failed to parse idmap header");
+    LOG(WARNING) << "failed to parse idmap header of '" << idmap_path << "'";
+    return ok();
   }
 
-  uint32_t target_crc;
-  if (target_apk_path == kFrameworkPath && android_crc_) {
-    target_crc = *android_crc_;
-  } else {
-    auto target_crc_status = GetCrc(target_apk_path, &target_crc);
-    if (!target_crc_status.isOk()) {
-      *_aidl_return = false;
-      return target_crc_status;
-    }
-
-    // Loading the framework zip can take several milliseconds. Cache the crc of the framework
-    // resource APK to reduce repeated work during boot.
-    if (target_apk_path == kFrameworkPath) {
-      android_crc_ = target_crc;
-    }
+  const auto target = GetTargetContainer(target_path);
+  if (!target) {
+    *_aidl_return = false;
+    LOG(WARNING) << "failed to load target '" << target_path << "'";
+    return ok();
   }
 
-  uint32_t overlay_crc;
-  auto overlay_crc_status = GetCrc(overlay_apk_path, &overlay_crc);
-  if (!overlay_crc_status.isOk()) {
+  const auto overlay = OverlayResourceContainer::FromPath(overlay_path);
+  if (!overlay) {
     *_aidl_return = false;
-    return overlay_crc_status;
+    LOG(WARNING) << "failed to load overlay '" << overlay_path << "'";
+    return ok();
   }
 
   // TODO(162841629): Support passing overlay name to idmap2d verify
   auto up_to_date =
-      header->IsUpToDate(target_apk_path, overlay_apk_path, "", target_crc, overlay_crc,
+      header->IsUpToDate(*GetPointer(*target), **overlay, "",
                          ConvertAidlArgToPolicyBitmask(fulfilled_policies), enforce_overlayable);
 
   *_aidl_return = static_cast<bool>(up_to_date);
-  return *_aidl_return ? ok() : error(up_to_date.GetErrorMessage());
+  if (!up_to_date) {
+    LOG(WARNING) << "idmap '" << idmap_path
+                 << "' not up to date : " << up_to_date.GetErrorMessage();
+  }
+  return ok();
 }
 
-Status Idmap2Service::createIdmap(const std::string& target_apk_path,
-                                  const std::string& overlay_apk_path, int32_t fulfilled_policies,
-                                  bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
+Status Idmap2Service::createIdmap(const std::string& target_path, const std::string& overlay_path,
+                                  int32_t fulfilled_policies, bool enforce_overlayable,
+                                  int32_t user_id ATTRIBUTE_UNUSED,
                                   std::optional<std::string>* _aidl_return) {
   assert(_aidl_return);
-  SYSTRACE << "Idmap2Service::createIdmap " << target_apk_path << " " << overlay_apk_path;
+  SYSTRACE << "Idmap2Service::createIdmap " << target_path << " " << overlay_path;
   _aidl_return->reset();
 
   const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
 
-  const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+  const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
   const uid_t uid = IPCThreadState::self()->getCallingUid();
   if (!UidHasWriteAccessToPath(uid, idmap_path)) {
     return error(base::StringPrintf("will not write to %s: calling uid %d lacks write accesss",
                                     idmap_path.c_str(), uid));
   }
 
-  const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  if (!target_apk) {
-    return error("failed to load apk " + target_apk_path);
+  const auto target = GetTargetContainer(target_path);
+  if (!target) {
+    return error("failed to load target '%s'" + target_path);
   }
 
-  const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  if (!overlay_apk) {
-    return error("failed to load apk " + overlay_apk_path);
+  const auto overlay = OverlayResourceContainer::FromPath(overlay_path);
+  if (!overlay) {
+    return error("failed to load apk overlay '%s'" + overlay_path);
   }
 
   // TODO(162841629): Support passing overlay name to idmap2d create
-  const auto idmap =
-      Idmap::FromApkAssets(*target_apk, *overlay_apk, "", policy_bitmask, enforce_overlayable);
+  const auto idmap = Idmap::FromContainers(*GetPointer(*target), **overlay, "", policy_bitmask,
+                                           enforce_overlayable);
   if (!idmap) {
     return error(idmap.GetErrorMessage());
   }
@@ -220,4 +197,25 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path,
   return ok();
 }
 
+idmap2::Result<Idmap2Service::TargetResourceContainerPtr> Idmap2Service::GetTargetContainer(
+    const std::string& target_path) {
+  if (target_path == kFrameworkPath) {
+    if (framework_apk_cache_ == nullptr) {
+      // Initialize the framework APK cache.
+      auto target = TargetResourceContainer::FromPath(target_path);
+      if (!target) {
+        return target.GetError();
+      }
+      framework_apk_cache_ = std::move(*target);
+    }
+    return {framework_apk_cache_.get()};
+  }
+
+  auto target = TargetResourceContainer::FromPath(target_path);
+  if (!target) {
+    return target.GetError();
+  }
+  return {std::move(*target)};
+}
+
 }  // namespace android::os
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index 0127e874b444a3a030730ace837f29b26d97113c..869a4d981f424ea4d50a1c5a29d1d047a9fbe382 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -18,12 +18,13 @@
 #define IDMAP2_IDMAP2D_IDMAP2SERVICE_H_
 
 #include <android-base/unique_fd.h>
+#include <android/os/BnIdmap2.h>
 #include <binder/BinderService.h>
+#include <idmap2/ResourceContainer.h>
+#include <idmap2/Result.h>
 
 #include <string>
 
-#include "android/os/BnIdmap2.h"
-
 namespace android::os {
 
 class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 {
@@ -32,27 +33,44 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 {
     return "idmap";
   }
 
-  binder::Status getIdmapPath(const std::string& overlay_apk_path, int32_t user_id,
+  binder::Status getIdmapPath(const std::string& overlay_path, int32_t user_id,
                               std::string* _aidl_return) override;
 
-  binder::Status removeIdmap(const std::string& overlay_apk_path, int32_t user_id,
+  binder::Status removeIdmap(const std::string& overlay_path, int32_t user_id,
                              bool* _aidl_return) override;
 
-  binder::Status verifyIdmap(const std::string& target_apk_path,
-                             const std::string& overlay_apk_path, int32_t fulfilled_policies,
-                             bool enforce_overlayable, int32_t user_id,
+  binder::Status verifyIdmap(const std::string& target_path, const std::string& overlay_path,
+                             int32_t fulfilled_policies, bool enforce_overlayable, int32_t user_id,
                              bool* _aidl_return) override;
 
-  binder::Status createIdmap(const std::string& target_apk_path,
-                             const std::string& overlay_apk_path, int32_t fulfilled_policies,
-                             bool enforce_overlayable, int32_t user_id,
+  binder::Status createIdmap(const std::string& target_path, const std::string& overlay_path,
+                             int32_t fulfilled_policies, bool enforce_overlayable, int32_t user_id,
                              std::optional<std::string>* _aidl_return) override;
 
  private:
-  // Cache the crc of the android framework package since the crc cannot change without a reboot.
-  std::optional<uint32_t> android_crc_;
+  // idmap2d is killed after a period of inactivity, so any information stored on this class should
+  // be able to be recalculated if idmap2 dies and restarts.
+  std::unique_ptr<idmap2::TargetResourceContainer> framework_apk_cache_;
+
+  template <typename T>
+  using MaybeUniquePtr = std::variant<std::unique_ptr<T>, T*>;
+
+  using TargetResourceContainerPtr = MaybeUniquePtr<idmap2::TargetResourceContainer>;
+  idmap2::Result<TargetResourceContainerPtr> GetTargetContainer(const std::string& target_path);
+
+  template <typename T>
+  WARN_UNUSED static const T* GetPointer(const MaybeUniquePtr<T>& ptr);
 };
 
+template <typename T>
+const T* Idmap2Service::GetPointer(const MaybeUniquePtr<T>& ptr) {
+  auto u = std::get_if<T*>(&ptr);
+  if (u != nullptr) {
+    return *u;
+  }
+  return std::get<std::unique_ptr<T>>(ptr).get();
+}
+
 }  // namespace android::os
 
 #endif  // IDMAP2_IDMAP2D_IDMAP2SERVICE_H_
diff --git a/cmds/idmap2/include/idmap2/FabricatedOverlay.h b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
new file mode 100644
index 0000000000000000000000000000000000000000..d82315723f71cdaab831b9b2e1af31eab587ac1e
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_FABRICATEDOVERLAY_H
+#define IDMAP2_INCLUDE_IDMAP2_FABRICATEDOVERLAY_H
+
+#include <libidmap2/proto/fabricated_v1.pb.h>
+
+#include <iostream>
+#include <map>
+#include <memory>
+#include <unordered_map>
+
+#include "idmap2/ResourceContainer.h"
+#include "idmap2/Result.h"
+
+namespace android::idmap2 {
+
+struct FabricatedOverlay {
+  struct Builder {
+    Builder(const std::string& package_name, const std::string& name,
+            const std::string& target_package_name);
+
+    Builder& SetOverlayable(const std::string& name);
+
+    Builder& SetResourceValue(const std::string& resource_name, uint8_t data_type,
+                              uint32_t data_value);
+
+    WARN_UNUSED Result<FabricatedOverlay> Build();
+
+   private:
+    struct Entry {
+      std::string resource_name;
+      DataType data_type;
+      DataValue data_value;
+    };
+
+    std::string package_name_;
+    std::string name_;
+    std::string target_package_name_;
+    std::string target_overlayable_;
+    std::vector<Entry> entries_;
+  };
+
+  Result<Unit> ToBinaryStream(std::ostream& stream);
+  static Result<FabricatedOverlay> FromBinaryStream(std::istream& stream);
+
+ private:
+  struct SerializedData {
+    std::unique_ptr<uint8_t[]> data;
+    size_t data_size;
+    uint32_t crc;
+  };
+
+  Result<SerializedData*> InitializeData() const;
+  Result<uint32_t> GetCrc() const;
+
+  FabricatedOverlay(pb::FabricatedOverlay&& overlay, std::optional<uint32_t> crc_from_disk = {});
+
+  pb::FabricatedOverlay overlay_pb_;
+  std::optional<uint32_t> crc_from_disk_;
+  mutable std::optional<SerializedData> data_;
+
+  friend struct FabricatedOverlayContainer;
+};
+
+struct FabricatedOverlayContainer : public OverlayResourceContainer {
+  static Result<std::unique_ptr<FabricatedOverlayContainer>> FromPath(std::string path);
+  static std::unique_ptr<FabricatedOverlayContainer> FromOverlay(FabricatedOverlay&& overlay);
+
+  // inherited from OverlayResourceContainer
+  WARN_UNUSED Result<OverlayManifestInfo> FindOverlayInfo(const std::string& name) const override;
+  WARN_UNUSED Result<OverlayData> GetOverlayData(const OverlayManifestInfo& info) const override;
+
+  // inherited from ResourceContainer
+  WARN_UNUSED Result<uint32_t> GetCrc() const override;
+  WARN_UNUSED const std::string& GetPath() const override;
+  WARN_UNUSED Result<std::string> GetResourceName(ResourceId id) const override;
+
+  ~FabricatedOverlayContainer() override;
+
+ private:
+  FabricatedOverlayContainer(FabricatedOverlay&& overlay, std::string&& path);
+  FabricatedOverlay overlay_;
+  std::string path_;
+};
+
+}  // namespace android::idmap2
+
+#endif  // IDMAP2_INCLUDE_IDMAP2_FABRICATEDOVERLAY_H
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 1b815c1197cad334ae003b1d2a08c5061a5daeeb..58aff42b1e98754f6db39ed98e9042958a891538 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -23,8 +23,8 @@
  *                               debug_info
  * data                       := data_header target_entry* target_inline_entry* overlay_entry*
  *                               string_pool
- * data_header                := target_package_id overlay_package_id padding(2) target_entry_count
- *                               target_inline_entry_count overlay_entry_count string_pool_index
+ * data_header                := target_entry_count target_inline_entry_count overlay_entry_count
+ *                               string_pool_index
  * target_entry               := target_id overlay_id
  * target_inline_entry        := target_id Res_value::size padding(1) Res_value::type
  *                               Res_value::value
@@ -68,11 +68,10 @@
 #include <vector>
 
 #include "android-base/macros.h"
-#include "androidfw/ApkAssets.h"
 #include "androidfw/ResourceTypes.h"
 #include "androidfw/StringPiece.h"
+#include "idmap2/ResourceContainer.h"
 #include "idmap2/ResourceMapping.h"
-#include "idmap2/ZipFile.h"
 
 namespace android::idmap2 {
 
@@ -85,9 +84,6 @@ static constexpr const uint32_t kIdmapMagic = android::kIdmapMagic;
 // current version of the idmap binary format; must be incremented when the format is changed
 static constexpr const uint32_t kIdmapCurrentVersion = android::kIdmapCurrentVersion;
 
-// Retrieves a crc generated using all of the files within the zip that can affect idmap generation.
-Result<uint32_t> GetPackageCrc(const ZipFile& zip_info);
-
 class IdmapHeader {
  public:
   static std::unique_ptr<const IdmapHeader> FromBinaryStream(std::istream& stream);
@@ -135,9 +131,9 @@ class IdmapHeader {
   // Invariant: anytime the idmap data encoding is changed, the idmap version
   // field *must* be incremented. Because of this, we know that if the idmap
   // header is up-to-date the entire file is up-to-date.
-  Result<Unit> IsUpToDate(const std::string& target_path, const std::string& overlay_path,
-                          const std::string& overlay_name, PolicyBitmask fulfilled_policies,
-                          bool enforce_overlayable) const;
+  Result<Unit> IsUpToDate(const TargetResourceContainer& target,
+                          const OverlayResourceContainer& overlay, const std::string& overlay_name,
+                          PolicyBitmask fulfilled_policies, bool enforce_overlayable) const;
 
   Result<Unit> IsUpToDate(const std::string& target_path, const std::string& overlay_path,
                           const std::string& overlay_name, uint32_t target_crc,
@@ -169,14 +165,6 @@ class IdmapData {
    public:
     static std::unique_ptr<const Header> FromBinaryStream(std::istream& stream);
 
-    inline PackageId GetTargetPackageId() const {
-      return target_package_id_;
-    }
-
-    inline PackageId GetOverlayPackageId() const {
-      return overlay_package_id_;
-    }
-
     inline uint32_t GetTargetEntryCount() const {
       return target_entry_count;
     }
@@ -196,8 +184,6 @@ class IdmapData {
     void accept(Visitor* v) const;
 
    private:
-    PackageId target_package_id_;
-    PackageId overlay_package_id_;
     uint32_t target_entry_count;
     uint32_t target_entry_inline_count;
     uint32_t overlay_entry_count;
@@ -275,11 +261,10 @@ class Idmap {
   // file is used; change this in the next version of idmap to use a named
   // package instead; also update FromApkAssets to take additional parameters:
   // the target and overlay package names
-  static Result<std::unique_ptr<const Idmap>> FromApkAssets(const ApkAssets& target_apk_assets,
-                                                            const ApkAssets& overlay_apk_assets,
-                                                            const std::string& overlay_name,
-                                                            const PolicyBitmask& fulfilled_policies,
-                                                            bool enforce_overlayable);
+  static Result<std::unique_ptr<const Idmap>> FromContainers(
+      const TargetResourceContainer& target, const OverlayResourceContainer& overlay,
+      const std::string& overlay_name, const PolicyBitmask& fulfilled_policies,
+      bool enforce_overlayable);
 
   const std::unique_ptr<const IdmapHeader>& GetHeader() const {
     return header_;
diff --git a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
index 2b4c761241754c166ca1f804b08564244414748c..4464201a1f2e838e4dd3d6a227aac5a82e9ccfb6 100644
--- a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
+++ b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
@@ -41,9 +41,8 @@ class PrettyPrintVisitor : public Visitor {
 
  private:
   std::ostream& stream_;
-  AssetManager2 target_am_;
-  AssetManager2 overlay_am_;
-  std::vector<std::unique_ptr<const ApkAssets>> apk_assets_;
+  std::unique_ptr<TargetResourceContainer> target_;
+  std::unique_ptr<OverlayResourceContainer> overlay_;
 };
 
 }  // namespace idmap2
diff --git a/cmds/idmap2/include/idmap2/RawPrintVisitor.h b/cmds/idmap2/include/idmap2/RawPrintVisitor.h
index 45835164ef8e8a25d5f04fcdbfc46e8a82afbf61..ebd0d1eb2fbcbd8eb29eae39b63ac26e2323b09e 100644
--- a/cmds/idmap2/include/idmap2/RawPrintVisitor.h
+++ b/cmds/idmap2/include/idmap2/RawPrintVisitor.h
@@ -49,10 +49,9 @@ class RawPrintVisitor : public Visitor {
   void pad(size_t padding);
 
   std::ostream& stream_;
-  std::vector<std::unique_ptr<const ApkAssets>> apk_assets_;
-  AssetManager2 target_am_;
-  AssetManager2 overlay_am_;
   size_t offset_;
+  std::unique_ptr<TargetResourceContainer> target_;
+  std::unique_ptr<OverlayResourceContainer> overlay_;
 };
 
 }  // namespace idmap2
diff --git a/cmds/idmap2/include/idmap2/ResourceContainer.h b/cmds/idmap2/include/idmap2/ResourceContainer.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a22dc668e629c7c6197b4dbf9e6e79a72e16361
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/ResourceContainer.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_RESOURCECONTAINER_H
+#define IDMAP2_INCLUDE_IDMAP2_RESOURCECONTAINER_H
+
+#include <string>
+#include <variant>
+#include <vector>
+
+#include "idmap2/Policies.h"
+#include "idmap2/ResourceUtils.h"
+
+namespace android::idmap2 {
+
+struct ResourceContainer {
+  WARN_UNUSED virtual Result<uint32_t> GetCrc() const = 0;
+  WARN_UNUSED virtual const std::string& GetPath() const = 0;
+  WARN_UNUSED virtual Result<std::string> GetResourceName(ResourceId id) const = 0;
+
+  virtual ~ResourceContainer() = default;
+};
+
+struct TargetResourceContainer : public ResourceContainer {
+  static Result<std::unique_ptr<TargetResourceContainer>> FromPath(std::string path);
+
+  WARN_UNUSED virtual Result<bool> DefinesOverlayable() const = 0;
+  WARN_UNUSED virtual Result<const android::OverlayableInfo*> GetOverlayableInfo(
+      ResourceId id) const = 0;
+  WARN_UNUSED virtual Result<ResourceId> GetResourceId(const std::string& name) const = 0;
+
+  ~TargetResourceContainer() override = default;
+};
+
+struct OverlayManifestInfo {
+  std::string name;             // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string target_package;   // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string target_name;      // NOLINT(misc-non-private-member-variables-in-classes)
+  ResourceId resource_mapping;  // NOLINT(misc-non-private-member-variables-in-classes)
+};
+
+struct OverlayData {
+  struct ResourceIdValue {
+    // The overlay resource id.
+    ResourceId overlay_id;
+
+    // Whether or not references to the overlay resource id should be rewritten to its corresponding
+    // target id during resource resolution.
+    bool rewrite_id;
+  };
+
+  struct Value {
+    std::string resource_name;
+    std::variant<ResourceIdValue, TargetValue> value;
+  };
+
+  struct InlineStringPoolData {
+    // The binary data of the android::ResStringPool string pool.
+    std::unique_ptr<uint8_t[]> data;
+
+    // The length of the binary data.
+    uint32_t data_length;
+
+    // The offset added to TargetValue#data_value (the index of the string in the inline string
+    // pool) in order to prevent the indices of the overlay resource table string pool from
+    // colliding with the inline string pool indices.
+    uint32_t string_pool_offset;
+  };
+
+  // The overlay's mapping of target resource name to overlaid value. Use a vector to enforce that
+  // the overlay pairs are inserted into the ResourceMapping in the specified ordered.
+  std::vector<Value> pairs;
+
+  // If the overlay maps a target resource to a string literal (not a string resource), then the
+  // this field contains information about the string pool in which the string literal resides so it
+  // can be inlined into an idmap.
+  std::optional<InlineStringPoolData> string_pool_data;
+};
+
+struct OverlayResourceContainer : public ResourceContainer {
+  static Result<std::unique_ptr<OverlayResourceContainer>> FromPath(std::string path);
+
+  WARN_UNUSED virtual Result<OverlayManifestInfo> FindOverlayInfo(
+      const std::string& name) const = 0;
+  WARN_UNUSED virtual Result<OverlayData> GetOverlayData(const OverlayManifestInfo& info) const = 0;
+
+  ~OverlayResourceContainer() override = default;
+};
+
+}  // namespace android::idmap2
+
+#endif  // IDMAP2_INCLUDE_IDMAP2_RESOURCECONTAINER_H
diff --git a/cmds/idmap2/include/idmap2/ResourceMapping.h b/cmds/idmap2/include/idmap2/ResourceMapping.h
index f66916ccb78c109aa57cc57f8f2eee1327169e80..5a0a384f75a31f66ad4405e4f276d5167a1866a1 100644
--- a/cmds/idmap2/include/idmap2/ResourceMapping.h
+++ b/cmds/idmap2/include/idmap2/ResourceMapping.h
@@ -17,30 +17,22 @@
 #ifndef IDMAP2_INCLUDE_IDMAP2_RESOURCEMAPPING_H_
 #define IDMAP2_INCLUDE_IDMAP2_RESOURCEMAPPING_H_
 
+#include <androidfw/ApkAssets.h>
+
 #include <map>
 #include <memory>
 #include <utility>
 
-#include "androidfw/ApkAssets.h"
+#include "idmap2/FabricatedOverlay.h"
 #include "idmap2/LogInfo.h"
 #include "idmap2/Policies.h"
 #include "idmap2/ResourceUtils.h"
 #include "idmap2/Result.h"
 #include "idmap2/XmlParser.h"
 
-using android::idmap2::utils::OverlayManifestInfo;
-
 using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
 
 namespace android::idmap2 {
-
-struct TargetValue {
-  typedef uint8_t DataType;
-  typedef uint32_t DataValue;
-  DataType data_type;
-  DataValue data_value;
-};
-
 using TargetResourceMap = std::map<ResourceId, std::variant<ResourceId, TargetValue>>;
 using OverlayResourceMap = std::map<ResourceId, ResourceId>;
 
@@ -49,94 +41,60 @@ class ResourceMapping {
   // Creates a ResourceMapping using the target and overlay APKs. Setting enforce_overlayable to
   // `false` disables all overlayable and policy enforcement: this is intended for backwards
   // compatibility pre-Q and unit tests.
-  static Result<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);
+  static Result<ResourceMapping> FromContainers(const TargetResourceContainer& target,
+                                                const OverlayResourceContainer& overlay,
+                                                const OverlayManifestInfo& overlay_info,
+                                                const PolicyBitmask& fulfilled_policies,
+                                                bool enforce_overlayable, LogInfo& log_info);
 
   // Retrieves the mapping of target resource id to overlay value.
-  inline const TargetResourceMap& GetTargetToOverlayMap() const {
-    return target_map_;
-  }
+  WARN_UNUSED const TargetResourceMap& GetTargetToOverlayMap() const;
 
   // Retrieves the mapping of overlay resource id to target resource id. This allows a reference to
   // an overlay resource to appear as a reference to its corresponding target resource at runtime.
-  OverlayResourceMap GetOverlayToTargetMap() const;
-
-  // Retrieves the build-time package id of the target package.
-  inline uint32_t GetTargetPackageId() const {
-    return target_package_id_;
-  }
-
-  // Retrieves the build-time package id of the overlay package.
-  inline uint32_t GetOverlayPackageId() const {
-    return overlay_package_id_;
-  }
+  WARN_UNUSED const OverlayResourceMap& GetOverlayToTargetMap() const;
 
   // Retrieves the offset that was added to the index of inline string overlay values so the indices
   // do not collide with the indices of the overlay resource table string pool.
-  inline uint32_t GetStringPoolOffset() const {
-    return string_pool_offset_;
-  }
+  WARN_UNUSED uint32_t GetStringPoolOffset() const;
 
   // Retrieves the raw string pool data from the xml referenced in android:resourcesMap.
-  inline const StringPiece GetStringPoolData() const {
-    return StringPiece(reinterpret_cast<const char*>(string_pool_data_.get()),
-                       string_pool_data_length_);
-  }
+  WARN_UNUSED StringPiece GetStringPoolData() const;
 
  private:
   ResourceMapping() = default;
 
-  // Maps a target resource id to an overlay resource id.
-  // If rewrite_overlay_reference is `true` then references to the overlay
-  // resource should appear as a reference to its corresponding target resource at runtime.
-  Result<Unit> AddMapping(ResourceId target_resource, ResourceId overlay_resource,
-                          bool rewrite_overlay_reference);
-
-  // Maps a target resource id to a data type and value combination.
-  // The `data_type` is the runtime format of the data value (see Res_value::dataType).
-  Result<Unit> AddMapping(ResourceId target_resource, TargetValue::DataType data_type,
-                          TargetValue::DataValue data_value);
-
-  // Removes the overlay value mapping for the target resource.
-  void RemoveMapping(ResourceId target_resource);
-
-  // Parses the mapping of target resources to overlay resources to generate a ResourceMapping.
-  static Result<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);
-
-  // Generates a ResourceMapping that maps target resources to overlay resources by name. To overlay
-  // a target resource, a resource must exist in the overlay with the same type and entry name as
-  // the target resource.
-  static Result<ResourceMapping> CreateResourceMappingLegacy(const AssetManager2* target_am,
-                                                             const AssetManager2* overlay_am,
-                                                             const LoadedPackage* target_package,
-                                                             const LoadedPackage* overlay_package,
-                                                             LogInfo& log_info);
-
-  // Removes resources that do not pass policy or overlayable checks of the target package.
-  void FilterOverlayableResources(const AssetManager2* target_am,
-                                  const LoadedPackage* target_package,
-                                  const LoadedPackage* overlay_package,
-                                  const OverlayManifestInfo& overlay_info,
-                                  const PolicyBitmask& fulfilled_policies, LogInfo& log_info);
+  // Maps a target resource id to an overlay resource id or a android::Res_value value.
+  //
+  // If `allow_rewriting_` is true, then the overlay-to-target map will be populated if the target
+  // resource id is mapped to an overlay resource id.
+  Result<Unit> AddMapping(ResourceId target_resource,
+                          const std::variant<OverlayData::ResourceIdValue, TargetValue>& value);
 
   TargetResourceMap target_map_;
-  std::multimap<ResourceId, ResourceId> overlay_map_;
-
-  uint32_t target_package_id_ = 0;
-  uint32_t overlay_package_id_ = 0;
+  OverlayResourceMap overlay_map_;
   uint32_t string_pool_offset_ = 0;
   uint32_t string_pool_data_length_ = 0;
   std::unique_ptr<uint8_t[]> string_pool_data_ = nullptr;
 };
 
+inline const TargetResourceMap& ResourceMapping::GetTargetToOverlayMap() const {
+  return target_map_;
+}
+
+inline const OverlayResourceMap& ResourceMapping::GetOverlayToTargetMap() const {
+  return overlay_map_;
+}
+
+inline uint32_t ResourceMapping::GetStringPoolOffset() const {
+  return string_pool_offset_;
+}
+
+inline StringPiece ResourceMapping::GetStringPoolData() const {
+  return StringPiece(reinterpret_cast<const char*>(string_pool_data_.get()),
+                     string_pool_data_length_);
+}
+
 }  // namespace android::idmap2
 
 #endif  // IDMAP2_INCLUDE_IDMAP2_RESOURCEMAPPING_H_
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index cd14d3e7254ca76421dc4d13a1785270fa0e821f..a0202dfee473f57ea2bf5a1d661e4dfc773b5668 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -22,19 +22,26 @@
 
 #include "androidfw/AssetManager2.h"
 #include "idmap2/Result.h"
-#include "idmap2/ZipFile.h"
 
 namespace android::idmap2 {
 
-// use typedefs to let the compiler warn us about implicit casts
-typedef uint32_t ResourceId;  // 0xpptteeee
-typedef uint8_t PackageId;    // pp in 0xpptteeee
-typedef uint8_t TypeId;       // tt in 0xpptteeee
-typedef uint16_t EntryId;     // eeee in 0xpptteeee
-
 #define EXTRACT_TYPE(resid) ((0x00ff0000 & (resid)) >> 16)
 #define EXTRACT_ENTRY(resid) (0x0000ffff & (resid))
 
+// use typedefs to let the compiler warn us about implicit casts
+using ResourceId = uint32_t;  // 0xpptteeee
+using PackageId = uint8_t;    // pp in 0xpptteeee
+using TypeId = uint8_t;       // tt in 0xpptteeee
+using EntryId = uint16_t;     // eeee in 0xpptteeee
+
+using DataType = uint8_t;    // Res_value::dataType
+using DataValue = uint32_t;  // Res_value::data
+
+struct TargetValue {
+  DataType data_type;
+  DataValue data_value;
+};
+
 namespace utils {
 
 // Returns whether the Res_value::data_type represents a dynamic or regular resource reference.
@@ -43,20 +50,10 @@ bool IsReference(uint8_t data_type);
 // Converts the Res_value::data_type to a human-readable string representation.
 StringPiece DataTypeToString(uint8_t data_type);
 
-struct OverlayManifestInfo {
-  std::string name;            // NOLINT(misc-non-private-member-variables-in-classes)
-  std::string target_package;  // NOLINT(misc-non-private-member-variables-in-classes)
-  std::string target_name;     // NOLINT(misc-non-private-member-variables-in-classes)
-  uint32_t resource_mapping;   // NOLINT(misc-non-private-member-variables-in-classes)
-};
-
-Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
-                                                       const std::string& name);
-
+// Retrieves the type and entry name of the resource in the AssetManager in the form type/entry.
 Result<std::string> ResToTypeEntryName(const AssetManager2& am, ResourceId resid);
 
 }  // namespace utils
-
 }  // namespace android::idmap2
 
 #endif  // IDMAP2_INCLUDE_IDMAP2_RESOURCEUTILS_H_
diff --git a/cmds/idmap2/include/idmap2/XmlParser.h b/cmds/idmap2/include/idmap2/XmlParser.h
index 1c74ab3bb691bb12464d82dd535feb2d3ea57a8a..c968a5e6c04fd16693262d0abcfc2421b265dbab 100644
--- a/cmds/idmap2/include/idmap2/XmlParser.h
+++ b/cmds/idmap2/include/idmap2/XmlParser.h
@@ -30,8 +30,7 @@
 
 namespace android::idmap2 {
 
-class XmlParser {
- public:
+struct XmlParser {
   using Event = ResXMLParser::event_code_t;
   class iterator;
 
@@ -127,23 +126,19 @@ class XmlParser {
   };
 
   // Creates a new xml parser beginning at the first tag.
-  static Result<std::unique_ptr<const XmlParser>> Create(const void* data, size_t size,
-                                                         bool copy_data = false);
-  ~XmlParser();
+  static Result<XmlParser> Create(const void* data, size_t size, bool copy_data = false);
 
   inline iterator tree_iterator() const {
-    return iterator(tree_);
+    return iterator(*tree_);
   }
 
   inline const ResStringPool& get_strings() const {
-    return tree_.getStrings();
+    return tree_->getStrings();
   }
 
  private:
-  XmlParser() = default;
-  mutable ResXMLTree tree_;
-
-  DISALLOW_COPY_AND_ASSIGN(XmlParser);
+  explicit XmlParser(std::unique_ptr<ResXMLTree> tree);
+  mutable std::unique_ptr<ResXMLTree> tree_;
 };
 
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/include/idmap2/ZipFile.h b/cmds/idmap2/include/idmap2/ZipFile.h
deleted file mode 100644
index 8f50e36256f6366730af0105c5731ee8c9600da0..0000000000000000000000000000000000000000
--- a/cmds/idmap2/include/idmap2/ZipFile.h
+++ /dev/null
@@ -1,60 +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.
- */
-
-#ifndef IDMAP2_INCLUDE_IDMAP2_ZIPFILE_H_
-#define IDMAP2_INCLUDE_IDMAP2_ZIPFILE_H_
-
-#include <memory>
-#include <string>
-
-#include "android-base/macros.h"
-#include "idmap2/Result.h"
-#include "ziparchive/zip_archive.h"
-
-namespace android::idmap2 {
-
-struct MemoryChunk {
-  size_t size;
-  uint8_t buf[0];
-
-  static std::unique_ptr<MemoryChunk> Allocate(size_t size);
-
- private:
-  MemoryChunk() {
-  }
-};
-
-class ZipFile {
- public:
-  static std::unique_ptr<const ZipFile> Open(const std::string& path);
-
-  std::unique_ptr<const MemoryChunk> Uncompress(const std::string& entryPath) const;
-  Result<uint32_t> Crc(const std::string& entryPath) const;
-
-  ~ZipFile();
-
- private:
-  explicit ZipFile(const ::ZipArchiveHandle handle) : handle_(handle) {
-  }
-
-  const ::ZipArchiveHandle handle_;
-
-  DISALLOW_COPY_AND_ASSIGN(ZipFile);
-};
-
-}  // namespace android::idmap2
-
-#endif  // IDMAP2_INCLUDE_IDMAP2_ZIPFILE_H_
diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
index c16310792d128a9c867422dd0e2586e64971b97e..3bbe9d91deb60b2e2f4d73aa05dfadd3b95fa288 100644
--- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
+++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
@@ -87,10 +87,6 @@ void BinaryStreamVisitor::visit(const IdmapData& data) {
 }
 
 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 0000000000000000000000000000000000000000..4a348ac232bc3144ed7bf4117809dc7b0978c27f
--- /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 a0cc407fc9484337d0bd326c69a49841422c76b2..6515d5516d83b8397c8f3072f0c795f9a030adc9 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 @@ bool WARN_UNUSED ReadString(std::istream& stream, std::string* out) {
 
 }  // 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 @@ std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& s
   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 @@ Result<Unit> IdmapHeader::IsUpToDate(const std::string& target_path,
 
 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 @@ Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping(
   }
 
   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 @@ Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping(
   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 7e090a983f95988e00a5b941fc2f64f62772965d..721612cc567b117205b52a72edcd1e166e7a4be8 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 Idmap& idmap ATTRIBUTE_UNUSED) {
 
 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 @@ void PrettyPrintVisitor::visit(const IdmapHeader& header) {
     }
   }
 
-  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::Header& header ATTRIBUTE_UNUSED)
 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 @@ void PrettyPrintVisitor::visit(const IdmapData& data) {
     }
 
     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 b517aa3a0c01b31f5bed394918366366318c985a..a016a36a2e3df5418324abb81051d71acd76e9d1 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 @@ void RawPrintVisitor::visit(const IdmapHeader& header) {
   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 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
     }
 
     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 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
 
   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 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
           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 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
 
   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 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
     }
 
     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& data ATTRIBUTE_UNUSED) {
 }
 
 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 0000000000000000000000000000000000000000..91cb43c216ef738eaeee9874420ad8ef77d6abee
--- /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 46eeb8e6ac80b61e512dd326131389675bbc778f..3bbbf248c87d6d5832f3a0fee80ddb92d8a82395 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 @@ std::string ConcatPolicies(const std::vector<std::string>& policies) {
   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 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
   // 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,317 +75,92 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
                      " <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;
-  }
-  int id = packages[0]->GetPackageId();
-  return loaded_arsc.GetPackageById(id);
-}
-
-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);
+std::string GetDebugResourceName(const ResourceContainer& container, ResourceId resid) {
+  auto name = container.GetResourceName(resid);
+  if (name) {
+    return *name;
   }
-
-  // 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;
+  return StringPrintf("0x%08x", resid);
 }
-
 }  // 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");
-  }
-
-  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) {
-      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")");
-    }
-
-    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");
+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();
+  }
+
+  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;
     }
 
-    // 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);
-    }
-  }
-
-  return resource_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;
+    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;
+      }
     }
 
-    // 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;
+    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());
     }
-
-    // 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);
+  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;
   }
 
-  for (const ResourceId target_resid : remove_ids) {
-    RemoveMapping(target_resid);
-  }
+  return std::move(mapping);
 }
 
-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);
-  }
-
-  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) {
+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);
   }
@@ -395,49 +168,19 @@ Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource, ResourceId
   // 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);
+  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));
+    }
+  } else {
+    auto overlay_value = std::get<TargetValue>(value);
+    target_map_.insert(std::make_pair(target_resource, overlay_value));
   }
 
-  // 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 4e85e57513003514caf62e83ec0a0dfa411aaf74..e809bf1f4b02ebb2068fca6f651dcc1a676254c2 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 @@ Result<std::string> ResToTypeEntryName(const AssetManager2& am, uint32_t resid)
   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 00baea46f90931b5271ce75690c08304992e3714..70822c8902881f1e6af9a43636a7cab38263b78c 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -151,16 +151,18 @@ Result<std::string> XmlParser::Node::GetAttributeStringValue(const std::string&
   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 @@ Result<std::unique_ptr<const XmlParser>> XmlParser::Create(const void* data, siz
     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 1e1a218163f042221088a612dbd216506607f519..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..a392b2b6d8566bdd56685f554930b466e705329f
--- /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
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index 524aabcec6521a35aa90223d5977cf52279579d3..bf63327427871210205ff0fa7098731e41bf676c 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -33,7 +33,7 @@ using ::testing::NotNull;
 namespace android::idmap2 {
 
 TEST(BinaryStreamVisitorTests, CreateBinaryStreamViaBinaryStreamVisitor) {
-  std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+  std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
   std::istringstream raw_stream(raw);
 
   auto result1 = Idmap::FromBinaryStream(raw_stream);
diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..79ab2438af74336cd55fa2e8b1f03d36d8be2361
--- /dev/null
+++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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 <android-base/file.h>
+#include <gtest/gtest.h>
+#include <idmap2/FabricatedOverlay.h>
+
+#include <fstream>
+
+namespace android::idmap2 {
+
+TEST(FabricatedOverlayTests, OverlayInfo) {
+  auto overlay =
+      FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
+          .SetOverlayable("TestResources")
+          .Build();
+
+  ASSERT_TRUE(overlay);
+  auto container = FabricatedOverlayContainer::FromOverlay(std::move(*overlay));
+  auto info = container->FindOverlayInfo("SandTheme");
+  ASSERT_TRUE(info);
+  EXPECT_EQ("SandTheme", (*info).name);
+  EXPECT_EQ("TestResources", (*info).target_name);
+
+  info = container->FindOverlayInfo("OceanTheme");
+  ASSERT_FALSE(info);
+}
+
+TEST(FabricatedOverlayTests, SetResourceValue) {
+  auto overlay =
+      FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
+          .SetResourceValue("com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U)
+          .SetResourceValue("com.example.target.split:integer/int2", Res_value::TYPE_INT_DEC, 2U)
+          .SetResourceValue("string/int3", Res_value::TYPE_REFERENCE, 0x7f010000)
+          .Build();
+  ASSERT_TRUE(overlay);
+  auto container = FabricatedOverlayContainer::FromOverlay(std::move(*overlay));
+  auto info = container->FindOverlayInfo("SandTheme");
+  ASSERT_TRUE(info);
+  ASSERT_TRUE((*info).target_name.empty());
+
+  auto crc = (*container).GetCrc();
+  ASSERT_TRUE(crc) << crc.GetErrorMessage();
+  EXPECT_NE(0U, *crc);
+
+  auto pairs = container->GetOverlayData(*info);
+  ASSERT_TRUE(pairs);
+  EXPECT_FALSE(pairs->string_pool_data.has_value());
+  ASSERT_EQ(3U, pairs->pairs.size());
+
+  auto& it = pairs->pairs[0];
+  ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
+  auto entry = std::get_if<TargetValue>(&it.value);
+  ASSERT_NE(nullptr, entry);
+  ASSERT_EQ(1U, entry->data_value);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->data_type);
+
+  it = pairs->pairs[1];
+  ASSERT_EQ("com.example.target:string/int3", it.resource_name);
+  entry = std::get_if<TargetValue>(&it.value);
+  ASSERT_NE(nullptr, entry);
+  ASSERT_EQ(0x7f010000, entry->data_value);
+  ASSERT_EQ(Res_value::TYPE_REFERENCE, entry->data_type);
+
+  it = pairs->pairs[2];
+  ASSERT_EQ("com.example.target.split:integer/int2", it.resource_name);
+  entry = std::get_if<TargetValue>(&it.value);
+  ASSERT_NE(nullptr, entry);
+  ASSERT_EQ(2U, entry->data_value);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->data_type);
+}
+
+TEST(FabricatedOverlayTests, SetResourceValueBadArgs) {
+  {
+    auto builder =
+        FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
+            .SetResourceValue("int1", Res_value::TYPE_INT_DEC, 1U);
+    ASSERT_FALSE(builder.Build());
+  }
+  {
+    auto builder =
+        FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
+            .SetResourceValue("com.example.target:int2", Res_value::TYPE_INT_DEC, 1U);
+    ASSERT_FALSE(builder.Build());
+  }
+}
+
+TEST(FabricatedOverlayTests, SerializeAndDeserialize) {
+  auto overlay =
+      FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
+          .SetOverlayable("TestResources")
+          .SetResourceValue("com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U)
+          .Build();
+  ASSERT_TRUE(overlay);
+  TemporaryFile tf;
+  std::ofstream out(tf.path);
+  ASSERT_TRUE((*overlay).ToBinaryStream(out));
+  out.close();
+
+  auto container = OverlayResourceContainer::FromPath(tf.path);
+  ASSERT_TRUE(container) << container.GetErrorMessage();
+  EXPECT_EQ(tf.path, (*container)->GetPath());
+
+  auto crc = (*container)->GetCrc();
+  ASSERT_TRUE(crc) << crc.GetErrorMessage();
+  EXPECT_NE(0U, *crc);
+
+  auto info = (*container)->FindOverlayInfo("SandTheme");
+  ASSERT_TRUE(info) << info.GetErrorMessage();
+  EXPECT_EQ("SandTheme", (*info).name);
+  EXPECT_EQ("TestResources", (*info).target_name);
+
+  auto pairs = (*container)->GetOverlayData(*info);
+  ASSERT_TRUE(pairs) << pairs.GetErrorMessage();
+  EXPECT_EQ(1U, pairs->pairs.size());
+
+  auto& it = pairs->pairs[0];
+  ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
+  auto entry = std::get_if<TargetValue>(&it.value);
+  ASSERT_NE(nullptr, entry);
+  EXPECT_EQ(1U, entry->data_value);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, entry->data_type);
+}
+
+}  // namespace android::idmap2
\ No newline at end of file
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 16b68f01e8f5adfa17c6024d2d66676c4cc36529..9516ff83d7184f6113fd2efd6cd4725be0e3164b 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <android-base/file.h>
+
 #include <cstdio>  // fclose
 #include <fstream>
 #include <memory>
@@ -61,12 +63,12 @@ TEST(IdmapTests, TestCanonicalIdmapPathFor) {
 }
 
 TEST(IdmapTests, CreateIdmapHeaderFromBinaryStream) {
-  std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+  std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
   std::istringstream stream(raw);
   std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
   ASSERT_THAT(header, NotNull());
   ASSERT_EQ(header->GetMagic(), 0x504d4449U);
-  ASSERT_EQ(header->GetVersion(), 0x07U);
+  ASSERT_EQ(header->GetVersion(), 0x08U);
   ASSERT_EQ(header->GetTargetCrc(), 0x1234U);
   ASSERT_EQ(header->GetOverlayCrc(), 0x5678U);
   ASSERT_EQ(header->GetFulfilledPolicies(), 0x11);
@@ -81,7 +83,7 @@ TEST(IdmapTests, IdmapFailParsingDifferentVersion) {
   std::stringstream stream;
   stream << android::kIdmapMagic;
   stream << 0xffffffffU;
-  stream << std::string(kJunkSize, (char) 0xffU);
+  stream << std::string(kJunkSize, (char)0xffU);
   ASSERT_FALSE(Idmap::FromBinaryStream(stream));
 }
 
@@ -90,14 +92,13 @@ TEST(IdmapTests, IdmapFailParsingDifferentMagic) {
   std::stringstream stream;
   stream << 0xffffffffU;
   stream << android::kIdmapCurrentVersion;
-  stream << std::string(kJunkSize, (char) 0xffU);
+  stream << std::string(kJunkSize, (char)0xffU);
   ASSERT_FALSE(Idmap::FromBinaryStream(stream));
 }
 
 TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) {
   const size_t offset = kIdmapRawDataOffset;
-  std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset),
-                  kIdmapRawDataLen - offset);
+  std::string raw(reinterpret_cast<const char*>(kIdmapRawData + offset), kIdmapRawDataLen - offset);
   std::istringstream stream(raw);
 
   std::unique_ptr<const IdmapData::Header> header = IdmapData::Header::FromBinaryStream(stream);
@@ -108,8 +109,7 @@ TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) {
 
 TEST(IdmapTests, CreateIdmapDataFromBinaryStream) {
   const size_t offset = kIdmapRawDataOffset;
-  std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset),
-                  kIdmapRawDataLen - offset);
+  std::string raw(reinterpret_cast<const char*>(kIdmapRawData + offset), kIdmapRawDataLen - offset);
   std::istringstream stream(raw);
 
   std::unique_ptr<const IdmapData> data = IdmapData::FromBinaryStream(stream);
@@ -134,7 +134,7 @@ TEST(IdmapTests, CreateIdmapDataFromBinaryStream) {
 }
 
 TEST(IdmapTests, CreateIdmapFromBinaryStream) {
-  std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+  std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
   std::istringstream stream(raw);
 
   auto result = Idmap::FromBinaryStream(stream);
@@ -143,7 +143,7 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) {
 
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
-  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x07U);
+  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x08U);
   ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U);
   ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), kIdmapRawDataPolicies);
@@ -177,7 +177,7 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) {
 }
 
 TEST(IdmapTests, GracefullyFailToCreateIdmapFromCorruptBinaryStream) {
-  std::string raw(reinterpret_cast<const char*>(idmap_raw_data),
+  std::string raw(reinterpret_cast<const char*>(kIdmapRawData),
                   10);  // data too small
   std::istringstream stream(raw);
 
@@ -189,14 +189,14 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) {
   std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
   std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk";
 
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
+  auto target = TargetResourceContainer::FromPath(target_apk_path);
+  ASSERT_TRUE(target);
 
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
+  auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+  ASSERT_TRUE(overlay);
 
-  auto idmap_result = Idmap::FromApkAssets(
-      *target_apk, *overlay_apk, TestConstants::OVERLAY_NAME_ALL_POLICIES, PolicyFlags::PUBLIC,
+  auto idmap_result = Idmap::FromContainers(
+      **target, **overlay, TestConstants::OVERLAY_NAME_ALL_POLICIES, PolicyFlags::PUBLIC,
       /* enforce_overlayable */ true);
   ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
   auto& idmap = *idmap_result;
@@ -204,7 +204,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) {
 
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
-  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x07U);
+  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x08U);
   ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC);
   ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), PolicyFlags::PUBLIC);
@@ -218,15 +218,15 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssets) {
   std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
   std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk";
 
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
+  auto target = TargetResourceContainer::FromPath(target_apk_path);
+  ASSERT_TRUE(target);
 
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
+  auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+  ASSERT_TRUE(overlay);
 
-  auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk,
-                                           TestConstants::OVERLAY_NAME_DEFAULT, PolicyFlags::PUBLIC,
-                                           /* enforce_overlayable */ true);
+  auto idmap_result = Idmap::FromContainers(
+      **target, **overlay, TestConstants::OVERLAY_NAME_DEFAULT, PolicyFlags::PUBLIC,
+      /* enforce_overlayable */ true);
   ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
   auto& idmap = *idmap_result;
   ASSERT_THAT(idmap, NotNull());
@@ -255,25 +255,66 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssets) {
   ASSERT_OVERLAY_ENTRY(overlay_entries[3], R::overlay::string::str4, R::target::string::str4);
 }
 
+TEST(IdmapTests, FabricatedOverlay) {
+  std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+  auto target = TargetResourceContainer::FromPath(target_apk_path);
+  ASSERT_TRUE(target);
+
+  auto frro = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "test.target")
+                  .SetOverlayable("TestResources")
+                  .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U)
+                  .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000)
+                  .Build();
+
+  ASSERT_TRUE(frro);
+  TemporaryFile tf;
+  std::ofstream out(tf.path);
+  ASSERT_TRUE((*frro).ToBinaryStream(out));
+  out.close();
+
+  auto overlay = OverlayResourceContainer::FromPath(tf.path);
+  ASSERT_TRUE(overlay);
+
+  auto idmap_result = Idmap::FromContainers(**target, **overlay, "SandTheme", PolicyFlags::PUBLIC,
+                                            /* enforce_overlayable */ true);
+  ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
+  auto& idmap = *idmap_result;
+  ASSERT_THAT(idmap, NotNull());
+
+  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+  ASSERT_EQ(dataBlocks.size(), 1U);
+
+  const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+  ASSERT_THAT(data, NotNull());
+  ASSERT_EQ(data->GetTargetEntries().size(), 0U);
+  ASSERT_EQ(data->GetOverlayEntries().size(), 0U);
+
+  const auto& target_inline_entries = data->GetTargetInlineEntries();
+  ASSERT_EQ(target_inline_entries.size(), 2U);
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1,
+                             Res_value::TYPE_INT_DEC, 2U);
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1,
+                             Res_value::TYPE_REFERENCE, 0x7f010000);
+}
+
 TEST(IdmapTests, FailCreateIdmapInvalidName) {
   std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
   std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk";
 
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
+  auto target = TargetResourceContainer::FromPath(target_apk_path);
+  ASSERT_TRUE(target);
 
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
+  auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+  ASSERT_TRUE(overlay);
 
   {
-    auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, "", PolicyFlags::PUBLIC,
-                                             /* enforce_overlayable */ true);
+    auto idmap_result = Idmap::FromContainers(**target, **overlay, "", PolicyFlags::PUBLIC,
+                                              /* enforce_overlayable */ true);
     ASSERT_FALSE(idmap_result);
   }
   {
-    auto idmap_result =
-        Idmap::FromApkAssets(*target_apk, *overlay_apk, "unknown", PolicyFlags::PUBLIC,
-                             /* enforce_overlayable */ true);
+    auto idmap_result = Idmap::FromContainers(**target, **overlay, "unknown", PolicyFlags::PUBLIC,
+                                              /* enforce_overlayable */ true);
     ASSERT_FALSE(idmap_result);
   }
 }
@@ -282,15 +323,15 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssetsSharedLibOverlay) {
   std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
   std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay-shared.apk";
 
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
+  auto target = TargetResourceContainer::FromPath(target_apk_path);
+  ASSERT_TRUE(target);
 
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
+  auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+  ASSERT_TRUE(overlay);
 
-  auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk,
-                                           TestConstants::OVERLAY_NAME_DEFAULT, PolicyFlags::PUBLIC,
-                                           /* enforce_overlayable */ true);
+  auto idmap_result = Idmap::FromContainers(
+      **target, **overlay, TestConstants::OVERLAY_NAME_DEFAULT, PolicyFlags::PUBLIC,
+      /* enforce_overlayable */ true);
   ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
   auto& idmap = *idmap_result;
   ASSERT_THAT(idmap, NotNull());
@@ -328,30 +369,29 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssetsSharedLibOverlay) {
 }
 
 Result<std::unique_ptr<const IdmapData>> TestIdmapDataFromApkAssets(
-    const std::string& local_target_apk_path, const std::string& local_overlay_apk_path,
+    const std::string& local_target_path, const std::string& local_overlay_path,
     const std::string& overlay_name, const PolicyBitmask& fulfilled_policies,
     bool enforce_overlayable) {
-  auto overlay_info =
-      utils::ExtractOverlayManifestInfo(GetTestDataPath() + local_overlay_apk_path, overlay_name);
-  if (!overlay_info) {
-    return overlay_info.GetError();
+  const std::string target_path(GetTestDataPath() + local_target_path);
+  auto target = TargetResourceContainer::FromPath(target_path);
+  if (!target) {
+    return Error(R"(Failed to load target "%s")", target_path.c_str());
   }
 
-  const std::string target_apk_path(GetTestDataPath() + local_target_apk_path);
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  if (!target_apk) {
-    return Error(R"(Failed to load target apk "%s")", target_apk_path.data());
+  const std::string overlay_path(GetTestDataPath() + local_overlay_path);
+  auto overlay = OverlayResourceContainer::FromPath(overlay_path);
+  if (!overlay) {
+    return Error(R"(Failed to load overlay "%s")", overlay_path.c_str());
   }
 
-  const std::string overlay_apk_path(GetTestDataPath() + local_overlay_apk_path);
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  if (!overlay_apk) {
-    return Error(R"(Failed to load overlay apk "%s")", overlay_apk_path.data());
+  auto overlay_info = (*overlay)->FindOverlayInfo(overlay_name);
+  if (!overlay_info) {
+    return Error(R"(Failed to find overlay name "%s")", overlay_name.c_str());
   }
 
   LogInfo log_info;
-  auto mapping = ResourceMapping::FromApkAssets(*target_apk, *overlay_apk, *overlay_info,
-                                                fulfilled_policies, enforce_overlayable, log_info);
+  auto mapping = ResourceMapping::FromContainers(**target, **overlay, *overlay_info,
+                                                 fulfilled_policies, enforce_overlayable, log_info);
   if (!mapping) {
     return mapping.GetError();
   }
@@ -360,11 +400,9 @@ Result<std::unique_ptr<const IdmapData>> TestIdmapDataFromApkAssets(
 }
 
 TEST(IdmapTests, CreateIdmapDataDoNotRewriteNonOverlayResourceId) {
-  auto idmap_data =
-      TestIdmapDataFromApkAssets("/target/target.apk", "/overlay/overlay.apk", "DifferentPackages",
-
-                                 PolicyFlags::PUBLIC,
-                                 /* enforce_overlayable */ false);
+  auto idmap_data = TestIdmapDataFromApkAssets("/target/target.apk", "/overlay/overlay.apk",
+                                               "DifferentPackages", PolicyFlags::PUBLIC,
+                                               /* enforce_overlayable */ false);
 
   ASSERT_TRUE(idmap_data) << idmap_data.GetErrorMessage();
   auto& data = *idmap_data;
@@ -417,7 +455,7 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
   const uint32_t target_crc = kIdmapRawDataTargetCrc;
   const uint32_t overlay_crc = kIdmapRawOverlayCrc;
 
-  std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+  std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
   std::istringstream raw_stream(raw);
 
   auto result = Idmap::FromBinaryStream(raw_stream);
@@ -468,8 +506,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
   ASSERT_THAT(bad_target_crc_header, NotNull());
   ASSERT_NE(header->GetTargetCrc(), bad_target_crc_header->GetTargetCrc());
   ASSERT_FALSE(bad_target_crc_header->IsUpToDate(target_apk_path, overlay_apk_path, overlay_name,
-                                            target_crc, overlay_crc, policies,
-                                            /* enforce_overlayable */ true));
+                                                 target_crc, overlay_crc, policies,
+                                                 /* enforce_overlayable */ true));
 
   // overlay crc: bytes (0xc, 0xf)
   std::string bad_overlay_crc_string(stream.str());
@@ -483,8 +521,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
   ASSERT_THAT(bad_overlay_crc_header, NotNull());
   ASSERT_NE(header->GetOverlayCrc(), bad_overlay_crc_header->GetOverlayCrc());
   ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate(target_apk_path, overlay_apk_path, overlay_name,
-                                            target_crc, overlay_crc, policies,
-                                            /* enforce_overlayable */ true));
+                                                  target_crc, overlay_crc, policies,
+                                                  /* enforce_overlayable */ true));
 
   // fulfilled policy: bytes (0x10, 0x13)
   std::string bad_policy_string(stream.str());
@@ -522,8 +560,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
   ASSERT_THAT(bad_target_path_header, NotNull());
   ASSERT_NE(header->GetTargetPath(), bad_target_path_header->GetTargetPath());
   ASSERT_FALSE(bad_target_path_header->IsUpToDate(target_apk_path, overlay_apk_path, overlay_name,
-                                            target_crc, overlay_crc, policies,
-                                            /* enforce_overlayable */ true));
+                                                  target_crc, overlay_crc, policies,
+                                                  /* enforce_overlayable */ true));
 
   // overlay path: bytes (0x2c, 0x37)
   std::string bad_overlay_path_string(stream.str());
@@ -576,7 +614,7 @@ class TestVisitor : public Visitor {
 };
 
 TEST(IdmapTests, TestVisitor) {
-  std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+  std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
   std::istringstream stream(raw);
 
   const auto idmap = Idmap::FromBinaryStream(stream);
diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
index 87ce0f13d19ed914cbe449df64bade40c9eec493..3d3d82a8c7dd667d752db233ddfc72a5c7591a44 100644
--- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
@@ -27,35 +27,31 @@
 #include "idmap2/Idmap.h"
 #include "idmap2/PrettyPrintVisitor.h"
 
-using android::ApkAssets;
 using android::base::StringPrintf;
-using ::testing::NotNull;
 
-using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
 
 namespace android::idmap2 {
 
 TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitor) {
   const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
+  auto target = TargetResourceContainer::FromPath(target_apk_path);
+  ASSERT_TRUE(target);
 
   const std::string overlay_apk_path(GetTestDataPath() + "/overlay/overlay.apk");
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
+  auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+  ASSERT_TRUE(overlay);
 
-  const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk,
-                                          TestConstants::OVERLAY_NAME_DEFAULT, PolicyFlags::PUBLIC,
-                                          /* enforce_overlayable */ true);
+  const auto idmap = Idmap::FromContainers(**target, **overlay, TestConstants::OVERLAY_NAME_DEFAULT,
+                                           PolicyFlags::PUBLIC, /* enforce_overlayable */ true);
   ASSERT_TRUE(idmap);
 
   std::stringstream stream;
   PrettyPrintVisitor visitor(stream);
   (*idmap)->accept(&visitor);
 
-  ASSERT_NE(stream.str().find("target apk path  : "), std::string::npos);
-  ASSERT_NE(stream.str().find("overlay apk path : "), std::string::npos);
+  ASSERT_NE(stream.str().find("target path  : "), std::string::npos);
+  ASSERT_NE(stream.str().find("overlay path : "), std::string::npos);
   ASSERT_NE(stream.str().find(StringPrintf("0x%08x -> 0x%08x (integer/int1 -> integer/int1)\n",
                                            R::target::integer::int1, R::overlay::integer::int1)),
             std::string::npos);
@@ -64,7 +60,7 @@ TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitor) {
 TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitorWithoutAccessToApks) {
   fclose(stderr);  // silence expected warnings from libandroidfw
 
-  std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+  std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
   std::istringstream raw_stream(raw);
 
   const auto idmap = Idmap::FromBinaryStream(raw_stream);
@@ -74,8 +70,8 @@ TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitorWithoutAccessToApks) {
   PrettyPrintVisitor visitor(stream);
   (*idmap)->accept(&visitor);
 
-  ASSERT_NE(stream.str().find("target apk path  : "), std::string::npos);
-  ASSERT_NE(stream.str().find("overlay apk path : "), std::string::npos);
+  ASSERT_NE(stream.str().find("target path  : "), std::string::npos);
+  ASSERT_NE(stream.str().find("overlay path : "), std::string::npos);
   ASSERT_NE(stream.str().find("0x7f020000 -> 0x7f020000 (\?\?\? -> \?\?\?)\n"), std::string::npos);
 }
 
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 88f85efb0f84b8bddd6839b5a47ea79088c96c16..a6371cb74f2e7dc3bd34198639f7732f6e6a7892 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -30,17 +30,16 @@
 #include "idmap2/RawPrintVisitor.h"
 
 using android::base::StringPrintf;
-using ::testing::NotNull;
 
 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
 
 namespace android::idmap2 {
 
-#define ASSERT_CONTAINS_REGEX(pattern, str)                       \
-  do {                                                            \
-    ASSERT_TRUE(std::regex_search(str, std::regex(pattern)))      \
-        << "pattern '" << pattern << "' not found in\n--------\n" \
-        << str << "--------";                                     \
+#define ASSERT_CONTAINS_REGEX(pattern, str)                         \
+  do {                                                              \
+    ASSERT_TRUE(std::regex_search(str, std::regex(pattern)))        \
+        << "pattern '" << (pattern) << "' not found in\n--------\n" \
+        << (str) << "--------";                                     \
   } while (0)
 
 #define ADDRESS "[0-9a-f]{8}: "
@@ -49,16 +48,15 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
   fclose(stderr);  // silence expected warnings
 
   const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
+  auto target = TargetResourceContainer::FromPath(target_apk_path);
+  ASSERT_TRUE(target);
 
   const std::string overlay_apk_path(GetTestDataPath() + "/overlay/overlay.apk");
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
+  auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+  ASSERT_TRUE(overlay);
 
-  const auto idmap =
-      Idmap::FromApkAssets(*target_apk, *overlay_apk, TestConstants::OVERLAY_NAME_DEFAULT,
-                           PolicyFlags::PUBLIC, /* enforce_overlayable */ true);
+  const auto idmap = Idmap::FromContainers(**target, **overlay, TestConstants::OVERLAY_NAME_DEFAULT,
+                                           PolicyFlags::PUBLIC, /* enforce_overlayable */ true);
   ASSERT_TRUE(idmap);
 
   std::stringstream stream;
@@ -66,7 +64,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
   (*idmap)->accept(&visitor);
 
   ASSERT_CONTAINS_REGEX(ADDRESS "504d4449  magic\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "00000007  version\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "00000008  version\n", stream.str());
   ASSERT_CONTAINS_REGEX(
       StringPrintf(ADDRESS "%s  target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING),
       stream.str());
@@ -75,8 +73,6 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
       stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000001  fulfilled policies: public\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000001  enforce overlayable\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "      7f  target package id\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "      7f  overlay package id\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000004  target entry count", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000000  target inline entry count", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000004  overlay entry count", stream.str());
@@ -104,7 +100,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
 TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
   fclose(stderr);  // silence expected warnings from libandroidfw
 
-  std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+  std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
   std::istringstream raw_stream(raw);
 
   const auto idmap = Idmap::FromBinaryStream(raw_stream);
@@ -115,7 +111,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
   (*idmap)->accept(&visitor);
 
   ASSERT_CONTAINS_REGEX(ADDRESS "504d4449  magic\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "00000007  version\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "00000008  version\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00001234  target crc\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00005678  overlay crc\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000011  fulfilled policies: public|signature\n", stream.str());
@@ -126,8 +122,6 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
   ASSERT_CONTAINS_REGEX(ADDRESS "........  overlay path: overlayX.apk\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "0000000b  overlay name size\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "........  overlay name: OverlayName\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "      7f  target package id\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "      7f  overlay package id\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000003  target entry count\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000001  target inline entry count\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000003  overlay entry count\n", stream.str());
@@ -140,7 +134,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
   ASSERT_CONTAINS_REGEX(ADDRESS "7f020000  overlay id\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f030002  target id\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000004  string pool size\n", stream.str());
-  ASSERT_CONTAINS_REGEX("000000a8: ........  string pool\n", stream.str());
+  ASSERT_CONTAINS_REGEX("000000a4: ........  string pool\n", stream.str());
 }
 
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 0362529c4f3b508c32ed9521807cc08730aa7595..5a1d808af06f28f0cf362610ae8ea3f139eb635c 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#include <android-base/file.h>
+#include <androidfw/ResourceTypes.h>
+#include <gtest/gtest.h>
+
 #include <cstdio>  // fclose
 #include <fstream>
 #include <memory>
@@ -22,14 +26,10 @@
 #include "R.h"
 #include "TestConstants.h"
 #include "TestHelpers.h"
-#include "androidfw/ResourceTypes.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
 #include "idmap2/LogInfo.h"
 #include "idmap2/ResourceMapping.h"
 
 using android::Res_value;
-using android::idmap2::utils::ExtractOverlayManifestInfo;
 
 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
 
@@ -41,32 +41,36 @@ namespace android::idmap2 {
     ASSERT_TRUE(result) << result.GetErrorMessage(); \
   } while (0)
 
-Result<ResourceMapping> TestGetResourceMapping(const std::string& local_target_apk_path,
-                                               const std::string& local_overlay_apk_path,
+Result<ResourceMapping> TestGetResourceMapping(const std::string& local_target_path,
+                                               const std::string& local_overlay_path,
                                                const std::string& overlay_name,
                                                const PolicyBitmask& fulfilled_policies,
                                                bool enforce_overlayable) {
-  auto overlay_info =
-      ExtractOverlayManifestInfo(GetTestDataPath() + local_overlay_apk_path, overlay_name);
-  if (!overlay_info) {
-    return overlay_info.GetError();
+  const std::string target_path = (local_target_path[0] == '/')
+                                      ? local_target_path
+                                      : (GetTestDataPath() + "/" + local_target_path);
+  auto target = TargetResourceContainer::FromPath(target_path);
+  if (!target) {
+    return Error(target.GetError(), R"(Failed to load target "%s")", target_path.c_str());
   }
 
-  const std::string target_apk_path(GetTestDataPath() + local_target_apk_path);
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  if (!target_apk) {
-    return Error(R"(Failed to load target apk "%s")", target_apk_path.data());
+  const std::string overlay_path = (local_overlay_path[0] == '/')
+                                       ? local_overlay_path
+                                       : (GetTestDataPath() + "/" + local_overlay_path);
+  auto overlay = OverlayResourceContainer::FromPath(overlay_path);
+  if (!overlay) {
+    return Error(overlay.GetError(), R"(Failed to load overlay "%s")", overlay_path.c_str());
   }
 
-  const std::string overlay_apk_path(GetTestDataPath() + local_overlay_apk_path);
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  if (!overlay_apk) {
-    return Error(R"(Failed to load overlay apk "%s")", overlay_apk_path.data());
+  auto overlay_info = (*overlay)->FindOverlayInfo(overlay_name);
+  if (!overlay_info) {
+    return Error(overlay_info.GetError(), R"(Failed to find overlay name "%s")",
+                 overlay_name.c_str());
   }
 
   LogInfo log_info;
-  return ResourceMapping::FromApkAssets(*target_apk, *overlay_apk, *overlay_info,
-                                        fulfilled_policies, enforce_overlayable, log_info);
+  return ResourceMapping::FromContainers(**target, **overlay, *overlay_info, fulfilled_policies,
+                                         enforce_overlayable, log_info);
 }
 
 Result<Unit> MappingExists(const ResourceMapping& mapping, ResourceId target_resource,
@@ -128,7 +132,7 @@ Result<Unit> MappingExists(const ResourceMapping& mapping, const ResourceId& tar
 }
 
 TEST(ResourceMappingTests, ResourcesFromApkAssetsLegacy) {
-  auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay-legacy.apk", "",
+  auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay-legacy.apk", "",
                                           PolicyFlags::PUBLIC, /* enforce_overlayable */ false);
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
@@ -145,7 +149,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsLegacy) {
 }
 
 TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) {
-  auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", "SwapNames",
+  auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk", "SwapNames",
                                           PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ false);
 
@@ -161,7 +165,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) {
 }
 
 TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) {
-  auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk",
+  auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
                                           "DifferentPackages", PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ false);
 
@@ -176,7 +180,7 @@ TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) {
 }
 
 TEST(ResourceMappingTests, InlineResources) {
-  auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", "Inline",
+  auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk", "Inline",
                                           PolicyFlags::PUBLIC, /* enforce_overlayable */ false);
 
   constexpr size_t overlay_string_pool_size = 10U;
@@ -189,8 +193,32 @@ TEST(ResourceMappingTests, InlineResources) {
   ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 73U));
 }
 
+TEST(ResourceMappingTests, FabricatedOverlay) {
+  auto frro = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "test.target")
+                  .SetOverlayable("TestResources")
+                  .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U)
+                  .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000)
+                  .Build();
+
+  ASSERT_TRUE(frro);
+  TemporaryFile tf;
+  std::ofstream out(tf.path);
+  ASSERT_TRUE((*frro).ToBinaryStream(out));
+  out.close();
+
+  auto resources = TestGetResourceMapping("target/target.apk", tf.path, "SandTheme",
+                                          PolicyFlags::PUBLIC, /* enforce_overlayable */ false);
+
+  ASSERT_TRUE(resources) << resources.GetErrorMessage();
+  auto& res = *resources;
+  ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
+  ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
+  ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE, 0x7f010000));
+  ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 2U));
+}
+
 TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
-  auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk",
+  auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
                                           TestConstants::OVERLAY_NAME_ALL_POLICIES,
                                           PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ true);
@@ -209,7 +237,7 @@ TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
 // Resources that are not declared as overlayable and resources that a protected by policies the
 // overlay does not fulfill must not map to overlay resources.
 TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
-  auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk",
+  auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
                                           TestConstants::OVERLAY_NAME_ALL_POLICIES,
                                           PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ true);
@@ -229,7 +257,7 @@ TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
 // overlay does not fulfilled can map to overlay resources when overlayable enforcement is turned
 // off.
 TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
-  auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk",
+  auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
                                           TestConstants::OVERLAY_NAME_ALL_POLICIES,
                                           PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ false);
@@ -264,7 +292,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore
 // Overlays that do not target an <overlayable> tag can overlay any resource if overlayable
 // enforcement is disabled.
 TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTargetName) {
-  auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay-legacy.apk", "",
+  auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay-legacy.apk", "",
                                           PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ false);
 
@@ -284,10 +312,9 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTarget
 // Overlays that are neither pre-installed nor signed with the same signature as the target cannot
 // overlay packages that have not defined overlayable resources.
 TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
-  auto resources =
-      TestGetResourceMapping("/target/target-no-overlayable.apk", "/overlay/overlay.apk",
-                             "NoTargetName", PolicyFlags::PUBLIC,
-                             /* enforce_overlayable */ true);
+  auto resources = TestGetResourceMapping("target/target-no-overlayable.apk", "overlay/overlay.apk",
+                                          "NoTargetName", PolicyFlags::PUBLIC,
+                                          /* enforce_overlayable */ true);
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
   ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
@@ -297,9 +324,9 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
 // signed with the same signature as the reference package can overlay packages that have not
 // defined overlayable resources.
 TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
-  auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void {
+  auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) {
     auto resources =
-        TestGetResourceMapping("/target/target-no-overlayable.apk", "/overlay/overlay.apk",
+        TestGetResourceMapping("target/target-no-overlayable.apk", "overlay/overlay.apk",
                                TestConstants::OVERLAY_NAME_ALL_POLICIES, fulfilled_policies,
                                /* enforce_overlayable */ true);
 
diff --git a/cmds/idmap2/tests/ResourceUtilsTests.cpp b/cmds/idmap2/tests/ResourceUtilsTests.cpp
index 1f6bf49f5f0e1bdaafb752a861d6abbc8e939d55..69142086765c07b75a3814c06e7b8f1514c8b09b 100644
--- a/cmds/idmap2/tests/ResourceUtilsTests.cpp
+++ b/cmds/idmap2/tests/ResourceUtilsTests.cpp
@@ -17,10 +17,12 @@
 #include <memory>
 #include <string>
 
+#include "R.h"
 #include "TestHelpers.h"
 #include "androidfw/ApkAssets.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "idmap2/ResourceContainer.h"
 #include "idmap2/ResourceUtils.h"
 #include "idmap2/Result.h"
 
@@ -49,8 +51,8 @@ class ResourceUtilsTests : public Idmap2Tests {
 };
 
 TEST_F(ResourceUtilsTests, ResToTypeEntryName) {
-  Result<std::string> name = utils::ResToTypeEntryName(GetAssetManager(), 0x7f010000U);
-  ASSERT_TRUE(name);
+  Result<std::string> name = utils::ResToTypeEntryName(GetAssetManager(), R::target::integer::int1);
+  ASSERT_TRUE(name) << name.GetErrorMessage();
   ASSERT_EQ(*name, "integer/int1");
 }
 
@@ -60,25 +62,34 @@ TEST_F(ResourceUtilsTests, ResToTypeEntryNameNoSuchResourceId) {
 }
 
 TEST_F(ResourceUtilsTests, InvalidValidOverlayNameInvalidAttributes) {
-  auto info = utils::ExtractOverlayManifestInfo(GetTestDataPath() + "/overlay/overlay-invalid.apk",
-                                                "InvalidName");
+  auto overlay =
+      OverlayResourceContainer::FromPath(GetTestDataPath() + "/overlay/overlay-invalid.apk");
+  ASSERT_TRUE(overlay);
+
+  auto info = (*overlay)->FindOverlayInfo("InvalidName");
   ASSERT_FALSE(info);
 }
 
 TEST_F(ResourceUtilsTests, ValidOverlayNameInvalidAttributes) {
-  auto info = utils::ExtractOverlayManifestInfo(GetTestDataPath() + "/overlay/overlay-invalid.apk",
-                                                "ValidName");
+  auto overlay =
+      OverlayResourceContainer::FromPath(GetTestDataPath() + "/overlay/overlay-invalid.apk");
+  ASSERT_TRUE(overlay);
+
+  auto info = (*overlay)->FindOverlayInfo("ValidName");
   ASSERT_FALSE(info);
 }
 
 TEST_F(ResourceUtilsTests, ValidOverlayNameAndTargetPackageInvalidAttributes) {
-  auto info = utils::ExtractOverlayManifestInfo(GetTestDataPath() + "/overlay/overlay-invalid.apk",
-                                                "ValidNameAndTargetPackage");
+  auto overlay =
+      OverlayResourceContainer::FromPath(GetTestDataPath() + "/overlay/overlay-invalid.apk");
+  ASSERT_TRUE(overlay);
+
+  auto info = (*overlay)->FindOverlayInfo("ValidNameAndTargetPackage");
   ASSERT_TRUE(info);
   ASSERT_EQ("ValidNameAndTargetPackage", info->name);
   ASSERT_EQ("Valid", info->target_package);
-  ASSERT_EQ("", info->target_name); // Attribute resource id could not be found
-  ASSERT_EQ(0, info->resource_mapping); // Attribute resource id could not be found
+  ASSERT_EQ("", info->target_name);      // Attribute resource id could not be found
+  ASSERT_EQ(0, info->resource_mapping);  // Attribute resource id could not be found
 }
 
-}// namespace android::idmap2
+}  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h
index 842af3dd7b3c0fa6914ffa153c0e748a8f0a7cc1..6b5f3a8a98eb9f5950d2e4f206efc0abb3e9fe16 100644
--- a/cmds/idmap2/tests/TestHelpers.h
+++ b/cmds/idmap2/tests/TestHelpers.h
@@ -24,13 +24,13 @@
 
 namespace android::idmap2 {
 
-const unsigned char idmap_raw_data[] = {
+const unsigned char kIdmapRawData[] = {
     // IDMAP HEADER
     // 0x0: magic
     0x49, 0x44, 0x4d, 0x50,
 
     // 0x4: version
-    0x07, 0x00, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x00,
 
     // 0x8: target crc
     0x34, 0x12, 0x00, 0x00,
@@ -70,81 +70,72 @@ const unsigned char idmap_raw_data[] = {
     0x64, 0x65, 0x62, 0x75, 0x67, 0x00, 0x00, 0x00,
 
     // DATA HEADER
-    // 0x54: target_package_id
-    0x7f,
-
-    // 0x55: overlay_package_id
-    0x7f,
-
-    // 0x56: padding
-    0x00, 0x00,
-
-    // 0x58: target_entry_count
+    // 0x54: target_entry_count
     0x03, 0x00, 0x00, 0x00,
 
-    // 0x5c: target_inline_entry_count
+    // 0x58: target_inline_entry_count
     0x01, 0x00, 0x00, 0x00,
 
-    // 0x60: overlay_entry_count
+    // 0x5c: overlay_entry_count
     0x03, 0x00, 0x00, 0x00,
 
-    // 0x64: string_pool_offset
+    // 0x60: string_pool_offset
     0x00, 0x00, 0x00, 0x00,
 
     // TARGET ENTRIES
-    // 0x68: target id (0x7f020000)
+    // 0x64: target id (0x7f020000)
     0x00, 0x00, 0x02, 0x7f,
 
-    // 0x6c: overlay_id (0x7f020000)
+    // 0x68: overlay_id (0x7f020000)
     0x00, 0x00, 0x02, 0x7f,
 
-    // 0x70: target id (0x7f030000)
+    // 0x6c: target id (0x7f030000)
     0x00, 0x00, 0x03, 0x7f,
 
-    // 0x74: overlay_id (0x7f030000)
+    // 0x70: overlay_id (0x7f030000)
     0x00, 0x00, 0x03, 0x7f,
 
-    // 0x78: target id (0x7f030002)
+    // 0x74: target id (0x7f030002)
     0x02, 0x00, 0x03, 0x7f,
 
-    // 0x7c: overlay_id (0x7f030001)
+    // 0x78: overlay_id (0x7f030001)
     0x01, 0x00, 0x03, 0x7f,
 
     // INLINE TARGET ENTRIES
 
-    // 0x80: target_id
+    // 0x7c: target_id
     0x00, 0x00, 0x04, 0x7f,
 
-    // 0x84: Res_value::size (value ignored by idmap)
+    // 0x80: Res_value::size (value ignored by idmap)
     0x08, 0x00,
 
-    // 0x87: Res_value::res0 (value ignored by idmap)
+    // 0x82: Res_value::res0 (value ignored by idmap)
     0x00,
 
-    // 0x88: Res_value::dataType (TYPE_INT_HEX)
+    // 0x83: Res_value::dataType (TYPE_INT_HEX)
     0x11,
 
-    // 0x8c: Res_value::data
+    // 0x84: Res_value::data
     0x78, 0x56, 0x34, 0x12,
 
     // OVERLAY ENTRIES
-    // 0x90: 0x7f020000 -> 0x7f020000
+    // 0x88: 0x7f020000 -> 0x7f020000
     0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f,
 
-    // 0x98: 0x7f030000 -> 0x7f030000
+    // 0x90: 0x7f030000 -> 0x7f030000
     0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f,
 
-    // 0xa0: 0x7f030001 -> 0x7f030002
+    // 0x98: 0x7f030001 -> 0x7f030002
     0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f,
 
-    // 0xa4: string pool
+    // 0xa0: string pool
     // string length,
     0x04, 0x00, 0x00, 0x00,
 
-    // 0xa8 string contents "test"
+    // 0xa4 string contents "test"
     0x74, 0x65, 0x73, 0x74};
 
-const unsigned int kIdmapRawDataLen = 0xac;
+const unsigned int kIdmapRawDataLen = 0xa8;
 const unsigned int kIdmapRawDataOffset = 0x54;
 const unsigned int kIdmapRawDataTargetCrc = 0x1234;
 const unsigned int kIdmapRawOverlayCrc = 0x5678;
diff --git a/cmds/idmap2/tests/XmlParserTests.cpp b/cmds/idmap2/tests/XmlParserTests.cpp
index 1a7eaca4d67b977e5fa939fd5c1fc4390b65dfab..eaf10a7d9282f310a78e81dd09af7854a5babbf9 100644
--- a/cmds/idmap2/tests/XmlParserTests.cpp
+++ b/cmds/idmap2/tests/XmlParserTests.cpp
@@ -19,25 +19,25 @@
 #include <string>
 
 #include "TestHelpers.h"
-#include "gmock/gmock.h"
+#include "androidfw/AssetsProvider.h"
 #include "gtest/gtest.h"
 #include "idmap2/XmlParser.h"
-#include "idmap2/ZipFile.h"
 
 namespace android::idmap2 {
 
-Result<std::unique_ptr<const XmlParser>> CreateTestParser(const std::string& test_file) {
-  auto zip = ZipFile::Open(GetTestDataPath() + "/target/target.apk");
+Result<XmlParser> CreateTestParser(const std::string& test_file) {
+  auto zip = ZipAssetsProvider::Create(GetTestDataPath() + "/target/target.apk");
   if (zip == nullptr) {
     return Error("Failed to open zip file");
   }
 
-  auto data = zip->Uncompress(test_file);
+  auto data = zip->Open(test_file);
   if (data == nullptr) {
     return Error("Failed to open xml file");
   }
 
-  return XmlParser::Create(data->buf, data->size, /* copy_data */ true);
+  return XmlParser::Create(data->getBuffer(true /* aligned*/), data->getLength(),
+                           /* copy_data */ true);
 }
 
 TEST(XmlParserTests, Create) {
@@ -54,7 +54,7 @@ TEST(XmlParserTests, NextChild) {
   auto xml = CreateTestParser("res/xml/test.xml");
   ASSERT_TRUE(xml) << xml.GetErrorMessage();
 
-  auto root_iter = (*xml)->tree_iterator();
+  auto root_iter = xml->tree_iterator();
   ASSERT_EQ(root_iter->event(), XmlParser::Event::START_TAG);
   ASSERT_EQ(root_iter->name(), "a");
 
@@ -85,7 +85,7 @@ TEST(XmlParserTests, AttributeValues) {
   ASSERT_TRUE(xml) << xml.GetErrorMessage();
 
   // Start at the <a> tag.
-  auto root_iter = (*xml)->tree_iterator();
+  auto root_iter = xml->tree_iterator();
 
   // Start at the <b> tag.
   auto a_iter = root_iter.begin();
@@ -111,8 +111,8 @@ TEST(XmlParserTests, IteratorEquality) {
   ASSERT_TRUE(xml) << xml.GetErrorMessage();
 
   // Start at the <a> tag.
-  auto root_iter_1 = (*xml)->tree_iterator();
-  auto root_iter_2 = (*xml)->tree_iterator();
+  auto root_iter_1 = xml->tree_iterator();
+  auto root_iter_2 = xml->tree_iterator();
   ASSERT_EQ(root_iter_1, root_iter_2);
   ASSERT_EQ(*root_iter_1, *root_iter_2);
 
@@ -146,7 +146,7 @@ TEST(XmlParserTests, Backtracking) {
   ASSERT_TRUE(xml) << xml.GetErrorMessage();
 
   // Start at the <a> tag.
-  auto root_iter_1 = (*xml)->tree_iterator();
+  auto root_iter_1 = xml->tree_iterator();
 
   // Start at the <b> tag.
   auto a_iter_1 = root_iter_1.begin();
diff --git a/cmds/idmap2/tests/ZipFileTests.cpp b/cmds/idmap2/tests/ZipFileTests.cpp
deleted file mode 100644
index 3fca43621945ee67b68411ce2c4f519b1c749963..0000000000000000000000000000000000000000
--- a/cmds/idmap2/tests/ZipFileTests.cpp
+++ /dev/null
@@ -1,66 +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 <cstdio>  // fclose
-#include <string>
-
-#include "TestHelpers.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "idmap2/Result.h"
-#include "idmap2/ZipFile.h"
-
-using ::testing::IsNull;
-using ::testing::NotNull;
-
-namespace android::idmap2 {
-
-TEST(ZipFileTests, BasicOpen) {
-  auto zip = ZipFile::Open(GetTestDataPath() + "/target/target.apk");
-  ASSERT_THAT(zip, NotNull());
-
-  fclose(stderr);  // silence expected warnings from libziparchive
-  auto fail = ZipFile::Open(GetTestDataPath() + "/does-not-exist");
-  ASSERT_THAT(fail, IsNull());
-}
-
-TEST(ZipFileTests, Crc) {
-  auto zip = ZipFile::Open(GetTestDataPath() + "/target/target.apk");
-  ASSERT_THAT(zip, NotNull());
-
-  Result<uint32_t> crc = zip->Crc("AndroidManifest.xml");
-  ASSERT_TRUE(crc);
-  ASSERT_EQ(*crc, 0x762f3d24);
-
-  Result<uint32_t> crc2 = zip->Crc("does-not-exist");
-  ASSERT_FALSE(crc2);
-}
-
-TEST(ZipFileTests, Uncompress) {
-  auto zip = ZipFile::Open(GetTestDataPath() + "/target/target.apk");
-  ASSERT_THAT(zip, NotNull());
-
-  auto data = zip->Uncompress("assets/lorem-ipsum.txt");
-  ASSERT_THAT(data, NotNull());
-  const std::string lorem_ipsum("Lorem ipsum dolor sit amet.\n");
-  ASSERT_THAT(data->size, lorem_ipsum.size());
-  ASSERT_THAT(std::string(reinterpret_cast<const char*>(data->buf), data->size), lorem_ipsum);
-
-  auto fail = zip->Uncompress("does-not-exist");
-  ASSERT_THAT(fail, IsNull());
-}
-
-}  // namespace android::idmap2
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index f1998a583a21a820fd37b8cd0ee55fe02a90811b..af06e2e80cec5086f0025e04e5e9593413a0f700 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -188,7 +188,7 @@ static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t forma
   ATRACE_NAME(base::StringPrintf("LoadApkAssets(%s)", path.c_str()).c_str());
 
   auto loader_assets = LoaderAssetsProvider::Create(env, assets_provider);
-  std::unique_ptr<const ApkAssets> apk_assets;
+  std::unique_ptr<ApkAssets> apk_assets;
   switch (format) {
     case FORMAT_APK: {
       auto assets = MultiAssetsProvider::Create(std::move(loader_assets),
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml
index 38e5fa18300cc8de27eb871f773bbc40cfebf72f..926b1864d97c6db3e89e37d99abdbae478e64e88 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml
@@ -25,7 +25,6 @@
     <item target="integer/matrix_100100" value="@integer/matrix_100100"/>
     <item target="integer/matrix_100101" value="@integer/matrix_100101"/>
     <item target="integer/matrix_100110" value="@integer/matrix_100110"/>
-    <item target="integer/matrix_100110" value="@integer/matrix_100110"/>
     <item target="integer/matrix_100111" value="@integer/matrix_100111"/>
     <item target="integer/matrix_101000" value="@integer/matrix_101000"/>
     <item target="integer/matrix_101001" value="@integer/matrix_101001"/>
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index ca5981c0dd5cb83076123ca821ef80706cfbeb06..9c743cea592a6c03d6df5980af826973d71b0e64 100755
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -83,8 +83,16 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
     return {};
   }
 
+  std::unique_ptr<AssetsProvider> overlay_assets;
   const std::string overlay_path(loaded_idmap->OverlayApkPath());
-  auto overlay_assets = ZipAssetsProvider::Create(overlay_path);
+  if (IsFabricatedOverlay(overlay_path)) {
+    // Fabricated overlays do not contain resource definitions. All of the overlay resource values
+    // are defined inline in the idmap.
+    overlay_assets = EmptyAssetsProvider::Create();
+  } else {
+    // The overlay should be an APK.
+    overlay_assets = ZipAssetsProvider::Create(overlay_path);
+  }
   if (overlay_assets == nullptr) {
     return {};
   }
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 03ab62f48870b9e0dd8ce083d9583942506fd4a4..36bde5ccf267b84ea633e931b6bd66f47c07c4f3 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -102,9 +102,8 @@ AssetManager2::AssetManager2() {
   memset(&configuration_, 0, sizeof(configuration_));
 }
 
-bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
-                                 bool invalidate_caches) {
-  apk_assets_ = apk_assets;
+bool AssetManager2::SetApkAssets(std::vector<const ApkAssets*> apk_assets, bool invalidate_caches) {
+  apk_assets_ = std::move(apk_assets);
   BuildDynamicRefTable();
   RebuildFilterList();
   if (invalidate_caches) {
@@ -137,6 +136,36 @@ void AssetManager2::BuildDynamicRefTable() {
   // 0x01 is reserved for the android package.
   int next_package_id = 0x02;
   for (const ApkAssets* apk_assets : sorted_apk_assets) {
+    std::shared_ptr<OverlayDynamicRefTable> overlay_ref_table;
+    if (auto loaded_idmap = apk_assets->GetLoadedIdmap(); loaded_idmap != nullptr) {
+      // The target package must precede the overlay package in the apk assets paths in order
+      // to take effect.
+      auto iter = apk_assets_package_ids.find(std::string(loaded_idmap->TargetApkPath()));
+      if (iter == apk_assets_package_ids.end()) {
+         LOG(INFO) << "failed to find target package for overlay "
+                   << loaded_idmap->OverlayApkPath();
+      } else {
+        uint8_t target_package_id = iter->second;
+
+        // Create a special dynamic reference table for the overlay to rewrite references to
+        // overlay resources as references to the target resources they overlay.
+        overlay_ref_table = std::make_shared<OverlayDynamicRefTable>(
+            loaded_idmap->GetOverlayDynamicRefTable(target_package_id));
+
+        // Add the overlay resource map to the target package's set of overlays.
+        const uint8_t target_idx = package_ids_[target_package_id];
+        CHECK(target_idx != 0xff) << "overlay target '" << loaded_idmap->TargetApkPath()
+                                  << "'added to apk_assets_package_ids but does not have an"
+                                  << " assigned package group";
+
+        PackageGroup& target_package_group = package_groups_[target_idx];
+        target_package_group.overlays_.push_back(
+            ConfiguredOverlay{loaded_idmap->GetTargetResourcesMap(target_package_id,
+                                                                  overlay_ref_table.get()),
+                              apk_assets_cookies[apk_assets]});
+      }
+    }
+
     const LoadedArsc* loaded_arsc = apk_assets->GetLoadedArsc();
     for (const std::unique_ptr<const LoadedPackage>& package : loaded_arsc->GetPackages()) {
       // Get the package ID or assign one if a shared library.
@@ -147,50 +176,25 @@ void AssetManager2::BuildDynamicRefTable() {
         package_id = package->GetPackageId();
       }
 
-      // Add the mapping for package ID to index if not present.
       uint8_t idx = package_ids_[package_id];
       if (idx == 0xff) {
+        // Add the mapping for package ID to index if not present.
         package_ids_[package_id] = idx = static_cast<uint8_t>(package_groups_.size());
-        package_groups_.push_back({});
-
-        if (apk_assets->IsOverlay()) {
-          // The target package must precede the overlay package in the apk assets paths in order
-          // to take effect.
-          const auto& loaded_idmap = apk_assets->GetLoadedIdmap();
-          auto target_package_iter = apk_assets_package_ids.find(
-              std::string(loaded_idmap->TargetApkPath()));
-          if (target_package_iter == apk_assets_package_ids.end()) {
-             LOG(INFO) << "failed to find target package for overlay "
-                       << loaded_idmap->OverlayApkPath();
-          } else {
-            const uint8_t target_package_id = target_package_iter->second;
-            const uint8_t target_idx = package_ids_[target_package_id];
-            CHECK(target_idx != 0xff) << "overlay added to apk_assets_package_ids but does not"
-                                      << " have an assigned package group";
-
-            PackageGroup& target_package_group = package_groups_[target_idx];
-
-            // Create a special dynamic reference table for the overlay to rewrite references to
-            // overlay resources as references to the target resources they overlay.
-            auto overlay_table = std::make_shared<OverlayDynamicRefTable>(
-                loaded_idmap->GetOverlayDynamicRefTable(target_package_id));
-            package_groups_.back().dynamic_ref_table = overlay_table;
-
-            // Add the overlay resource map to the target package's set of overlays.
-            target_package_group.overlays_.push_back(
-                ConfiguredOverlay{loaded_idmap->GetTargetResourcesMap(target_package_id,
-                                                                      overlay_table.get()),
-                                  apk_assets_cookies[apk_assets]});
-          }
+        PackageGroup& new_group = package_groups_.emplace_back();
+
+        if (overlay_ref_table != nullptr) {
+          // If this package is from an overlay, use a dynamic reference table that can rewrite
+          // overlay resource ids to their corresponding target resource ids.
+          new_group.dynamic_ref_table = overlay_ref_table;
         }
 
-        DynamicRefTable* ref_table = package_groups_.back().dynamic_ref_table.get();
+        DynamicRefTable* ref_table = new_group.dynamic_ref_table.get();
         ref_table->mAssignedPackageId = package_id;
         ref_table->mAppAsLib = package->IsDynamic() && package->GetPackageId() == 0x7f;
       }
-      PackageGroup* package_group = &package_groups_[idx];
 
       // Add the package and to the set of packages with the same ID.
+      PackageGroup* package_group = &package_groups_[idx];
       package_group->packages_.push_back(ConfiguredPackage{package.get(), {}});
       package_group->cookies_.push_back(apk_assets_cookies[apk_assets]);
 
@@ -578,7 +582,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
 
   const PackageGroup& package_group = package_groups_[package_idx];
   auto result = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
-                                 stop_at_first_match, ignore_configuration);
+                                  stop_at_first_match, ignore_configuration);
   if (UNLIKELY(!result.has_value())) {
     return base::unexpected(result.error());
   }
diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp
index 23cacf88a6db56ddf5f637b4d4624cb135e667f0..f3c48f7f9fc84a69c4d080065084e7e52263350c 100644
--- a/libs/androidfw/AssetsProvider.cpp
+++ b/libs/androidfw/AssetsProvider.cpp
@@ -84,7 +84,7 @@ const std::string& ZipAssetsProvider::PathOrDebugName::GetDebugName() const {
   return value_;
 }
 
-ZipAssetsProvider::ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path,
+ZipAssetsProvider::ZipAssetsProvider(ZipArchiveHandle handle, PathOrDebugName&& path,
                                      time_t last_mod_time)
     : zip_handle_(handle, ::CloseArchive),
       name_(std::forward<PathOrDebugName>(path)),
@@ -93,7 +93,7 @@ ZipAssetsProvider::ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path,
 std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path) {
   ZipArchiveHandle handle;
   if (int32_t result = OpenArchive(path.c_str(), &handle); result != 0) {
-    LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
+    LOG(ERROR) << "Failed to open APK '" << path << "': " << ::ErrorCodeString(result);
     CloseArchive(handle);
     return {};
   }
@@ -253,6 +253,14 @@ bool ZipAssetsProvider::ForEachFile(const std::string& root_path,
     return result == -1;
 }
 
+std::optional<uint32_t> ZipAssetsProvider::GetCrc(std::string_view path) const {
+  ::ZipEntry entry;
+  if (FindEntry(zip_handle_.get(), path, &entry) != 0) {
+    return {};
+  }
+  return entry.crc32;
+}
+
 const std::string& ZipAssetsProvider::GetDebugName() const {
   return name_.GetDebugName();
 }
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index f216f55771c21fde1958f9496a8748e138d56f03..efd1f6a25786a31579babdae9a3afa29b44d0537 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -54,12 +54,6 @@ struct Idmap_header {
 };
 
 struct Idmap_data_header {
-  uint8_t target_package_id;
-  uint8_t overlay_package_id;
-
-  // Padding to ensure 4 byte alignment for target_entry_count
-  uint16_t p0;
-
   uint32_t target_entry_count;
   uint32_t target_inline_entry_count;
   uint32_t overlay_entry_count;
@@ -158,19 +152,19 @@ IdmapResMap::Result IdmapResMap::Lookup(uint32_t target_res_id) const {
     return {};
   }
 
-  // The resource ids encoded within the idmap are build-time resource ids.
-  target_res_id = (0x00FFFFFFU & target_res_id)
-      | (((uint32_t) data_header_->target_package_id) << 24U);
+  // The resource ids encoded within the idmap are build-time resource ids so do not consider the
+  // package id when determining if the resource in the target package is overlaid.
+  target_res_id &= 0x00FFFFFFU;
 
   // Check if the target resource is mapped to an overlay resource.
   auto first_entry = entries_;
   auto end_entry = entries_ + dtohl(data_header_->target_entry_count);
   auto entry = std::lower_bound(first_entry, end_entry, target_res_id,
-                                [](const Idmap_target_entry &e, const uint32_t target_id) {
-    return dtohl(e.target_id) < target_id;
+                                [](const Idmap_target_entry& e, const uint32_t target_id) {
+    return (0x00FFFFFFU & dtohl(e.target_id)) < target_id;
   });
 
-  if (entry != end_entry && dtohl(entry->target_id) == target_res_id) {
+  if (entry != end_entry && (0x00FFFFFFU & dtohl(entry->target_id)) == target_res_id) {
     uint32_t overlay_resource_id = dtohl(entry->overlay_id);
     // Lookup the resource without rewriting the overlay resource id back to the target resource id
     // being looked up.
@@ -182,12 +176,13 @@ IdmapResMap::Result IdmapResMap::Lookup(uint32_t target_res_id) const {
   auto first_inline_entry = inline_entries_;
   auto end_inline_entry = inline_entries_ + dtohl(data_header_->target_inline_entry_count);
   auto inline_entry = std::lower_bound(first_inline_entry, end_inline_entry, target_res_id,
-                                       [](const Idmap_target_entry_inline &e,
+                                       [](const Idmap_target_entry_inline& e,
                                           const uint32_t target_id) {
-    return dtohl(e.target_id) < target_id;
+    return (0x00FFFFFFU & dtohl(e.target_id)) < target_id;
   });
 
-  if (inline_entry != end_inline_entry && dtohl(inline_entry->target_id) == target_res_id) {
+  if (inline_entry != end_inline_entry &&
+      (0x00FFFFFFU & dtohl(inline_entry->target_id)) == target_res_id) {
     return Result(inline_entry->value);
   }
   return {};
@@ -235,7 +230,7 @@ std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size
   }
   return std::string_view(data, *len);
 }
-}
+} // namespace
 
 LoadedIdmap::LoadedIdmap(std::string&& idmap_path,
                          const Idmap_header* header,
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 223382731bc017c20a2f02ec56fd87f08bb40c37..30500abc39c028cac74ea1dc3c859da61dad9801 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -25,6 +25,7 @@
 #include <string.h>
 
 #include <algorithm>
+#include <fstream>
 #include <limits>
 #include <map>
 #include <memory>
@@ -44,6 +45,7 @@
 
 #ifdef __ANDROID__
 #include <binder/TextOutput.h>
+
 #endif
 
 #ifndef INT32_MAX
@@ -233,6 +235,15 @@ void Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs
     fill9patchOffsets(reinterpret_cast<Res_png_9patch*>(outData));
 }
 
+bool IsFabricatedOverlay(const std::string& path) {
+  std::ifstream fin(path);
+  uint32_t magic;
+  if (fin.read(reinterpret_cast<char*>(&magic), sizeof(uint32_t))) {
+    return magic == kFabricatedOverlayMagic;
+  }
+  return false;
+}
+
 static bool assertIdmapHeader(const void* idmap, size_t size) {
     if (reinterpret_cast<uintptr_t>(idmap) & 0x03) {
         ALOGE("idmap: header is not word aligned");
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 6fbd6aa0df7b47d4e1e855432f24da499e346eb5..2255973f10391f65463e06a6747e520458699a70 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -101,7 +101,7 @@ class AssetManager2 {
   // Only pass invalidate_caches=false when it is known that the structure
   // change in ApkAssets is due to a safe addition of resources with completely
   // new resource IDs.
-  bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true);
+  bool SetApkAssets(std::vector<const ApkAssets*> apk_assets, bool invalidate_caches = true);
 
   inline const std::vector<const ApkAssets*> GetApkAssets() const {
     return apk_assets_;
diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h
index 7b06947f45aace68a785bcceae197d053ddfe436..6f16ff453905fc5c73eea912cd584a4a005f7167 100644
--- a/libs/androidfw/include/androidfw/AssetsProvider.h
+++ b/libs/androidfw/include/androidfw/AssetsProvider.h
@@ -88,6 +88,8 @@ struct ZipAssetsProvider : public AssetsProvider {
   WARN_UNUSED const std::string& GetDebugName() const override;
   WARN_UNUSED bool IsUpToDate() const override;
 
+  WARN_UNUSED std::optional<uint32_t> GetCrc(std::string_view path) const;
+
   ~ZipAssetsProvider() override = default;
  protected:
   std::unique_ptr<Asset> OpenInternal(const std::string& path, Asset::AccessMode mode,
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index 0ded79309bc1010677f69b8f0c567c8c3d696f96..6804472b3d173a9881279a5ae4ef632d6d11987a 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -168,15 +168,14 @@ class LoadedIdmap {
   }
 
   // Returns a mapping from target resource ids to overlay values.
-  const IdmapResMap GetTargetResourcesMap(
-      uint8_t target_assigned_package_id, const OverlayDynamicRefTable* overlay_ref_table) const {
+  const IdmapResMap GetTargetResourcesMap(uint8_t target_assigned_package_id,
+                                          const OverlayDynamicRefTable* overlay_ref_table) const {
     return IdmapResMap(data_header_, target_entries_, target_inline_entries_,
                        target_assigned_package_id, overlay_ref_table);
   }
 
   // Returns a dynamic reference table for a loaded overlay package.
-  const OverlayDynamicRefTable GetOverlayDynamicRefTable(
-      uint8_t target_assigned_package_id) const {
+  const OverlayDynamicRefTable GetOverlayDynamicRefTable(uint8_t target_assigned_package_id) const {
     return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id);
   }
 
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index bfd564c258ee7601385f00fd1d10a7e4c8bb200b..168a863df2bc1198716638f81dc4d420d8bedf61 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -43,8 +43,19 @@
 
 namespace android {
 
-constexpr const static uint32_t kIdmapMagic = 0x504D4449u;
-constexpr const static uint32_t kIdmapCurrentVersion = 0x00000007u;
+constexpr const uint32_t kIdmapMagic = 0x504D4449u;
+constexpr const uint32_t kIdmapCurrentVersion = 0x00000008u;
+
+// This must never change.
+constexpr const uint32_t kFabricatedOverlayMagic = 0x4f525246; // FRRO (big endian)
+
+// The version should only be changed when a backwards-incompatible change must be made to the
+// fabricated overlay file format. Old fabricated overlays must be migrated to the new file format
+// to prevent losing fabricated overlay data.
+constexpr const uint32_t kFabricatedOverlayCurrentVersion = 1;
+
+// Returns whether or not the path represents a fabricated overlay.
+bool IsFabricatedOverlay(const std::string& path);
 
 /**
  * In C++11, char16_t is defined as *at least* 16 bits. We do a lot of
diff --git a/libs/androidfw/tests/data/overlay/overlay.idmap b/libs/androidfw/tests/data/overlay/overlay.idmap
index 723413c3cea87aa8306952de0638db9eba854a95..88eadccb38cf63c58de22232f152901695bbfea3 100644
Binary files a/libs/androidfw/tests/data/overlay/overlay.idmap and b/libs/androidfw/tests/data/overlay/overlay.idmap differ