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

Commit a2fbe126 authored by Mohammad Samiul Islam's avatar Mohammad Samiul Islam Committed by Android (Google) Code Review
Browse files

Merge changes from topic "rollback-of-apk-in-apex"

* changes:
  Check if number of packages enabled for rollback is equal to number of sessions
  Rollback user data of apks-in-apex while rolling back the apex
parents 7135c036 3ffedc45
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -76,6 +76,11 @@ public final class PackageRollbackInfo implements Parcelable {
     */
    private final boolean mIsApex;

    /**
     * Whether this instance represents the PackageRollbackInfo for an APK in APEX.
     */
    private final boolean mIsApkInApex;

    /*
     * The list of users for which snapshots have been saved.
     */
@@ -157,6 +162,10 @@ public final class PackageRollbackInfo implements Parcelable {
    public @PackageManager.RollbackDataPolicy int getRollbackDataPolicy() {
        return mRollbackDataPolicy;
    }
    /** @hide */
    public boolean isApkInApex() {
        return mIsApkInApex;
    }

    /** @hide */
    public IntArray getSnapshottedUsers() {
@@ -190,17 +199,18 @@ public final class PackageRollbackInfo implements Parcelable {
    public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
            VersionedPackage packageRolledBackTo,
            @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
            boolean isApex, @NonNull IntArray snapshottedUsers,
            boolean isApex, boolean isApkInApex, @NonNull IntArray snapshottedUsers,
            @NonNull SparseLongArray ceSnapshotInodes) {
        this(packageRolledBackFrom, packageRolledBackTo, pendingBackups, pendingRestores, isApex,
                snapshottedUsers, ceSnapshotInodes, PackageManager.RollbackDataPolicy.RESTORE);
                isApkInApex, snapshottedUsers, ceSnapshotInodes,
                PackageManager.RollbackDataPolicy.RESTORE);
    }

    /** @hide */
    public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
            VersionedPackage packageRolledBackTo,
            @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
            boolean isApex, @NonNull IntArray snapshottedUsers,
            boolean isApex, boolean isApkInApex, @NonNull IntArray snapshottedUsers,
            @NonNull SparseLongArray ceSnapshotInodes,
            @PackageManager.RollbackDataPolicy int rollbackDataPolicy) {
        this.mVersionRolledBackFrom = packageRolledBackFrom;
@@ -209,6 +219,7 @@ public final class PackageRollbackInfo implements Parcelable {
        this.mPendingRestores = pendingRestores;
        this.mIsApex = isApex;
        this.mRollbackDataPolicy = rollbackDataPolicy;
        this.mIsApkInApex = isApkInApex;
        this.mSnapshottedUsers = snapshottedUsers;
        this.mCeSnapshotInodes = ceSnapshotInodes;
    }
@@ -217,6 +228,7 @@ public final class PackageRollbackInfo implements Parcelable {
        this.mVersionRolledBackFrom = VersionedPackage.CREATOR.createFromParcel(in);
        this.mVersionRolledBackTo = VersionedPackage.CREATOR.createFromParcel(in);
        this.mIsApex = in.readBoolean();
        this.mIsApkInApex = in.readBoolean();
        this.mPendingRestores = null;
        this.mPendingBackups = null;
        this.mSnapshottedUsers = null;
@@ -234,6 +246,7 @@ public final class PackageRollbackInfo implements Parcelable {
        mVersionRolledBackFrom.writeToParcel(out, flags);
        mVersionRolledBackTo.writeToParcel(out, flags);
        out.writeBoolean(mIsApex);
        out.writeBoolean(mIsApkInApex);
    }

    public static final @NonNull Parcelable.Creator<PackageRollbackInfo> CREATOR =
+6 −0
Original line number Diff line number Diff line
@@ -810,6 +810,12 @@ public abstract class PackageManagerInternal {
     */
    public abstract boolean isApexPackage(String packageName);

    /**
     * Returns list of {@code packageName} of apks inside the given apex.
     * @param apexPackageName Package name of the apk container of apex
     */
    public abstract List<String> getApksInApex(String apexPackageName);

    /**
     * Uninstalls given {@code packageName}.
     *
+122 −23
Original line number Diff line number Diff line
@@ -32,10 +32,13 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.parsing.AndroidPackage;
import android.os.Environment;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.sysprop.ApexProperties;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Singleton;
import android.util.Slog;

@@ -44,15 +47,20 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;

import com.google.android.collect.Lists;

import java.io.File;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
@@ -97,12 +105,27 @@ abstract class ApexManager {
     * Minimal information about APEX mount points and the original APEX package they refer to.
     */
    static class ActiveApexInfo {
        @Nullable public final String apexModuleName;
        public final File apexDirectory;
        public final File preinstalledApexPath;
        public final File preInstalledApexPath;

        private ActiveApexInfo(File apexDirectory, File preInstalledApexPath) {
            this(null, apexDirectory, preInstalledApexPath);
        }

        private ActiveApexInfo(File apexDirectory, File preinstalledApexPath) {
        private ActiveApexInfo(@Nullable String apexModuleName, File apexDirectory,
                File preInstalledApexPath) {
            this.apexModuleName = apexModuleName;
            this.apexDirectory = apexDirectory;
            this.preinstalledApexPath = preinstalledApexPath;
            this.preInstalledApexPath = preInstalledApexPath;
        }

        private ActiveApexInfo(ApexInfo apexInfo) {
            this(
                    apexInfo.moduleName,
                    new File(Environment.getApexDirectory() + File.separator
                            + apexInfo.moduleName),
                    new File(apexInfo.preinstalledModulePath));
        }
    }

@@ -231,6 +254,17 @@ abstract class ApexManager {
     */
    abstract boolean uninstallApex(String apexPackagePath);

    /**
     * Registers an APK package as an embedded apk of apex.
     */
    abstract void registerApkInApex(AndroidPackage pkg);

    /**
     * Returns list of {@code packageName} of apks inside the given apex.
     * @param apexPackageName Package name of the apk container of apex
     */
    abstract List<String> getApksInApex(String apexPackageName);

    /**
     * Dumps various state information to the provided {@link PrintWriter} object.
     *
@@ -255,16 +289,33 @@ abstract class ApexManager {
    static class ApexManagerImpl extends ApexManager {
        private final IApexService mApexService;
        private final Object mLock = new Object();

        @GuardedBy("mLock")
        private Set<ActiveApexInfo> mActiveApexInfosCache;

        /**
         * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
         * AndroidManifest.xml}
         *
         * <p>Note that key of this map is {@code packageName} field of the corresponding {@code
         * AndroidManifest.xml}.
         * Contains the list of {@code packageName}s of apks-in-apex for given
         * {@code apexModuleName}. See {@link #mPackageNameToApexModuleName} to understand the
         * difference between {@code packageName} and {@code apexModuleName}.
         */
        @GuardedBy("mLock")
        private Map<String, List<String>> mApksInApex = new ArrayMap<>();

        @GuardedBy("mLock")
        private List<PackageInfo> mAllPackagesCache;

        /**
         * An APEX is a file format that delivers the apex-payload wrapped in an apk container. The
         * apk container has a reference name, called {@code packageName}, which is found inside the
         * {@code AndroidManifest.xml}. The apex payload inside the container also has a reference
         * name, called {@code apexModuleName}, which is found in {@code apex_manifest.json} file.
         *
         * {@link #mPackageNameToApexModuleName} contains the mapping from {@code packageName} of
         * the apk container to {@code apexModuleName} of the apex-payload inside.
         */
        @GuardedBy("mLock")
        private Map<String, String> mPackageNameToApexModuleName;

        ApexManagerImpl(IApexService apexService) {
            mApexService = apexService;
        }
@@ -291,19 +342,26 @@ abstract class ApexManager {

        @Override
        List<ActiveApexInfo> getActiveApexInfos() {
            synchronized (mLock) {
                if (mActiveApexInfosCache == null) {
                    try {
                return Arrays.stream(mApexService.getActivePackages())
                        .map(apexInfo -> new ActiveApexInfo(
                                new File(
                                Environment.getApexDirectory() + File.separator
                                        + apexInfo.moduleName),
                                new File(apexInfo.preinstalledModulePath))).collect(
                                Collectors.toList());
                        mActiveApexInfosCache = new ArraySet<>();
                        final ApexInfo[] activePackages = mApexService.getActivePackages();
                        for (int i = 0; i < activePackages.length; i++) {
                            ApexInfo apexInfo = activePackages[i];
                            mActiveApexInfosCache.add(new ActiveApexInfo(apexInfo));
                        }
                    } catch (RemoteException e) {
                        Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
                    }
                }
                if (mActiveApexInfosCache != null) {
                    return new ArrayList<>(mActiveApexInfosCache);
                } else {
                    return Collections.emptyList();
                }
            }
        }

        @Override
        void systemReady(Context context) {
@@ -325,6 +383,7 @@ abstract class ApexManager {
                }
                try {
                    mAllPackagesCache = new ArrayList<>();
                    mPackageNameToApexModuleName = new HashMap<>();
                    HashSet<String> activePackagesSet = new HashSet<>();
                    HashSet<String> factoryPackagesSet = new HashSet<>();
                    final ApexInfo[] allPkgs = mApexService.getAllPackages();
@@ -350,6 +409,7 @@ abstract class ApexManager {
                        final PackageInfo packageInfo =
                                PackageParser.generatePackageInfo(pkg, ai, flags);
                        mAllPackagesCache.add(packageInfo);
                        mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName);
                        if (ai.isActive) {
                            if (activePackagesSet.contains(packageInfo.packageName)) {
                                throw new IllegalStateException(
@@ -366,7 +426,6 @@ abstract class ApexManager {
                            }
                            factoryPackagesSet.add(packageInfo.packageName);
                        }

                    }
                } catch (RemoteException re) {
                    Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
@@ -533,6 +592,37 @@ abstract class ApexManager {
            }
        }

        @Override
        void registerApkInApex(AndroidPackage pkg) {
            synchronized (mLock) {
                final Iterator<ActiveApexInfo> it = mActiveApexInfosCache.iterator();
                while (it.hasNext()) {
                    final ActiveApexInfo aai = it.next();
                    if (pkg.getBaseCodePath().startsWith(aai.apexDirectory.getAbsolutePath())) {
                        List<String> apks = mApksInApex.get(aai.apexModuleName);
                        if (apks == null) {
                            apks = Lists.newArrayList();
                            mApksInApex.put(aai.apexModuleName, apks);
                        }
                        apks.add(pkg.getPackageName());
                    }
                }
            }
        }

        @Override
        List<String> getApksInApex(String apexPackageName) {
            // TODO(b/142712057): Avoid calling populateAllPackagesCacheIfNeeded during boot.
            populateAllPackagesCacheIfNeeded();
            synchronized (mLock) {
                String moduleName = mPackageNameToApexModuleName.get(apexPackageName);
                if (moduleName == null) {
                    return Collections.emptyList();
                }
                return mApksInApex.getOrDefault(moduleName, Collections.emptyList());
            }
        }

        /**
         * Dump information about the packages contained in a particular cache
         * @param packagesCache the cache to print information about.
@@ -614,7 +704,6 @@ abstract class ApexManager {
     * updating APEX packages.
     */
    private static final class ApexManagerFlattenedApex extends ApexManager {

        @Override
        List<ActiveApexInfo> getActiveApexInfos() {
            // There is no apexd running in case of flattened apex
@@ -720,6 +809,16 @@ abstract class ApexManager {
            throw new UnsupportedOperationException();
        }

        @Override
        void registerApkInApex(AndroidPackage pkg) {
            // No-op
        }

        @Override
        List<String> getApksInApex(String apexPackageName) {
            return Collections.emptyList();
        }

        @Override
        void dump(PrintWriter pw, String packageName) {
            // No-op
+3 −4
Original line number Diff line number Diff line
@@ -188,7 +188,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
        }
    };

    public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) {
    public PackageInstallerService(Context context, PackageManagerService pm) {
        mContext = context;
        mPm = pm;
        mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class);
@@ -206,9 +206,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
        mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
        mSessionsDir.mkdirs();

        mApexManager = am;

        mStagingManager = new StagingManager(this, am, context);
        mApexManager = ApexManager.getInstance();
        mStagingManager = new StagingManager(this, context);
    }

    boolean okToSendBroadcasts()  {
+16 −4
Original line number Diff line number Diff line
@@ -492,6 +492,7 @@ public class PackageManagerService extends IPackageManager.Stub
    static final int SCAN_AS_PRODUCT = 1 << 20;
    static final int SCAN_AS_SYSTEM_EXT = 1 << 21;
    static final int SCAN_AS_ODM = 1 << 22;
    static final int SCAN_AS_APK_IN_APEX = 1 << 23;
    @IntDef(flag = true, prefix = { "SCAN_" }, value = {
            SCAN_NO_DEX,
@@ -2589,6 +2590,9 @@ public class PackageManagerService extends IPackageManager.Stub
                    & (SCAN_AS_VENDOR | SCAN_AS_ODM | SCAN_AS_PRODUCT | SCAN_AS_SYSTEM_EXT)) != 0) {
                return true;
            }
            if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
                return true;
            }
            return false;
        }
@@ -3332,7 +3336,7 @@ public class PackageManagerService extends IPackageManager.Stub
                }
            }
            mInstallerService = new PackageInstallerService(mContext, this, mApexManager);
            mInstallerService = new PackageInstallerService(mContext, this);
            final Pair<ComponentName, String> instantAppResolverComponent =
                    getInstantAppResolverLPr();
            if (instantAppResolverComponent != null) {
@@ -11713,6 +11717,9 @@ public class PackageManagerService extends IPackageManager.Stub
            mSettings.insertPackageSettingLPw(pkgSetting, pkg);
            // Add the new setting to mPackages
            mPackages.put(pkg.getAppInfoPackageName(), pkg);
            if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
                mApexManager.registerApkInApex(pkg);
            }
            // Add the package's KeySets to the global KeySetManagerService
            KeySetManagerService ksms = mSettings.mKeySetManagerService;
@@ -17760,10 +17767,10 @@ public class PackageManagerService extends IPackageManager.Stub
            ApexManager.ActiveApexInfo apexInfo) {
        for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
            SystemPartition sp = SYSTEM_PARTITIONS.get(i);
            if (apexInfo.preinstalledApexPath.getAbsolutePath().startsWith(
            if (apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
                    sp.folder.getAbsolutePath())) {
                return new SystemPartition(apexInfo.apexDirectory, sp.scanFlag,
                        false /* hasOverlays */);
                return new SystemPartition(apexInfo.apexDirectory,
                        sp.scanFlag | SCAN_AS_APK_IN_APEX, false /* hasOverlays */);
            }
        }
        return null;
@@ -23453,6 +23460,11 @@ public class PackageManagerService extends IPackageManager.Stub
            return PackageManagerService.this.mApexManager.isApexPackage(packageName);
        }
        @Override
        public List<String> getApksInApex(String apexPackageName) {
            return PackageManagerService.this.mApexManager.getApksInApex(apexPackageName);
        }
        @Override
        public void uninstallApex(String packageName, long versionCode, int userId,
                IntentSender intentSender, int flags) {
Loading