Merge "Add overlayable configurator resources" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4515014469
@@ -4451,4 +4451,11 @@
|
||||
<bool name="config_pdp_reject_enable_retry">false</bool>
|
||||
<!-- pdp data reject retry delay in ms -->
|
||||
<integer name="config_pdp_reject_retry_delay_ms">-1</integer>
|
||||
|
||||
<!-- Package name that is recognized as an actor for the packages listed in
|
||||
@array/config_overlayableConfiguratorTargets. If an overlay targeting one of the listed
|
||||
targets is signed with the same signature as the configurator, the overlay will be granted
|
||||
the "actor" policy. -->
|
||||
<string name="config_overlayableConfigurator" translatable="false" />
|
||||
<string-array name="config_overlayableConfiguratorTargets" translatable="false" />
|
||||
</resources>
|
||||
|
||||
@@ -4025,4 +4025,6 @@
|
||||
<java-symbol type="string" name="config_pdp_reject_service_not_subscribed" />
|
||||
<java-symbol type="string" name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" />
|
||||
|
||||
<java-symbol type="string" name="config_overlayableConfigurator" />
|
||||
<java-symbol type="array" name="config_overlayableConfiguratorTargets" />
|
||||
</resources>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -50,8 +50,8 @@ public class OverlayActorEnforcer {
|
||||
/**
|
||||
* @return nullable actor result with {@link ActorState} failure status
|
||||
*/
|
||||
static Pair<String, ActorState> getPackageNameForActor(String actorUriString,
|
||||
Map<String, Map<String, String>> namedActors) {
|
||||
static Pair<String, ActorState> getPackageNameForActor(@NonNull String actorUriString,
|
||||
@NonNull Map<String, Map<String, String>> namedActors) {
|
||||
Uri actorUri = Uri.parse(actorUriString);
|
||||
|
||||
String actorScheme = actorUri.getScheme();
|
||||
|
||||
@@ -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<PackageInfo> getOverlayPackages(final int userId) {
|
||||
final List<PackageInfo> overlays = mPackageManagerInternal.getOverlayPackages(userId);
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> 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<String> 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<String> 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<Boolean, Boolean> 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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<OverlayInfo> 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<String, List<OverlayInfo>> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<OverlayInfo> 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<String, Package> 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<Package> 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<Package> 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<Package> 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<Package> 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<String> 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<String> overlayableNames = new ArrayList<>();
|
||||
private final ArraySet<Integer> 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<PackageInfo> 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<String, Map<String, String>> 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<String> mIdmapFiles = new ArraySet<>();
|
||||
private final ArrayMap<String, IdmapHeader> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user