diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a205fcf9520b6..2dc3996e3d7bb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4451,4 +4451,11 @@
false
-1
+
+
+
+
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 758a4f7baffc0..6ce25d45b16c9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4025,4 +4025,6 @@
+
+
diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java
index 910ed44df0f87..19fa9204935d3 100644
--- a/services/core/java/com/android/server/om/IdmapDaemon.java
+++ b/services/core/java/com/android/server/om/IdmapDaemon.java
@@ -30,6 +30,7 @@ import android.util.Slog;
import com.android.server.FgThread;
+import java.io.File;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
@@ -124,9 +125,13 @@ class IdmapDaemon {
}
}
- String getIdmapPath(String overlayPath, int userId) throws TimeoutException, RemoteException {
+ boolean idmapExists(String overlayPath, int userId) {
try (Connection c = connect()) {
- return mService.getIdmapPath(overlayPath, userId);
+ return new File(mService.getIdmapPath(overlayPath, userId)).isFile();
+ } catch (Exception e) {
+ Slog.wtf(TAG, "failed to check if idmap exists for " + overlayPath + ": "
+ + e.getMessage());
+ return false;
}
}
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 90c85ada9defc..735d669835208 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -27,10 +27,10 @@ import android.content.pm.PackageInfo;
import android.os.Build.VERSION_CODES;
import android.os.OverlayablePolicy;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.util.Slog;
-import java.io.File;
+import com.android.internal.util.ArrayUtils;
+
import java.io.IOException;
/**
@@ -55,12 +55,16 @@ class IdmapManager {
VENDOR_IS_Q_OR_LATER = isQOrLater;
}
- private final OverlayableInfoCallback mOverlayableCallback;
private final IdmapDaemon mIdmapDaemon;
+ private final OverlayableInfoCallback mOverlayableCallback;
+ private final String mOverlayableConfigurator;
+ private final String[] mOverlayableConfiguratorTargets;
- IdmapManager(final OverlayableInfoCallback verifyCallback) {
+ IdmapManager(final IdmapDaemon idmapDaemon, final OverlayableInfoCallback verifyCallback) {
mOverlayableCallback = verifyCallback;
- mIdmapDaemon = IdmapDaemon.getInstance();
+ mIdmapDaemon = idmapDaemon;
+ mOverlayableConfigurator = verifyCallback.getOverlayableConfigurator();
+ mOverlayableConfiguratorTargets = verifyCallback.getOverlayableConfiguratorTargets() ;
}
/**
@@ -103,23 +107,11 @@ class IdmapManager {
}
boolean idmapExists(@NonNull final OverlayInfo oi) {
- return new File(getIdmapPath(oi.baseCodePath, oi.userId)).isFile();
+ return mIdmapDaemon.idmapExists(oi.baseCodePath, oi.userId);
}
boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) {
- return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath(), userId))
- .isFile();
- }
-
- private @NonNull String getIdmapPath(@NonNull final String overlayPackagePath,
- final int userId) {
- try {
- return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId);
- } catch (Exception e) {
- Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": "
- + e.getMessage());
- return "";
- }
+ return mIdmapDaemon.idmapExists(overlayPackage.applicationInfo.getBaseCodePath(), userId);
}
/**
@@ -198,9 +190,17 @@ class IdmapManager {
String targetOverlayableName = overlayPackage.targetOverlayableName;
if (targetOverlayableName != null) {
try {
+ if (!mOverlayableConfigurator.isEmpty()
+ && ArrayUtils.contains(mOverlayableConfiguratorTargets,
+ targetPackage.packageName)
+ && mOverlayableCallback.signaturesMatching(mOverlayableConfigurator,
+ overlayPackage.packageName, userId)) {
+ return true;
+ }
+
OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget(
targetPackage.packageName, targetOverlayableName, userId);
- if (overlayableInfo != null) {
+ if (overlayableInfo != null && overlayableInfo.actor != null) {
String actorPackageName = OverlayActorEnforcer.getPackageNameForActor(
overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first;
if (mOverlayableCallback.signaturesMatching(actorPackageName,
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index ef6655dd224ed..2bc34998785b3 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -50,8 +50,8 @@ public class OverlayActorEnforcer {
/**
* @return nullable actor result with {@link ActorState} failure status
*/
- static Pair getPackageNameForActor(String actorUriString,
- Map> namedActors) {
+ static Pair getPackageNameForActor(@NonNull String actorUriString,
+ @NonNull Map> namedActors) {
Uri actorUri = Uri.parse(actorUriString);
String actorScheme = actorUri.getScheme();
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 6a8e465529d78..086ab81832544 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -45,6 +45,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.content.res.ApkAssets;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
@@ -62,6 +63,7 @@ import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.R;
import com.android.internal.content.om.OverlayConfig;
import com.android.server.FgThread;
import com.android.server.IoThread;
@@ -246,7 +248,7 @@ public final class OverlayManagerService extends SystemService {
new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
mPackageManager = new PackageManagerHelperImpl(context);
mUserManager = UserManagerService.getInstance();
- IdmapManager im = new IdmapManager(mPackageManager);
+ IdmapManager im = new IdmapManager(IdmapDaemon.getInstance(), mPackageManager);
mSettings = new OverlayManagerSettings();
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
OverlayConfig.getSystemInstance(), getDefaultOverlayPackages(),
@@ -1118,6 +1120,17 @@ public final class OverlayManagerService extends SystemService {
return false;
}
+ @Override
+ public String getOverlayableConfigurator() {
+ return Resources.getSystem().getString(R.string.config_overlayableConfigurator);
+ }
+
+ @Override
+ public String[] getOverlayableConfiguratorTargets() {
+ return Resources.getSystem().getStringArray(
+ R.array.config_overlayableConfiguratorTargets);
+ }
+
@Override
public List getOverlayPackages(final int userId) {
final List overlays = mPackageManagerInternal.getOverlayPackages(userId);
diff --git a/services/core/java/com/android/server/om/OverlayableInfoCallback.java b/services/core/java/com/android/server/om/OverlayableInfoCallback.java
index 5066ecdd6316f..41c341adf1bc0 100644
--- a/services/core/java/com/android/server/om/OverlayableInfoCallback.java
+++ b/services/core/java/com/android/server/om/OverlayableInfoCallback.java
@@ -80,4 +80,24 @@ public interface OverlayableInfoCallback {
* in the system returns {@link PackageManager#SIGNATURE_MATCH}
*/
boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
+
+ /**
+ * Retrieves the package name that is recognized as an actor for the packages specified by
+ * {@link #getOverlayableConfiguratorTargets()}.
+ */
+ @NonNull
+ default String getOverlayableConfigurator() {
+ return "";
+ }
+
+ /**
+ * Retrieves the target packages that recognize the {@link #getOverlayableConfigurator} as an
+ * actor for its overlayable declarations. Overlays targeting one of the specified targets that
+ * are signed with the same signature as the overlayable configurator will be granted the
+ * "actor" policy.
+ */
+ @NonNull
+ default String[] getOverlayableConfiguratorTargets() {
+ return new String[0];
+ }
}
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 f35eecf05f320..b7692f912e393 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 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
@Test
public void testUpdateOverlaysForUser() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
- installTargetPackage("some.other.target", USER);
- installOverlayPackage(OVERLAY, TARGET, USER);
+ addSystemPackage(target(TARGET), USER);
+ addSystemPackage(target("some.other.target"), USER);;
+ addSystemPackage(overlay(OVERLAY, TARGET), USER);
// do nothing, expect no change
final List a = impl.updateOverlaysForUser(USER);
@@ -54,8 +54,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
assertTrue(a.contains(TARGET));
// upgrade overlay, keep target
- beginUpgradeOverlayPackage(OVERLAY, USER);
- endUpgradeOverlayPackage(OVERLAY, TARGET, USER);
+ addSystemPackage(overlay(OVERLAY, TARGET), USER);
final List b = impl.updateOverlaysForUser(USER);
assertEquals(1, b.size());
@@ -67,7 +66,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
assertTrue(c.contains(TARGET));
// upgrade overlay, switch to new target
- addOverlayPackage(OVERLAY, "some.other.target", USER, true, false, 0);
+ addSystemPackage(overlay(OVERLAY, "some.other.target"), USER);
final List d = impl.updateOverlaysForUser(USER);
assertEquals(2, d.size());
assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target")));
@@ -81,23 +80,24 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
@Test
public void testImmutableEnabledChange() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
- addOverlayPackage(OVERLAY, TARGET, USER, false, false, 0);
+ configureSystemOverlay(OVERLAY, false /* mutable */, false /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o1);
assertFalse(o1.isEnabled());
assertFalse(o1.isMutable);
- addOverlayPackage(OVERLAY, TARGET, USER, false, true, 0);
+ configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o2);
assertTrue(o2.isEnabled());
assertFalse(o2.isMutable);
- addOverlayPackage(OVERLAY, TARGET, USER, false, false, 0);
+ configureSystemOverlay(OVERLAY, false /* mutable */, false /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o3);
@@ -108,23 +108,24 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
@Test
public void testMutableEnabledChangeHasNoEffect() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */);
- addOverlayPackage(OVERLAY, TARGET, USER, true, false, 0);
impl.updateOverlaysForUser(USER);
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o1);
assertFalse(o1.isEnabled());
assertTrue(o1.isMutable);
- addOverlayPackage(OVERLAY, TARGET, USER, true, true, 0);
+ configureSystemOverlay(OVERLAY, true /* mutable */, true /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o2);
assertFalse(o2.isEnabled());
assertTrue(o2.isMutable);
- addOverlayPackage(OVERLAY, TARGET, USER, true, false, 0);
+ configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o3);
@@ -135,15 +136,16 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
@Test
public void testMutableEnabledToImmutableEnabled() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
final BiConsumer setOverlay = (mutable, enabled) -> {
- addOverlayPackage(OVERLAY, TARGET, USER, mutable, enabled, 0);
+ configureSystemOverlay(OVERLAY, mutable, enabled, 0 /* priority */);
impl.updateOverlaysForUser(USER);
- final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
- assertNotNull(o1);
- assertEquals(enabled, o1.isEnabled());
- assertEquals(mutable, o1.isMutable);
+ final OverlayInfo o = impl.getOverlayInfo(OVERLAY, USER);
+ assertNotNull(o);
+ assertEquals(enabled, o.isEnabled());
+ assertEquals(mutable, o.isMutable);
};
// Immutable/enabled -> mutable/enabled
@@ -178,70 +180,76 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
@Test
public void testMutablePriorityChange() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
- addOverlayPackage(OVERLAY, TARGET, USER, true, true, 0);
- addOverlayPackage(OVERLAY2, TARGET, USER, true, true, 1);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ installNewPackage(overlay(OVERLAY2, TARGET), USER);
+ configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */);
+ configureSystemOverlay(OVERLAY2, true /* mutable */, false /* enabled */, 1 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o1);
assertEquals(0, o1.priority);
+ assertFalse(o1.isEnabled());
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY2, USER);
assertNotNull(o2);
assertEquals(1, o2.priority);
+ assertFalse(o2.isEnabled());
// Overlay priority changing between reboots should not affect enable state of mutable
- // overlays
+ // overlays.
impl.setEnabled(OVERLAY, true, USER);
// Reorder the overlays
- addOverlayPackage(OVERLAY, TARGET, USER, true, true, 1);
- addOverlayPackage(OVERLAY2, TARGET, USER, true, true, 0);
+ configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 1 /* priority */);
+ configureSystemOverlay(OVERLAY2, true /* mutable */, false /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o3);
assertEquals(1, o3.priority);
+ assertTrue(o3.isEnabled());
final OverlayInfo o4 = impl.getOverlayInfo(OVERLAY2, USER);
assertNotNull(o4);
assertEquals(0, o4.priority);
- assertTrue(o1.isEnabled());
+ assertFalse(o4.isEnabled());
}
@Test
public void testImmutablePriorityChange() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
- addOverlayPackage(OVERLAY, TARGET, USER, false, true, 0);
- addOverlayPackage(OVERLAY2, TARGET, USER, false, true, 1);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ installNewPackage(overlay(OVERLAY2, TARGET), USER);
+ configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 0 /* priority */);
+ configureSystemOverlay(OVERLAY2, false /* mutable */, true /* enabled */, 1 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o1);
assertEquals(0, o1.priority);
+ assertTrue(o1.isEnabled());
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY2, USER);
assertNotNull(o2);
assertEquals(1, o2.priority);
-
- // Overlay priority changing between reboots should not affect enable state of mutable
- // overlays
- impl.setEnabled(OVERLAY, true, USER);
+ assertTrue(o2.isEnabled());
// Reorder the overlays
- addOverlayPackage(OVERLAY, TARGET, USER, false, true, 1);
- addOverlayPackage(OVERLAY2, TARGET, USER, false, true, 0);
+ configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 1 /* priority */);
+ configureSystemOverlay(OVERLAY2, false /* mutable */, true /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o3);
assertEquals(1, o3.priority);
+ assertTrue(o3.isEnabled());
final OverlayInfo o4 = impl.getOverlayInfo(OVERLAY2, USER);
assertNotNull(o4);
assertEquals(0, o4.priority);
- assertTrue(o1.isEnabled());
+ assertTrue(o4.isEnabled());
}
}
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 cd73432357507..b25af05438294 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -26,6 +26,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.content.om.OverlayInfo;
+import android.os.OverlayablePolicy;
import androidx.test.runner.AndroidJUnit4;
@@ -49,11 +50,9 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
private static final String OVERLAY3 = OVERLAY + "3";
private static final int USER3 = USER2 + 1;
- // tests: basics
-
@Test
- public void testGetOverlayInfo() throws Exception {
- installOverlayPackage(OVERLAY, TARGET, USER);
+ public void testGetOverlayInfo() {
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
final OverlayManagerServiceImpl impl = getImpl();
final OverlayInfo oi = impl.getOverlayInfo(OVERLAY, USER);
@@ -64,10 +63,10 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testGetOverlayInfosForTarget() throws Exception {
- installOverlayPackage(OVERLAY, TARGET, USER);
- installOverlayPackage(OVERLAY2, TARGET, USER);
- installOverlayPackage(OVERLAY3, TARGET, USER2);
+ public void testGetOverlayInfosForTarget() {
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ installNewPackage(overlay(OVERLAY2, TARGET), USER);
+ installNewPackage(overlay(OVERLAY3, TARGET), USER2);
final OverlayManagerServiceImpl impl = getImpl();
final List ois = impl.getOverlayInfosForTarget(TARGET, USER);
@@ -89,11 +88,11 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testGetOverlayInfosForUser() throws Exception {
- installTargetPackage(TARGET, USER);
- installOverlayPackage(OVERLAY, TARGET, USER);
- installOverlayPackage(OVERLAY2, TARGET, USER);
- installOverlayPackage(OVERLAY3, TARGET2, USER);
+ public void testGetOverlayInfosForUser() {
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ installNewPackage(overlay(OVERLAY2, TARGET), USER);
+ installNewPackage(overlay(OVERLAY3, TARGET2), USER);
final OverlayManagerServiceImpl impl = getImpl();
final Map> everything = impl.getOverlaysForUser(USER);
@@ -116,91 +115,86 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testPriority() throws Exception {
- installOverlayPackage(OVERLAY, TARGET, USER);
- installOverlayPackage(OVERLAY2, TARGET, USER);
- installOverlayPackage(OVERLAY3, TARGET, USER);
+ public void testPriority() {
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ installNewPackage(overlay(OVERLAY2, TARGET), USER);
+ installNewPackage(overlay(OVERLAY3, TARGET), USER);
final OverlayManagerServiceImpl impl = getImpl();
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY2, USER);
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY3, USER);
- assertOverlayInfoList(TARGET, USER, o1, o2, o3);
+ assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);
assertTrue(impl.setLowestPriority(OVERLAY3, USER));
- assertOverlayInfoList(TARGET, USER, o3, o1, o2);
+ assertOverlayInfoForTarget(TARGET, USER, o3, o1, o2);
assertTrue(impl.setHighestPriority(OVERLAY3, USER));
- assertOverlayInfoList(TARGET, USER, o1, o2, o3);
+ assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);
assertTrue(impl.setPriority(OVERLAY, OVERLAY2, USER));
- assertOverlayInfoList(TARGET, USER, o2, o1, o3);
+ assertOverlayInfoForTarget(TARGET, USER, o2, o1, o3);
}
@Test
- public void testOverlayInfoStateTransitions() throws Exception {
+ public void testOverlayInfoStateTransitions() {
final OverlayManagerServiceImpl impl = getImpl();
assertNull(impl.getOverlayInfo(OVERLAY, USER));
- installOverlayPackage(OVERLAY, TARGET, USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
assertState(STATE_MISSING_TARGET, OVERLAY, USER);
- installTargetPackage(TARGET, USER);
+ final DummyDeviceState.PackageBuilder target = target(TARGET);
+ installNewPackage(target, USER);
assertState(STATE_DISABLED, OVERLAY, USER);
impl.setEnabled(OVERLAY, true, USER);
assertState(STATE_ENABLED, OVERLAY, USER);
// target upgrades do not change the state of the overlay
- beginUpgradeTargetPackage(TARGET, USER);
+ upgradePackage(target, USER);
assertState(STATE_ENABLED, OVERLAY, USER);
- endUpgradeTargetPackage(TARGET, USER);
- assertState(STATE_ENABLED, OVERLAY, USER);
-
- uninstallTargetPackage(TARGET, USER);
+ uninstallPackage(TARGET, USER);
assertState(STATE_MISSING_TARGET, OVERLAY, USER);
- installTargetPackage(TARGET, USER);
+ installNewPackage(target, USER);
assertState(STATE_ENABLED, OVERLAY, USER);
}
@Test
- public void testOnOverlayPackageUpgraded() throws Exception {
- final OverlayManagerServiceImpl impl = getImpl();
+ public void testOnOverlayPackageUpgraded() {
final DummyListener listener = getListener();
- installTargetPackage(TARGET, USER);
- installOverlayPackage(OVERLAY, TARGET, USER);
- impl.onOverlayPackageReplacing(OVERLAY, USER);
+ final DummyDeviceState.PackageBuilder target = target(TARGET);
+ final DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET);
+ installNewPackage(target, USER);
+ installNewPackage(overlay, USER);
listener.count = 0;
- impl.onOverlayPackageReplaced(OVERLAY, USER);
- assertEquals(1, listener.count);
-
- // upgrade to a version where the overlay has changed its target
- beginUpgradeOverlayPackage(OVERLAY, USER);
- listener.count = 0;
- endUpgradeOverlayPackage(OVERLAY, "some.other.target", USER);
- // expect once for the old target package, once for the new target package
+ upgradePackage(overlay, USER);
assertEquals(2, listener.count);
- beginUpgradeOverlayPackage(OVERLAY, USER);
+ // upgrade to a version where the overlay has changed its target
+ // expect once for the old target package, once for the new target package
listener.count = 0;
- endUpgradeOverlayPackage(OVERLAY, "some.other.target", USER);
- assertEquals(1, listener.count);
+ final DummyDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target");
+ upgradePackage(overlay2, USER);
+ assertEquals(3, listener.count);
+
+ listener.count = 0;
+ upgradePackage(overlay2, USER);
+ assertEquals(2, listener.count);
}
- // tests: listener interface
-
@Test
- public void testListener() throws Exception {
+ public void testListener() {
final OverlayManagerServiceImpl impl = getImpl();
final DummyListener listener = getListener();
- installOverlayPackage(OVERLAY, TARGET, USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
assertEquals(1, listener.count);
listener.count = 0;
- installTargetPackage(TARGET, USER);
+ installNewPackage(target(TARGET), USER);
assertEquals(1, listener.count);
listener.count = 0;
@@ -211,4 +205,49 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
impl.setEnabled(OVERLAY, true, USER);
assertEquals(0, listener.count);
}
+
+ @Test
+ public void testConfigurator() {
+ final DummyPackageManagerHelper packageManager = getPackageManager();
+ packageManager.overlayableConfigurator = "actor";
+ packageManager.overlayableConfiguratorTargets = new String[]{TARGET};
+ reinitializeImpl();
+
+ installNewPackage(target("actor").setCertificate("one"), USER);
+ installNewPackage(target(TARGET)
+ .addOverlayable("TestResources")
+ .setCertificate("two"), USER);
+
+ final DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources")
+ .setCertificate("one");
+ installNewPackage(overlay, USER);
+
+ final DummyIdmapDaemon idmapDaemon = getIdmapDaemon();
+ final DummyIdmapDaemon.IdmapHeader idmap = idmapDaemon.getIdmap(overlay.build().apkPath);
+ assertNotNull(idmap);
+ assertEquals(OverlayablePolicy.ACTOR_SIGNATURE,
+ idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
+ }
+
+ @Test
+ public void testConfiguratorDifferentSignatures() {
+ final DummyPackageManagerHelper packageManager = getPackageManager();
+ packageManager.overlayableConfigurator = "actor";
+ packageManager.overlayableConfiguratorTargets = new String[]{TARGET};
+ reinitializeImpl();
+
+ installNewPackage(target("actor").setCertificate("one"), USER);
+ installNewPackage(target(TARGET)
+ .addOverlayable("TestResources")
+ .setCertificate("two"), USER);
+
+ final DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources")
+ .setCertificate("two");
+ installNewPackage(overlay, USER);
+
+ final DummyIdmapDaemon idmapDaemon = getIdmapDaemon();
+ final DummyIdmapDaemon.IdmapHeader idmap = idmapDaemon.getIdmap(overlay.build().apkPath);
+ assertNotNull(idmap);
+ assertEquals(0, idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
+ }
}
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 9eda718ed922b..ec6a48182a252 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -17,6 +17,7 @@
package com.android.server.om;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -26,17 +27,19 @@ import android.content.om.OverlayInfo.State;
import android.content.om.OverlayableInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.util.ArrayMap;
import android.util.ArraySet;
import androidx.annotation.Nullable;
import com.android.internal.content.om.OverlayConfig;
+import org.junit.Assert;
import org.junit.Before;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Iterator;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -47,29 +50,48 @@ class OverlayManagerServiceImplTestsBase {
private OverlayManagerServiceImpl mImpl;
private DummyDeviceState mState;
private DummyListener mListener;
+ private DummyPackageManagerHelper mPackageManager;
+ private DummyIdmapDaemon mIdmapDaemon;
+ private OverlayConfig mOverlayConfig;
@Before
public void setUp() {
mState = new DummyDeviceState();
mListener = new DummyListener();
- final DummyPackageManagerHelper pmh = new DummyPackageManagerHelper(mState);
+ mPackageManager = new DummyPackageManagerHelper(mState);
+ mIdmapDaemon = new DummyIdmapDaemon(mState);
+ mOverlayConfig = mock(OverlayConfig.class);
+ when(mOverlayConfig.getPriority(any())).thenReturn(OverlayConfig.DEFAULT_PRIORITY);
+ when(mOverlayConfig.isEnabled(any())).thenReturn(false);
+ when(mOverlayConfig.isMutable(any())).thenReturn(true);
+ reinitializeImpl();
+ }
- mImpl = new OverlayManagerServiceImpl(pmh,
- new DummyIdmapManager(mState, pmh),
+ void reinitializeImpl() {
+ mImpl = new OverlayManagerServiceImpl(mPackageManager,
+ new IdmapManager(mIdmapDaemon, mPackageManager),
new OverlayManagerSettings(),
- mState.mOverlayConfig,
+ mOverlayConfig,
new String[0],
mListener);
}
- public OverlayManagerServiceImpl getImpl() {
+ OverlayManagerServiceImpl getImpl() {
return mImpl;
}
- public DummyListener getListener() {
+ DummyListener getListener() {
return mListener;
}
+ DummyPackageManagerHelper getPackageManager() {
+ return mPackageManager;
+ }
+
+ DummyIdmapDaemon getIdmapDaemon() {
+ return mIdmapDaemon;
+ }
+
void assertState(@State int expected, final String overlayPackageName, int userId) {
final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId);
if (info == null) {
@@ -81,7 +103,7 @@ class OverlayManagerServiceImplTestsBase {
assertEquals(msg, expected, info.state);
}
- void assertOverlayInfoList(final String targetPackageName, int userId,
+ void assertOverlayInfoForTarget(final String targetPackageName, int userId,
OverlayInfo... overlayInfos) {
final List expected =
mImpl.getOverlayInfosForTarget(targetPackageName, userId);
@@ -89,198 +111,202 @@ class OverlayManagerServiceImplTestsBase {
assertEquals(expected, actual);
}
- /**
- * Creates an overlay configured through {@link OverlayConfig}.
- *
- * @throws IllegalStateException if the package is already installed
- */
- void addOverlayPackage(String packageName, String targetPackageName, int userId,
- boolean mutable, boolean enabled, int priority) {
- mState.addOverlay(packageName, targetPackageName, userId, mutable, enabled, priority);
+ DummyDeviceState.PackageBuilder target(String packageName) {
+ return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
+ null /* targetOverlayableName */);
+ }
+
+ DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) {
+ return overlay(packageName, targetPackageName, null /* targetOverlayableName */);
+ }
+
+ DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName,
+ String targetOverlayableName) {
+ return new DummyDeviceState.PackageBuilder(packageName, targetPackageName,
+ targetOverlayableName);
+ }
+
+ void addSystemPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
+ mState.add(pkg, userId);
+ }
+
+ void configureSystemOverlay(String packageName, boolean mutable, boolean enabled,
+ int priority) {
+ when(mOverlayConfig.getPriority(packageName)).thenReturn(priority);
+ when(mOverlayConfig.isEnabled(packageName)).thenReturn(enabled);
+ when(mOverlayConfig.isMutable(packageName)).thenReturn(mutable);
}
/**
- * Adds the target package to the device.
+ * Adds the package to the device.
*
* This corresponds to when the OMS receives the
* {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast.
*
- * @throws IllegalStateException if the package is not currently installed
+ * @throws IllegalStateException if the package is currently installed
*/
- void installTargetPackage(String packageName, int userId) {
- if (mState.select(packageName, userId) != null) {
- throw new IllegalStateException("package already installed");
+ void installNewPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
+ if (mState.select(pkg.packageName, userId) != null) {
+ throw new IllegalStateException("package " + pkg.packageName + " already installed");
+ }
+ mState.add(pkg, userId);
+ if (pkg.targetPackage == null) {
+ mImpl.onTargetPackageAdded(pkg.packageName, userId);
+ } else {
+ mImpl.onOverlayPackageAdded(pkg.packageName, userId);
}
- mState.addTarget(packageName, userId);
- mImpl.onTargetPackageAdded(packageName, userId);
}
/**
- * Begins upgrading the target package.
+ * Begins upgrading the package.
*
* This corresponds to when the OMS receives the
* {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast with the
- * {@link android.content.Intent#EXTRA_REPLACING} extra.
- *
- * @throws IllegalStateException if the package is not currently installed
- */
- void beginUpgradeTargetPackage(String packageName, int userId) {
- if (mState.select(packageName, userId) == null) {
- throw new IllegalStateException("package not installed");
- }
- mImpl.onTargetPackageReplacing(packageName, userId);
- }
-
- /**
- * Ends upgrading the target package.
- *
- * This corresponds to when the OMS receives the
+ * {@link android.content.Intent#EXTRA_REPLACING} extra and then receives the
* {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the
* {@link android.content.Intent#EXTRA_REPLACING} extra.
*
* @throws IllegalStateException if the package is not currently installed
*/
- void endUpgradeTargetPackage(String packageName, int userId) {
- if (mState.select(packageName, userId) == null) {
- throw new IllegalStateException("package not installed");
+ void upgradePackage(DummyDeviceState.PackageBuilder pkg, int userId) {
+ final DummyDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId);
+ if (replacedPackage == null) {
+ throw new IllegalStateException("package " + pkg.packageName + " not installed");
+ }
+ if (replacedPackage.targetPackageName != null) {
+ mImpl.onOverlayPackageReplacing(pkg.packageName, userId);
+ }
+
+ mState.add(pkg, userId);
+ if (pkg.targetPackage == null) {
+ mImpl.onTargetPackageReplaced(pkg.packageName, userId);
+ } else {
+ mImpl.onOverlayPackageReplaced(pkg.packageName, userId);
}
- mState.addTarget(packageName, userId);
- mImpl.onTargetPackageReplaced(packageName, userId);
}
/**
- * Removes the target package from the device.
+ * Removes the package from the device.
*
* This corresponds to when the OMS receives the
* {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast.
*
* @throws IllegalStateException if the package is not currently installed
*/
- void uninstallTargetPackage(String packageName, int userId) {
- if (mState.select(packageName, userId) == null) {
- throw new IllegalStateException("package not installed");
+ void uninstallPackage(String packageName, int userId) {
+ final DummyDeviceState.Package pkg = mState.select(packageName, userId);
+ if (pkg == null) {
+ throw new IllegalStateException("package " + packageName+ " not installed");
+ }
+ mState.remove(pkg.packageName);
+ if (pkg.targetPackageName == null) {
+ mImpl.onTargetPackageRemoved(pkg.packageName, userId);
+ } else {
+ mImpl.onOverlayPackageRemoved(pkg.packageName, userId);
}
- mState.remove(packageName, userId);
- mImpl.onTargetPackageRemoved(packageName, userId);
}
- /**
- * Adds the overlay package to the device.
- *
- * This corresponds to when the OMS receives the
- * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast.
- *
- * @throws IllegalStateException if the package is already installed
- */
- void installOverlayPackage(String packageName, String targetPackageName, int userId) {
- if (mState.select(packageName, userId) != null) {
- throw new IllegalStateException("package already installed");
- }
- mState.addOverlay(packageName, targetPackageName, userId);
- mImpl.onOverlayPackageAdded(packageName, userId);
- }
+ /** Represents the state of packages installed on a fake device. */
+ static class DummyDeviceState {
+ private ArrayMap mPackages = new ArrayMap<>();
- /**
- * Begins upgrading the overlay package.
- *
- * This corresponds to when the OMS receives the
- * {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast with the
- * {@link android.content.Intent#EXTRA_REPLACING} extra.
- *
- * @throws IllegalStateException if the package is not currently installed
- */
- void beginUpgradeOverlayPackage(String packageName, int userId) {
- if (mState.select(packageName, userId) == null) {
- throw new IllegalStateException("package not installed, cannot upgrade");
- }
+ void add(PackageBuilder pkgBuilder, int userId) {
+ final Package pkg = pkgBuilder.build();
+ final Package previousPkg = select(pkg.packageName, userId);
+ mPackages.put(pkg.packageName, pkg);
- mImpl.onOverlayPackageReplacing(packageName, userId);
- }
-
- /**
- * Ends upgrading the overlay package, potentially changing its target package.
- *
- * This corresponds to when the OMS receives the
- * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the
- * {@link android.content.Intent#EXTRA_REPLACING} extra.
- *
- * @throws IllegalStateException if the package is not currently installed
- */
- void endUpgradeOverlayPackage(String packageName, String targetPackageName, int userId) {
- if (mState.select(packageName, userId) == null) {
- throw new IllegalStateException("package not installed, cannot upgrade");
- }
-
- mState.addOverlay(packageName, targetPackageName, userId);
- mImpl.onOverlayPackageReplaced(packageName, userId);
- }
-
- private static final class DummyDeviceState {
- private List mPackages = new ArrayList<>();
- private OverlayConfig mOverlayConfig = mock(OverlayConfig.class);
-
- /** Adds a non-overlay to the device. */
- public void addTarget(String packageName, int userId) {
- remove(packageName, userId);
- mPackages.add(new Package(packageName, userId, null, false, false, 0));
- }
-
- /** Adds an overlay to the device. */
- public void addOverlay(String packageName, String targetPackageName, int userId) {
- addOverlay(packageName, targetPackageName, userId, true, false, OverlayConfig.DEFAULT_PRIORITY);
- }
-
- /** Adds a configured overlay to the device. */
- public void addOverlay(String packageName, String targetPackageName, int userId,
- boolean mutable, boolean enabled, int priority) {
- remove(packageName, userId);
- mPackages.add(new Package(packageName, userId, targetPackageName, mutable, enabled,
- priority));
- when(mOverlayConfig.getPriority(packageName)).thenReturn(priority);
- when(mOverlayConfig.isEnabled(packageName)).thenReturn(enabled);
- when(mOverlayConfig.isMutable(packageName)).thenReturn(mutable);
- }
-
- /** Remove a package from the device. */
- public void remove(String packageName, int userId) {
- final Iterator iter = mPackages.iterator();
- while (iter.hasNext()) {
- final Package pkg = iter.next();
- if (pkg.packageName.equals(packageName) && pkg.userId == userId) {
- iter.remove();
- return;
- }
+ pkg.installedUserIds.add(userId);
+ if (previousPkg != null) {
+ pkg.installedUserIds.addAll(previousPkg.installedUserIds);
}
}
- /** Retrieves all packages on device for a particular user. */
- public List select(int userId) {
- return mPackages.stream().filter(p -> p.userId == userId).collect(Collectors.toList());
+ void remove(String packageName) {
+ mPackages.remove(packageName);
}
- /** Retrieves the package with the specified package name for a particular user. */
- public Package select(String packageName, int userId) {
- return mPackages.stream().filter(
- p -> p.packageName.equals(packageName) && p.userId == userId)
- .findFirst().orElse(null);
+ void uninstall(String packageName, int userId) {
+ final Package pkg = mPackages.get(packageName);
+ if (pkg != null) {
+ pkg.installedUserIds.remove(userId);
+ }
}
- private static final class Package {
- public final String packageName;
- public final int userId;
- public final String targetPackageName;
- public final boolean mutable;
- public final boolean enabled;
- public final int priority;
+ List select(int userId) {
+ return mPackages.values().stream().filter(p -> p.installedUserIds.contains(userId))
+ .collect(Collectors.toList());
+ }
- private Package(String packageName, int userId, String targetPackageName,
- boolean mutable, boolean enabled, int priority) {
+ Package select(String packageName, int userId) {
+ final Package pkg = mPackages.get(packageName);
+ return pkg != null && pkg.installedUserIds.contains(userId) ? pkg : null;
+ }
+
+ private Package selectFromPath(String path) {
+ return mPackages.values().stream()
+ .filter(p -> p.apkPath.equals(path)).findFirst().orElse(null);
+ }
+
+ static final class PackageBuilder {
+ private String packageName;
+ private String targetPackage;
+ private String certificate = "[default]";
+ private int version = 0;
+ private ArrayList overlayableNames = new ArrayList<>();
+ private String targetOverlayableName;
+
+ private PackageBuilder(String packageName, String targetPackage,
+ String targetOverlayableName) {
+ this.packageName = packageName;
+ this.targetPackage = targetPackage;
+ this.targetOverlayableName = targetOverlayableName;
+ }
+
+ PackageBuilder setCertificate(String certificate) {
+ this.certificate = certificate;
+ return this;
+ }
+
+ PackageBuilder addOverlayable(String overlayableName) {
+ overlayableNames.add(overlayableName);
+ return this;
+ }
+
+ PackageBuilder setVersion(int version) {
+ this.version = version;
+ return this;
+ }
+
+ Package build() {
+ final String apkPath = String.format("%s/%s/base.apk",
+ targetPackage == null ? "/system/app/:" : "/vendor/overlay/:",
+ packageName);
+ final Package newPackage = new Package(packageName, targetPackage,
+ targetOverlayableName, version, apkPath, certificate);
+ newPackage.overlayableNames.addAll(overlayableNames);
+ return newPackage;
+ }
+ }
+
+ static final class Package {
+ final String packageName;
+ final String targetPackageName;
+ final String targetOverlayableName;
+ final int versionCode;
+ final String apkPath;
+ final String certificate;
+ final ArrayList overlayableNames = new ArrayList<>();
+ private final ArraySet installedUserIds = new ArraySet<>();
+
+ private Package(String packageName, String targetPackageName,
+ String targetOverlayableName, int versionCode, String apkPath,
+ String certificate) {
this.packageName = packageName;
- this.userId = userId;
this.targetPackageName = targetPackageName;
- this.mutable = mutable;
- this.enabled = enabled;
- this.priority = priority;
+ this.targetOverlayableName = targetOverlayableName;
+ this.versionCode = versionCode;
+ this.apkPath = apkPath;
+ this.certificate = certificate;
}
}
}
@@ -288,6 +314,8 @@ class OverlayManagerServiceImplTestsBase {
static final class DummyPackageManagerHelper implements PackageManagerHelper,
OverlayableInfoCallback {
private final DummyDeviceState mState;
+ String[] overlayableConfiguratorTargets = new String[0];
+ String overlayableConfigurator = "";
private DummyPackageManagerHelper(DummyDeviceState state) {
mState = state;
@@ -300,13 +328,12 @@ class OverlayManagerServiceImplTestsBase {
return null;
}
final ApplicationInfo ai = new ApplicationInfo();
- ai.sourceDir = String.format("%s/%s/base.apk",
- pkg.targetPackageName == null ? "/system/app/" : "/vendor/overlay/",
- pkg.packageName);
+ ai.sourceDir = pkg.apkPath;
PackageInfo pi = new PackageInfo();
pi.applicationInfo = ai;
pi.packageName = pkg.packageName;
pi.overlayTarget = pkg.targetPackageName;
+ pi.targetOverlayableName = pkg.targetOverlayableName;
pi.overlayCategory = "dummy-category-" + pkg.targetPackageName;
return pi;
}
@@ -314,14 +341,16 @@ class OverlayManagerServiceImplTestsBase {
@Override
public boolean signaturesMatching(@NonNull String packageName1,
@NonNull String packageName2, int userId) {
- return false;
+ final DummyDeviceState.Package pkg1 = mState.select(packageName1, userId);
+ final DummyDeviceState.Package pkg2 = mState.select(packageName2, userId);
+ return pkg1 != null && pkg2 != null && pkg1.certificate.equals(pkg2.certificate);
}
@Override
public List getOverlayPackages(int userId) {
return mState.select(userId).stream()
.filter(p -> p.targetPackageName != null)
- .map(p -> getPackageInfo(p.packageName, p.userId))
+ .map(p -> getPackageInfo(p.packageName, userId))
.collect(Collectors.toList());
}
@@ -329,7 +358,11 @@ class OverlayManagerServiceImplTestsBase {
@Override
public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
@NonNull String targetOverlayableName, int userId) {
- throw new UnsupportedOperationException();
+ final DummyDeviceState.Package pkg = mState.select(packageName, userId);
+ if (pkg == null || !pkg.overlayableNames.contains(targetOverlayableName)) {
+ return null;
+ }
+ return new OverlayableInfo(targetOverlayableName, null /* actor */);
}
@Nullable
@@ -341,69 +374,98 @@ class OverlayManagerServiceImplTestsBase {
@NonNull
@Override
public Map> getNamedActors() {
- throw new UnsupportedOperationException();
+ return Collections.emptyMap();
}
@Override
public boolean doesTargetDefineOverlayable(String targetPackageName, int userId) {
- throw new UnsupportedOperationException();
+ final DummyDeviceState.Package pkg = mState.select(targetPackageName, userId);
+ return pkg != null && pkg.overlayableNames.contains(targetPackageName);
}
@Override
public void enforcePermission(String permission, String message) throws SecurityException {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public String[] getOverlayableConfiguratorTargets() {
+ return overlayableConfiguratorTargets;
+ }
+
+ @Override
+ public String getOverlayableConfigurator() {
+ return overlayableConfigurator;
+ }
}
- static class DummyIdmapManager extends IdmapManager {
+ static class DummyIdmapDaemon extends IdmapDaemon {
private final DummyDeviceState mState;
- private Set mIdmapFiles = new ArraySet<>();
+ private final ArrayMap mIdmapFiles = new ArrayMap<>();
- private DummyIdmapManager(DummyDeviceState state,
- DummyPackageManagerHelper packageManagerHelper) {
- super(packageManagerHelper);
- mState = state;
+ DummyIdmapDaemon(DummyDeviceState state) {
+ this.mState = state;
+ }
+
+ private int getCrc(@NonNull final String path) {
+ final DummyDeviceState.Package pkg = mState.selectFromPath(path);
+ Assert.assertNotNull(pkg);
+ return pkg.versionCode;
}
@Override
- boolean createIdmap(@NonNull final PackageInfo targetPackage,
- @NonNull final PackageInfo overlayPackage, int userId) {
- final DummyDeviceState.Package t = mState.select(targetPackage.packageName, userId);
- if (t == null) {
+ String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
+ int userId) {
+ mIdmapFiles.put(overlayPath, new IdmapHeader(getCrc(targetPath),
+ getCrc(overlayPath), targetPath, policies, enforce));
+ return overlayPath;
+ }
+
+ @Override
+ boolean removeIdmap(String overlayPath, int userId) {
+ return mIdmapFiles.remove(overlayPath) != null;
+ }
+
+ @Override
+ boolean verifyIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
+ int userId) {
+ final IdmapHeader idmap = mIdmapFiles.get(overlayPath);
+ if (idmap == null) {
return false;
}
- final DummyDeviceState.Package o = mState.select(overlayPackage.packageName, userId);
- if (o == null) {
- return false;
+ return idmap.isUpToDate(getCrc(targetPath), getCrc(overlayPath), targetPath);
+ }
+
+ @Override
+ boolean idmapExists(String overlayPath, int userId) {
+ return mIdmapFiles.containsKey(overlayPath);
+ }
+
+ IdmapHeader getIdmap(String overlayPath) {
+ return mIdmapFiles.get(overlayPath);
+ }
+
+ static class IdmapHeader {
+ private final int targetCrc;
+ private final int overlayCrc;
+ final String targetPath;
+ final int policies;
+ final boolean enforceOverlayable;
+
+ private IdmapHeader(int targetCrc, int overlayCrc, String targetPath, int policies,
+ boolean enforceOverlayable) {
+ this.targetCrc = targetCrc;
+ this.overlayCrc = overlayCrc;
+ this.targetPath = targetPath;
+ this.policies = policies;
+ this.enforceOverlayable = enforceOverlayable;
}
- final String key = createKey(overlayPackage.packageName, userId);
- return mIdmapFiles.add(key);
- }
- @Override
- boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) {
- final String key = createKey(oi.packageName, oi.userId);
- if (!mIdmapFiles.contains(key)) {
- return false;
+ private boolean isUpToDate(int expectedTargetCrc, int expectedOverlayCrc,
+ String expectedTargetPath) {
+ return expectedTargetCrc == targetCrc && expectedOverlayCrc == overlayCrc
+ && expectedTargetPath.equals(targetPath);
}
- mIdmapFiles.remove(key);
- return true;
- }
-
- @Override
- boolean idmapExists(@NonNull final OverlayInfo oi) {
- final String key = createKey(oi.packageName, oi.userId);
- return mIdmapFiles.contains(key);
- }
-
- @Override
- boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) {
- final String key = createKey(overlayPackage.packageName, userId);
- return mIdmapFiles.contains(key);
- }
-
- private String createKey(@NonNull final String packageName, final int userId) {
- return String.format("%s:%d", packageName, userId);
}
}