Merge "Enforce the overlayable mechanism for self-targeting"
diff --git a/cmds/idmap2/self_targeting/SelfTargeting.cpp b/cmds/idmap2/self_targeting/SelfTargeting.cpp
index 20aa7d3..a8aa033 100644
--- a/cmds/idmap2/self_targeting/SelfTargeting.cpp
+++ b/cmds/idmap2/self_targeting/SelfTargeting.cpp
@@ -38,9 +38,10 @@
 constexpr const mode_t kIdmapFilePermission = S_IRUSR | S_IWUSR;  // u=rw-, g=---, o=---
 
 extern "C" bool
-CreateFrroFile(std::string& out_err_result, std::string& packageName, std::string& overlayName,
-               std::string& targetPackageName, std::optional<std::string>& targetOverlayable,
-               std::vector<FabricatedOverlayEntryParameters>& entries_params,
+CreateFrroFile(std::string& out_err_result, const std::string& packageName,
+               const std::string& overlayName, const std::string& targetPackageName,
+               const std::optional<std::string>& targetOverlayable,
+               const std::vector<FabricatedOverlayEntryParameters>& entries_params,
                const std::string& frro_file_path) {
     android::idmap2::FabricatedOverlay::Builder builder(packageName, overlayName,
                                                         targetPackageName);
@@ -90,9 +91,46 @@
     return true;
 }
 
+static PolicyBitmask GetFulfilledPolicy(const bool isSystem, const bool isVendor,
+                                        const bool isProduct, const bool isTargetSignature,
+                                        const bool isOdm, const bool isOem) {
+    auto fulfilled_policy = static_cast<PolicyBitmask>(PolicyFlags::PUBLIC);
+
+    if (isSystem) {
+        fulfilled_policy |= PolicyFlags::SYSTEM_PARTITION;
+    }
+    if (isVendor) {
+        fulfilled_policy |= PolicyFlags::VENDOR_PARTITION;
+    }
+    if (isProduct) {
+        fulfilled_policy |= PolicyFlags::PRODUCT_PARTITION;
+    }
+    if (isOdm) {
+        fulfilled_policy |= PolicyFlags::ODM_PARTITION;
+    }
+    if (isOem) {
+        fulfilled_policy |= PolicyFlags::OEM_PARTITION;
+    }
+    if (isTargetSignature) {
+        fulfilled_policy |= PolicyFlags::SIGNATURE;
+    }
+
+    // Not support actor_signature and config_overlay_signature
+    fulfilled_policy &=
+            ~(PolicyFlags::ACTOR_SIGNATURE | PolicyFlags::CONFIG_SIGNATURE);
+
+    ALOGV(
+            "fulfilled_policy = 0x%08x, isSystem = %d, isVendor = %d, isProduct = %d,"
+            " isTargetSignature = %d, isOdm = %d, isOem = %d,",
+            fulfilled_policy, isSystem, isVendor, isProduct, isTargetSignature, isOdm, isOem);
+    return fulfilled_policy;
+}
+
 extern "C" bool
 CreateIdmapFile(std::string& out_err, const std::string& targetPath, const std::string& overlayPath,
-                const std::string& idmapPath, const std::string& overlayName) {
+                const std::string& idmapPath, const std::string& overlayName,
+                const bool isSystem, const bool isVendor, const bool isProduct,
+                const bool isTargetSignature, const bool isOdm, const bool isOem) {
     // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap
     // guarantees that existing memory maps will continue to be valid and unaffected. The file must
     // be deleted before attempting to create the idmap, so that if idmap  creation fails, the
@@ -114,14 +152,11 @@
     }
 
     // Overlay self target process. Only allow self-targeting types.
-    const auto fulfilled_policies = static_cast<PolicyBitmask>(
-            PolicyFlags::PUBLIC | PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION |
-            PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE | PolicyFlags::ODM_PARTITION |
-            PolicyFlags::OEM_PARTITION | PolicyFlags::ACTOR_SIGNATURE |
-            PolicyFlags::CONFIG_SIGNATURE);
+    const auto fulfilled_policies = GetFulfilledPolicy(isSystem, isVendor, isProduct,
+                                                       isTargetSignature, isOdm, isOem);
 
     const auto idmap = Idmap::FromContainers(**target, **overlay, overlayName,
-                                             fulfilled_policies, false /* enforce_overlayable */);
+                                             fulfilled_policies, true /* enforce_overlayable */);
     if (!idmap) {
         out_err = base::StringPrintf("Failed to create idmap because of %s",
                                      idmap.GetErrorMessage().c_str());
diff --git a/core/java/com/android/internal/content/om/OverlayManagerImpl.java b/core/java/com/android/internal/content/om/OverlayManagerImpl.java
index 76e068d..e56c06e 100644
--- a/core/java/com/android/internal/content/om/OverlayManagerImpl.java
+++ b/core/java/com/android/internal/content/om/OverlayManagerImpl.java
@@ -170,6 +170,16 @@
         mBasePath = baseFile.toPath();
     }
 
+    private boolean isSameWithTargetSignature(final String targetPackage) {
+        final PackageManager packageManager = mContext.getPackageManager();
+        final String packageName = mContext.getPackageName();
+        if (TextUtils.equals(packageName, targetPackage)) {
+            return true;
+        }
+        return packageManager.checkSignatures(packageName, targetPackage)
+                == PackageManager.SIGNATURE_MATCH;
+    }
+
     /**
      * Check if the overlay name is valid or not.
      *
@@ -202,6 +212,9 @@
     /**
      * Save FabricatedOverlay instance as frro and idmap files.
      *
+     * <p>In order to fill the overlayable policy, it's necessary to collect the information from
+     * app. And then, the information is passed to native layer to fill the overlayable policy
+     *
      * @param overlayInternal the FabricatedOverlayInternal to be saved.
      */
     public void registerFabricatedOverlay(@NonNull FabricatedOverlayInternal overlayInternal)
@@ -214,6 +227,9 @@
         final String overlayName = checkOverlayNameValid(overlayInternal.overlayName);
         checkPackageName(overlayInternal.packageName);
         checkPackageName(overlayInternal.targetPackageName);
+        Preconditions.checkStringNotEmpty(
+                overlayInternal.targetOverlayable,
+                "Target overlayable should be neither null nor empty string.");
 
         final ApplicationInfo applicationInfo = mContext.getApplicationInfo();
         final String targetPackage = Preconditions.checkStringNotEmpty(
@@ -223,7 +239,17 @@
 
         createFrroFile(frroPath.toString(), overlayInternal);
         try {
-            createIdmapFile(targetPackage, frroPath.toString(), idmapPath.toString(), overlayName);
+            createIdmapFile(
+                    targetPackage,
+                    frroPath.toString(),
+                    idmapPath.toString(),
+                    overlayName,
+                    applicationInfo.isSystemApp() || applicationInfo.isSystemExt() /* isSystem */,
+                    applicationInfo.isVendor(),
+                    applicationInfo.isProduct(),
+                    isSameWithTargetSignature(overlayInternal.targetPackageName),
+                    applicationInfo.isOdm(),
+                    applicationInfo.isOem());
         } catch (IOException e) {
             if (!frroPath.toFile().delete()) {
                 Log.w(TAG, "Failed to delete file " + frroPath);
@@ -315,7 +341,13 @@
             @NonNull String targetPath,
             @NonNull String overlayPath,
             @NonNull String idmapPath,
-            @NonNull String overlayName)
+            @NonNull String overlayName,
+            boolean isSystem,
+            boolean isVendor,
+            boolean isProduct,
+            boolean isSameWithTargetSignature,
+            boolean isOdm,
+            boolean isOem)
             throws IOException;
 
     private static native FabricatedOverlayInfo getFabricatedOverlayInfo(
diff --git a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
index df55e42..bba1760 100644
--- a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
+++ b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
@@ -123,8 +123,12 @@
 
     bool callCreateIdmapFile(std::string& out_error, const std::string& targetPath,
                              const std::string& overlayPath, const std::string& idmapPath,
-                             const std::string& overlayName) {
-        return createIdmapFileFuncPtr_(out_error, targetPath, overlayPath, idmapPath, overlayName);
+                             const std::string& overlayName, const bool isSystem,
+                             const bool isVendor, const bool isProduct,
+                             const bool isTargetSignature, const bool isOdm, const bool isOem) {
+        return createIdmapFileFuncPtr_(out_error, targetPath, overlayPath, idmapPath, overlayName,
+                                       isSystem, isVendor, isProduct, isTargetSignature, isOdm,
+                                       isOem);
     }
 
     bool callGetFabricatedOverlayInfo(std::string& out_error, const std::string& overlay_path,
@@ -158,7 +162,10 @@
     typedef bool (*CreateIdmapFileFunc)(std::string& out_error, const std::string& targetPath,
                                         const std::string& overlayPath,
                                         const std::string& idmapPath,
-                                        const std::string& overlayName);
+                                        const std::string& overlayName, const jboolean isSystem,
+                                        const jboolean isVendor, const jboolean isProduct,
+                                        const jboolean isSameWithTargetSignature,
+                                        const jboolean isOdm, const jboolean isOem);
 
     typedef bool (*GetFabricatedOverlayInfoFunc)(std::string& out_error,
                                                  const std::string& overlay_path,
@@ -295,7 +302,9 @@
 }
 
 static void CreateIdmapFile(JNIEnv* env, jclass /* clazz */, jstring jsTargetPath,
-                            jstring jsOverlayPath, jstring jsIdmapPath, jstring jsOverlayName) {
+                            jstring jsOverlayPath, jstring jsIdmapPath, jstring jsOverlayName,
+                            jboolean isSystem, jboolean isVendor, jboolean isProduct,
+                            jboolean isTargetSignature, jboolean isOdm, jboolean isOem) {
     DynamicLibraryLoader& dlLoader = EnsureDynamicLibraryLoader(env);
     if (!dlLoader) {
         jniThrowNullPointerException(env, "libidmap2 is not loaded");
@@ -327,7 +336,10 @@
 
     std::string err_result;
     if (!dlLoader.callCreateIdmapFile(err_result, targetPath.c_str(), overlayPath.c_str(),
-                                      idmapPath.c_str(), overlayName.c_str())) {
+                                      idmapPath.c_str(), overlayName.c_str(),
+                                      (isSystem == JNI_TRUE), (isVendor == JNI_TRUE),
+                                      (isProduct == JNI_TRUE), (isTargetSignature == JNI_TRUE),
+                                      (isOdm == JNI_TRUE), (isOem == JNI_TRUE))) {
         jniThrowException(env, kIOException, err_result.c_str());
         return;
     }
@@ -374,7 +386,7 @@
         {"createFrroFile", "(Ljava/lang/String;Landroid/os/FabricatedOverlayInternal;)V",
          reinterpret_cast<void*>(self_targeting::CreateFrroFile)},
         {"createIdmapFile",
-         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZZZZ)V",
          reinterpret_cast<void*>(self_targeting::CreateIdmapFile)},
         {"getFabricatedOverlayInfo", "(Ljava/lang/String;)Landroid/os/FabricatedOverlayInfo;",
          reinterpret_cast<void*>(self_targeting::GetFabricatedOverlayInfo)},
diff --git a/core/tests/overlaytests/device_self_targeting/Android.bp b/core/tests/overlaytests/device_self_targeting/Android.bp
index 82998db..063c569 100644
--- a/core/tests/overlaytests/device_self_targeting/Android.bp
+++ b/core/tests/overlaytests/device_self_targeting/Android.bp
@@ -29,6 +29,7 @@
         "androidx.test.rules",
         "androidx.test.runner",
         "androidx.test.ext.junit",
+        "mockito-target-minus-junit4",
         "truth-prebuilt",
     ],
 
diff --git a/core/tests/overlaytests/device_self_targeting/res/values/overlayable.xml b/core/tests/overlaytests/device_self_targeting/res/values/overlayable.xml
new file mode 100644
index 0000000..5cc214d
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/res/values/overlayable.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2022 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="PublicOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="public">
+            <item type="color" name="public_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="SignatureOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="signature">
+            <item type="color" name="mycolor" />
+            <item type="color" name="signature_overlayable_color" />
+            <item type="string" name="mystring" />
+            <item type="drawable" name="mydrawable" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="SystemAppOverlayable" actor="overlay://theme">
+        <!-- The app in system partition can overlay the below resources -->
+        <policy type="system">
+            <item type="color" name="system_app_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="OdmOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="odm">
+            <item type="color" name="odm_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="OemOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="oem">
+            <item type="color" name="oem_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="VendorOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="vendor">
+            <item type="color" name="vendor_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="ProductOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="product">
+            <item type="color" name="product_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="ActorOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="actor">
+            <item type="color" name="actor_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="ConfigOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="config_signature">
+            <item type="color" name="config_overlayable_color" />
+        </policy>
+    </overlayable>
+
+</resources>
diff --git a/core/tests/overlaytests/device_self_targeting/res/values/values.xml b/core/tests/overlaytests/device_self_targeting/res/values/values.xml
index f0b4a6f..d82de97 100644
--- a/core/tests/overlaytests/device_self_targeting/res/values/values.xml
+++ b/core/tests/overlaytests/device_self_targeting/res/values/values.xml
@@ -17,4 +17,14 @@
 <resources>
     <color name="mycolor">#ff112233</color>
     <string name="mystring">hello</string>
+
+    <color name="public_overlayable_color">#000</color>
+    <color name="signature_overlayable_color">#000</color>
+    <color name="system_app_overlayable_color">#000</color>
+    <color name="odm_overlayable_color">#000</color>
+    <color name="oem_overlayable_color">#000</color>
+    <color name="vendor_overlayable_color">#000</color>
+    <color name="product_overlayable_color">#000</color>
+    <color name="actor_overlayable_color">#000</color>
+    <color name="config_overlayable_color">#000</color>
 </resources>
diff --git a/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java b/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java
index ca58410..8a9ab5b 100644
--- a/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java
+++ b/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java
@@ -17,15 +17,22 @@
 package com.android.overlaytest;
 
 import static android.content.Context.MODE_PRIVATE;
+import static android.content.pm.PackageManager.SIGNATURE_NO_MATCH;
 
 import static com.android.internal.content.om.OverlayManagerImpl.SELF_TARGET;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.graphics.Color;
 import android.os.FabricatedOverlayInternal;
@@ -72,11 +79,23 @@
     private static final String TARGET_COLOR_RES = "color/mycolor";
     private static final String TARGET_STRING_RES = "string/mystring";
     private static final String TARGET_DRAWABLE_RES = "drawable/mydrawable";
+    private static final String PUBLIC_OVERLAYABLE = "PublicOverlayable";
+    private static final String SIGNATURE_OVERLAYABLE = "SignatureOverlayable";
+    private static final String SYSTEM_APP_OVERLAYABLE = "SystemAppOverlayable";
+    private static final String ODM_OVERLAYABLE = "OdmOverlayable";
+    private static final String OEM_OVERLAYABLE = "OemOverlayable";
+    private static final String VENDOR_OVERLAYABLE = "VendorOverlayable";
+    private static final String PRODUCT_OVERLAYABLE = "ProductOverlayable";
+    private static final String ACTOR_OVERLAYABLE = "ActorOverlayable";
+    private static final String CONFIG_OVERLAYABLE = "ConfigOverlayable";
 
     private Context mContext;
     private OverlayManagerImpl mOverlayManagerImpl;
     private String mOverlayName;
 
+    private PackageManager mMockPackageManager;
+    private ApplicationInfo mMockApplicationInfo;
+
     @Rule public TestName mTestName = new TestName();
 
     @Rule public Expect expect = Expect.create();
@@ -111,7 +130,36 @@
     public void setUp() throws IOException {
         clearDir();
         mOverlayName = mTestName.getMethodName();
-        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        mMockApplicationInfo = mock(ApplicationInfo.class);
+        when(mMockApplicationInfo.isSystemApp()).thenReturn(false);
+        when(mMockApplicationInfo.isSystemExt()).thenReturn(false);
+        when(mMockApplicationInfo.isOdm()).thenReturn(false);
+        when(mMockApplicationInfo.isOem()).thenReturn(false);
+        when(mMockApplicationInfo.isVendor()).thenReturn(false);
+        when(mMockApplicationInfo.isProduct()).thenReturn(false);
+        when(mMockApplicationInfo.getBaseCodePath()).thenReturn(
+                context.getApplicationInfo().getBaseCodePath());
+        mMockApplicationInfo.sourceDir = context.getApplicationInfo().sourceDir;
+
+        mMockPackageManager = mock(PackageManager.class);
+        when(mMockPackageManager.checkSignatures(anyString(), anyString()))
+                .thenReturn(SIGNATURE_NO_MATCH);
+
+        mContext =
+                new ContextWrapper(context) {
+                    @Override
+                    public ApplicationInfo getApplicationInfo() {
+                        return mMockApplicationInfo;
+                    }
+
+                    @Override
+                    public PackageManager getPackageManager() {
+                        return mMockPackageManager;
+                    }
+                };
+
         mOverlayManagerImpl = new OverlayManagerImpl(mContext);
     }
 
@@ -144,12 +192,14 @@
 
     private <T> FabricatedOverlayInternal createOverlayWithName(
             @NonNull String overlayName,
+            @NonNull String targetOverlayable,
             @NonNull String targetPackageName,
             @NonNull List<Pair<String, Pair<String, T>>> entryDefinitions) {
         final String packageName = mContext.getPackageName();
         FabricatedOverlayInternal overlayInternal = new FabricatedOverlayInternal();
         overlayInternal.overlayName = overlayName;
         overlayInternal.targetPackageName = targetPackageName;
+        overlayInternal.targetOverlayable = targetOverlayable;
         overlayInternal.packageName = packageName;
 
         addOverlayEntry(overlayInternal, entryDefinitions);
@@ -162,6 +212,7 @@
         FabricatedOverlayInternal overlayInternal =
                 createOverlayWithName(
                         mOverlayName,
+                        SYSTEM_APP_OVERLAYABLE,
                         "android",
                         List.of(Pair.create("color/white", Pair.create(null, Color.BLACK))));
 
@@ -190,6 +241,7 @@
         FabricatedOverlayInternal overlayInternal =
                 createOverlayWithName(
                         mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
                         mContext.getPackageName(),
                         List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
 
@@ -215,6 +267,7 @@
         FabricatedOverlayInternal overlayInternal =
                 createOverlayWithName(
                         mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
                         mContext.getPackageName(),
                         List.of(Pair.create(TARGET_STRING_RES, Pair.create(null, "HELLO"))));
 
@@ -242,6 +295,7 @@
         FabricatedOverlayInternal overlayInternal =
                 createOverlayWithName(
                         mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
                         mContext.getPackageName(),
                         List.of(Pair.create(TARGET_DRAWABLE_RES,
                                             Pair.create(null, parcelFileDescriptor))));
@@ -268,6 +322,7 @@
         FabricatedOverlayInternal overlayInternal =
                 createOverlayWithName(
                         mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
                         mContext.getPackageName(),
                         List.of(Pair.create("color/not_existed", Pair.create(null, "HELLO"))));
 
@@ -301,6 +356,7 @@
         FabricatedOverlayInternal overlayInternal =
                 createOverlayWithName(
                         mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
                         mContext.getPackageName(),
                         List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
         mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
@@ -309,6 +365,7 @@
         overlayInternal =
                 createOverlayWithName(
                         secondOverlayName,
+                        SIGNATURE_OVERLAYABLE,
                         mContext.getPackageName(),
                         List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
         mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
@@ -341,6 +398,7 @@
         FabricatedOverlayInternal overlayInternal =
                 createOverlayWithName(
                         mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
                         mContext.getPackageName(),
                         List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
         mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
@@ -349,6 +407,7 @@
         overlayInternal =
                 createOverlayWithName(
                         mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
                         mContext.getPackageName(),
                         List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
         mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
@@ -408,4 +467,177 @@
 
         assertThrows(SecurityException.class, () -> new OverlayManagerImpl(fakeContext));
     }
+
+    FabricatedOverlayInternal prepareFabricatedOverlayInternal(
+            String targetOverlayableName, String targetEntryName) {
+        return createOverlayWithName(
+                mOverlayName,
+                targetOverlayableName,
+                mContext.getPackageName(),
+                List.of(
+                        Pair.create(
+                                targetEntryName,
+                                Pair.create(null, Color.WHITE))));
+    }
+
+    @Test
+    public void registerOverlayOnSystemOverlayable_selfIsNotSystemApp_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                SYSTEM_APP_OVERLAYABLE,
+                "color/system_app_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnOdmOverlayable_selfIsNotOdm_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                ODM_OVERLAYABLE,
+                "color/odm_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnOemOverlayable_selfIsNotOem_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                OEM_OVERLAYABLE,
+                "color/oem_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnVendorOverlayable_selfIsNotVendor_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                VENDOR_OVERLAYABLE,
+                "color/vendor_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnProductOverlayable_selfIsNotProduct_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                PRODUCT_OVERLAYABLE,
+                "color/product_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnActorOverlayable_notSupport_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                ACTOR_OVERLAYABLE,
+                "color/actor_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnConfigOverlayable_notSupport_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                CONFIG_OVERLAYABLE,
+                "color/config_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnPublicOverlayable_shouldAlwaysSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                PUBLIC_OVERLAYABLE,
+                "color/public_overlayable_color");
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void registerOverlayOnSystemOverlayable_selfIsSystemApp_shouldSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                SYSTEM_APP_OVERLAYABLE,
+                "color/system_app_overlayable_color");
+        when(mMockApplicationInfo.isSystemApp()).thenReturn(true);
+        when(mMockApplicationInfo.isSystemExt()).thenReturn(true);
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void registerOverlayOnOdmOverlayable_selfIsOdm_shouldSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                ODM_OVERLAYABLE,
+                "color/odm_overlayable_color");
+        when(mMockApplicationInfo.isOdm()).thenReturn(true);
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void registerOverlayOnOemOverlayable_selfIsOem_shouldSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                OEM_OVERLAYABLE,
+                "color/oem_overlayable_color");
+        when(mMockApplicationInfo.isOem()).thenReturn(true);
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void registerOverlayOnVendorOverlayable_selfIsVendor_shouldSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                VENDOR_OVERLAYABLE,
+                "color/vendor_overlayable_color");
+        when(mMockApplicationInfo.isVendor()).thenReturn(true);
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void registerOverlayOnProductOverlayable_selfIsProduct_shouldSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                PRODUCT_OVERLAYABLE,
+                "color/product_overlayable_color");
+        when(mMockApplicationInfo.isProduct()).thenReturn(true);
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
 }