OMS: Add config_signature policy handling

Alongside SIGNATURE and ACTOR_SIGNATURE policies, add CONFIG_SIGNATURE
policy to overlayable that overlay fulfills if it is signed with the
same certificate as the reference package whose package name is
declared in 'config-signature' tag of SystemConfig and is vetted by
OMS that it's a system pre-installed package.

BUG: 158726924
TEST: regular aapt2, idmap2, OMS tests

Merged-In: I645ee72271496008742886274be0d63a2985201b
Change-Id: I645ee72271496008742886274be0d63a2985201b
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
index 02b27a8..403d8c5 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
@@ -29,4 +29,5 @@
   const int ODM_PARTITION = 0x00000020;
   const int OEM_PARTITION = 0x00000040;
   const int ACTOR_SIGNATURE = 0x00000080;
+  const int CONFIG_SIGNATURE = 0x0000100;
 }
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 34589a1..fd8b4eb 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -61,10 +61,13 @@
                               const ResourceId& target_resource) {
   static constexpr const PolicyBitmask sDefaultPolicies =
       PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION |
-      PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE;
+      PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE |
+      PolicyFlags::CONFIG_SIGNATURE;
 
   // If the resource does not have an overlayable definition, allow the resource to be overlaid if
-  // the overlay is preinstalled or signed with the same signature as the target.
+  // the overlay is preinstalled, signed with the same signature as the target or signed with the
+  // same signature as reference package defined in SystemConfig under 'overlay-config-signature'
+  // tag.
   if (!target_package.DefinesOverlayable()) {
     return (sDefaultPolicies & fulfilled_policies) != 0
                ? Result<Unit>({})
diff --git a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
index 5bd353a..8046319 100644
--- a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
+++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
@@ -37,16 +37,18 @@
 constexpr const char* kPolicyOem = "oem";
 constexpr const char* kPolicyProduct = "product";
 constexpr const char* kPolicyPublic = "public";
+constexpr const char* kPolicyConfigSignature = "config_signature";
 constexpr const char* kPolicySignature = "signature";
 constexpr const char* kPolicySystem = "system";
 constexpr const char* kPolicyVendor = "vendor";
 
-inline static const std::array<std::pair<StringPiece, PolicyFlags>, 8> kPolicyStringToFlag = {
+inline static const std::array<std::pair<StringPiece, PolicyFlags>, 9> kPolicyStringToFlag = {
     std::pair{kPolicyActor, PolicyFlags::ACTOR_SIGNATURE},
     {kPolicyOdm, PolicyFlags::ODM_PARTITION},
     {kPolicyOem, PolicyFlags::OEM_PARTITION},
     {kPolicyProduct, PolicyFlags::PRODUCT_PARTITION},
     {kPolicyPublic, PolicyFlags::PUBLIC},
+    {kPolicyConfigSignature, PolicyFlags::CONFIG_SIGNATURE},
     {kPolicySignature, PolicyFlags::SIGNATURE},
     {kPolicySystem, PolicyFlags::SYSTEM_PARTITION},
     {kPolicyVendor, PolicyFlags::VENDOR_PARTITION},
diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h
index aed263a..89b4346 100644
--- a/cmds/idmap2/tests/R.h
+++ b/cmds/idmap2/tests/R.h
@@ -41,16 +41,17 @@
     constexpr ResourceId not_overlayable = 0x7f020003;
     constexpr ResourceId other = 0x7f020004;
     constexpr ResourceId policy_actor = 0x7f020005;
-    constexpr ResourceId policy_odm = 0x7f020006;
-    constexpr ResourceId policy_oem = 0x7f020007;
-    constexpr ResourceId policy_product = 0x7f020008;
-    constexpr ResourceId policy_public = 0x7f020009;
-    constexpr ResourceId policy_signature = 0x7f02000a;
-    constexpr ResourceId policy_system = 0x7f02000b;
-    constexpr ResourceId policy_system_vendor = 0x7f02000c;
-    constexpr ResourceId str1 = 0x7f02000d;
-    constexpr ResourceId str3 = 0x7f02000f;
-    constexpr ResourceId str4 = 0x7f020010;
+    constexpr ResourceId policy_config_signature = 0x7f020006;
+    constexpr ResourceId policy_odm = 0x7f020007;
+    constexpr ResourceId policy_oem = 0x7f020008;
+    constexpr ResourceId policy_product = 0x7f020009;
+    constexpr ResourceId policy_public = 0x7f02000a;
+    constexpr ResourceId policy_signature = 0x7f02000b;
+    constexpr ResourceId policy_system = 0x7f02000c;
+    constexpr ResourceId policy_system_vendor = 0x7f02000d;
+    constexpr ResourceId str1 = 0x7f02000e;
+    constexpr ResourceId str3 = 0x7f020010;
+    constexpr ResourceId str4 = 0x7f020011;
 
     namespace literal {
       inline const std::string str1 = hexify(R::target::string::str1);
@@ -92,14 +93,15 @@
   constexpr ResourceId not_overlayable = 0x7f010000;
   constexpr ResourceId other = 0x7f010001;
   constexpr ResourceId policy_actor = 0x7f010002;
-  constexpr ResourceId policy_odm = 0x7f010003;
-  constexpr ResourceId policy_oem = 0x7f010004;
-  constexpr ResourceId policy_product = 0x7f010005;
-  constexpr ResourceId policy_public = 0x7f010006;
-  constexpr ResourceId policy_signature = 0x7f010007;
-  constexpr ResourceId policy_system = 0x7f010008;
-  constexpr ResourceId policy_system_vendor = 0x7f010009;
-};
+  constexpr ResourceId policy_config_signature = 0x7f010003;
+  constexpr ResourceId policy_odm = 0x7f010004;
+  constexpr ResourceId policy_oem = 0x7f010005;
+  constexpr ResourceId policy_product = 0x7f010006;
+  constexpr ResourceId policy_public = 0x7f010007;
+  constexpr ResourceId policy_signature = 0x7f010008;
+  constexpr ResourceId policy_system = 0x7f010009;
+  constexpr ResourceId policy_system_vendor = 0x7f01000a;
+}
 // clang-format on
 
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index de039f4..3ec6ac2 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -237,7 +237,7 @@
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
   auto& res = *resources;
-  ASSERT_EQ(res.GetTargetToOverlayMap().size(), 10U);
+  ASSERT_EQ(res.GetTargetToOverlayMap().size(), 11U);
   ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
                               R::system_overlay_invalid::string::not_overlayable,
                               false /* rewrite */));
@@ -256,6 +256,10 @@
   ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
                               R::system_overlay_invalid::string::policy_public,
                               false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature,
+                              Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::policy_config_signature,
+                              false /* rewrite */));
   ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
                               R::system_overlay_invalid::string::policy_signature,
                               false /* rewrite */));
@@ -298,8 +302,9 @@
   ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
 }
 
-// Overlays that are pre-installed or are signed with the same signature as the target can overlay
-// packages that have not defined overlayable resources.
+// Overlays that are pre-installed or are signed with the same signature as the target  or are signed
+// with the same signature as the reference package can overlay packages that have not defined
+// overlayable resources.
 TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
   auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void {
     auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
@@ -309,7 +314,7 @@
 
     ASSERT_TRUE(resources) << resources.GetErrorMessage();
     auto& res = *resources;
-    ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U);
+    ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 11U);
     ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
                                 R::system_overlay_invalid::string::not_overlayable,
                                 false /* rewrite */));
@@ -330,6 +335,10 @@
     ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
                                 R::system_overlay_invalid::string::policy_public,
                                 false /* rewrite */));
+    ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature,
+                                Res_value::TYPE_REFERENCE,
+                                R::system_overlay_invalid::string::policy_config_signature,
+                                false /* rewrite */));
     ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
                                 R::system_overlay_invalid::string::policy_signature,
                                 false /* rewrite */));
@@ -342,6 +351,7 @@
   };
 
   CheckEntries(PolicyFlags::SIGNATURE);
+  CheckEntries(PolicyFlags::CONFIG_SIGNATURE);
   CheckEntries(PolicyFlags::PRODUCT_PARTITION);
   CheckEntries(PolicyFlags::SYSTEM_PARTITION);
   CheckEntries(PolicyFlags::VENDOR_PARTITION);
diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h
index 6bc924e..641a7a8 100644
--- a/cmds/idmap2/tests/TestConstants.h
+++ b/cmds/idmap2/tests/TestConstants.h
@@ -19,11 +19,11 @@
 
 namespace android::idmap2::TestConstants {
 
-constexpr const auto TARGET_CRC = 0x41c60c8c;
-constexpr const auto TARGET_CRC_STRING = "41c60c8c";
+constexpr const auto TARGET_CRC =  0x7c2d4719;
+constexpr const auto TARGET_CRC_STRING = "7c2d4719";
 
-constexpr const auto OVERLAY_CRC = 0xc054fb26;
-constexpr const auto OVERLAY_CRC_STRING = "c054fb26";
+constexpr const auto OVERLAY_CRC = 0x5afff726;
+constexpr const auto OVERLAY_CRC_STRING = "5afff726";
 
 }  // namespace android::idmap2::TestConstants
 
diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
index 7c25985..dab25b1 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
index c75f3e1..c8b95c2 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-shared.apk b/cmds/idmap2/tests/data/overlay/overlay-shared.apk
index 93dcc82..0a8b737 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-shared.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-shared.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
index 5b8a6e4..fd41182 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
index 698a1fd..b24765f 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay.apk b/cmds/idmap2/tests/data/overlay/overlay.apk
index 1db303f..870575e 100644
--- a/cmds/idmap2/tests/data/overlay/overlay.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
index 51e19de..e0fd204 100644
--- a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
+++ b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
Binary files differ
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
index 7119d82..ebaf49c 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
@@ -26,6 +26,7 @@
     <string name="policy_odm">policy_odm</string>
     <string name="policy_oem">policy_oem</string>
     <string name="policy_actor">policy_actor</string>
+    <string name="policy_config_signature">policy_config_signature</string>
 
     <!-- Requests to overlay a resource that is not declared as overlayable. -->
     <string name="not_overlayable">not_overlayable</string>
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
index bd99098..a63daf8 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
index a0fba43..90d2803 100644
--- a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
+++ 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
index ad4cd48..57e6c43 100644
--- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -45,6 +45,10 @@
         <item type="string" name="policy_actor" />
     </policy>
 
+    <policy type="config_signature">
+        <item type="string" name="policy_config_signature"/>
+    </policy>
+
     <!-- Resources publicly overlayable -->
     <policy type="public">
         <item type="string" name="policy_public" />
diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml
index 5230e25..00909a9 100644
--- a/cmds/idmap2/tests/data/target/res/values/values.xml
+++ b/cmds/idmap2/tests/data/target/res/values/values.xml
@@ -37,6 +37,7 @@
     <string name="policy_system">policy_system</string>
     <string name="policy_system_vendor">policy_system_vendor</string>
     <string name="policy_actor">policy_actor</string>
+    <string name="policy_config_signature">policy_config_signature</string>
 
     <string name="other">other</string>
 </resources>
diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
index 58504a7..cc3491d 100644
--- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk
+++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index c80e5eb..4a58c5e 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index ea390cd..4fc66bc 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -19,6 +19,7 @@
 import static com.android.internal.util.ArrayUtils.appendInt;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.pm.FeatureInfo;
@@ -238,6 +239,14 @@
      */
     private Map<String, Map<String, String>> mNamedActors = null;
 
+    // Package name of the package pre-installed on a read-only
+    // partition that is used to verify if an overlay package fulfills
+    // the 'config_signature' policy by comparing their signatures:
+    // if the overlay package is signed with the same certificate as
+    // the package declared in 'config-signature' tag, then the
+    // overlay package fulfills the 'config_signature' policy.
+    private String mOverlayConfigSignaturePackage;
+
     public static SystemConfig getInstance() {
         if (!isSystemProcess()) {
             Slog.wtf(TAG, "SystemConfig is being accessed by a process other than "
@@ -433,6 +442,12 @@
         return mNamedActors != null ? mNamedActors : Collections.emptyMap();
     }
 
+    @Nullable
+    public String getOverlayConfigSignaturePackage() {
+        return TextUtils.isEmpty(mOverlayConfigSignaturePackage)
+                ? null : mOverlayConfigSignaturePackage;
+    }
+
     /**
      * Only use for testing. Do NOT use in production code.
      * @param readPermissions false to create an empty SystemConfig; true to read the permissions.
@@ -1151,6 +1166,27 @@
                         }
                         XmlUtils.skipCurrentTag(parser);
                     } break;
+                    case "overlay-config-signature": {
+                        if (allowAll) {
+                            String pkgName = parser.getAttributeValue(null, "package");
+                            if (pkgName == null) {
+                                Slog.w(TAG, "<" + name + "> without package in " + permFile
+                                        + " at " + parser.getPositionDescription());
+                            } else {
+                                if (TextUtils.isEmpty(mOverlayConfigSignaturePackage)) {
+                                    mOverlayConfigSignaturePackage = pkgName.intern();
+                                } else {
+                                    throw new IllegalStateException("Reference signature package "
+                                                  + "defined as both "
+                                                  + mOverlayConfigSignaturePackage
+                                                  + " and " + pkgName);
+                                }
+                            }
+                        } else {
+                            logNotAllowedInPartition(name, permFile, parser);
+                        }
+                        XmlUtils.skipCurrentTag(parser);
+                    } break;
                     case "rollback-whitelisted-app": {
                         String pkgname = parser.getAttributeValue(null, "package");
                         if (pkgname == null) {
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index e351a46..e10a7f3 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1717,6 +1717,10 @@
     // The overlay must be signed with the same signature as the actor declared for the target
     // resource
     ACTOR_SIGNATURE = 0x00000080,
+
+    // The overlay must be signed with the same signature as the reference package declared
+    // in the SystemConfig
+    CONFIG_SIGNATURE = 0x00000100,
   };
 
   using PolicyBitmask = uint32_t;
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index b241bd1..ad1986a 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -69,6 +69,7 @@
     public static final int PACKAGE_WIFI = 13;
     public static final int PACKAGE_COMPANION = 14;
     public static final int PACKAGE_RETAIL_DEMO = 15;
+    public static final int PACKAGE_OVERLAY_CONFIG_SIGNATURE = 16;
 
     @IntDef(flag = true, prefix = "RESOLVE_", value = {
             RESOLVE_NON_BROWSER_ONLY,
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index d6b1b27..cb6e960 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -27,6 +27,7 @@
 import android.os.Build.VERSION_CODES;
 import android.os.OverlayablePolicy;
 import android.os.SystemProperties;
+import android.text.TextUtils;
 import android.util.Slog;
 
 import java.io.IOException;
@@ -53,11 +54,20 @@
     }
 
     private final IdmapDaemon mIdmapDaemon;
-    private final OverlayableInfoCallback mOverlayableCallback;
+    private final PackageManagerHelper mPackageManager;
 
-    IdmapManager(final IdmapDaemon idmapDaemon, final OverlayableInfoCallback verifyCallback) {
-        mOverlayableCallback = verifyCallback;
+    /**
+     * Package name of the reference package defined in 'config-signature' tag of
+     * SystemConfig or empty String if tag not defined. This package is vetted on scan by
+     * PackageManagerService that it's a system package and is used to check if overlay matches
+     * its signature in order to fulfill the config_signature policy.
+     */
+    private final String mConfigSignaturePackage;
+
+    IdmapManager(final IdmapDaemon idmapDaemon, final PackageManagerHelper packageManager) {
+        mPackageManager = packageManager;
         mIdmapDaemon = idmapDaemon;
+        mConfigSignaturePackage = packageManager.getConfigSignaturePackage();
     }
 
     /**
@@ -139,7 +149,7 @@
         int fulfilledPolicies = OverlayablePolicy.PUBLIC;
 
         // Overlay matches target signature
-        if (mOverlayableCallback.signaturesMatching(targetPackage.packageName,
+        if (mPackageManager.signaturesMatching(targetPackage.packageName,
                 overlayPackage.packageName, userId)) {
             fulfilledPolicies |= OverlayablePolicy.SIGNATURE;
         }
@@ -149,6 +159,16 @@
             fulfilledPolicies |= OverlayablePolicy.ACTOR_SIGNATURE;
         }
 
+        // If SystemConfig defines 'config-signature' package, given that
+        // this package is vetted by OverlayManagerService that it's a
+        // preinstalled package, check if overlay matches its signature.
+        if (!TextUtils.isEmpty(mConfigSignaturePackage)
+                && mPackageManager.signaturesMatching(mConfigSignaturePackage,
+                                                           overlayPackage.packageName,
+                                                           userId)) {
+            fulfilledPolicies |= OverlayablePolicy.CONFIG_SIGNATURE;
+        }
+
         // Vendor partition (/vendor)
         if (ai.isVendor()) {
             return fulfilledPolicies | OverlayablePolicy.VENDOR_PARTITION;
@@ -183,12 +203,12 @@
         String targetOverlayableName = overlayPackage.targetOverlayableName;
         if (targetOverlayableName != null) {
             try {
-                OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget(
+                OverlayableInfo overlayableInfo = mPackageManager.getOverlayableForTarget(
                         targetPackage.packageName, targetOverlayableName, userId);
                 if (overlayableInfo != null && overlayableInfo.actor != null) {
                     String actorPackageName = OverlayActorEnforcer.getPackageNameForActor(
-                            overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first;
-                    if (mOverlayableCallback.signaturesMatching(actorPackageName,
+                            overlayableInfo.actor, mPackageManager.getNamedActors()).first;
+                    if (mPackageManager.signaturesMatching(actorPackageName,
                             overlayPackage.packageName, userId)) {
                         return true;
                     }
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index 2bc3499..8c03c6c 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -45,7 +45,7 @@
     // By default, the reason is not logged to prevent leaks of why it failed
     private static final boolean DEBUG_REASON = false;
 
-    private final OverlayableInfoCallback mOverlayableCallback;
+    private final PackageManagerHelper mPackageManager;
 
     /**
      * @return nullable actor result with {@link ActorState} failure status
@@ -79,8 +79,8 @@
         return Pair.create(packageName, ActorState.ALLOWED);
     }
 
-    public OverlayActorEnforcer(@NonNull OverlayableInfoCallback overlayableCallback) {
-        mOverlayableCallback = overlayableCallback;
+    public OverlayActorEnforcer(@NonNull PackageManagerHelper packageManager) {
+        mPackageManager = packageManager;
     }
 
     void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName,
@@ -110,7 +110,7 @@
                 return ActorState.ALLOWED;
         }
 
-        String[] callingPackageNames = mOverlayableCallback.getPackagesForUid(callingUid);
+        String[] callingPackageNames = mPackageManager.getPackagesForUid(callingUid);
         if (ArrayUtils.isEmpty(callingPackageNames)) {
             return ActorState.NO_PACKAGES_FOR_UID;
         }
@@ -125,12 +125,12 @@
 
         if (TextUtils.isEmpty(targetOverlayableName)) {
             try {
-                if (mOverlayableCallback.doesTargetDefineOverlayable(targetPackageName, userId)) {
+                if (mPackageManager.doesTargetDefineOverlayable(targetPackageName, userId)) {
                     return ActorState.MISSING_TARGET_OVERLAYABLE_NAME;
                 } else {
                     // If there's no overlayable defined, fallback to the legacy permission check
                     try {
-                        mOverlayableCallback.enforcePermission(
+                        mPackageManager.enforcePermission(
                                 android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
 
                         // If the previous method didn't throw, check passed
@@ -146,7 +146,7 @@
 
         OverlayableInfo targetOverlayable;
         try {
-            targetOverlayable = mOverlayableCallback.getOverlayableForTarget(targetPackageName,
+            targetOverlayable = mPackageManager.getOverlayableForTarget(targetPackageName,
                     targetOverlayableName, userId);
         } catch (IOException e) {
             return ActorState.UNABLE_TO_GET_TARGET;
@@ -160,7 +160,7 @@
         if (TextUtils.isEmpty(actor)) {
             // If there's no actor defined, fallback to the legacy permission check
             try {
-                mOverlayableCallback.enforcePermission(
+                mPackageManager.enforcePermission(
                         android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
 
                 // If the previous method didn't throw, check passed
@@ -170,7 +170,7 @@
             }
         }
 
-        Map<String, Map<String, String>> namedActors = mOverlayableCallback.getNamedActors();
+        Map<String, Map<String, String>> namedActors = mPackageManager.getNamedActors();
         Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors);
         ActorState actorUriState = actorUriPair.second;
         if (actorUriState != ActorState.ALLOWED) {
@@ -178,7 +178,7 @@
         }
 
         String packageName = actorUriPair.first;
-        PackageInfo packageInfo = mOverlayableCallback.getPackageInfo(packageName, userId);
+        PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, userId);
         if (packageInfo == null) {
             return ActorState.MISSING_APP_INFO;
         }
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 3968153..0f8c9c7 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -1053,8 +1053,7 @@
         }
     }
 
-    private static final class PackageManagerHelperImpl implements PackageManagerHelper,
-            OverlayableInfoCallback {
+    private static final class PackageManagerHelperImpl implements PackageManagerHelper  {
 
         private final Context mContext;
         private final IPackageManager mPackageManager;
@@ -1127,6 +1126,14 @@
             return overlays;
         }
 
+        @Override
+        public String getConfigSignaturePackage() {
+            final String[] pkgs = mPackageManagerInternal.getKnownPackageNames(
+                    PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE,
+                    UserHandle.USER_SYSTEM);
+            return (pkgs.length == 0) ? null : pkgs[0];
+        }
+
         @Nullable
         @Override
         public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
diff --git a/services/core/java/com/android/server/om/OverlayableInfoCallback.java b/services/core/java/com/android/server/om/OverlayableInfoCallback.java
deleted file mode 100644
index 5066ecd..0000000
--- a/services/core/java/com/android/server/om/OverlayableInfoCallback.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-package com.android.server.om;
-
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.om.OverlayableInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-
-import com.android.server.pm.PackageManagerServiceUtils;
-
-import java.io.IOException;
-import java.util.Map;
-
-/**
- * Delegate to the system for querying information about overlayables and packages.
- */
-public interface OverlayableInfoCallback {
-
-    /**
-     * Read from the APK and AndroidManifest of a package to return the overlayable defined for
-     * a given name.
-     *
-     * @throws IOException if the target can't be read
-     */
-    @Nullable
-    OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
-            @NonNull String targetOverlayableName, int userId)
-            throws IOException;
-
-    /**
-     * @see PackageManager#getPackagesForUid(int)
-     */
-    @Nullable
-    String[] getPackagesForUid(int uid);
-
-    /**
-     * @param userId user to filter package visibility by
-     * @see PackageManager#getPackageInfo(String, int)
-     */
-    @Nullable
-    PackageInfo getPackageInfo(@NonNull String packageName, int userId);
-
-    /**
-     * @return map of system pre-defined, uniquely named actors; keys are namespace,
-     * value maps actor name to package name
-     */
-    @NonNull
-    Map<String, Map<String, String>> getNamedActors();
-
-    /**
-     * @return true if the target package has declared an overlayable
-     */
-    boolean doesTargetDefineOverlayable(String targetPackageName, int userId) throws IOException;
-
-    /**
-     * @throws SecurityException containing message if the caller doesn't have the given
-     *                           permission
-     */
-    void enforcePermission(String permission, String message) throws SecurityException;
-
-    /**
-     * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages
-     *     in the system returns {@link PackageManager#SIGNATURE_MATCH}
-     */
-    boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
-}
diff --git a/services/core/java/com/android/server/om/PackageManagerHelper.java b/services/core/java/com/android/server/om/PackageManagerHelper.java
index ec9c5e6..b1a8b4e 100644
--- a/services/core/java/com/android/server/om/PackageManagerHelper.java
+++ b/services/core/java/com/android/server/om/PackageManagerHelper.java
@@ -17,11 +17,17 @@
 package com.android.server.om;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.om.OverlayableInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 
+import com.android.server.pm.PackageManagerServiceUtils;
+
+import java.io.IOException;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Delegate for {@link PackageManager} and {@link PackageManagerInternal} functionality,
@@ -30,7 +36,65 @@
  * @hide
  */
 interface PackageManagerHelper {
-    PackageInfo getPackageInfo(@NonNull String packageName, int userId);
-    boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
+    /**
+     * @return true if the target package has declared an overlayable
+     */
+    boolean doesTargetDefineOverlayable(String targetPackageName, int userId) throws IOException;
+
+    /**
+     * @throws SecurityException containing message if the caller doesn't have the given
+     *                           permission
+     */
+    void enforcePermission(String permission, String message) throws SecurityException;
+
+    /**
+     * Returns the package name of the reference package defined in 'overlay-config-signature' tag
+     * of SystemConfig. This package is vetted on scan by PackageManagerService that it's a system
+     * package and is used to check if overlay matches its signature in order to fulfill the
+     * config_signature policy.
+     */
+    @Nullable
+    String getConfigSignaturePackage();
+
+    /**
+     * @return map of system pre-defined, uniquely named actors; keys are namespace,
+     * value maps actor name to package name
+     */
+    @NonNull
+    Map<String, Map<String, String>> getNamedActors();
+
+    /**
+     * @see PackageManagerInternal#getOverlayPackages(int)
+     */
     List<PackageInfo> getOverlayPackages(int userId);
+
+    /**
+     * Read from the APK and AndroidManifest of a package to return the overlayable defined for
+     * a given name.
+     *
+     * @throws IOException if the target can't be read
+     */
+    @Nullable
+    OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
+            @NonNull String targetOverlayableName, int userId)
+            throws IOException;
+
+    /**
+     * @see PackageManager#getPackagesForUid(int)
+     */
+    @Nullable
+    String[] getPackagesForUid(int uid);
+
+    /**
+     * @param userId user to filter package visibility by
+     * @see PackageManager#getPackageInfo(String, int)
+     */
+    @Nullable
+    PackageInfo getPackageInfo(@NonNull String packageName, int userId);
+
+    /**
+     * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages
+     *     in the system returns {@link PackageManager#SIGNATURE_MATCH}
+     */
+    boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4f0c707..fddd46a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -120,6 +120,7 @@
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceUtils.comparePackageSignatures;
 import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
 import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
 import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
@@ -1114,6 +1115,7 @@
         public @Nullable String storageManagerPackage;
         public @Nullable String defaultTextClassifierPackage;
         public @Nullable String systemTextClassifierPackage;
+        public @Nullable String overlayConfigSignaturePackage;
         public ViewCompiler viewCompiler;
         public @Nullable String wellbeingPackage;
         public @Nullable String retailDemoPackage;
@@ -1646,6 +1648,7 @@
     final @Nullable String mServicesExtensionPackageName;
     final @Nullable String mSharedSystemSharedLibraryPackageName;
     final @Nullable String mRetailDemoPackage;
+    final @Nullable String mOverlayConfigSignaturePackage;
 
     private final PackageUsage mPackageUsage = new PackageUsage();
     private final CompilerStats mCompilerStats = new CompilerStats();
@@ -2808,6 +2811,7 @@
         mIncidentReportApproverPackage = testParams.incidentReportApproverPackage;
         mServicesExtensionPackageName = testParams.servicesExtensionPackageName;
         mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName;
+        mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage;
 
         mResolveComponentName = testParams.resolveComponentName;
         mPackages.putAll(testParams.packages);
@@ -3373,6 +3377,7 @@
             mAppPredictionServicePackage = getAppPredictionServicePackageName();
             mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
             mRetailDemoPackage = getRetailDemoPackageName();
+            mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName();
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
@@ -12096,12 +12101,8 @@
                 if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
                     // Exempt SharedUsers signed with the platform key.
                     PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
-                    if ((platformPkgSetting.signatures.mSigningDetails
-                            != PackageParser.SigningDetails.UNKNOWN)
-                            && (compareSignatures(
-                                    platformPkgSetting.signatures.mSigningDetails.signatures,
-                            pkg.getSigningDetails().signatures)
-                                            != PackageManager.SIGNATURE_MATCH)) {
+                    if (!comparePackageSignatures(platformPkgSetting,
+                            pkg.getSigningDetails().signatures)) {
                         throw new PackageManagerException("Apps that share a user with a " +
                                 "privileged app must themselves be marked as privileged. " +
                                 pkg.getPackageName() + " shares privileged user " +
@@ -12148,12 +12149,8 @@
                     if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) {
                         final PackageSetting platformPkgSetting =
                                 mSettings.getPackageLPr("android");
-                        if ((platformPkgSetting.signatures.mSigningDetails
-                                    != PackageParser.SigningDetails.UNKNOWN)
-                                && (compareSignatures(
-                                        platformPkgSetting.signatures.mSigningDetails.signatures,
-                                pkg.getSigningDetails().signatures)
-                                    != PackageManager.SIGNATURE_MATCH)) {
+                        if (!comparePackageSignatures(platformPkgSetting,
+                                pkg.getSigningDetails().signatures)) {
                             throw new PackageManagerException("Overlay "
                                     + pkg.getPackageName()
                                     + " must target Q or later, "
@@ -12162,24 +12159,35 @@
                     }
 
                     // A non-preloaded overlay package, without <overlay android:targetName>, will
-                    // only be used if it is signed with the same certificate as its target. If the
-                    // target is already installed, check this here to augment the last line of
-                    // defence which is OMS.
+                    // only be used if it is signed with the same certificate as its target OR if
+                    // it is signed with the same certificate as a reference package declared
+                    // in 'config-signature' tag of SystemConfig.
+                    // If the target is already installed or 'config-signature' tag in SystemConfig
+                    // is set, check this here to augment the last line of defence which is OMS.
                     if (pkg.getOverlayTargetName() == null) {
                         final PackageSetting targetPkgSetting =
                                 mSettings.getPackageLPr(pkg.getOverlayTarget());
                         if (targetPkgSetting != null) {
-                            if ((targetPkgSetting.signatures.mSigningDetails
-                                        != PackageParser.SigningDetails.UNKNOWN)
-                                    && (compareSignatures(
-                                            targetPkgSetting.signatures.mSigningDetails.signatures,
-                                    pkg.getSigningDetails().signatures)
-                                        != PackageManager.SIGNATURE_MATCH)) {
-                                throw new PackageManagerException("Overlay "
-                                        + pkg.getPackageName() + " and target "
-                                        + pkg.getOverlayTarget() + " signed with"
-                                        + " different certificates, and the overlay lacks"
-                                        + " <overlay android:targetName>");
+                            if (!comparePackageSignatures(targetPkgSetting,
+                                    pkg.getSigningDetails().signatures)) {
+                                // check reference signature
+                                if (mOverlayConfigSignaturePackage == null) {
+                                    throw new PackageManagerException("Overlay "
+                                            + pkg.getPackageName() + " and target "
+                                            + pkg.getOverlayTarget() + " signed with"
+                                            + " different certificates, and the overlay lacks"
+                                            + " <overlay android:targetName>");
+                                }
+                                final PackageSetting refPkgSetting =
+                                        mSettings.getPackageLPr(mOverlayConfigSignaturePackage);
+                                if (!comparePackageSignatures(refPkgSetting,
+                                        pkg.getSigningDetails().signatures)) {
+                                    throw new PackageManagerException("Overlay "
+                                            + pkg.getPackageName() + " signed with a different "
+                                            + "certificate than both the reference package and "
+                                            + "target " + pkg.getOverlayTarget() + ", and the "
+                                            + "overlay lacks <overlay android:targetName>");
+                                }
                             }
                         }
                     }
@@ -20712,6 +20720,11 @@
         return ensureSystemPackageName(contentCaptureServiceComponentName.getPackageName());
     }
 
+    public String getOverlayConfigSignaturePackageName() {
+        return ensureSystemPackageName(SystemConfig.getInstance()
+                .getOverlayConfigSignaturePackage());
+    }
+
     @Nullable
     private String getRetailDemoPackageName() {
         final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage);
@@ -24228,6 +24241,8 @@
                     return TextUtils.isEmpty(mRetailDemoPackage)
                             ? ArrayUtils.emptyArray(String.class)
                             : new String[] {mRetailDemoPackage};
+                case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE:
+                    return filterOnlySystemPackages(getOverlayConfigSignaturePackageName());
                 default:
                     return ArrayUtils.emptyArray(String.class);
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 03f4708..de0e4b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -488,6 +488,18 @@
     }
 
     /**
+     * Returns true if the signature set of the package is identical to the specified signature
+     * set or if the signing details of the package are unknown.
+     */
+    public static boolean comparePackageSignatures(PackageSetting pkgSetting,
+            Signature[] signatures) {
+        return pkgSetting.signatures.mSigningDetails
+                == PackageParser.SigningDetails.UNKNOWN
+                || compareSignatures(pkgSetting.signatures.mSigningDetails.signatures, signatures)
+                == PackageManager.SIGNATURE_MATCH;
+    }
+
+    /**
      * Used for backward compatibility to make sure any packages with
      * certificate chains get upgraded to the new style. {@code existingSigs}
      * will be in the old format (since they were stored on disk from before the
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
index e08eea2..0839273 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
@@ -160,7 +160,7 @@
         private val hasPermission: Boolean = false,
         private val overlayableInfo: OverlayableInfo? = null,
         private vararg val packageNames: String = arrayOf("com.test.actor.one")
-    ) : OverlayableInfoCallback {
+    ) : PackageManagerHelper {
 
         override fun getNamedActors() = if (isActor) {
             mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME))
@@ -195,6 +195,14 @@
             }
         }
 
+        override fun getConfigSignaturePackage(): String {
+            throw UnsupportedOperationException()
+        }
+
+        override fun getOverlayPackages(userId: Int): MutableList<PackageInfo> {
+            throw UnsupportedOperationException()
+        }
+
         override fun signaturesMatching(pkgName1: String, pkgName2: String, userId: Int): Boolean {
             throw UnsupportedOperationException()
         }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
index b7692f9..e281f2b 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
@@ -44,9 +44,9 @@
     @Test
     public void testUpdateOverlaysForUser() {
         final OverlayManagerServiceImpl impl = getImpl();
-        addSystemPackage(target(TARGET), USER);
-        addSystemPackage(target("some.other.target"), USER);;
-        addSystemPackage(overlay(OVERLAY, TARGET), USER);
+        addPackage(target(TARGET), USER);
+        addPackage(target("some.other.target"), USER);
+        addPackage(overlay(OVERLAY, TARGET), USER);
 
         // do nothing, expect no change
         final List<String> a = impl.updateOverlaysForUser(USER);
@@ -54,7 +54,7 @@
         assertTrue(a.contains(TARGET));
 
         // upgrade overlay, keep target
-        addSystemPackage(overlay(OVERLAY, TARGET), USER);
+        addPackage(overlay(OVERLAY, TARGET), USER);
 
         final List<String> b = impl.updateOverlaysForUser(USER);
         assertEquals(1, b.size());
@@ -66,7 +66,7 @@
         assertTrue(c.contains(TARGET));
 
         // upgrade overlay, switch to new target
-        addSystemPackage(overlay(OVERLAY, "some.other.target"), USER);
+        addPackage(overlay(OVERLAY, "some.other.target"), USER);
         final List<String> d = impl.updateOverlaysForUser(USER);
         assertEquals(2, d.size());
         assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target")));
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index f4c5506..c1d862a 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -19,6 +19,7 @@
 import static android.content.om.OverlayInfo.STATE_DISABLED;
 import static android.content.om.OverlayInfo.STATE_ENABLED;
 import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
+import static android.os.OverlayablePolicy.CONFIG_SIGNATURE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -49,6 +50,10 @@
     private static final String OVERLAY3 = OVERLAY + "3";
     private static final int USER3 = USER2 + 1;
 
+    private static final String CONFIG_SIGNATURE_REFERENCE_PKG = "com.dummy.ref";
+    private static final String CERT_CONFIG_OK = "config_certificate_ok";
+    private static final String CERT_CONFIG_NOK = "config_certificate_nok";
+
     @Test
     public void testGetOverlayInfo() {
         installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -204,4 +209,87 @@
         impl.setEnabled(OVERLAY, true, USER);
         assertEquals(0, listener.count);
     }
+
+    @Test
+    public void testConfigSignaturePolicyOk() {
+        setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
+        reinitializeImpl();
+
+        addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+        installNewPackage(target(TARGET), USER);
+        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_OK), USER);
+
+        final DummyIdmapDaemon idmapd = getIdmapd();
+        final DummyDeviceState state = getState();
+        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+        DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertTrue((CONFIG_SIGNATURE & idmap.policies) == CONFIG_SIGNATURE);
+    }
+
+    @Test
+    public void testConfigSignaturePolicyCertNok() {
+        setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
+        reinitializeImpl();
+
+        addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+        installNewPackage(target(TARGET), USER);
+        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+        final DummyIdmapDaemon idmapd = getIdmapd();
+        final DummyDeviceState state = getState();
+        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+        DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+    }
+
+    @Test
+    public void testConfigSignaturePolicyNoConfig() {
+        addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+        installNewPackage(target(TARGET), USER);
+        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+        final DummyIdmapDaemon idmapd = getIdmapd();
+        final DummyDeviceState state = getState();
+        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+        DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+    }
+
+    @Test
+    public void testConfigSignaturePolicyNoRefPkg() {
+        installNewPackage(target(TARGET), USER);
+        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+        final DummyIdmapDaemon idmapd = getIdmapd();
+        final DummyDeviceState state = getState();
+        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+        DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+    }
+
+    @Test
+    public void testConfigSignaturePolicyRefPkgNotSystem() {
+        setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
+        reinitializeImpl();
+
+        addPackage(app(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+        installNewPackage(target(TARGET), USER);
+        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+        final DummyIdmapDaemon idmapd = getIdmapd();
+        final DummyDeviceState state = getState();
+        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+        DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index 733310b..2faf29f 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -27,6 +27,7 @@
 import android.content.om.OverlayableInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
@@ -52,6 +53,7 @@
     private DummyPackageManagerHelper mPackageManager;
     private DummyIdmapDaemon mIdmapDaemon;
     private OverlayConfig mOverlayConfig;
+    private String mConfigSignaturePackageName;
 
     @Before
     public void setUp() {
@@ -83,6 +85,18 @@
         return mListener;
     }
 
+    DummyIdmapDaemon getIdmapd() {
+        return mIdmapDaemon;
+    }
+
+    DummyDeviceState getState() {
+        return mState;
+    }
+
+    void setConfigSignaturePackageName(String packageName) {
+        mConfigSignaturePackageName = packageName;
+    }
+
     void assertState(@State int expected, final String overlayPackageName, int userId) {
         final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId);
         if (info == null) {
@@ -102,9 +116,14 @@
         assertEquals(expected, actual);
     }
 
+    DummyDeviceState.PackageBuilder app(String packageName) {
+        return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
+                null /* targetOverlayableName */, "data");
+    }
+
     DummyDeviceState.PackageBuilder target(String packageName) {
         return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
-                null /* targetOverlayableName */);
+                null /* targetOverlayableName */, "");
     }
 
     DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) {
@@ -114,10 +133,10 @@
     DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName,
             String targetOverlayableName) {
         return new DummyDeviceState.PackageBuilder(packageName, targetPackageName,
-                targetOverlayableName);
+                targetOverlayableName, "");
     }
 
-    void addSystemPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
+    void addPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
         mState.add(pkg, userId);
     }
 
@@ -242,15 +261,17 @@
             private String packageName;
             private String targetPackage;
             private String certificate = "[default]";
+            private String partition;
             private int version = 0;
             private ArrayList<String> overlayableNames = new ArrayList<>();
             private String targetOverlayableName;
 
             private PackageBuilder(String packageName, String targetPackage,
-                    String targetOverlayableName) {
+                    String targetOverlayableName, String partition) {
                 this.packageName = packageName;
                 this.targetPackage = targetPackage;
                 this.targetOverlayableName = targetOverlayableName;
+                this.partition = partition;
             }
 
             PackageBuilder setCertificate(String certificate) {
@@ -269,9 +290,19 @@
             }
 
             Package build() {
-                final String apkPath = String.format("%s/%s/base.apk",
-                        targetPackage == null ? "/system/app/:" : "/vendor/overlay/:",
-                        packageName);
+                String path = "";
+                if (TextUtils.isEmpty(partition)) {
+                    if (targetPackage == null) {
+                        path = "/system/app";
+                    } else {
+                        path = "/vendor/overlay";
+                    }
+                } else {
+                    String type = targetPackage == null ? "app" : "overlay";
+                    path = String.format("%s/%s", partition, type);
+                }
+
+                final String apkPath = String.format("%s/%s/base.apk", path, packageName);
                 final Package newPackage = new Package(packageName, targetPackage,
                         targetOverlayableName, version, apkPath, certificate);
                 newPackage.overlayableNames.addAll(overlayableNames);
@@ -302,8 +333,7 @@
         }
     }
 
-    static final class DummyPackageManagerHelper implements PackageManagerHelper,
-            OverlayableInfoCallback {
+    final class DummyPackageManagerHelper implements PackageManagerHelper {
         private final DummyDeviceState mState;
 
         private DummyPackageManagerHelper(DummyDeviceState state) {
@@ -343,6 +373,11 @@
                     .collect(Collectors.toList());
         }
 
+        @Override
+        public @NonNull String getConfigSignaturePackage() {
+            return mConfigSignaturePackageName;
+        }
+
         @Nullable
         @Override
         public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index ab9ce66..b1e1a77 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -168,6 +168,7 @@
     ODM = 6;
     OEM = 7;
     ACTOR = 8;
+    CONFIG_SIGNATURE = 9;
   }
 
   // The location of the <item> declaration in source.
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 59627ce..6932baf 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -776,6 +776,7 @@
   OverlayableItem overlayable_item_three(group_one);
   overlayable_item_three.policies |= PolicyFlags::SIGNATURE;
   overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE;
+  overlayable_item_three.policies |= PolicyFlags::CONFIG_SIGNATURE;
 
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
@@ -830,7 +831,8 @@
   EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
   EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
   EXPECT_EQ(result_overlayable.policies, PolicyFlags::SIGNATURE
-                                           | PolicyFlags::ACTOR_SIGNATURE);
+                                           | PolicyFlags::ACTOR_SIGNATURE
+                                           | PolicyFlags::CONFIG_SIGNATURE);
 }
 
 TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) {
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 2fd01d7..7eb8ebd 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -404,6 +404,9 @@
       case pb::OverlayableItem::ACTOR:
         out_overlayable->policies |= PolicyFlags::ACTOR_SIGNATURE;
         break;
+      case pb::OverlayableItem::CONFIG_SIGNATURE:
+        out_overlayable->policies |= PolicyFlags::CONFIG_SIGNATURE;
+        break;
       default:
         *out_error = "unknown overlayable policy";
         return false;
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index ba6df22..831229f 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -325,6 +325,9 @@
   if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR);
   }
+  if (overlayable_item.policies & PolicyFlags::CONFIG_SIGNATURE) {
+    pb_overlayable_item->add_policy(pb::OverlayableItem::CONFIG_SIGNATURE);
+  }
 
   if (source_pool != nullptr) {
     SerializeSourceToPb(overlayable_item.source, source_pool,