From a8fc0153456d0579e7ae0a58ca8bfc3ff73ddfcc Mon Sep 17 00:00:00 2001 From: felkachang Date: Thu, 22 Sep 2022 20:00:34 +0800 Subject: [PATCH] Enforce the overlayable mechanism for self-targeting The overlayable mechanism has defined which roles can overlay the specified resources and which resources are overlayable. In order to reduce the argument between platform and applications, self-targeting applications should enforce the overlayable mechanism. It makes the overlay range be defined in the overlayable list. It also defines the limitation of what kind of package can overlay the resources of the self-targeting application. To fill the policy flag, OverlayManagerImpl.java gets the following information and passes them as bool type to JNI OverlayManagerImpl. * SYSTEM_PARTITION * VENDOR_PARTITION * PRODUCT_PARTITION * ODM_PARTITION * OEM_PARTITION * SIGNATURE Not support * ACTOR_SIGNATURE * CONFIG_SIGNATURE JNI OverlayManagerImpl fills the policy flags according to the information from the ApplicationInfo. 'enforce_overlayable'is true to enforce checking overlayable before generating an idmap. Fixes: 238061808 Bug: 205919743 Test: atest \ OverlayHostTests \ OverlayDeviceTests \ SelfTargetingOverlayDeviceTests \ OverlayRemountedTest \ FrameworksServicesTests:com.android.server.om \ CtsContentTestCases:android.content.om.cts \ idmap2_tests Change-Id: I749d1a90a00f0a91e7796bc0f9f668f9ecfdb8b0 --- cmds/idmap2/self_targeting/SelfTargeting.cpp | 55 +++- .../content/om/OverlayManagerImpl.java | 36 ++- ...internal_content_om_OverlayManagerImpl.cpp | 24 +- .../device_self_targeting/Android.bp | 1 + .../res/values/overlayable.xml | 84 +++++++ .../res/values/values.xml | 10 + .../overlaytest/OverlayManagerImplTest.java | 234 +++++++++++++++++- 7 files changed, 425 insertions(+), 19 deletions(-) create mode 100644 core/tests/overlaytests/device_self_targeting/res/values/overlayable.xml diff --git a/cmds/idmap2/self_targeting/SelfTargeting.cpp b/cmds/idmap2/self_targeting/SelfTargeting.cpp index 20aa7d32a3c29..a8aa03309b169 100644 --- a/cmds/idmap2/self_targeting/SelfTargeting.cpp +++ b/cmds/idmap2/self_targeting/SelfTargeting.cpp @@ -38,9 +38,10 @@ namespace android::self_targeting { 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& targetOverlayable, - std::vector& entries_params, +CreateFrroFile(std::string& out_err_result, const std::string& packageName, + const std::string& overlayName, const std::string& targetPackageName, + const std::optional& targetOverlayable, + const std::vector& entries_params, const std::string& frro_file_path) { android::idmap2::FabricatedOverlay::Builder builder(packageName, overlayName, targetPackageName); @@ -90,9 +91,46 @@ CreateFrroFile(std::string& out_err_result, std::string& packageName, std::strin 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(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 @@ CreateIdmapFile(std::string& out_err, const std::string& targetPath, const std:: } // Overlay self target process. Only allow self-targeting types. - const auto fulfilled_policies = static_cast( - 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 76e068d11d74c..e56c06e318a8c 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 @@ public class OverlayManagerImpl { 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 @@ public class OverlayManagerImpl { /** * Save FabricatedOverlay instance as frro and idmap files. * + *

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 @@ public class OverlayManagerImpl { 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 @@ public class OverlayManagerImpl { 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 @@ public class OverlayManagerImpl { @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 df55e424f2ed6..bba1760bc45c8 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 @@ public: 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 @@ private: 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 CreateFrroFile(JNIEnv* env, jclass /*clazz*/, jstring jsFrroFilePath } 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 @@ static void CreateIdmapFile(JNIEnv* env, jclass /* clazz */, jstring jsTargetPat 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 @@ static const JNINativeMethod gOverlayManagerMethods[] = { {"createFrroFile", "(Ljava/lang/String;Landroid/os/FabricatedOverlayInternal;)V", reinterpret_cast(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(self_targeting::CreateIdmapFile)}, {"getFabricatedOverlayInfo", "(Ljava/lang/String;)Landroid/os/FabricatedOverlayInfo;", reinterpret_cast(self_targeting::GetFabricatedOverlayInfo)}, diff --git a/core/tests/overlaytests/device_self_targeting/Android.bp b/core/tests/overlaytests/device_self_targeting/Android.bp index 82998dbdae278..063c5694ab5be 100644 --- a/core/tests/overlaytests/device_self_targeting/Android.bp +++ b/core/tests/overlaytests/device_self_targeting/Android.bp @@ -29,6 +29,7 @@ android_test { "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 0000000000000..5cc214d859d26 --- /dev/null +++ b/core/tests/overlaytests/device_self_targeting/res/values/overlayable.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 f0b4a6fe89696..d82de97177170 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 @@ #ff112233 hello + + #000 + #000 + #000 + #000 + #000 + #000 + #000 + #000 + #000 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 ca584106a910b..8a9ab5b7a9024 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 @@ public class OverlayManagerImplTest { 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 class OverlayManagerImplTest { 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 @@ public class OverlayManagerImplTest { private FabricatedOverlayInternal createOverlayWithName( @NonNull String overlayName, + @NonNull String targetOverlayable, @NonNull String targetPackageName, @NonNull List>> 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 @@ public class OverlayManagerImplTest { FabricatedOverlayInternal overlayInternal = createOverlayWithName( mOverlayName, + SYSTEM_APP_OVERLAYABLE, "android", List.of(Pair.create("color/white", Pair.create(null, Color.BLACK)))); @@ -190,6 +241,7 @@ public class OverlayManagerImplTest { FabricatedOverlayInternal overlayInternal = createOverlayWithName( mOverlayName, + SIGNATURE_OVERLAYABLE, mContext.getPackageName(), List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE)))); @@ -215,6 +267,7 @@ public class OverlayManagerImplTest { FabricatedOverlayInternal overlayInternal = createOverlayWithName( mOverlayName, + SIGNATURE_OVERLAYABLE, mContext.getPackageName(), List.of(Pair.create(TARGET_STRING_RES, Pair.create(null, "HELLO")))); @@ -242,6 +295,7 @@ public class OverlayManagerImplTest { FabricatedOverlayInternal overlayInternal = createOverlayWithName( mOverlayName, + SIGNATURE_OVERLAYABLE, mContext.getPackageName(), List.of(Pair.create(TARGET_DRAWABLE_RES, Pair.create(null, parcelFileDescriptor)))); @@ -268,6 +322,7 @@ public class OverlayManagerImplTest { FabricatedOverlayInternal overlayInternal = createOverlayWithName( mOverlayName, + SIGNATURE_OVERLAYABLE, mContext.getPackageName(), List.of(Pair.create("color/not_existed", Pair.create(null, "HELLO")))); @@ -301,6 +356,7 @@ public class OverlayManagerImplTest { 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 @@ public class OverlayManagerImplTest { 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 @@ public class OverlayManagerImplTest { 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 @@ public class OverlayManagerImplTest { 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 @@ public class OverlayManagerImplTest { 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); + } }