From 2f1944bf0e225b0fd96d57cfbca40fb717e4f475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= Date: Tue, 10 Apr 2018 17:44:42 +0200 Subject: [PATCH 1/2] 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 --- core/java/android/content/om/OverlayInfo.java | 29 +++++- .../server/om/OverlayManagerServiceImpl.java | 93 +++++++++++++------ .../server/om/OverlayManagerSettings.java | 2 +- 3 files changed, 91 insertions(+), 33 deletions(-) diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java index 6e63342698b34..579cd6a24849a 100644 --- a/core/java/android/content/om/OverlayInfo.java +++ b/core/java/android/content/om/OverlayInfo.java @@ -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 CREATOR = diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index bb36ab1897656..f001a059e0abe 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -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 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 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); diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java index e176351fcb765..b011278c9c030 100644 --- a/services/core/java/com/android/server/om/OverlayManagerSettings.java +++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java @@ -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; } From a525e2239a95c79d62e27b18fc5e4f13789ab352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= Date: Tue, 10 Apr 2018 16:57:33 +0200 Subject: [PATCH 2/2] OMS: teach the OMS about static RROs Teach the OMS about static RROs (those with ) and add a new OVERLAY_ENABLED_STATIC state to OverlayInfo. This makes isStatic less of an edge case and something that can be reasoned about together with the other states. Bug: 78809704 Test: atest OverlayHostTests OverlayDeviceTests Change-Id: Ia785554ed2bcf7679888c3ccdaeaedca1430a477 --- core/java/android/content/om/OverlayInfo.java | 16 +++++++++++++++- .../server/om/OverlayManagerServiceImpl.java | 5 +++++ .../server/om/OverlayManagerSettings.java | 1 + .../server/om/OverlayManagerShellCommand.java | 1 + 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java index 579cd6a24849a..3ae6ffb7d995c 100644 --- a/core/java/android/content/om/OverlayInfo.java +++ b/core/java/android/content/om/OverlayInfo.java @@ -38,6 +38,7 @@ public final class OverlayInfo implements Parcelable { STATE_NO_IDMAP, STATE_DISABLED, STATE_ENABLED, + STATE_ENABLED_STATIC, STATE_TARGET_UPGRADING, STATE_OVERLAY_UPGRADING, }) @@ -90,7 +91,16 @@ public final class OverlayInfo implements Parcelable { public static final int STATE_OVERLAY_UPGRADING = 5; /** - * Category for theme overlays. + * The overlay package is currently enabled because it is marked as + * 'static'. It cannot be disabled but will change state if for instance + * its target is uninstalled. + */ + public static final int STATE_ENABLED_STATIC = 6; + + /** + * Overlay category: theme. + *

+ * Change how Android (including the status bar, dialogs, ...) looks. */ public static final String CATEGORY_THEME = "android.theme"; @@ -194,6 +204,7 @@ public final class OverlayInfo implements Parcelable { case STATE_NO_IDMAP: case STATE_DISABLED: case STATE_ENABLED: + case STATE_ENABLED_STATIC: case STATE_TARGET_UPGRADING: case STATE_OVERLAY_UPGRADING: break; @@ -243,6 +254,7 @@ public final class OverlayInfo implements Parcelable { public boolean isEnabled() { switch (state) { case STATE_ENABLED: + case STATE_ENABLED_STATIC: return true; default: return false; @@ -267,6 +279,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_TARGET_UPGRADING: return "STATE_TARGET_UPGRADING"; case STATE_OVERLAY_UPGRADING: diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index f001a059e0abe..a3aa52718965a 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -18,6 +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_MISSING_TARGET; import static android.content.om.OverlayInfo.STATE_NO_IDMAP; import static android.content.om.OverlayInfo.STATE_OVERLAY_UPGRADING; @@ -681,6 +682,10 @@ 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; } diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java index b011278c9c030..36bf83dfe92ca 100644 --- a/services/core/java/com/android/server/om/OverlayManagerSettings.java +++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java @@ -309,6 +309,7 @@ final class OverlayManagerSettings { pw.print("mState.............: "); pw.println(OverlayInfo.stateToString(item.getState())); pw.print("mIsEnabled.........: "); pw.println(item.isEnabled()); pw.print("mIsStatic..........: "); pw.println(item.isStatic()); + pw.print("mPriority..........: "); pw.println(item.mPriority); pw.print("mCategory..........: "); pw.println(item.mCategory); pw.decreaseIndent(); diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java index 54bb115c54052..d576d330c4a83 100644 --- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java +++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java @@ -126,6 +126,7 @@ final class OverlayManagerShellCommand extends ShellCommand { final OverlayInfo oi = overlaysForTarget.get(i); String status; switch (oi.state) { + case OverlayInfo.STATE_ENABLED_STATIC: case OverlayInfo.STATE_ENABLED: status = "[x]"; break;