Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2f1944bf authored by Mårten Kongstad's avatar Mårten Kongstad Committed by Todd Kennedy
Browse files

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
parent 35424828
Loading
Loading
Loading
Loading
+26 −3
Original line number Original line Diff line number Diff line
@@ -18,7 +18,6 @@ package android.content.om;


import android.annotation.IntDef;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;


@@ -125,6 +124,23 @@ public final class OverlayInfo implements Parcelable {
     */
     */
    public final int userId;
    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.
     * 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) {
    public OverlayInfo(@NonNull OverlayInfo source, @State int state) {
        this(source.packageName, source.targetPackageName, source.category, source.baseCodePath,
        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,
    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.packageName = packageName;
        this.targetPackageName = targetPackageName;
        this.targetPackageName = targetPackageName;
        this.category = category;
        this.category = category;
        this.baseCodePath = baseCodePath;
        this.baseCodePath = baseCodePath;
        this.state = state;
        this.state = state;
        this.userId = userId;
        this.userId = userId;
        this.priority = priority;
        this.isStatic = isStatic;
        ensureValidState();
        ensureValidState();
    }
    }


@@ -154,6 +173,8 @@ public final class OverlayInfo implements Parcelable {
        baseCodePath = source.readString();
        baseCodePath = source.readString();
        state = source.readInt();
        state = source.readInt();
        userId = source.readInt();
        userId = source.readInt();
        priority = source.readInt();
        isStatic = source.readBoolean();
        ensureValidState();
        ensureValidState();
    }
    }


@@ -194,6 +215,8 @@ public final class OverlayInfo implements Parcelable {
        dest.writeString(baseCodePath);
        dest.writeString(baseCodePath);
        dest.writeInt(state);
        dest.writeInt(state);
        dest.writeInt(userId);
        dest.writeInt(userId);
        dest.writeInt(priority);
        dest.writeBoolean(isStatic);
    }
    }


    public static final Parcelable.Creator<OverlayInfo> CREATOR =
    public static final Parcelable.Creator<OverlayInfo> CREATOR =
+64 −29
Original line number Original line Diff line number Diff line
@@ -63,6 +63,38 @@ final class OverlayManagerServiceImpl {
    private final String[] mDefaultOverlays;
    private final String[] mDefaultOverlays;
    private final OverlayChangeListener mListener;
    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,
    OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager,
            @NonNull final IdmapManager idmapManager,
            @NonNull final IdmapManager idmapManager,
            @NonNull final OverlayManagerSettings settings,
            @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);
        List<PackageInfo> overlayPackages = mPackageManager.getOverlayPackages(newUserId);
        final int overlayPackagesSize = overlayPackages.size();
        final int overlayPackagesSize = overlayPackages.size();
        for (int i = 0; i < overlayPackagesSize; i++) {
        for (int i = 0; i < overlayPackagesSize; i++) {
            final PackageInfo overlayPackage = overlayPackages.get(i);
            final PackageInfo overlayPackage = overlayPackages.get(i);
            final OverlayInfo oi = storedOverlayInfos.get(overlayPackage.packageName);
            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,
                mSettings.init(overlayPackage.packageName, newUserId,
                        overlayPackage.overlayTarget,
                        overlayPackage.overlayTarget,
                        overlayPackage.applicationInfo.getBaseCodePath(),
                        overlayPackage.applicationInfo.getBaseCodePath(),
                        overlayPackage.isStaticOverlayPackage(),
                        overlayPackage.isStaticOverlayPackage(),
                        overlayPackage.overlayPriority,
                        overlayPackage.overlayPriority,
                        overlayPackage.overlayCategory);
                        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);
            storedOverlayInfos.remove(overlayPackage.packageName);
        }
        }


@@ -148,6 +167,22 @@ final class OverlayManagerServiceImpl {
            packagesToUpdateAssets.add(oi.targetPackageName);
            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
        // remove target packages that are not installed
        final Iterator<String> iter = packagesToUpdateAssets.iterator();
        final Iterator<String> iter = packagesToUpdateAssets.iterator();
        while (iter.hasNext()) {
        while (iter.hasNext()) {
@@ -351,15 +386,13 @@ final class OverlayManagerServiceImpl {


        try {
        try {
            final OverlayInfo oldOi = mSettings.getOverlayInfo(packageName, userId);
            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,
                mSettings.init(packageName, userId, pkg.overlayTarget,
                        pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
                        pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
                        pkg.overlayPriority, pkg.overlayCategory);
                        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)) {
            if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
@@ -604,6 +637,8 @@ final class OverlayManagerServiceImpl {
        if (overlayPackage != null) {
        if (overlayPackage != null) {
            modified |= mSettings.setBaseCodePath(overlayPackageName, userId,
            modified |= mSettings.setBaseCodePath(overlayPackageName, userId,
                    overlayPackage.applicationInfo.getBaseCodePath());
                    overlayPackage.applicationInfo.getBaseCodePath());
            modified |= mSettings.setCategory(overlayPackageName, userId,
                    overlayPackage.overlayCategory);
        }
        }


        final @OverlayInfo.State int currentState = mSettings.getState(overlayPackageName, userId);
        final @OverlayInfo.State int currentState = mSettings.getState(overlayPackageName, userId);
+1 −1
Original line number Original line Diff line number Diff line
@@ -528,7 +528,7 @@ final class OverlayManagerSettings {
        private OverlayInfo getOverlayInfo() {
        private OverlayInfo getOverlayInfo() {
            if (mCache == null) {
            if (mCache == null) {
                mCache = new OverlayInfo(mPackageName, mTargetPackageName, mCategory, mBaseCodePath,
                mCache = new OverlayInfo(mPackageName, mTargetPackageName, mCategory, mBaseCodePath,
                        mState, mUserId);
                        mState, mUserId, mPriority, mIsStatic);
            }
            }
            return mCache;
            return mCache;
        }
        }