Merge "Add enforcement of idmap policies"
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 423bbd2..803f83c 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -39,6 +39,7 @@
         "libidmap2/CommandLineOptions.cpp",
         "libidmap2/FileUtils.cpp",
         "libidmap2/Idmap.cpp",
+        "libidmap2/Policies.cpp",
         "libidmap2/PrettyPrintVisitor.cpp",
         "libidmap2/RawPrintVisitor.cpp",
         "libidmap2/ResourceUtils.cpp",
@@ -88,6 +89,7 @@
         "tests/Idmap2BinaryTests.cpp",
         "tests/IdmapTests.cpp",
         "tests/Main.cpp",
+        "tests/PoliciesTests.cpp",
         "tests/PrettyPrintVisitorTests.cpp",
         "tests/RawPrintVisitorTests.cpp",
         "tests/ResourceUtilsTests.cpp",
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index b075673..c455ac0 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -27,17 +27,25 @@
 #include "idmap2/CommandLineOptions.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
 
 using android::ApkAssets;
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Idmap;
+using android::idmap2::PoliciesToBitmask;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+using android::idmap2::Result;
 using android::idmap2::utils::kIdmapFilePermissionMask;
 
 bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
   std::string target_apk_path;
   std::string overlay_apk_path;
   std::string idmap_path;
+  std::vector<std::string> policies;
+  bool ignore_overlayable;
 
   const CommandLineOptions opts =
       CommandLineOptions("idmap2 create")
@@ -47,12 +55,28 @@
           .MandatoryOption("--overlay-apk-path",
                            "input: path to apk which contains the new resource values",
                            &overlay_apk_path)
-          .MandatoryOption("--idmap-path", "output: path to where to write idmap file",
-                           &idmap_path);
+          .MandatoryOption("--idmap-path", "output: path to where to write idmap file", &idmap_path)
+          .OptionalOption("--policy",
+                          "input: an overlayable policy this overlay fulfills "
+                          "(if none or supplied, the overlay policy will default to \"public\")",
+                          &policies)
+          .OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks",
+                        &ignore_overlayable);
   if (!opts.Parse(args, out_error)) {
     return false;
   }
 
+  PolicyBitmask fulfilled_policies = 0;
+  if (auto result = PoliciesToBitmask(policies, out_error)) {
+    fulfilled_policies |= *result;
+  } else {
+    return false;
+  }
+
+  if (fulfilled_policies == 0) {
+    fulfilled_policies |= PolicyFlags::POLICY_PUBLIC;
+  }
+
   const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
   if (!target_apk) {
     out_error << "error: failed to load apk " << target_apk_path << std::endl;
@@ -66,7 +90,8 @@
   }
 
   const std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, out_error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           fulfilled_policies, !ignore_overlayable, out_error);
   if (!idmap) {
     return false;
   }
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index 4f88127..a269ee9 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -21,8 +21,11 @@
 #include <set>
 #include <sstream>
 #include <string>
+#include <utility>
 #include <vector>
 
+#include "android-base/properties.h"
+
 #include "idmap2/CommandLineOptions.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
@@ -34,6 +37,10 @@
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Idmap;
 using android::idmap2::MemoryChunk;
+using android::idmap2::PoliciesToBitmask;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+using android::idmap2::Result;
 using android::idmap2::Xml;
 using android::idmap2::ZipFile;
 using android::idmap2::utils::FindFiles;
@@ -45,11 +52,19 @@
     return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path);
   }
 
-  std::string apk_path;    // NOLINT(misc-non-private-member-variables-in-classes)
-  std::string idmap_path;  // NOLINT(misc-non-private-member-variables-in-classes)
-  int priority;            // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string apk_path;               // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string idmap_path;             // NOLINT(misc-non-private-member-variables-in-classes)
+  int priority;                       // NOLINT(misc-non-private-member-variables-in-classes)
+  std::vector<std::string> policies;  // NOLINT(misc-non-private-member-variables-in-classes)
+  bool ignore_overlayable;            // NOLINT(misc-non-private-member-variables-in-classes)
 };
 
+bool VendorIsQOrLater() {
+  // STOPSHIP(b/119390857): Check api version once Q sdk version is finalized
+  std::string version = android::base::GetProperty("ro.vndk.version", "Q");
+  return version == "Q" || version == "q";
+}
+
 std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
                                                        bool recursive, std::ostream& out_error) {
   const auto predicate = [](unsigned char type, const std::string& path) -> bool {
@@ -70,6 +85,22 @@
   return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
 }
 
+PolicyBitmask PolicyForPath(const std::string& apk_path) {
+  static const std::vector<std::pair<std::string, PolicyBitmask>> values = {
+      {"/product/", PolicyFlags::POLICY_PRODUCT_PARTITION},
+      {"/system/", PolicyFlags::POLICY_SYSTEM_PARTITION},
+      {"/vendor/", PolicyFlags::POLICY_VENDOR_PARTITION},
+  };
+
+  for (auto const& pair : values) {
+    if (apk_path.compare(0, pair.first.size(), pair.first) == 0) {
+      return pair.second | PolicyFlags::POLICY_PUBLIC;
+    }
+  }
+
+  return PolicyFlags::POLICY_PUBLIC;
+}
+
 }  // namespace
 
 bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
@@ -77,6 +108,7 @@
   std::string target_package_name;
   std::string target_apk_path;
   std::string output_directory;
+  std::vector<std::string> override_policies;
   bool recursive = false;
 
   const CommandLineOptions opts =
@@ -89,7 +121,12 @@
           .MandatoryOption("--target-apk-path", "path to target apk", &target_apk_path)
           .MandatoryOption("--output-directory",
                            "directory in which to write artifacts (idmap files and overlays.list)",
-                           &output_directory);
+                           &output_directory)
+          .OptionalOption(
+              "--override-policy",
+              "input: an overlayable policy this overlay fulfills "
+              "(if none or supplied, the overlays will not have their policies overriden",
+              &override_policies);
   if (!opts.Parse(args, out_error)) {
     return false;
   }
@@ -144,29 +181,63 @@
       continue;
     }
 
-    // Sort the static overlays in ascending priority order
+    PolicyBitmask fulfilled_policies;
+    if (!override_policies.empty()) {
+      if (Result<PolicyBitmask> result = PoliciesToBitmask(override_policies, out_error)) {
+        fulfilled_policies = *result;
+      } else {
+        return false;
+      }
+    } else {
+      fulfilled_policies = PolicyForPath(path);
+    }
+
+    bool ignore_overlayable = false;
+    if ((fulfilled_policies & PolicyFlags::POLICY_VENDOR_PARTITION) != 0 && !VendorIsQOrLater()) {
+      // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
+      // restrictions on this overlay because the pre-Q platform has no understanding of
+      // overlayable.
+      ignore_overlayable = true;
+    }
+
     std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);
-    InputOverlay input{path, idmap_path, priority};
+
+    // Sort the static overlays in ascending priority order
+    InputOverlay input{path, idmap_path, priority, override_policies, ignore_overlayable};
     interesting_apks.insert(
         std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
   }
 
   std::stringstream stream;
   for (const auto& overlay : interesting_apks) {
+    // Create the idmap for the overlay if it currently does not exist or if it is not up to date.
     std::stringstream dev_null;
-    if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}), dev_null) &&
-        !Create(std::vector<std::string>({
-                    "--target-apk-path",
-                    target_apk_path,
-                    "--overlay-apk-path",
-                    overlay.apk_path,
-                    "--idmap-path",
-                    overlay.idmap_path,
-                }),
-                out_error)) {
-      return false;
+
+    std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path};
+    for (const std::string& policy : overlay.policies) {
+      verify_args.emplace_back("--policy");
+      verify_args.emplace_back(policy);
     }
-    stream <<  overlay.idmap_path << std::endl;
+
+    if (!Verify(std::vector<std::string>(verify_args), dev_null)) {
+      std::vector<std::string> create_args = {"--target-apk-path",  target_apk_path,
+                                              "--overlay-apk-path", overlay.apk_path,
+                                              "--idmap-path",       overlay.idmap_path};
+      if (overlay.ignore_overlayable) {
+        create_args.emplace_back("--ignore-overlayable");
+      }
+
+      for (const std::string& policy : overlay.policies) {
+        verify_args.emplace_back("--policy");
+        verify_args.emplace_back(policy);
+      }
+
+      if (!Create(create_args, out_error)) {
+        return false;
+      }
+    }
+
+    stream << overlay.idmap_path << std::endl;
   }
 
   std::cout << stream.str();
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index d2e46e1..a3c7527 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -26,12 +26,15 @@
 #include <string>
 
 #include "android-base/macros.h"
+#include "android-base/stringprintf.h"
 #include "utils/String8.h"
 #include "utils/Trace.h"
 
 #include "idmap2/BinaryStreamVisitor.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
 
 #include "idmap2d/Idmap2Service.h"
 
@@ -39,6 +42,8 @@
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::Idmap;
 using android::idmap2::IdmapHeader;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::Result;
 using android::idmap2::utils::kIdmapFilePermissionMask;
 
 namespace {
@@ -54,6 +59,10 @@
   return Status::fromExceptionCode(Status::EX_NONE, msg.c_str());
 }
 
+PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
+  return static_cast<PolicyBitmask>(arg);
+}
+
 }  // namespace
 
 namespace android::os {
@@ -78,6 +87,8 @@
 }
 
 Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path,
+                                  int32_t fulfilled_policies ATTRIBUTE_UNUSED,
+                                  bool enforce_overlayable ATTRIBUTE_UNUSED,
                                   int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
   assert(_aidl_return);
   const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
@@ -86,11 +97,15 @@
   fin.close();
   std::stringstream dev_null;
   *_aidl_return = header && header->IsUpToDate(dev_null);
+
+  // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed
+
   return ok();
 }
 
 Status Idmap2Service::createIdmap(const std::string& target_apk_path,
-                                  const std::string& overlay_apk_path, int32_t user_id,
+                                  const std::string& overlay_apk_path, int32_t fulfilled_policies,
+                                  bool enforce_overlayable, int32_t user_id,
                                   std::unique_ptr<std::string>* _aidl_return) {
   assert(_aidl_return);
   std::stringstream trace;
@@ -101,6 +116,8 @@
 
   _aidl_return->reset(nullptr);
 
+  const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
+
   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);
@@ -113,7 +130,8 @@
 
   std::stringstream err;
   const std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, err);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           policy_bitmask, enforce_overlayable, err);
   if (!idmap) {
     return error(err.str());
   }
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index e0bc22e..1aab059 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -39,11 +39,12 @@
   binder::Status removeIdmap(const std::string& overlay_apk_path, int32_t user_id,
                              bool* _aidl_return);
 
-  binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t user_id,
-                             bool* _aidl_return);
+  binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t fulfilled_policies,
+                             bool enforce_overlayable, int32_t user_id, bool* _aidl_return);
 
   binder::Status createIdmap(const std::string& target_apk_path,
-                             const std::string& overlay_apk_path, int32_t user_id,
+                             const std::string& overlay_apk_path, int32_t fulfilled_policies,
+                             bool enforce_overlayable, int32_t user_id,
                              std::unique_ptr<std::string>* _aidl_return);
 };
 
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
index d475417..ea7274f 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
@@ -20,9 +20,18 @@
  * @hide
  */
 interface IIdmap2 {
+  const int POLICY_PUBLIC = 0x00000001;
+  const int POLICY_SYSTEM_PARTITION = 0x00000002;
+  const int POLICY_VENDOR_PARTITION = 0x00000004;
+  const int POLICY_PRODUCT_PARTITION = 0x00000008;
+
   @utf8InCpp String getIdmapPath(@utf8InCpp String overlayApkPath, int userId);
   boolean removeIdmap(@utf8InCpp String overlayApkPath, int userId);
-  boolean verifyIdmap(@utf8InCpp String overlayApkPath, int userId);
+  boolean verifyIdmap(@utf8InCpp String overlayApkPath, int fulfilledPolicies,
+                      boolean enforceOverlayable, int userId);
   @nullable @utf8InCpp String createIdmap(@utf8InCpp String targetApkPath,
-                                          @utf8InCpp String overlayApkPath, int userId);
+                                          @utf8InCpp String overlayApkPath,
+                                          int fulfilledPolicies,
+                                          boolean enforceOverlayable,
+                                          int userId);
 }
diff --git a/cmds/idmap2/include/idmap2/CommandLineOptions.h b/cmds/idmap2/include/idmap2/CommandLineOptions.h
index b93e716..6db6bf9 100644
--- a/cmds/idmap2/include/idmap2/CommandLineOptions.h
+++ b/cmds/idmap2/include/idmap2/CommandLineOptions.h
@@ -44,6 +44,8 @@
                                       std::vector<std::string>* value);
   CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
                                      std::string* value);
+  CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
+                                     std::vector<std::string>* value);
   bool Parse(const std::vector<std::string>& argv, std::ostream& outError) const;
   void Usage(std::ostream& out) const;
 
@@ -56,6 +58,7 @@
       COUNT_OPTIONAL,
       COUNT_EXACTLY_ONCE,
       COUNT_ONCE_OR_MORE,
+      COUNT_OPTIONAL_ONCE_OR_MORE,
     } count;
     bool argument;
   };
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index b989e4c..1666dc8 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -57,6 +57,8 @@
 #include "androidfw/ResourceTypes.h"
 #include "androidfw/StringPiece.h"
 
+#include "idmap2/Policies.h"
+
 namespace android::idmap2 {
 
 class Idmap;
@@ -233,11 +235,10 @@
   // 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 std::unique_ptr<const Idmap> FromApkAssets(const std::string& target_apk_path,
-                                                    const ApkAssets& target_apk_assets,
-                                                    const std::string& overlay_apk_path,
-                                                    const ApkAssets& overlay_apk_assets,
-                                                    std::ostream& out_error);
+  static std::unique_ptr<const Idmap> FromApkAssets(
+      const std::string& target_apk_path, const ApkAssets& target_apk_assets,
+      const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
+      const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error);
 
   inline const std::unique_ptr<const IdmapHeader>& GetHeader() const {
     return header_;
diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h
new file mode 100644
index 0000000..eecee25
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/Policies.h
@@ -0,0 +1,41 @@
+/*
+ * 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 <ostream>
+#include <string>
+#include <vector>
+
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
+
+#include "Result.h"
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
+#define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
+
+namespace android::idmap2 {
+
+using PolicyFlags = ResTable_overlayable_policy_header::PolicyFlags;
+using PolicyBitmask = uint32_t;
+
+// Parses a the string representation of a set of policies into a bitmask. The format of the string
+// is the same as for the <policy> element.
+Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies,
+                                        std::ostream& err);
+
+}  // namespace android::idmap2
+
+#endif  // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
index cabc8f3..a49a607 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -68,9 +68,18 @@
   return *this;
 }
 
+CommandLineOptions& CommandLineOptions::OptionalOption(const std::string& name,
+                                                       const std::string& description,
+                                                       std::vector<std::string>* value) {
+  assert(value != nullptr);
+  auto func = [value](const std::string& arg) -> void { value->push_back(arg); };
+  options_.push_back(Option{name, description, func, Option::COUNT_OPTIONAL_ONCE_OR_MORE, true});
+  return *this;
+}
+
 bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostream& outError) const {
   const auto pivot = std::partition(options_.begin(), options_.end(), [](const Option& opt) {
-    return opt.count != Option::COUNT_OPTIONAL;
+    return opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
   });
   std::set<std::string> mandatory_opts;
   std::transform(options_.begin(), pivot, std::inserter(mandatory_opts, mandatory_opts.end()),
@@ -122,7 +131,8 @@
   size_t maxLength = 0;
   out << "usage: " << name_;
   for (const Option& opt : options_) {
-    const bool mandatory = opt.count != Option::COUNT_OPTIONAL;
+    const bool mandatory =
+        opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
     out << " ";
     if (!mandatory) {
       out << "[";
@@ -134,9 +144,15 @@
       out << opt.name;
       maxLength = std::max(maxLength, opt.name.size());
     }
+
+    if (opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) {
+      out << " [..]";
+    }
+
     if (!mandatory) {
       out << "]";
     }
+
     if (opt.count == Option::COUNT_ONCE_OR_MORE) {
       out << " [" << opt.name << " arg [..]]";
     }
@@ -150,7 +166,8 @@
       out << opt.name;
     }
     out << "    " << opt.description;
-    if (opt.count == Option::COUNT_ONCE_OR_MORE) {
+    if (opt.count == Option::COUNT_ONCE_OR_MORE ||
+        opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) {
       out << " (can be provided multiple times)";
     }
     out << std::endl;
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 37d6af8..2890ae1 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -274,11 +274,23 @@
   return std::move(idmap);
 }
 
-std::unique_ptr<const Idmap> Idmap::FromApkAssets(const std::string& target_apk_path,
-                                                  const ApkAssets& target_apk_assets,
-                                                  const std::string& overlay_apk_path,
-                                                  const ApkAssets& overlay_apk_assets,
-                                                  std::ostream& out_error) {
+bool CheckOverlayable(const LoadedPackage& target_package, PolicyBitmask fulfilled_polices,
+                      ResourceId resid) {
+  const OverlayableInfo* info = target_package.GetOverlayableInfo(resid);
+  if (info == nullptr) {
+    // If the resource does not have an overlayable definition, allow the resource to be overlaid.
+    // Once overlayable enforcement is turned on, this check will return false.
+    return true;
+  }
+
+  // Enforce policy restrictions if the resource is declared as overlayable.
+  return (info->policy_flags & fulfilled_polices) != 0;
+}
+
+std::unique_ptr<const Idmap> Idmap::FromApkAssets(
+    const std::string& target_apk_path, const ApkAssets& target_apk_assets,
+    const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
+    const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error) {
   AssetManager2 target_asset_manager;
   if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true, false)) {
     out_error << "error: failed to create target asset manager" << std::endl;
@@ -380,6 +392,15 @@
     if (target_resid == 0) {
       continue;
     }
+
+    if (enforce_overlayable && !CheckOverlayable(*target_pkg, fulfilled_policies, target_resid)) {
+      // The resources must be defined as overlayable and the overlay must fulfill at least one
+      // policy enforced on the overlayable resource
+      LOG(WARNING) << "overlay \"" << overlay_apk_path << "\" is not allowed to overlay resource \""
+                   << full_name << "\"" << std::endl;
+      continue;
+    }
+
     matching_resources.Add(target_resid, overlay_resid);
   }
 
diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp
new file mode 100644
index 0000000..0f87ef0
--- /dev/null
+++ b/cmds/idmap2/libidmap2/Policies.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 <iterator>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "androidfw/ResourceTypes.h"
+
+#include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
+
+namespace android::idmap2 {
+
+namespace {
+
+const std::map<android::StringPiece, PolicyFlags> kStringToFlag = {
+    {"public", PolicyFlags::POLICY_PUBLIC},
+    {"product", PolicyFlags::POLICY_PRODUCT_PARTITION},
+    {"system", PolicyFlags::POLICY_SYSTEM_PARTITION},
+    {"vendor", PolicyFlags::POLICY_VENDOR_PARTITION},
+};
+}  // namespace
+
+Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies,
+                                        std::ostream& err) {
+  PolicyBitmask bitmask = 0;
+  for (const std::string& policy : policies) {
+    const auto iter = kStringToFlag.find(policy);
+    if (iter != kStringToFlag.end()) {
+      bitmask |= iter->second;
+    } else {
+      err << "error: unknown policy \"" << policy << "\"";
+      return kResultError;
+    }
+  }
+
+  return Result<PolicyBitmask>(bitmask);
+}
+
+}  // namespace android::idmap2
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
diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk
index 8634747..2049123 100644
--- a/libs/androidfw/tests/data/overlayable/overlayable.apk
+++ b/libs/androidfw/tests/data/overlayable/overlayable.apk
Binary files differ
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 16143d3..74fbea1 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -24,11 +24,14 @@
 
 import android.annotation.NonNull;
 import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.os.Build.VERSION_CODES;
 import android.os.IBinder;
 import android.os.IIdmap2;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.Slog;
 
@@ -51,6 +54,13 @@
     private final Installer mInstaller;
     private IIdmap2 mIdmap2Service;
 
+    private static final boolean VENDOR_IS_Q_OR_LATER;
+    static {
+        // STOPSHIP(b/119390857): Check api version once Q sdk version is finalized
+        final String value = SystemProperties.get("ro.vndk.version", "Q");
+        VENDOR_IS_Q_OR_LATER = value.equals("Q") || value.equals("q");
+    }
+
     IdmapManager(final Installer installer) {
         mInstaller = installer;
         if (FEATURE_FLAG_IDMAP2) {
@@ -69,10 +79,13 @@
         final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
         try {
             if (FEATURE_FLAG_IDMAP2) {
-                if (mIdmap2Service.verifyIdmap(overlayPath, userId)) {
+                int policies = determineFulfilledPolicies(overlayPackage);
+                boolean enforce = enforceOverlayable(overlayPackage);
+                if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) {
                     return true;
                 }
-                return mIdmap2Service.createIdmap(targetPath, overlayPath, userId) != null;
+                return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce,
+                    userId) != null;
             } else {
                 mInstaller.idmap(targetPath, overlayPath, sharedGid);
                 return true;
@@ -156,4 +169,71 @@
             }, SECOND_IN_MILLIS);
         }
     }
+
+    /**
+     * Checks if overlayable and policies should be enforced on the specified overlay for backwards
+     * compatibility with pre-Q overlays.
+     */
+    private boolean enforceOverlayable(@NonNull final PackageInfo overlayPackage) {
+        final ApplicationInfo ai = overlayPackage.applicationInfo;
+        if (ai.targetSdkVersion >= VERSION_CODES.Q) {
+            // Always enforce policies for overlays targeting Q+.
+            return true;
+        }
+
+        if (ai.isVendor() && !VENDOR_IS_Q_OR_LATER) {
+            // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
+            // restrictions on this overlay because the pre-Q platform has no understanding of
+            // overlayable.
+            return false;
+        }
+
+        // Do not enforce overlayable restrictions on pre-Q overlays signed with the
+        // platform signature.
+        return !ai.isSignedWithPlatformKey();
+    }
+
+    /**
+     * Retrieves a bitmask for idmap2 that represents the policies the specified overlay fulfills.
+     * @throws SecurityException if the overlay is not allowed to overlay any resource
+     */
+    private int determineFulfilledPolicies(@NonNull final PackageInfo overlayPackage)
+            throws SecurityException {
+        final ApplicationInfo ai = overlayPackage.applicationInfo;
+        final boolean overlayIsQOrLater = ai.targetSdkVersion >= VERSION_CODES.Q;
+
+        int fulfilledPolicies = 0;
+
+        // TODO(b/119402606) : Add signature policy
+
+        // Vendor partition (/vendor)
+        if (ai.isVendor()) {
+            if (overlayIsQOrLater) {
+                fulfilledPolicies |= IIdmap2.POLICY_VENDOR_PARTITION;
+            } else if (VENDOR_IS_Q_OR_LATER) {
+                throw new SecurityException("Overlay must target Q sdk or higher");
+            }
+        }
+
+        // Product partition (/product)
+        if (ai.isProduct()) {
+            if (overlayIsQOrLater) {
+                fulfilledPolicies |= IIdmap2.POLICY_PRODUCT_PARTITION;
+            } else {
+                throw new SecurityException("Overlay must target Q sdk or higher");
+            }
+        }
+
+        // System partition (/system)
+        if (ai.isSystemApp()) {
+            if (overlayIsQOrLater) {
+                fulfilledPolicies |= IIdmap2.POLICY_SYSTEM_PARTITION;
+            } else {
+                throw new SecurityException("Overlay must target Q sdk or higher");
+            }
+        }
+
+        // All overlays can overlay resources with the public policy
+        return fulfilledPolicies | IIdmap2.POLICY_PUBLIC;
+    }
 }