OMS: rebase settings when overlays update
When an overlay package has been upgraded, OMS needs to reconcile any previous settings about the overlay with the new state of affairs. Sometimes it is possible to rebase the OMS settings on the new information [e.g. the overlay has changed categories]; sometimes the OMS settings have to be scrapped [e.g. the overlay has changed target package]. Update OMS to do The Right Thing. Bug: 78809704 Test: manual (adb shell stop, adb push specially prepared overlays, adb shell start, adb exec-out cmd overlay dump) Change-Id: Icd1ae633dbee5b5ca957fa6b652af6209b4b1260
This commit is contained in:
committed by
Todd Kennedy
parent
3542482875
commit
2f1944bf0e
@@ -18,7 +18,6 @@ package android.content.om;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
@@ -125,6 +124,23 @@ 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.
|
||||
*
|
||||
* @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
|
||||
* exposed to 3rd party.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final boolean isStatic;
|
||||
|
||||
/**
|
||||
* Create a new OverlayInfo based on source with an updated state.
|
||||
*
|
||||
@@ -133,17 +149,20 @@ public final class OverlayInfo implements Parcelable {
|
||||
*/
|
||||
public OverlayInfo(@NonNull OverlayInfo source, @State int state) {
|
||||
this(source.packageName, source.targetPackageName, source.category, source.baseCodePath,
|
||||
state, source.userId);
|
||||
state, source.userId, source.priority, source.isStatic);
|
||||
}
|
||||
|
||||
public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
|
||||
@Nullable String category, @NonNull String baseCodePath, int state, int userId) {
|
||||
@NonNull String category, @NonNull String baseCodePath, int state, int userId,
|
||||
int priority, boolean isStatic) {
|
||||
this.packageName = packageName;
|
||||
this.targetPackageName = targetPackageName;
|
||||
this.category = category;
|
||||
this.baseCodePath = baseCodePath;
|
||||
this.state = state;
|
||||
this.userId = userId;
|
||||
this.priority = priority;
|
||||
this.isStatic = isStatic;
|
||||
ensureValidState();
|
||||
}
|
||||
|
||||
@@ -154,6 +173,8 @@ public final class OverlayInfo implements Parcelable {
|
||||
baseCodePath = source.readString();
|
||||
state = source.readInt();
|
||||
userId = source.readInt();
|
||||
priority = source.readInt();
|
||||
isStatic = source.readBoolean();
|
||||
ensureValidState();
|
||||
}
|
||||
|
||||
@@ -194,6 +215,8 @@ public final class OverlayInfo implements Parcelable {
|
||||
dest.writeString(baseCodePath);
|
||||
dest.writeInt(state);
|
||||
dest.writeInt(userId);
|
||||
dest.writeInt(priority);
|
||||
dest.writeBoolean(isStatic);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<OverlayInfo> CREATOR =
|
||||
|
||||
@@ -63,6 +63,38 @@ final class OverlayManagerServiceImpl {
|
||||
private final String[] mDefaultOverlays;
|
||||
private final OverlayChangeListener mListener;
|
||||
|
||||
/**
|
||||
* Helper method to merge the overlay manager's (as read from overlays.xml)
|
||||
* and package manager's (as parsed from AndroidManifest.xml files) views
|
||||
* on overlays.
|
||||
*
|
||||
* Both managers are usually in agreement, but especially after an OTA things
|
||||
* may differ. The package manager is always providing the truth; the overlay
|
||||
* manager has to adapt. Depending on what has changed about an overlay, we
|
||||
* 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,
|
||||
@Nullable final OverlayInfo oldSettings) {
|
||||
if (oldSettings == null) {
|
||||
return true;
|
||||
}
|
||||
if (!Objects.equals(theTruth.overlayTarget, oldSettings.targetPackageName)) {
|
||||
return true;
|
||||
}
|
||||
if (theTruth.isStaticOverlayPackage() != oldSettings.isStatic) {
|
||||
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) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager,
|
||||
@NonNull final IdmapManager idmapManager,
|
||||
@NonNull final OverlayManagerSettings settings,
|
||||
@@ -99,42 +131,29 @@ final class OverlayManagerServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
// Reset overlays if something critical like the target package name
|
||||
// has changed
|
||||
List<PackageInfo> overlayPackages = mPackageManager.getOverlayPackages(newUserId);
|
||||
final int overlayPackagesSize = overlayPackages.size();
|
||||
for (int i = 0; i < overlayPackagesSize; i++) {
|
||||
final PackageInfo overlayPackage = overlayPackages.get(i);
|
||||
final OverlayInfo oi = storedOverlayInfos.get(overlayPackage.packageName);
|
||||
if (oi == null || !oi.targetPackageName.equals(overlayPackage.overlayTarget)) {
|
||||
// Reset the overlay if it didn't exist or had the wrong target package.
|
||||
|
||||
if (mustReinitializeOverlay(overlayPackage, oi)) {
|
||||
// if targetPackageName has changed the package that *used* to
|
||||
// be the target must also update its assets
|
||||
if (oi != null) {
|
||||
packagesToUpdateAssets.add(oi.targetPackageName);
|
||||
}
|
||||
|
||||
mSettings.init(overlayPackage.packageName, newUserId,
|
||||
overlayPackage.overlayTarget,
|
||||
overlayPackage.applicationInfo.getBaseCodePath(),
|
||||
overlayPackage.isStaticOverlayPackage(),
|
||||
overlayPackage.overlayPriority,
|
||||
overlayPackage.overlayCategory);
|
||||
|
||||
if (oi != null) {
|
||||
// The targetPackageName we have stored doesn't match the overlay's target.
|
||||
// Queue the old target for an update as well.
|
||||
packagesToUpdateAssets.add(oi.targetPackageName);
|
||||
}
|
||||
} else {
|
||||
// Update all other components of an overlay that don't require a hard reset.
|
||||
if (!Objects.equals(oi.category, overlayPackage.overlayCategory)) {
|
||||
// When changing categories, it is ok just to update our internal state.
|
||||
mSettings.setCategory(overlayPackage.packageName, newUserId,
|
||||
overlayPackage.overlayCategory);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
updateState(overlayPackage.overlayTarget, overlayPackage.packageName, newUserId, 0);
|
||||
} catch (OverlayManagerSettings.BadKeyException e) {
|
||||
Slog.e(TAG, "failed to update settings", e);
|
||||
mSettings.remove(overlayPackage.packageName, newUserId);
|
||||
}
|
||||
|
||||
packagesToUpdateAssets.add(overlayPackage.overlayTarget);
|
||||
storedOverlayInfos.remove(overlayPackage.packageName);
|
||||
}
|
||||
|
||||
@@ -148,6 +167,22 @@ final class OverlayManagerServiceImpl {
|
||||
packagesToUpdateAssets.add(oi.targetPackageName);
|
||||
}
|
||||
|
||||
// make sure every overlay's state is up-to-date; this needs to happen
|
||||
// after old overlays have been removed, or we risk removing a
|
||||
// legitimate idmap file if a new overlay package has the same apk path
|
||||
// as the removed overlay package used to have
|
||||
for (int i = 0; i < overlayPackagesSize; i++) {
|
||||
final PackageInfo overlayPackage = overlayPackages.get(i);
|
||||
try {
|
||||
updateState(overlayPackage.overlayTarget, overlayPackage.packageName,
|
||||
newUserId, 0);
|
||||
} catch (OverlayManagerSettings.BadKeyException e) {
|
||||
Slog.e(TAG, "failed to update settings", e);
|
||||
mSettings.remove(overlayPackage.packageName, newUserId);
|
||||
}
|
||||
packagesToUpdateAssets.add(overlayPackage.overlayTarget);
|
||||
}
|
||||
|
||||
// remove target packages that are not installed
|
||||
final Iterator<String> iter = packagesToUpdateAssets.iterator();
|
||||
while (iter.hasNext()) {
|
||||
@@ -351,15 +386,13 @@ final class OverlayManagerServiceImpl {
|
||||
|
||||
try {
|
||||
final OverlayInfo oldOi = mSettings.getOverlayInfo(packageName, userId);
|
||||
if (!oldOi.targetPackageName.equals(pkg.overlayTarget)) {
|
||||
if (mustReinitializeOverlay(pkg, oldOi)) {
|
||||
if (oldOi != null && !oldOi.targetPackageName.equals(pkg.overlayTarget)) {
|
||||
mListener.onOverlaysChanged(pkg.overlayTarget, userId);
|
||||
}
|
||||
mSettings.init(packageName, userId, pkg.overlayTarget,
|
||||
pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
|
||||
pkg.overlayPriority, pkg.overlayCategory);
|
||||
} else {
|
||||
if (!Objects.equals(oldOi.category, pkg.overlayCategory)) {
|
||||
// Update the category in-place.
|
||||
mSettings.setCategory(packageName, userId, pkg.overlayCategory);
|
||||
}
|
||||
}
|
||||
|
||||
if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
|
||||
@@ -604,6 +637,8 @@ final class OverlayManagerServiceImpl {
|
||||
if (overlayPackage != null) {
|
||||
modified |= mSettings.setBaseCodePath(overlayPackageName, userId,
|
||||
overlayPackage.applicationInfo.getBaseCodePath());
|
||||
modified |= mSettings.setCategory(overlayPackageName, userId,
|
||||
overlayPackage.overlayCategory);
|
||||
}
|
||||
|
||||
final @OverlayInfo.State int currentState = mSettings.getState(overlayPackageName, userId);
|
||||
|
||||
@@ -528,7 +528,7 @@ final class OverlayManagerSettings {
|
||||
private OverlayInfo getOverlayInfo() {
|
||||
if (mCache == null) {
|
||||
mCache = new OverlayInfo(mPackageName, mTargetPackageName, mCategory, mBaseCodePath,
|
||||
mState, mUserId);
|
||||
mState, mUserId, mPriority, mIsStatic);
|
||||
}
|
||||
return mCache;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user