Make overlay config work with immutable non-android overlays
This change renames staticness to mutability and changes the OMS to
query OverlayConfig. Changing the enabled state of immutable overlays
and changing the mutability of overlays causes the overlays to be
reinitialized and the default-enabled states to be reapplied. The
default-enabled state is applied whenever the settings for the overlay
is initialized.
Bug: 135048762
Test: use package manager to dump overlay paths of package with
static/immutable overlays
Test: verify "cmd overlay dump"
Test: atest OverlayManagerServiceImplTests
Test: atest OverlayManagerServiceImplRebootTests
Change-Id: I791befee7f4c7c6ab5ad69cd5d1f3d85e7424f96
This commit is contained in:
@@ -45,7 +45,7 @@ public final class OverlayInfo implements Parcelable {
|
||||
STATE_NO_IDMAP,
|
||||
STATE_DISABLED,
|
||||
STATE_ENABLED,
|
||||
STATE_ENABLED_STATIC,
|
||||
STATE_ENABLED_IMMUTABLE,
|
||||
// @Deprecated STATE_TARGET_IS_BEING_REPLACED,
|
||||
STATE_OVERLAY_IS_BEING_REPLACED,
|
||||
})
|
||||
@@ -117,11 +117,12 @@ public final class OverlayInfo implements Parcelable {
|
||||
|
||||
/**
|
||||
* The overlay package is currently enabled because it is marked as
|
||||
* 'static'. It cannot be disabled but will change state if for instance
|
||||
* 'immutable'. It cannot be disabled but will change state if for instance
|
||||
* its target is uninstalled.
|
||||
* @hide
|
||||
*/
|
||||
public static final int STATE_ENABLED_STATIC = 6;
|
||||
@Deprecated
|
||||
public static final int STATE_ENABLED_IMMUTABLE = 6;
|
||||
|
||||
/**
|
||||
* Overlay category: theme.
|
||||
@@ -180,21 +181,21 @@ public final class OverlayInfo implements Parcelable {
|
||||
public final int userId;
|
||||
|
||||
/**
|
||||
* Priority as read from the manifest. Used if isStatic is true. Not
|
||||
* intended to be exposed to 3rd party.
|
||||
* Priority as configured by {@link com.android.internal.content.om.OverlayConfig}.
|
||||
* Not intended to be exposed to 3rd party.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final int priority;
|
||||
|
||||
/**
|
||||
* isStatic as read from the manifest. If true, the overlay is
|
||||
* unconditionally loaded and cannot be unloaded. Not intended to be
|
||||
* isMutable as configured by {@link com.android.internal.content.om.OverlayConfig}.
|
||||
* If false, the overlay is unconditionally loaded and cannot be unloaded. Not intended to be
|
||||
* exposed to 3rd party.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final boolean isStatic;
|
||||
public final boolean isMutable;
|
||||
|
||||
/**
|
||||
* Create a new OverlayInfo based on source with an updated state.
|
||||
@@ -207,14 +208,14 @@ public final class OverlayInfo implements Parcelable {
|
||||
public OverlayInfo(@NonNull OverlayInfo source, @State int state) {
|
||||
this(source.packageName, source.targetPackageName, source.targetOverlayableName,
|
||||
source.category, source.baseCodePath, state, source.userId, source.priority,
|
||||
source.isStatic);
|
||||
source.isMutable);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
|
||||
@Nullable String targetOverlayableName, @Nullable String category,
|
||||
@NonNull String baseCodePath, int state, int userId,
|
||||
int priority, boolean isStatic) {
|
||||
int priority, boolean isMutable) {
|
||||
this.packageName = packageName;
|
||||
this.targetPackageName = targetPackageName;
|
||||
this.targetOverlayableName = targetOverlayableName;
|
||||
@@ -223,7 +224,7 @@ public final class OverlayInfo implements Parcelable {
|
||||
this.state = state;
|
||||
this.userId = userId;
|
||||
this.priority = priority;
|
||||
this.isStatic = isStatic;
|
||||
this.isMutable = isMutable;
|
||||
ensureValidState();
|
||||
}
|
||||
|
||||
@@ -237,7 +238,7 @@ public final class OverlayInfo implements Parcelable {
|
||||
state = source.readInt();
|
||||
userId = source.readInt();
|
||||
priority = source.readInt();
|
||||
isStatic = source.readBoolean();
|
||||
isMutable = source.readBoolean();
|
||||
ensureValidState();
|
||||
}
|
||||
|
||||
@@ -307,7 +308,7 @@ public final class OverlayInfo implements Parcelable {
|
||||
case STATE_NO_IDMAP:
|
||||
case STATE_DISABLED:
|
||||
case STATE_ENABLED:
|
||||
case STATE_ENABLED_STATIC:
|
||||
case STATE_ENABLED_IMMUTABLE:
|
||||
case STATE_TARGET_IS_BEING_REPLACED:
|
||||
case STATE_OVERLAY_IS_BEING_REPLACED:
|
||||
break;
|
||||
@@ -331,7 +332,7 @@ public final class OverlayInfo implements Parcelable {
|
||||
dest.writeInt(state);
|
||||
dest.writeInt(userId);
|
||||
dest.writeInt(priority);
|
||||
dest.writeBoolean(isStatic);
|
||||
dest.writeBoolean(isMutable);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Parcelable.Creator<OverlayInfo> CREATOR =
|
||||
@@ -360,7 +361,7 @@ public final class OverlayInfo implements Parcelable {
|
||||
public boolean isEnabled() {
|
||||
switch (state) {
|
||||
case STATE_ENABLED:
|
||||
case STATE_ENABLED_STATIC:
|
||||
case STATE_ENABLED_IMMUTABLE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -386,8 +387,8 @@ public final class OverlayInfo implements Parcelable {
|
||||
return "STATE_DISABLED";
|
||||
case STATE_ENABLED:
|
||||
return "STATE_ENABLED";
|
||||
case STATE_ENABLED_STATIC:
|
||||
return "STATE_ENABLED_STATIC";
|
||||
case STATE_ENABLED_IMMUTABLE:
|
||||
return "STATE_ENABLED_IMMUTABLE";
|
||||
case STATE_TARGET_IS_BEING_REPLACED:
|
||||
return "STATE_TARGET_IS_BEING_REPLACED";
|
||||
case STATE_OVERLAY_IS_BEING_REPLACED:
|
||||
|
||||
@@ -46,12 +46,13 @@ import java.util.function.Supplier;
|
||||
* @see OverlayConfigParser
|
||||
*/
|
||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
|
||||
final public class OverlayConfig {
|
||||
public class OverlayConfig {
|
||||
static final String TAG = "OverlayConfig";
|
||||
|
||||
// The default priority of an overlay that has not been configured. Overlays with default
|
||||
// priority have a higher precedence than configured overlays.
|
||||
private static final int DEFAULT_PRIORITY = Integer.MAX_VALUE;
|
||||
@VisibleForTesting
|
||||
public static final int DEFAULT_PRIORITY = Integer.MAX_VALUE;
|
||||
|
||||
@VisibleForTesting
|
||||
public static final class Configuration {
|
||||
|
||||
@@ -62,6 +62,7 @@ import android.util.AtomicFile;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.content.om.OverlayConfig;
|
||||
import com.android.server.FgThread;
|
||||
import com.android.server.IoThread;
|
||||
import com.android.server.LocalServices;
|
||||
@@ -248,7 +249,8 @@ public final class OverlayManagerService extends SystemService {
|
||||
IdmapManager im = new IdmapManager(mPackageManager);
|
||||
mSettings = new OverlayManagerSettings();
|
||||
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
|
||||
getDefaultOverlayPackages(), new OverlayChangeListener());
|
||||
OverlayConfig.getSystemInstance(), getDefaultOverlayPackages(),
|
||||
new OverlayChangeListener());
|
||||
mActorEnforcer = new OverlayActorEnforcer(mPackageManager);
|
||||
|
||||
final IntentFilter packageFilter = new IntentFilter();
|
||||
@@ -835,7 +837,7 @@ public final class OverlayManagerService extends SystemService {
|
||||
case "basecodepath":
|
||||
case "state":
|
||||
case "isenabled":
|
||||
case "isstatic":
|
||||
case "ismutable":
|
||||
case "priority":
|
||||
case "category":
|
||||
dumpState.setField(arg);
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.android.server.om;
|
||||
|
||||
import static android.content.om.OverlayInfo.STATE_DISABLED;
|
||||
import static android.content.om.OverlayInfo.STATE_ENABLED;
|
||||
import static android.content.om.OverlayInfo.STATE_ENABLED_STATIC;
|
||||
import static android.content.om.OverlayInfo.STATE_ENABLED_IMMUTABLE;
|
||||
import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
|
||||
import static android.content.om.OverlayInfo.STATE_NO_IDMAP;
|
||||
import static android.content.om.OverlayInfo.STATE_OVERLAY_IS_BEING_REPLACED;
|
||||
@@ -37,6 +37,7 @@ import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.content.om.OverlayConfig;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -69,6 +70,7 @@ final class OverlayManagerServiceImpl {
|
||||
private final PackageManagerHelper mPackageManager;
|
||||
private final IdmapManager mIdmapManager;
|
||||
private final OverlayManagerSettings mSettings;
|
||||
private final OverlayConfig mOverlayConfig;
|
||||
private final String[] mDefaultOverlays;
|
||||
private final OverlayChangeListener mListener;
|
||||
|
||||
@@ -83,7 +85,7 @@ final class OverlayManagerServiceImpl {
|
||||
* should either scrap the overlay manager's previous settings or merge the old
|
||||
* settings with the new.
|
||||
*/
|
||||
private static boolean mustReinitializeOverlay(@NonNull final PackageInfo theTruth,
|
||||
private boolean mustReinitializeOverlay(@NonNull final PackageInfo theTruth,
|
||||
@Nullable final OverlayInfo oldSettings) {
|
||||
if (oldSettings == null) {
|
||||
return true;
|
||||
@@ -94,27 +96,35 @@ final class OverlayManagerServiceImpl {
|
||||
if (!Objects.equals(theTruth.targetOverlayableName, oldSettings.targetOverlayableName)) {
|
||||
return true;
|
||||
}
|
||||
if (theTruth.isStaticOverlayPackage() != oldSettings.isStatic) {
|
||||
|
||||
boolean isMutable = isPackageConfiguredMutable(theTruth.packageName);
|
||||
if (isMutable != oldSettings.isMutable) {
|
||||
return true;
|
||||
}
|
||||
// a change in priority is only relevant for static RROs: specifically,
|
||||
// a regular RRO should not have its state reset only because a change
|
||||
// in priority
|
||||
if (theTruth.isStaticOverlayPackage()
|
||||
&& theTruth.overlayPriority != oldSettings.priority) {
|
||||
|
||||
if (getPackageConfiguredPriority(theTruth.packageName) != oldSettings.priority) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If an immutable overlay changes its configured enabled state, reinitialize the overlay.
|
||||
if (!isMutable && isPackageConfiguredEnabled(theTruth.packageName)
|
||||
!= oldSettings.isEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager,
|
||||
@NonNull final IdmapManager idmapManager,
|
||||
@NonNull final OverlayManagerSettings settings,
|
||||
@NonNull final OverlayConfig overlayConfig,
|
||||
@NonNull final String[] defaultOverlays,
|
||||
@NonNull final OverlayChangeListener listener) {
|
||||
mPackageManager = packageManager;
|
||||
mIdmapManager = idmapManager;
|
||||
mSettings = settings;
|
||||
mOverlayConfig = overlayConfig;
|
||||
mDefaultOverlays = defaultOverlays;
|
||||
mListener = listener;
|
||||
}
|
||||
@@ -162,8 +172,9 @@ final class OverlayManagerServiceImpl {
|
||||
overlayPackage.overlayTarget,
|
||||
overlayPackage.targetOverlayableName,
|
||||
overlayPackage.applicationInfo.getBaseCodePath(),
|
||||
overlayPackage.isStaticOverlayPackage(),
|
||||
overlayPackage.overlayPriority,
|
||||
isPackageConfiguredMutable(overlayPackage.packageName),
|
||||
isPackageConfiguredEnabled(overlayPackage.packageName),
|
||||
getPackageConfiguredPriority(overlayPackage.packageName),
|
||||
overlayPackage.overlayCategory);
|
||||
}
|
||||
|
||||
@@ -374,7 +385,9 @@ final class OverlayManagerServiceImpl {
|
||||
mSettings.init(packageName, userId, overlayPackage.overlayTarget,
|
||||
overlayPackage.targetOverlayableName,
|
||||
overlayPackage.applicationInfo.getBaseCodePath(),
|
||||
overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority,
|
||||
isPackageConfiguredMutable(overlayPackage.packageName),
|
||||
isPackageConfiguredEnabled(overlayPackage.packageName),
|
||||
getPackageConfiguredPriority(overlayPackage.packageName),
|
||||
overlayPackage.overlayCategory);
|
||||
try {
|
||||
if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) {
|
||||
@@ -439,8 +452,10 @@ final class OverlayManagerServiceImpl {
|
||||
mListener.onOverlaysChanged(pkg.overlayTarget, userId);
|
||||
}
|
||||
mSettings.init(packageName, userId, pkg.overlayTarget, pkg.targetOverlayableName,
|
||||
pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
|
||||
pkg.overlayPriority, pkg.overlayCategory);
|
||||
pkg.applicationInfo.getBaseCodePath(),
|
||||
isPackageConfiguredMutable(pkg.packageName),
|
||||
isPackageConfiguredEnabled(pkg.packageName),
|
||||
getPackageConfiguredPriority(pkg.packageName), pkg.overlayCategory);
|
||||
}
|
||||
|
||||
if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
|
||||
@@ -492,13 +507,13 @@ final class OverlayManagerServiceImpl {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore static overlays.
|
||||
if (overlayPackage.isStaticOverlayPackage()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
|
||||
if (!oi.isMutable) {
|
||||
// Ignore immutable overlays.
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean modified = mSettings.setEnabled(packageName, userId, enable);
|
||||
modified |= updateState(oi.targetPackageName, oi.packageName, userId, 0);
|
||||
|
||||
@@ -534,7 +549,8 @@ final class OverlayManagerServiceImpl {
|
||||
// Disable all other overlays.
|
||||
allOverlays.remove(oi);
|
||||
for (int i = 0; i < allOverlays.size(); i++) {
|
||||
final String disabledOverlayPackageName = allOverlays.get(i).packageName;
|
||||
final OverlayInfo disabledInfo = allOverlays.get(i);
|
||||
final String disabledOverlayPackageName = disabledInfo.packageName;
|
||||
final PackageInfo disabledOverlayPackageInfo = mPackageManager.getPackageInfo(
|
||||
disabledOverlayPackageName, userId);
|
||||
if (disabledOverlayPackageInfo == null) {
|
||||
@@ -542,8 +558,8 @@ final class OverlayManagerServiceImpl {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (disabledOverlayPackageInfo.isStaticOverlayPackage()) {
|
||||
// Don't touch static overlays.
|
||||
if (!disabledInfo.isMutable) {
|
||||
// Don't touch immutable overlays.
|
||||
continue;
|
||||
}
|
||||
if (withinCategory && !Objects.equals(disabledOverlayPackageInfo.overlayCategory,
|
||||
@@ -570,12 +586,16 @@ final class OverlayManagerServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPackageUpdatableOverlay(@NonNull final String packageName, final int userId) {
|
||||
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
|
||||
if (overlayPackage == null || overlayPackage.isStaticOverlayPackage()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
private boolean isPackageConfiguredMutable(@NonNull final String packageName) {
|
||||
return mOverlayConfig.isMutable(packageName);
|
||||
}
|
||||
|
||||
private int getPackageConfiguredPriority(@NonNull final String packageName) {
|
||||
return mOverlayConfig.getPriority(packageName);
|
||||
}
|
||||
|
||||
private boolean isPackageConfiguredEnabled(@NonNull final String packageName) {
|
||||
return mOverlayConfig.isEnabled(packageName);
|
||||
}
|
||||
|
||||
boolean setPriority(@NonNull final String packageName,
|
||||
@@ -585,7 +605,7 @@ final class OverlayManagerServiceImpl {
|
||||
+ newParentPackageName + " userId=" + userId);
|
||||
}
|
||||
|
||||
if (!isPackageUpdatableOverlay(packageName, userId)) {
|
||||
if (!isPackageConfiguredMutable(packageName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -605,7 +625,7 @@ final class OverlayManagerServiceImpl {
|
||||
Slog.d(TAG, "setHighestPriority packageName=" + packageName + " userId=" + userId);
|
||||
}
|
||||
|
||||
if (!isPackageUpdatableOverlay(packageName, userId)) {
|
||||
if (!isPackageConfiguredMutable(packageName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -625,7 +645,7 @@ final class OverlayManagerServiceImpl {
|
||||
Slog.d(TAG, "setLowestPriority packageName=" + packageName + " userId=" + userId);
|
||||
}
|
||||
|
||||
if (!isPackageUpdatableOverlay(packageName, userId)) {
|
||||
if (!isPackageConfiguredMutable(packageName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -682,10 +702,10 @@ final class OverlayManagerServiceImpl {
|
||||
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(overlayPackageName,
|
||||
userId);
|
||||
|
||||
// Static RROs targeting to "android", ie framework-res.apk, are handled by native layers.
|
||||
// Immutable RROs targeting to "android", ie framework-res.apk, are handled by native layers.
|
||||
if (targetPackage != null && overlayPackage != null
|
||||
&& !("android".equals(targetPackageName)
|
||||
&& overlayPackage.isStaticOverlayPackage())) {
|
||||
&& !isPackageConfiguredMutable(overlayPackageName))) {
|
||||
mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
|
||||
}
|
||||
|
||||
@@ -737,10 +757,6 @@ final class OverlayManagerServiceImpl {
|
||||
return STATE_NO_IDMAP;
|
||||
}
|
||||
|
||||
if (overlayPackage.isStaticOverlayPackage()) {
|
||||
return STATE_ENABLED_STATIC;
|
||||
}
|
||||
|
||||
final boolean enabled = mSettings.getEnabled(overlayPackage.packageName, userId);
|
||||
return enabled ? STATE_ENABLED : STATE_DISABLED;
|
||||
}
|
||||
|
||||
@@ -67,32 +67,27 @@ final class OverlayManagerSettings {
|
||||
private final ArrayList<SettingsItem> mItems = new ArrayList<>();
|
||||
|
||||
void init(@NonNull final String packageName, final int userId,
|
||||
@NonNull final String targetPackageName, @Nullable final String targetOverlayableName,
|
||||
@NonNull final String baseCodePath, boolean isStatic, int priority,
|
||||
@NonNull final String targetPackageName, @Nullable final String targetOverlayableName,
|
||||
@NonNull final String baseCodePath, boolean isMutable, boolean isEnabled, int priority,
|
||||
@Nullable String overlayCategory) {
|
||||
remove(packageName, userId);
|
||||
final SettingsItem item =
|
||||
new SettingsItem(packageName, userId, targetPackageName, targetOverlayableName,
|
||||
baseCodePath, isStatic, priority, overlayCategory);
|
||||
if (isStatic) {
|
||||
// All static overlays are always enabled.
|
||||
item.setEnabled(true);
|
||||
baseCodePath, OverlayInfo.STATE_UNKNOWN, isEnabled, isMutable, priority,
|
||||
overlayCategory);
|
||||
|
||||
int i;
|
||||
for (i = mItems.size() - 1; i >= 0; i--) {
|
||||
SettingsItem parentItem = mItems.get(i);
|
||||
if (parentItem.mIsStatic && parentItem.mPriority <= priority) {
|
||||
break;
|
||||
}
|
||||
int i;
|
||||
for (i = mItems.size() - 1; i >= 0; i--) {
|
||||
SettingsItem parentItem = mItems.get(i);
|
||||
if (parentItem.mPriority <= priority) {
|
||||
break;
|
||||
}
|
||||
int pos = i + 1;
|
||||
if (pos == mItems.size()) {
|
||||
mItems.add(item);
|
||||
} else {
|
||||
mItems.add(pos, item);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
int pos = i + 1;
|
||||
if (pos == mItems.size()) {
|
||||
mItems.add(item);
|
||||
} else {
|
||||
mItems.add(pos, item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,19 +177,19 @@ final class OverlayManagerSettings {
|
||||
|
||||
List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName,
|
||||
final int userId) {
|
||||
// Static RROs targeting "android" are loaded from AssetManager, and so they should be
|
||||
// Immutable RROs targeting "android" are loaded from AssetManager, and so they should be
|
||||
// ignored in OverlayManagerService.
|
||||
return selectWhereTarget(targetPackageName, userId)
|
||||
.filter((i) -> !(i.isStatic() && "android".equals(i.getTargetPackageName())))
|
||||
.filter((i) -> i.isMutable() || !"android".equals(i.getTargetPackageName()))
|
||||
.map(SettingsItem::getOverlayInfo)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
ArrayMap<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
|
||||
// Static RROs targeting "android" are loaded from AssetManager, and so they should be
|
||||
// Immutable RROs targeting "android" are loaded from AssetManager, and so they should be
|
||||
// ignored in OverlayManagerService.
|
||||
return selectWhereUser(userId)
|
||||
.filter((i) -> !(i.isStatic() && "android".equals(i.getTargetPackageName())))
|
||||
.filter((i) -> i.isMutable() || !"android".equals(i.getTargetPackageName()))
|
||||
.map(SettingsItem::getOverlayInfo)
|
||||
.collect(Collectors.groupingBy(info -> info.targetPackageName, ArrayMap::new,
|
||||
Collectors.toList()));
|
||||
@@ -320,7 +315,7 @@ final class OverlayManagerSettings {
|
||||
pw.println("mBaseCodePath..........: " + item.getBaseCodePath());
|
||||
pw.println("mState.................: " + OverlayInfo.stateToString(item.getState()));
|
||||
pw.println("mIsEnabled.............: " + item.isEnabled());
|
||||
pw.println("mIsStatic..............: " + item.isStatic());
|
||||
pw.println("mIsMutable.............: " + item.isMutable());
|
||||
pw.println("mPriority..............: " + item.mPriority);
|
||||
pw.println("mCategory..............: " + item.mCategory);
|
||||
|
||||
@@ -352,8 +347,8 @@ final class OverlayManagerSettings {
|
||||
case "isenabled":
|
||||
pw.println(item.mIsEnabled);
|
||||
break;
|
||||
case "isstatic":
|
||||
pw.println(item.mIsStatic);
|
||||
case "ismutable":
|
||||
pw.println(item.mIsMutable);
|
||||
break;
|
||||
case "priority":
|
||||
pw.println(item.mPriority);
|
||||
@@ -446,7 +441,7 @@ final class OverlayManagerSettings {
|
||||
final String category = XmlUtils.readStringAttribute(parser, ATTR_CATEGORY);
|
||||
|
||||
return new SettingsItem(packageName, userId, targetPackageName, targetOverlayableName,
|
||||
baseCodePath, state, isEnabled, isStatic, priority, category);
|
||||
baseCodePath, state, isEnabled, !isStatic, priority, category);
|
||||
}
|
||||
|
||||
public static void persist(@NonNull final ArrayList<SettingsItem> table,
|
||||
@@ -478,7 +473,7 @@ final class OverlayManagerSettings {
|
||||
XmlUtils.writeStringAttribute(xml, ATTR_BASE_CODE_PATH, item.mBaseCodePath);
|
||||
XmlUtils.writeIntAttribute(xml, ATTR_STATE, item.mState);
|
||||
XmlUtils.writeBooleanAttribute(xml, ATTR_IS_ENABLED, item.mIsEnabled);
|
||||
XmlUtils.writeBooleanAttribute(xml, ATTR_IS_STATIC, item.mIsStatic);
|
||||
XmlUtils.writeBooleanAttribute(xml, ATTR_IS_STATIC, !item.mIsMutable);
|
||||
XmlUtils.writeIntAttribute(xml, ATTR_PRIORITY, item.mPriority);
|
||||
XmlUtils.writeStringAttribute(xml, ATTR_CATEGORY, item.mCategory);
|
||||
xml.endTag(null, TAG_ITEM);
|
||||
@@ -494,36 +489,28 @@ final class OverlayManagerSettings {
|
||||
private @OverlayInfo.State int mState;
|
||||
private boolean mIsEnabled;
|
||||
private OverlayInfo mCache;
|
||||
private boolean mIsStatic;
|
||||
private boolean mIsMutable;
|
||||
private int mPriority;
|
||||
private String mCategory;
|
||||
|
||||
SettingsItem(@NonNull final String packageName, final int userId,
|
||||
@NonNull final String targetPackageName,
|
||||
@Nullable final String targetOverlayableName, @NonNull final String baseCodePath,
|
||||
final @OverlayInfo.State int state, final boolean isEnabled, final boolean isStatic,
|
||||
final int priority, @Nullable String category) {
|
||||
final @OverlayInfo.State int state, final boolean isEnabled,
|
||||
final boolean isMutable, final int priority, @Nullable String category) {
|
||||
mPackageName = packageName;
|
||||
mUserId = userId;
|
||||
mTargetPackageName = targetPackageName;
|
||||
mTargetOverlayableName = targetOverlayableName;
|
||||
mBaseCodePath = baseCodePath;
|
||||
mState = state;
|
||||
mIsEnabled = isEnabled || isStatic;
|
||||
mIsEnabled = isEnabled;
|
||||
mCategory = category;
|
||||
mCache = null;
|
||||
mIsStatic = isStatic;
|
||||
mIsMutable = isMutable;
|
||||
mPriority = priority;
|
||||
}
|
||||
|
||||
SettingsItem(@NonNull final String packageName, final int userId,
|
||||
@NonNull final String targetPackageName,
|
||||
@Nullable final String targetOverlayableName, @NonNull final String baseCodePath,
|
||||
final boolean isStatic, final int priority, @Nullable String category) {
|
||||
this(packageName, userId, targetPackageName, targetOverlayableName, baseCodePath,
|
||||
OverlayInfo.STATE_UNKNOWN, false, isStatic, priority, category);
|
||||
}
|
||||
|
||||
private String getTargetPackageName() {
|
||||
return mTargetPackageName;
|
||||
}
|
||||
@@ -567,7 +554,7 @@ final class OverlayManagerSettings {
|
||||
}
|
||||
|
||||
private boolean setEnabled(boolean enable) {
|
||||
if (mIsStatic) {
|
||||
if (!mIsMutable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -591,7 +578,7 @@ final class OverlayManagerSettings {
|
||||
private OverlayInfo getOverlayInfo() {
|
||||
if (mCache == null) {
|
||||
mCache = new OverlayInfo(mPackageName, mTargetPackageName, mTargetOverlayableName,
|
||||
mCategory, mBaseCodePath, mState, mUserId, mPriority, mIsStatic);
|
||||
mCategory, mBaseCodePath, mState, mUserId, mPriority, mIsMutable);
|
||||
}
|
||||
return mCache;
|
||||
}
|
||||
@@ -600,8 +587,8 @@ final class OverlayManagerSettings {
|
||||
mCache = null;
|
||||
}
|
||||
|
||||
private boolean isStatic() {
|
||||
return mIsStatic;
|
||||
private boolean isMutable() {
|
||||
return mIsMutable;
|
||||
}
|
||||
|
||||
private int getPriority() {
|
||||
|
||||
@@ -181,7 +181,7 @@ final class OverlayManagerShellCommand extends ShellCommand {
|
||||
private void printListOverlay(PrintWriter out, OverlayInfo oi) {
|
||||
String status;
|
||||
switch (oi.state) {
|
||||
case OverlayInfo.STATE_ENABLED_STATIC:
|
||||
case OverlayInfo.STATE_ENABLED_IMMUTABLE:
|
||||
case OverlayInfo.STATE_ENABLED:
|
||||
status = "[x]";
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.om;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.om.OverlayInfo;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceImplTestsBase {
|
||||
|
||||
private static final String OVERLAY = "com.dummy.overlay";
|
||||
private static final String TARGET = "com.dummy.target";
|
||||
private static final int USER = 0;
|
||||
|
||||
private static final String OVERLAY2 = OVERLAY + "2";
|
||||
|
||||
@Test
|
||||
public void testUpdateOverlaysForUser() {
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
installTargetPackage(TARGET, USER);
|
||||
installTargetPackage("some.other.target", USER);
|
||||
installOverlayPackage(OVERLAY, TARGET, USER);
|
||||
|
||||
// do nothing, expect no change
|
||||
final List<String> a = impl.updateOverlaysForUser(USER);
|
||||
assertEquals(1, a.size());
|
||||
assertTrue(a.contains(TARGET));
|
||||
|
||||
// upgrade overlay, keep target
|
||||
beginUpgradeOverlayPackage(OVERLAY, USER);
|
||||
endUpgradeOverlayPackage(OVERLAY, TARGET, USER);
|
||||
|
||||
final List<String> b = impl.updateOverlaysForUser(USER);
|
||||
assertEquals(1, b.size());
|
||||
assertTrue(b.contains(TARGET));
|
||||
|
||||
// do nothing, expect no change
|
||||
final List<String> c = impl.updateOverlaysForUser(USER);
|
||||
assertEquals(1, c.size());
|
||||
assertTrue(c.contains(TARGET));
|
||||
|
||||
// upgrade overlay, switch to new target
|
||||
addOverlayPackage(OVERLAY, "some.other.target", USER, true, false, 0);
|
||||
final List<String> d = impl.updateOverlaysForUser(USER);
|
||||
assertEquals(2, d.size());
|
||||
assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target")));
|
||||
|
||||
// do nothing, expect no change
|
||||
final List<String> f = impl.updateOverlaysForUser(USER);
|
||||
assertEquals(1, f.size());
|
||||
assertTrue(f.contains("some.other.target"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImmutableEnabledChange() {
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
installTargetPackage(TARGET, USER);
|
||||
|
||||
addOverlayPackage(OVERLAY, TARGET, USER, false, false, 0);
|
||||
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);
|
||||
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);
|
||||
impl.updateOverlaysForUser(USER);
|
||||
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
|
||||
assertNotNull(o3);
|
||||
assertFalse(o3.isEnabled());
|
||||
assertFalse(o3.isMutable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMutableEnabledChangeHasNoEffect() {
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
installTargetPackage(TARGET, USER);
|
||||
|
||||
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);
|
||||
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);
|
||||
impl.updateOverlaysForUser(USER);
|
||||
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
|
||||
assertNotNull(o3);
|
||||
assertFalse(o3.isEnabled());
|
||||
assertTrue(o3.isMutable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMutabilityChange() {
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
installTargetPackage(TARGET, USER);
|
||||
|
||||
addOverlayPackage(OVERLAY, TARGET, USER, false, true, 0);
|
||||
impl.updateOverlaysForUser(USER);
|
||||
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
|
||||
assertNotNull(o1);
|
||||
assertTrue(o1.isEnabled());
|
||||
assertFalse(o1.isMutable);
|
||||
|
||||
addOverlayPackage(OVERLAY, TARGET, USER, true, false, 0);
|
||||
impl.updateOverlaysForUser(USER);
|
||||
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY, USER);
|
||||
assertNotNull(o2);
|
||||
assertFalse(o2.isEnabled());
|
||||
assertTrue(o2.isMutable);
|
||||
|
||||
addOverlayPackage(OVERLAY, TARGET, USER, false, false, 0);
|
||||
impl.updateOverlaysForUser(USER);
|
||||
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
|
||||
assertNotNull(o3);
|
||||
assertFalse(o3.isEnabled());
|
||||
assertFalse(o3.isMutable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPriorityChange() {
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
installTargetPackage(TARGET, USER);
|
||||
|
||||
addOverlayPackage(OVERLAY, TARGET, USER, false, true, 0);
|
||||
addOverlayPackage(OVERLAY2, TARGET, USER, false, true, 1);
|
||||
impl.updateOverlaysForUser(USER);
|
||||
|
||||
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
|
||||
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY2, USER);
|
||||
assertNotNull(o1);
|
||||
assertNotNull(o2);
|
||||
assertEquals(0, o1.priority);
|
||||
assertEquals(1, o2.priority);
|
||||
|
||||
addOverlayPackage(OVERLAY, TARGET, USER, false, true, 1);
|
||||
addOverlayPackage(OVERLAY2, TARGET, USER, false, true, 0);
|
||||
impl.updateOverlaysForUser(USER);
|
||||
|
||||
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
|
||||
final OverlayInfo o4 = impl.getOverlayInfo(OVERLAY2, USER);
|
||||
assertNotNull(o3);
|
||||
assertNotNull(o4);
|
||||
assertEquals(1, o3.priority);
|
||||
assertEquals(0, o4.priority);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,9 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.om.OverlayInfo;
|
||||
@@ -33,6 +36,8 @@ import android.util.ArraySet;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.content.om.OverlayConfig;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -45,10 +50,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class OverlayManagerServiceImplTests {
|
||||
private OverlayManagerServiceImpl mImpl;
|
||||
private DummyDeviceState mState;
|
||||
private DummyListener mListener;
|
||||
public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTestsBase {
|
||||
|
||||
private static final String OVERLAY = "com.dummy.overlay";
|
||||
private static final String TARGET = "com.dummy.target";
|
||||
@@ -61,25 +63,14 @@ public class OverlayManagerServiceImplTests {
|
||||
private static final String OVERLAY3 = OVERLAY + "3";
|
||||
private static final int USER3 = USER2 + 1;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mState = new DummyDeviceState();
|
||||
mListener = new DummyListener();
|
||||
DummyPackageManagerHelper pmh = new DummyPackageManagerHelper(mState);
|
||||
mImpl = new OverlayManagerServiceImpl(pmh,
|
||||
new DummyIdmapManager(mState, pmh),
|
||||
new OverlayManagerSettings(),
|
||||
new String[0],
|
||||
mListener);
|
||||
}
|
||||
|
||||
// tests: basics
|
||||
|
||||
@Test
|
||||
public void testGetOverlayInfo() throws Exception {
|
||||
installOverlayPackage(OVERLAY, TARGET, USER, false);
|
||||
final OverlayInfo oi = mImpl.getOverlayInfo(OVERLAY, USER);
|
||||
installOverlayPackage(OVERLAY, TARGET, USER);
|
||||
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
final OverlayInfo oi = impl.getOverlayInfo(OVERLAY, USER);
|
||||
assertNotNull(oi);
|
||||
assertEquals(oi.packageName, OVERLAY);
|
||||
assertEquals(oi.targetPackageName, TARGET);
|
||||
@@ -88,87 +79,91 @@ public class OverlayManagerServiceImplTests {
|
||||
|
||||
@Test
|
||||
public void testGetOverlayInfosForTarget() throws Exception {
|
||||
installOverlayPackage(OVERLAY, TARGET, USER, false);
|
||||
installOverlayPackage(OVERLAY2, TARGET, USER, false);
|
||||
installOverlayPackage(OVERLAY, TARGET, USER);
|
||||
installOverlayPackage(OVERLAY2, TARGET, USER);
|
||||
installOverlayPackage(OVERLAY3, TARGET, USER2);
|
||||
|
||||
installOverlayPackage(OVERLAY3, TARGET, USER2, false);
|
||||
|
||||
final List<OverlayInfo> ois = mImpl.getOverlayInfosForTarget(TARGET, USER);
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
final List<OverlayInfo> ois = impl.getOverlayInfosForTarget(TARGET, USER);
|
||||
assertEquals(ois.size(), 2);
|
||||
assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY, USER)));
|
||||
assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY2, USER)));
|
||||
assertTrue(ois.contains(impl.getOverlayInfo(OVERLAY, USER)));
|
||||
assertTrue(ois.contains(impl.getOverlayInfo(OVERLAY2, USER)));
|
||||
|
||||
final List<OverlayInfo> ois2 = mImpl.getOverlayInfosForTarget(TARGET, USER2);
|
||||
final List<OverlayInfo> ois2 = impl.getOverlayInfosForTarget(TARGET, USER2);
|
||||
assertEquals(ois2.size(), 1);
|
||||
assertTrue(ois2.contains(mImpl.getOverlayInfo(OVERLAY3, USER2)));
|
||||
assertTrue(ois2.contains(impl.getOverlayInfo(OVERLAY3, USER2)));
|
||||
|
||||
final List<OverlayInfo> ois3 = mImpl.getOverlayInfosForTarget(TARGET, USER3);
|
||||
final List<OverlayInfo> ois3 = impl.getOverlayInfosForTarget(TARGET, USER3);
|
||||
assertNotNull(ois3);
|
||||
assertEquals(ois3.size(), 0);
|
||||
|
||||
final List<OverlayInfo> ois4 = mImpl.getOverlayInfosForTarget("no.such.overlay", USER);
|
||||
final List<OverlayInfo> ois4 = impl.getOverlayInfosForTarget("no.such.overlay", USER);
|
||||
assertNotNull(ois4);
|
||||
assertEquals(ois4.size(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOverlayInfosForUser() throws Exception {
|
||||
installOverlayPackage(OVERLAY, TARGET, USER, false);
|
||||
installOverlayPackage(OVERLAY2, TARGET, USER, false);
|
||||
installOverlayPackage(OVERLAY3, TARGET2, USER, false);
|
||||
installTargetPackage(TARGET, USER);
|
||||
installOverlayPackage(OVERLAY, TARGET, USER);
|
||||
installOverlayPackage(OVERLAY2, TARGET, USER);
|
||||
installOverlayPackage(OVERLAY3, TARGET2, USER);
|
||||
|
||||
final Map<String, List<OverlayInfo>> everything = mImpl.getOverlaysForUser(USER);
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
final Map<String, List<OverlayInfo>> everything = impl.getOverlaysForUser(USER);
|
||||
assertEquals(everything.size(), 2);
|
||||
|
||||
final List<OverlayInfo> ois = everything.get(TARGET);
|
||||
assertNotNull(ois);
|
||||
assertEquals(ois.size(), 2);
|
||||
assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY, USER)));
|
||||
assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY2, USER)));
|
||||
assertTrue(ois.contains(impl.getOverlayInfo(OVERLAY, USER)));
|
||||
assertTrue(ois.contains(impl.getOverlayInfo(OVERLAY2, USER)));
|
||||
|
||||
final List<OverlayInfo> ois2 = everything.get(TARGET2);
|
||||
assertNotNull(ois2);
|
||||
assertEquals(ois2.size(), 1);
|
||||
assertTrue(ois2.contains(mImpl.getOverlayInfo(OVERLAY3, USER)));
|
||||
assertTrue(ois2.contains(impl.getOverlayInfo(OVERLAY3, USER)));
|
||||
|
||||
final Map<String, List<OverlayInfo>> everything2 = mImpl.getOverlaysForUser(USER2);
|
||||
final Map<String, List<OverlayInfo>> everything2 = impl.getOverlaysForUser(USER2);
|
||||
assertNotNull(everything2);
|
||||
assertEquals(everything2.size(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPriority() throws Exception {
|
||||
installOverlayPackage(OVERLAY, TARGET, USER, false);
|
||||
installOverlayPackage(OVERLAY2, TARGET, USER, false);
|
||||
installOverlayPackage(OVERLAY3, TARGET, USER, false);
|
||||
installOverlayPackage(OVERLAY, TARGET, USER);
|
||||
installOverlayPackage(OVERLAY2, TARGET, USER);
|
||||
installOverlayPackage(OVERLAY3, TARGET, USER);
|
||||
|
||||
final OverlayInfo o1 = mImpl.getOverlayInfo(OVERLAY, USER);
|
||||
final OverlayInfo o2 = mImpl.getOverlayInfo(OVERLAY2, USER);
|
||||
final OverlayInfo o3 = mImpl.getOverlayInfo(OVERLAY3, 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);
|
||||
|
||||
assertTrue(mImpl.setLowestPriority(OVERLAY3, USER));
|
||||
assertTrue(impl.setLowestPriority(OVERLAY3, USER));
|
||||
assertOverlayInfoList(TARGET, USER, o3, o1, o2);
|
||||
|
||||
assertTrue(mImpl.setHighestPriority(OVERLAY3, USER));
|
||||
assertTrue(impl.setHighestPriority(OVERLAY3, USER));
|
||||
assertOverlayInfoList(TARGET, USER, o1, o2, o3);
|
||||
|
||||
assertTrue(mImpl.setPriority(OVERLAY, OVERLAY2, USER));
|
||||
assertTrue(impl.setPriority(OVERLAY, OVERLAY2, USER));
|
||||
assertOverlayInfoList(TARGET, USER, o2, o1, o3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlayInfoStateTransitions() throws Exception {
|
||||
assertNull(mImpl.getOverlayInfo(OVERLAY, USER));
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
assertNull(impl.getOverlayInfo(OVERLAY, USER));
|
||||
|
||||
installOverlayPackage(OVERLAY, TARGET, USER, true);
|
||||
installOverlayPackage(OVERLAY, TARGET, USER);
|
||||
assertState(STATE_MISSING_TARGET, OVERLAY, USER);
|
||||
|
||||
installTargetPackage(TARGET, USER);
|
||||
assertState(STATE_DISABLED, OVERLAY, USER);
|
||||
|
||||
mImpl.setEnabled(OVERLAY, true, USER);
|
||||
impl.setEnabled(OVERLAY, true, USER);
|
||||
assertState(STATE_ENABLED, OVERLAY, USER);
|
||||
|
||||
// target upgrades do not change the state of the overlay
|
||||
@@ -185,320 +180,49 @@ public class OverlayManagerServiceImplTests {
|
||||
assertState(STATE_ENABLED, OVERLAY, USER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateOverlaysForUser() throws Exception {
|
||||
installTargetPackage(TARGET, USER);
|
||||
installTargetPackage("some.other.target", USER);
|
||||
installOverlayPackage(OVERLAY, TARGET, USER, true);
|
||||
|
||||
// do nothing, expect no change
|
||||
List<String> a = mImpl.updateOverlaysForUser(USER);
|
||||
assertEquals(1, a.size());
|
||||
assertTrue(a.contains(TARGET));
|
||||
|
||||
// upgrade overlay, keep target
|
||||
upgradeOverlayPackage(OVERLAY, TARGET, USER, true);
|
||||
List<String> b = mImpl.updateOverlaysForUser(USER);
|
||||
assertEquals(1, b.size());
|
||||
assertTrue(b.contains(TARGET));
|
||||
|
||||
// do nothing, expect no change
|
||||
List<String> c = mImpl.updateOverlaysForUser(USER);
|
||||
assertEquals(1, c.size());
|
||||
assertTrue(c.contains(TARGET));
|
||||
|
||||
// upgrade overlay, switch to new target
|
||||
upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
|
||||
List<String> d = mImpl.updateOverlaysForUser(USER);
|
||||
assertEquals(2, d.size());
|
||||
assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target")));
|
||||
|
||||
// do nothing, expect no change
|
||||
List<String> e = mImpl.updateOverlaysForUser(USER);
|
||||
assertEquals(1, e.size());
|
||||
assertTrue(e.contains("some.other.target"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnOverlayPackageUpgraded() throws Exception {
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
final DummyListener listener = getListener();
|
||||
installTargetPackage(TARGET, USER);
|
||||
installOverlayPackage(OVERLAY, TARGET, USER, true);
|
||||
mImpl.onOverlayPackageReplacing(OVERLAY, USER);
|
||||
mListener.count = 0;
|
||||
mImpl.onOverlayPackageReplaced(OVERLAY, USER);
|
||||
assertEquals(1, mListener.count);
|
||||
installOverlayPackage(OVERLAY, TARGET, USER);
|
||||
impl.onOverlayPackageReplacing(OVERLAY, USER);
|
||||
listener.count = 0;
|
||||
impl.onOverlayPackageReplaced(OVERLAY, USER);
|
||||
assertEquals(1, listener.count);
|
||||
|
||||
// upgrade to a version where the overlay has changed its target
|
||||
upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
|
||||
mImpl.onOverlayPackageReplacing(OVERLAY, USER);
|
||||
mListener.count = 0;
|
||||
mImpl.onOverlayPackageReplaced(OVERLAY, USER);
|
||||
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
|
||||
assertEquals(2, mListener.count);
|
||||
assertEquals(2, listener.count);
|
||||
|
||||
upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
|
||||
mImpl.onOverlayPackageReplacing(OVERLAY, USER);
|
||||
mListener.count = 0;
|
||||
mImpl.onOverlayPackageReplaced(OVERLAY, USER);
|
||||
assertEquals(1, mListener.count);
|
||||
beginUpgradeOverlayPackage(OVERLAY, USER);
|
||||
listener.count = 0;
|
||||
endUpgradeOverlayPackage(OVERLAY, "some.other.target", USER);
|
||||
assertEquals(1, listener.count);
|
||||
}
|
||||
|
||||
// tests: listener interface
|
||||
|
||||
@Test
|
||||
public void testListener() throws Exception {
|
||||
installOverlayPackage(OVERLAY, TARGET, USER, true);
|
||||
assertEquals(1, mListener.count);
|
||||
mListener.count = 0;
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
final DummyListener listener = getListener();
|
||||
installOverlayPackage(OVERLAY, TARGET, USER);
|
||||
assertEquals(1, listener.count);
|
||||
listener.count = 0;
|
||||
|
||||
installTargetPackage(TARGET, USER);
|
||||
assertEquals(1, mListener.count);
|
||||
mListener.count = 0;
|
||||
assertEquals(1, listener.count);
|
||||
listener.count = 0;
|
||||
|
||||
mImpl.setEnabled(OVERLAY, true, USER);
|
||||
assertEquals(1, mListener.count);
|
||||
mListener.count = 0;
|
||||
impl.setEnabled(OVERLAY, true, USER);
|
||||
assertEquals(1, listener.count);
|
||||
listener.count = 0;
|
||||
|
||||
mImpl.setEnabled(OVERLAY, true, USER);
|
||||
assertEquals(0, mListener.count);
|
||||
}
|
||||
|
||||
// helper methods
|
||||
|
||||
private void assertState(int expected, final String overlayPackageName, int userId) {
|
||||
int actual = mImpl.getOverlayInfo(OVERLAY, USER).state;
|
||||
String msg = String.format("expected %s but was %s:",
|
||||
OverlayInfo.stateToString(expected), OverlayInfo.stateToString(actual));
|
||||
assertEquals(msg, expected, actual);
|
||||
}
|
||||
|
||||
private void assertOverlayInfoList(final String targetPackageName, int userId,
|
||||
OverlayInfo... overlayInfos) {
|
||||
final List<OverlayInfo> expected =
|
||||
mImpl.getOverlayInfosForTarget(targetPackageName, userId);
|
||||
final List<OverlayInfo> actual = Arrays.asList(overlayInfos);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
private void installTargetPackage(String packageName, int userId) {
|
||||
if (mState.select(packageName, userId) != null) {
|
||||
throw new IllegalStateException("package already installed");
|
||||
}
|
||||
mState.add(packageName, null, userId, false);
|
||||
mImpl.onTargetPackageAdded(packageName, userId);
|
||||
}
|
||||
|
||||
private void beginUpgradeTargetPackage(String packageName, int userId) {
|
||||
if (mState.select(packageName, userId) == null) {
|
||||
throw new IllegalStateException("package not installed");
|
||||
}
|
||||
mState.add(packageName, null, userId, false);
|
||||
mImpl.onTargetPackageReplacing(packageName, userId);
|
||||
}
|
||||
|
||||
private void endUpgradeTargetPackage(String packageName, int userId) {
|
||||
if (mState.select(packageName, userId) == null) {
|
||||
throw new IllegalStateException("package not installed");
|
||||
}
|
||||
mState.add(packageName, null, userId, false);
|
||||
mImpl.onTargetPackageReplaced(packageName, userId);
|
||||
}
|
||||
|
||||
private void uninstallTargetPackage(String packageName, int userId) {
|
||||
if (mState.select(packageName, userId) == null) {
|
||||
throw new IllegalStateException("package not installed");
|
||||
}
|
||||
mState.remove(packageName, userId);
|
||||
mImpl.onTargetPackageRemoved(packageName, userId);
|
||||
}
|
||||
|
||||
private void installOverlayPackage(String packageName, String targetPackageName, int userId,
|
||||
boolean canCreateIdmap) {
|
||||
if (mState.select(packageName, userId) != null) {
|
||||
throw new IllegalStateException("package already installed");
|
||||
}
|
||||
mState.add(packageName, targetPackageName, userId, canCreateIdmap);
|
||||
mImpl.onOverlayPackageAdded(packageName, userId);
|
||||
}
|
||||
|
||||
private void upgradeOverlayPackage(String packageName, String targetPackageName, int userId,
|
||||
boolean canCreateIdmap) {
|
||||
DummyDeviceState.Package pkg = mState.select(packageName, userId);
|
||||
if (pkg == null) {
|
||||
throw new IllegalStateException("package not installed, cannot upgrade");
|
||||
}
|
||||
pkg.targetPackageName = targetPackageName;
|
||||
pkg.canCreateIdmap = canCreateIdmap;
|
||||
}
|
||||
|
||||
private void uninstallOverlayPackage(String packageName, int userId) {
|
||||
// implement this when adding support for downloadable overlays
|
||||
throw new IllegalArgumentException("not implemented");
|
||||
}
|
||||
|
||||
private static final class DummyDeviceState {
|
||||
private List<Package> mPackages = new ArrayList<>();
|
||||
|
||||
public void add(String packageName, String targetPackageName, int userId,
|
||||
boolean canCreateIdmap) {
|
||||
remove(packageName, userId);
|
||||
Package pkg = new Package();
|
||||
pkg.packageName = packageName;
|
||||
pkg.targetPackageName = targetPackageName;
|
||||
pkg.userId = userId;
|
||||
pkg.canCreateIdmap = canCreateIdmap;
|
||||
mPackages.add(pkg);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Package> select(int userId) {
|
||||
List<Package> out = new ArrayList<>();
|
||||
final int packageCount = mPackages.size();
|
||||
for (int i = 0; i < packageCount; i++) {
|
||||
final Package pkg = mPackages.get(i);
|
||||
if (pkg.userId == userId) {
|
||||
out.add(pkg);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public Package select(String packageName, int userId) {
|
||||
final int packageCount = mPackages.size();
|
||||
for (int i = 0; i < packageCount; i++) {
|
||||
final Package pkg = mPackages.get(i);
|
||||
if (pkg.packageName.equals(packageName) && pkg.userId == userId) {
|
||||
return pkg;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final class Package {
|
||||
public String packageName;
|
||||
public int userId;
|
||||
public String targetPackageName;
|
||||
public boolean canCreateIdmap;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DummyPackageManagerHelper implements
|
||||
OverlayManagerServiceImpl.PackageManagerHelper {
|
||||
private final DummyDeviceState mState;
|
||||
|
||||
DummyPackageManagerHelper(DummyDeviceState state) {
|
||||
mState = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackageInfo getPackageInfo(@NonNull String packageName, int userId) {
|
||||
final DummyDeviceState.Package pkg = mState.select(packageName, userId);
|
||||
if (pkg == null) {
|
||||
return null;
|
||||
}
|
||||
ApplicationInfo ai = new ApplicationInfo();
|
||||
ai.sourceDir = String.format("%s/%s/base.apk",
|
||||
pkg.targetPackageName == null ? "/system/app/" : "/vendor/overlay/",
|
||||
pkg.packageName);
|
||||
PackageInfo pi = new PackageInfo();
|
||||
pi.applicationInfo = ai;
|
||||
pi.packageName = pkg.packageName;
|
||||
pi.overlayTarget = pkg.targetPackageName;
|
||||
pi.overlayCategory = "dummy-category-" + pkg.targetPackageName;
|
||||
return pi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean signaturesMatching(@NonNull String packageName1,
|
||||
@NonNull String packageName2, int userId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PackageInfo> getOverlayPackages(int userId) {
|
||||
List<PackageInfo> out = new ArrayList<>();
|
||||
final List<DummyDeviceState.Package> packages = mState.select(userId);
|
||||
final int packageCount = packages.size();
|
||||
for (int i = 0; i < packageCount; i++) {
|
||||
final DummyDeviceState.Package pkg = packages.get(i);
|
||||
if (pkg.targetPackageName != null) {
|
||||
out.add(getPackageInfo(pkg.packageName, pkg.userId));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DummyIdmapManager extends IdmapManager {
|
||||
private final DummyDeviceState mState;
|
||||
private Set<String> mIdmapFiles = new ArraySet<>();
|
||||
|
||||
DummyIdmapManager(DummyDeviceState state, DummyPackageManagerHelper packageManagerHelper) {
|
||||
super(packageManagerHelper);
|
||||
mState = state;
|
||||
}
|
||||
|
||||
@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) {
|
||||
return false;
|
||||
}
|
||||
final DummyDeviceState.Package o = mState.select(overlayPackage.packageName, userId);
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
if (!o.canCreateIdmap) {
|
||||
return false;
|
||||
}
|
||||
final String key = createKey(overlayPackage.packageName, userId);
|
||||
mIdmapFiles.add(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) {
|
||||
final String key = createKey(oi.packageName, oi.userId);
|
||||
if (!mIdmapFiles.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DummyListener implements OverlayManagerServiceImpl.OverlayChangeListener {
|
||||
public int count;
|
||||
|
||||
public void onOverlaysChanged(@NonNull String targetPackage, int userId) {
|
||||
count++;
|
||||
}
|
||||
impl.setEnabled(OVERLAY, true, USER);
|
||||
assertEquals(0, listener.count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.om;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.om.OverlayInfo;
|
||||
import android.content.om.OverlayInfo.State;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.internal.content.om.OverlayConfig;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** Base class for creating {@link OverlayManagerServiceImplTests} tests. */
|
||||
class OverlayManagerServiceImplTestsBase {
|
||||
private OverlayManagerServiceImpl mImpl;
|
||||
private DummyDeviceState mState;
|
||||
private DummyListener mListener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mState = new DummyDeviceState();
|
||||
mListener = new DummyListener();
|
||||
final DummyPackageManagerHelper pmh = new DummyPackageManagerHelper(mState);
|
||||
|
||||
mImpl = new OverlayManagerServiceImpl(pmh,
|
||||
new DummyIdmapManager(mState, pmh),
|
||||
new OverlayManagerSettings(),
|
||||
mState.mOverlayConfig,
|
||||
new String[0],
|
||||
mListener);
|
||||
}
|
||||
|
||||
public OverlayManagerServiceImpl getImpl() {
|
||||
return mImpl;
|
||||
}
|
||||
|
||||
public DummyListener getListener() {
|
||||
return mListener;
|
||||
}
|
||||
|
||||
void assertState(@State int expected, final String overlayPackageName, int userId) {
|
||||
final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId);
|
||||
if (info == null) {
|
||||
throw new IllegalStateException("package not installed");
|
||||
}
|
||||
|
||||
final String msg = String.format("expected %s but was %s:",
|
||||
OverlayInfo.stateToString(expected), OverlayInfo.stateToString(info.state));
|
||||
assertEquals(msg, expected, info.state);
|
||||
}
|
||||
|
||||
void assertOverlayInfoList(final String targetPackageName, int userId,
|
||||
OverlayInfo... overlayInfos) {
|
||||
final List<OverlayInfo> expected =
|
||||
mImpl.getOverlayInfosForTarget(targetPackageName, userId);
|
||||
final List<OverlayInfo> actual = Arrays.asList(overlayInfos);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the target 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
|
||||
*/
|
||||
void installTargetPackage(String packageName, int userId) {
|
||||
if (mState.select(packageName, userId) != null) {
|
||||
throw new IllegalStateException("package already installed");
|
||||
}
|
||||
mState.addTarget(packageName, userId);
|
||||
mImpl.onTargetPackageAdded(packageName, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins upgrading the target 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#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");
|
||||
}
|
||||
mState.addTarget(packageName, userId);
|
||||
mImpl.onTargetPackageReplaced(packageName, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the target 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");
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 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());
|
||||
}
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
private Package(String packageName, int userId, String targetPackageName,
|
||||
boolean mutable, boolean enabled, int priority) {
|
||||
this.packageName = packageName;
|
||||
this.userId = userId;
|
||||
this.targetPackageName = targetPackageName;
|
||||
this.mutable = mutable;
|
||||
this.enabled = enabled;
|
||||
this.priority = priority;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class DummyPackageManagerHelper implements
|
||||
OverlayManagerServiceImpl.PackageManagerHelper {
|
||||
private final DummyDeviceState mState;
|
||||
|
||||
private DummyPackageManagerHelper(DummyDeviceState state) {
|
||||
mState = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackageInfo getPackageInfo(@NonNull String packageName, int userId) {
|
||||
final DummyDeviceState.Package pkg = mState.select(packageName, userId);
|
||||
if (pkg == null) {
|
||||
return null;
|
||||
}
|
||||
final ApplicationInfo ai = new ApplicationInfo();
|
||||
ai.sourceDir = String.format("%s/%s/base.apk",
|
||||
pkg.targetPackageName == null ? "/system/app/" : "/vendor/overlay/",
|
||||
pkg.packageName);
|
||||
PackageInfo pi = new PackageInfo();
|
||||
pi.applicationInfo = ai;
|
||||
pi.packageName = pkg.packageName;
|
||||
pi.overlayTarget = pkg.targetPackageName;
|
||||
pi.overlayCategory = "dummy-category-" + pkg.targetPackageName;
|
||||
return pi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean signaturesMatching(@NonNull String packageName1,
|
||||
@NonNull String packageName2, int userId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PackageInfo> getOverlayPackages(int userId) {
|
||||
return mState.select(userId).stream()
|
||||
.filter(p -> p.targetPackageName != null)
|
||||
.map(p -> getPackageInfo(p.packageName, p.userId))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyIdmapManager extends IdmapManager {
|
||||
private final DummyDeviceState mState;
|
||||
private Set<String> mIdmapFiles = new ArraySet<>();
|
||||
|
||||
private DummyIdmapManager(DummyDeviceState state,
|
||||
DummyPackageManagerHelper packageManagerHelper) {
|
||||
super(packageManagerHelper);
|
||||
mState = state;
|
||||
}
|
||||
|
||||
@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) {
|
||||
return false;
|
||||
}
|
||||
final DummyDeviceState.Package o = mState.select(overlayPackage.packageName, userId);
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
final String key = createKey(overlayPackage.packageName, userId);
|
||||
mIdmapFiles.add(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) {
|
||||
final String key = createKey(oi.packageName, oi.userId);
|
||||
if (!mIdmapFiles.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyListener implements OverlayManagerServiceImpl.OverlayChangeListener {
|
||||
public int count;
|
||||
|
||||
public void onOverlaysChanged(@NonNull String targetPackage, int userId) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ public class OverlayManagerSettingsTests {
|
||||
STATE_DISABLED,
|
||||
0,
|
||||
0,
|
||||
false);
|
||||
true);
|
||||
|
||||
private static final OverlayInfo OVERLAY_B0 = new OverlayInfo(
|
||||
"com.dummy.overlay_b",
|
||||
@@ -69,7 +69,7 @@ public class OverlayManagerSettingsTests {
|
||||
STATE_DISABLED,
|
||||
0,
|
||||
0,
|
||||
false);
|
||||
true);
|
||||
|
||||
private static final OverlayInfo OVERLAY_C0 = new OverlayInfo(
|
||||
"com.dummy.overlay_c",
|
||||
@@ -80,7 +80,7 @@ public class OverlayManagerSettingsTests {
|
||||
STATE_DISABLED,
|
||||
0,
|
||||
0,
|
||||
false);
|
||||
true);
|
||||
|
||||
private static final OverlayInfo OVERLAY_A1 = new OverlayInfo(
|
||||
"com.dummy.overlay_a",
|
||||
@@ -91,7 +91,7 @@ public class OverlayManagerSettingsTests {
|
||||
STATE_DISABLED,
|
||||
1,
|
||||
0,
|
||||
false);
|
||||
true);
|
||||
|
||||
private static final OverlayInfo OVERLAY_B1 = new OverlayInfo(
|
||||
"com.dummy.overlay_b",
|
||||
@@ -102,7 +102,7 @@ public class OverlayManagerSettingsTests {
|
||||
STATE_DISABLED,
|
||||
1,
|
||||
0,
|
||||
false);
|
||||
true);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -238,7 +238,7 @@ public class OverlayManagerSettingsTests {
|
||||
STATE_DISABLED,
|
||||
0,
|
||||
0,
|
||||
false);
|
||||
true);
|
||||
insert(otherTarget);
|
||||
changed = mSettings.setPriority(OVERLAY_A0.packageName, otherTarget.packageName,
|
||||
OVERLAY_A0.userId);
|
||||
@@ -435,7 +435,7 @@ public class OverlayManagerSettingsTests {
|
||||
|
||||
private void insert(OverlayInfo oi) throws Exception {
|
||||
mSettings.init(oi.packageName, oi.userId, oi.targetPackageName, null, oi.baseCodePath,
|
||||
false, 0, oi.category);
|
||||
true, false,0, oi.category);
|
||||
mSettings.setState(oi.packageName, oi.userId, oi.state);
|
||||
mSettings.setEnabled(oi.packageName, oi.userId, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user