Add enforcement of idmap policies

Teaches idmap2 to recognize policy restrictions put on overlayable
resources. If overlayable enforcement is turned on for an overlay, then
any resources defined within the overlayable api of the target will have
policy restrictions imposed on them. All resources without overlayable
definitions will continue to be overlayable without policy restrictions.

Bug: 119390857
Test: atest idmap2 and booting

Co-authored-by: Ryan Mitchell <rtmitchell@google.com>
Change-Id: I7e435648eb6e4a87b0b90a7b2a0c3f33c1516ea6
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index 2698ac0..35ec1ff 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -78,7 +78,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
@@ -101,25 +102,52 @@
   header = loaded_idmap->GetEntryMapForType(0x02);
   ASSERT_THAT(header, NotNull());
 
-  success = LoadedIdmap::Lookup(header, 0x0002, &entry);
+  success = LoadedIdmap::Lookup(header, 0x0000, &entry);  // string/a
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0003, &entry);
+  success = LoadedIdmap::Lookup(header, 0x0001, &entry);  // string/b
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0002, &entry);  // string/c
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0003, &entry);  // string/not_overlayable
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0004, &entry);  // string/policy_product
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0005, &entry);  // string/policy_public
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0006, &entry);  // string/policy_system
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0007, &entry);  // string/policy_system_vendor
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0008, &entry);  // string/str1
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0000);
 
-  success = LoadedIdmap::Lookup(header, 0x0004, &entry);
+  success = LoadedIdmap::Lookup(header, 0x0009, &entry);  // string/str2
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0005, &entry);
+  success = LoadedIdmap::Lookup(header, 0x000a, &entry);  // string/str3
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0001);
 
-  success = LoadedIdmap::Lookup(header, 0x0006, &entry);
+  success = LoadedIdmap::Lookup(header, 0x000b, &entry);  // string/str4
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0002);
 
-  success = LoadedIdmap::Lookup(header, 0x0007, &entry);
+  success = LoadedIdmap::Lookup(header, 0x000c, &entry);  // string/x
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x000d, &entry);  // string/y
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x000e, &entry);  // string/z
   ASSERT_FALSE(success);
 }
 
diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
index c27d27a..39f18d3 100644
--- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp
+++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
@@ -121,6 +121,56 @@
   ASSERT_FALSE(success);
 }
 
+TEST(CommandLineOptionsTests, OptionalOptionList) {
+  std::vector<std::string> foo;
+  std::vector<std::string> bar;
+  CommandLineOptions opts = CommandLineOptions("test")
+                                .OptionalOption("--foo", "", &foo)
+                                .OptionalOption("--bar", "", &bar);
+  std::ostream fakeStdErr(nullptr);
+  bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+  ASSERT_TRUE(success);
+  ASSERT_EQ(foo.size(), 1U);
+  ASSERT_EQ(foo[0], "FOO");
+  ASSERT_EQ(bar.size(), 1U);
+  ASSERT_EQ(bar[0], "BAR");
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo", "BAZ"}, fakeStdErr);
+  ASSERT_TRUE(success);
+  ASSERT_EQ(foo.size(), 1U);
+  ASSERT_EQ(foo[0], "BAZ");
+  ASSERT_EQ(bar.size(), 0U);
+
+  foo.clear();
+  bar.clear();
+  success =
+      opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"}, fakeStdErr);
+  ASSERT_TRUE(success);
+  ASSERT_EQ(foo.size(), 2U);
+  ASSERT_EQ(foo[0], "BAZ");
+  ASSERT_EQ(foo[1], "BIZ");
+  ASSERT_EQ(bar.size(), 2U);
+  ASSERT_EQ(bar[0], "FIZ");
+  ASSERT_EQ(bar[1], "FUZZ");
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo"}, fakeStdErr);
+  ASSERT_FALSE(success);
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr);
+  ASSERT_FALSE(success);
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr);
+  ASSERT_FALSE(success);
+}
+
 TEST(CommandLineOptionsTests, CornerCases) {
   std::string foo;
   std::string bar;
@@ -172,6 +222,7 @@
   bool arg5 = false;
   bool arg6 = false;
   std::vector<std::string> arg7;
+  std::vector<std::string> arg8;
   CommandLineOptions opts = CommandLineOptions("test")
                                 .MandatoryOption("--aa", "description-aa", &arg1)
                                 .OptionalFlag("--bb", "description-bb", &arg5)
@@ -179,12 +230,13 @@
                                 .OptionalOption("--dd", "description-dd", &arg3)
                                 .MandatoryOption("--ee", "description-ee", &arg4)
                                 .OptionalFlag("--ff", "description-ff", &arg6)
-                                .MandatoryOption("--gg", "description-gg", &arg7);
+                                .MandatoryOption("--gg", "description-gg", &arg7)
+                                .OptionalOption("--hh", "description-hh", &arg8);
   std::stringstream stream;
   opts.Usage(stream);
   const std::string s = stream.str();
   ASSERT_NE(s.find("usage: test --aa arg [--bb] [--cc arg] [--dd arg] --ee arg [--ff] --gg arg "
-                   "[--gg arg [..]]"),
+                   "[--gg arg [..]] [--hh arg [..]]"),
             std::string::npos);
   ASSERT_NE(s.find("--aa arg    description-aa"), std::string::npos);
   ASSERT_NE(s.find("--ff        description-ff"), std::string::npos);
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index 4bf832a..d9d9a7f 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -37,10 +37,10 @@
                             [](unsigned char type ATTRIBUTE_UNUSED,
                                const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; });
   ASSERT_THAT(v, NotNull());
-  ASSERT_EQ(v->size(), 4U);
-  ASSERT_EQ(
-      std::set<std::string>(v->begin(), v->end()),
-      std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target"}));
+  ASSERT_EQ(v->size(), 6U);
+  ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
+            std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target",
+                                   root + "/system-overlay", root + "/system-overlay-invalid"}));
 }
 
 TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) {
@@ -49,11 +49,13 @@
     return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0;
   });
   ASSERT_THAT(v, NotNull());
-  ASSERT_EQ(v->size(), 4U);
+  ASSERT_EQ(v->size(), 6U);
   ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
             std::set<std::string>({root + "/target/target.apk", root + "/overlay/overlay.apk",
                                    root + "/overlay/overlay-static-1.apk",
-                                   root + "/overlay/overlay-static-2.apk"}));
+                                   root + "/overlay/overlay-static-2.apk",
+                                   root + "/system-overlay/system-overlay.apk",
+                                   root + "/system-overlay-invalid/system-overlay-invalid.apk"}));
 }
 
 TEST(FileUtilsTests, ReadFile) {
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 22f48e9..0c8f164 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -38,6 +38,7 @@
 #include "gtest/gtest.h"
 
 #include "androidfw/PosixUtils.h"
+
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
 
@@ -114,8 +115,9 @@
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
   ASSERT_NE(result->stdout.find("0x7f010000 -> 0x7f010000 integer/int1"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f020003 -> 0x7f020000 string/str1"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f020005 -> 0x7f020001 string/str3"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f020008 -> 0x7f020000 string/str1"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f02000a -> 0x7f020001 string/str3"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f02000b -> 0x7f020002 string/str4"), std::string::npos);
   ASSERT_EQ(result->stdout.find("00000210:     007f  target package id"), std::string::npos);
 
   // clang-format off
@@ -157,7 +159,8 @@
                                "--recursive",
                                "--target-package-name", "test.target",
                                "--target-apk-path", GetTargetApkPath(),
-                               "--output-directory", GetTempDirPath()});
+                               "--output-directory", GetTempDirPath(),
+                               "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -190,7 +193,8 @@
                           "--input-directory", GetTestDataPath() + "/overlay",
                           "--target-package-name", "test.target",
                           "--target-apk-path", GetTargetApkPath(),
-                          "--output-directory", GetTempDirPath()});
+                          "--output-directory", GetTempDirPath(),
+                          "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -207,7 +211,8 @@
                           "--recursive",
                           "--target-package-name", "test.target",
                           "--target-apk-path", GetTargetApkPath(),
-                          "--output-directory", GetTempDirPath()});
+                          "--output-directory", GetTempDirPath(),
+                          "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -222,7 +227,8 @@
                           "--input-directory", GetTempDirPath(),
                           "--target-package-name", "test.target",
                           "--target-apk-path", GetTargetApkPath(),
-                          "--output-directory", GetTempDirPath()});
+                          "--output-directory", GetTempDirPath(),
+                          "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -245,7 +251,7 @@
                           "lookup",
                           "--idmap-path", GetIdmapPath(),
                           "--config", "",
-                          "--resid", "0x7f020003"});  // string/str1
+                          "--resid", "0x7f020008"});  // string/str1
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -310,6 +316,18 @@
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_NE(result->status, EXIT_SUCCESS);
+
+  // unknown policy
+  // clang-format off
+  result = ExecuteBinary({"idmap2",
+                          "create",
+                          "--target-apk-path", GetTargetApkPath(),
+                          "--overlay-apk-path", GetOverlayApkPath(),
+                          "--idmap-path", GetIdmapPath(),
+                          "--policy", "this-does-not-exist"});
+  // clang-format on
+  ASSERT_THAT(result, NotNull());
+  ASSERT_NE(result->status, EXIT_SUCCESS);
 }
 
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 963f22e..c6eb71c 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -184,13 +184,14 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
   ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U);
-  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xf5ad1d1d);
+  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xca2093da);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xd470336b);
   ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
@@ -216,13 +217,127 @@
   ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetEntryCount(), 4U);
-  ASSERT_EQ(types[1]->GetEntryOffset(), 3U);
+  ASSERT_EQ(types[1]->GetEntryOffset(), 8U);
   ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);
   ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);
   ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);
   ASSERT_EQ(types[1]->GetEntry(3), 0x0002U);
 }
 
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
+  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());
+
+  const std::string overlay_apk_path(GetTestDataPath() + "/system-overlay/system-overlay.apk");
+  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+  ASSERT_THAT(overlay_apk, NotNull());
+
+  std::stringstream error;
+  std::unique_ptr<const Idmap> idmap =
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+                           /* enforce_overlayable */ true, error);
+  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_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+  ASSERT_EQ(types.size(), 1U);
+
+  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+  ASSERT_EQ(types[0]->GetEntryCount(), 3U);
+  ASSERT_EQ(types[0]->GetEntryOffset(), 5U);
+  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/policy_public
+  ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/policy_system
+  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_system_vendor
+}
+
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
+  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());
+
+  const std::string overlay_apk_path(GetTestDataPath() +
+                                     "/system-overlay-invalid/system-overlay-invalid.apk");
+  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+  ASSERT_THAT(overlay_apk, NotNull());
+
+  std::stringstream error;
+  std::unique_ptr<const Idmap> idmap =
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+                           /* enforce_overlayable */ true, error);
+  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_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+  ASSERT_EQ(types.size(), 1U);
+
+  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+  ASSERT_EQ(types[0]->GetEntryCount(), 5U);
+  ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
+  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);   // string/not_overlayable
+  ASSERT_EQ(types[0]->GetEntry(1), kNoEntry);  // string/policy_product
+  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);   // string/policy_public
+  ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);   // string/policy_system
+  ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);   // string/policy_system_vendor
+}
+
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
+  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());
+
+  const std::string overlay_apk_path(GetTestDataPath() +
+                                     "/system-overlay-invalid/system-overlay-invalid.apk");
+  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+  ASSERT_THAT(overlay_apk, NotNull());
+
+  std::stringstream error;
+  std::unique_ptr<const Idmap> idmap =
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+                           /* enforce_overlayable */ false, error);
+  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_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+  ASSERT_EQ(types.size(), 1U);
+
+  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+  ASSERT_EQ(types[0]->GetEntryCount(), 5U);
+  ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
+  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/not_overlayable
+  ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/policy_product
+  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_public
+  ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);  // string/policy_system
+  ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);  // string/policy_system_vendor
+}
+
 TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) {
   std::string target_apk_path(GetTestDataPath());
   for (int i = 0; i < 32; i++) {
@@ -239,7 +354,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, IsNull());
 }
 
@@ -255,8 +371,9 @@
   ASSERT_THAT(overlay_apk, NotNull());
 
   std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+  std::unique_ptr<const Idmap> idmap = Idmap::FromApkAssets(
+      target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+      /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp
new file mode 100644
index 0000000..ab567ad
--- /dev/null
+++ b/cmds/idmap2/tests/PoliciesTests.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 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 <string>
+
+#include "gtest/gtest.h"
+
+#include "TestHelpers.h"
+#include "idmap2/Policies.h"
+
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+
+namespace android::idmap2 {
+
+TEST(PoliciesTests, PoliciesToBitmasks) {
+  const Result<PolicyBitmask> bitmask1 = PoliciesToBitmask({"system"}, std::cerr);
+  ASSERT_NE(bitmask1, kResultError);
+  ASSERT_EQ(bitmask1, PolicyFlags::POLICY_SYSTEM_PARTITION);
+
+  const Result<PolicyBitmask> bitmask2 = PoliciesToBitmask({"system", "vendor"}, std::cerr);
+  ASSERT_NE(bitmask2, kResultError);
+  ASSERT_EQ(bitmask2, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+
+  const Result<PolicyBitmask> bitmask3 = PoliciesToBitmask({"vendor", "system"}, std::cerr);
+  ASSERT_NE(bitmask3, kResultError);
+  ASSERT_EQ(bitmask3, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+
+  const Result<PolicyBitmask> bitmask4 =
+      PoliciesToBitmask({"public", "product", "system", "vendor"}, std::cerr);
+  ASSERT_NE(bitmask4, kResultError);
+  ASSERT_EQ(bitmask4, PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION |
+                          PolicyFlags::POLICY_SYSTEM_PARTITION |
+                          PolicyFlags::POLICY_VENDOR_PARTITION);
+
+  const Result<PolicyBitmask> bitmask5 =
+      PoliciesToBitmask({"system", "system", "system"}, std::cerr);
+  ASSERT_NE(bitmask5, kResultError);
+  ASSERT_EQ(bitmask5, PolicyFlags::POLICY_SYSTEM_PARTITION);
+
+  const Result<PolicyBitmask> bitmask6 = PoliciesToBitmask({""}, std::cerr);
+  ASSERT_EQ(bitmask6, kResultError);
+
+  const Result<PolicyBitmask> bitmask7 = PoliciesToBitmask({"foo"}, std::cerr);
+  ASSERT_EQ(bitmask7, kResultError);
+
+  const Result<PolicyBitmask> bitmask8 = PoliciesToBitmask({"system", "foo"}, std::cerr);
+  ASSERT_EQ(bitmask8, kResultError);
+
+  const Result<PolicyBitmask> bitmask9 = PoliciesToBitmask({"system", ""}, std::cerr);
+  ASSERT_EQ(bitmask9, kResultError);
+
+  const Result<PolicyBitmask> bitmask10 = PoliciesToBitmask({"system "}, std::cerr);
+  ASSERT_EQ(bitmask10, kResultError);
+}
+
+}  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
index 7736bc0..eaa47cd 100644
--- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
@@ -25,6 +25,7 @@
 #include "androidfw/Idmap.h"
 
 #include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
 #include "idmap2/PrettyPrintVisitor.h"
 
 #include "TestHelpers.h"
@@ -32,6 +33,7 @@
 using ::testing::NotNull;
 
 using android::ApkAssets;
+using android::idmap2::PolicyBitmask;
 
 namespace android::idmap2 {
 
@@ -46,7 +48,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 0318cd2..b58c61a 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -42,7 +42,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
@@ -51,7 +52,7 @@
 
   ASSERT_NE(stream.str().find("00000000: 504d4449  magic\n"), std::string::npos);
   ASSERT_NE(stream.str().find("00000004: 00000001  version\n"), std::string::npos);
-  ASSERT_NE(stream.str().find("00000008: f5ad1d1d  target crc\n"), std::string::npos);
+  ASSERT_NE(stream.str().find("00000008: ca2093da  target crc\n"), std::string::npos);
   ASSERT_NE(stream.str().find("0000000c: d470336b  overlay crc\n"), std::string::npos);
   ASSERT_NE(stream.str().find("0000021c: 00000000  0x7f010000 -> 0x7f010000 integer/int1\n"),
             std::string::npos);
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
new file mode 100644
index 0000000..977cd97
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="test.overlay.system.invalid">
+    <overlay
+        android:targetPackage="test.target" />
+</manifest>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/build b/cmds/idmap2/tests/data/system-overlay-invalid/build
new file mode 100644
index 0000000..920e1f8
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/build
@@ -0,0 +1,26 @@
+# Copyright (C) 2019 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.
+
+FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+
+aapt2 compile --dir res -o compiled.flata
+
+aapt2 link \
+    --no-resource-removal \
+    -I "$FRAMEWORK_RES_APK" \
+    --manifest AndroidManifest.xml \
+    -o system-overlay-invalid.apk \
+    compiled.flata
+
+rm compiled.flata
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
new file mode 100644
index 0000000..5127707
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<resources>
+    <!-- This overlay will fulfill the policies "public|system". This allows it overlay the
+         following resources. -->
+    <string name="policy_system">policy_system</string>
+    <string name="policy_system_vendor">policy_system_vendor</string>
+    <string name="policy_public">policy_public</string>
+
+    <!-- It also requests to overlay a resource that belongs to a policy the overlay does not
+         fulfill.-->
+    <string name="policy_product">policy_product</string>
+
+    <!-- It also requests to overlay a resource that is not declared as overlayable.-->
+    <string name="not_overlayable">not_overlayable</string>
+</resources>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
new file mode 100644
index 0000000..c367f82
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
new file mode 100644
index 0000000..8af9064
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<manifest
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        package="test.overlay.system">
+    <overlay
+            android:targetPackage="test.target" />
+</manifest>
diff --git a/cmds/idmap2/tests/data/system-overlay/build b/cmds/idmap2/tests/data/system-overlay/build
new file mode 100644
index 0000000..be0d239
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/build
@@ -0,0 +1,26 @@
+# Copyright (C) 2019 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.
+
+FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+
+aapt2 compile --dir res -o compiled.flata
+
+aapt2 link \
+    --no-resource-removal \
+    -I "$FRAMEWORK_RES_APK" \
+    --manifest AndroidManifest.xml \
+    -o system-overlay.apk \
+    compiled.flata
+
+rm compiled.flata
diff --git a/cmds/idmap2/tests/data/system-overlay/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay/res/values/values.xml
new file mode 100644
index 0000000..6aaa0b0
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/res/values/values.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<resources>
+    <!-- This overlay will fulfill the policies "public|system". This allows it overlay the
+     following resources. -->
+    <string name="policy_system">policy_system</string>
+    <string name="policy_system_vendor">policy_system_vendor</string>
+    <string name="policy_public">policy_public</string>
+</resources>
diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
new file mode 100644
index 0000000..90f30eb
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
new file mode 100644
index 0000000..de19e6f
--- /dev/null
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<resources>
+<overlayable name="TestResources">
+    <!-- Publicly overlayable resources -->
+    <item type="string" name="a" />
+    <item type="string" name="b" />
+    <item type="string" name="c" />
+    <item type="string" name="str1" />
+    <item type="string" name="str2" />
+    <item type="string" name="str3" />
+    <item type="string" name="str4" />
+    <item type="string" name="x" />
+    <item type="string" name="y" />
+    <item type="string" name="z" />
+    <item type="integer" name="int1" />
+
+    <!-- Resources with partition restrictins -->
+    <policy type="system">
+        <item type="string" name="policy_system" />
+    </policy>
+
+    <policy type="system|vendor">
+        <item type="string" name="policy_system_vendor" />
+    </policy>
+
+    <policy type="product">
+        <item type="string" name="policy_product" />
+    </policy>
+
+    <policy type="public">
+        <item type="string" name="policy_public" />
+    </policy>
+</overlayable>
+</resources>
\ No newline at end of file
diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml
index 56bf0d6..ef9012e 100644
--- a/cmds/idmap2/tests/data/target/res/values/values.xml
+++ b/cmds/idmap2/tests/data/target/res/values/values.xml
@@ -25,4 +25,12 @@
     <string name="y">y</string>
     <string name="z">z</string>
     <integer name="int1">1</integer>
+
+    <!-- This resources is not marked as overlayable -->
+    <string name="not_overlayable">not_overlayable</string>
+
+    <string name="policy_system">policy_system</string>
+    <string name="policy_system_vendor">policy_system_vendor</string>
+    <string name="policy_product">policy_product</string>
+    <string name="policy_public">policy_public</string>
 </resources>
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index 18ecc27..9a6220d 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ