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

Commit 0a79b323 authored by Richard Uhler's avatar Richard Uhler
Browse files

Include all relevant packages in RollbackInfo.

Instead of a single target package. Needed for rollback of multiPackage
installs.

Additionally, expose this information by a public method rather than a
public field.

Bug: 112431924
Test: atest RollbackTest
Change-Id: I6e3ce87385abd37c48047db27bc443d3719ee023
parent 3da55268
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1695,10 +1695,10 @@ package android.content.rollback {
  public final class RollbackInfo implements android.os.Parcelable {
    method public int describeContents();
    method public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
    method public int getRollbackId();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
    field public final android.content.rollback.PackageRollbackInfo targetPackage;
  }
  public final class RollbackManager {
+14 −10
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;

import java.util.List;

/**
 * Information about a set of packages that can be, or already have been
 * rolled back together.
@@ -34,25 +36,20 @@ public final class RollbackInfo implements Parcelable {
     */
    private final int mRollbackId;

    /**
     * The package that needs to be rolled back.
     */
    public final PackageRollbackInfo targetPackage;
    private final List<PackageRollbackInfo> mPackages;

    // TODO: Add a list of additional packages rolled back due to atomic
    // install dependencies when rollback of atomic installs is supported.
    // TODO: Add a flag to indicate if reboot is required, when rollback of
    // staged installs is supported.

    /** @hide */
    public RollbackInfo(int rollbackId, PackageRollbackInfo targetPackage) {
    public RollbackInfo(int rollbackId, List<PackageRollbackInfo> packages) {
        this.mRollbackId = rollbackId;
        this.targetPackage = targetPackage;
        this.mPackages = packages;
    }

    private RollbackInfo(Parcel in) {
        mRollbackId = in.readInt();
        targetPackage = PackageRollbackInfo.CREATOR.createFromParcel(in);
        mPackages = in.createTypedArrayList(PackageRollbackInfo.CREATOR);
    }

    /**
@@ -62,6 +59,13 @@ public final class RollbackInfo implements Parcelable {
        return mRollbackId;
    }

    /**
     * Returns the list of package that are rolled back.
     */
    public List<PackageRollbackInfo> getPackages() {
        return mPackages;
    }

    @Override
    public int describeContents() {
        return 0;
@@ -70,7 +74,7 @@ public final class RollbackInfo implements Parcelable {
    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(mRollbackId);
        targetPackage.writeToParcel(out, flags);
        out.writeTypedList(mPackages);
    }

    public static final Parcelable.Creator<RollbackInfo> CREATOR =
+35 −21
Original line number Diff line number Diff line
@@ -219,7 +219,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
            if (info.getPackageName().equals(packageName)) {
                // TODO: Once the RollbackInfo API supports info about
                // dependant packages, add that info here.
                return new RollbackInfo(data.rollbackId, info);
                return new RollbackInfo(data.rollbackId, data.packages);
            }
        }
        return null;
@@ -279,18 +279,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
     */
    private void executeRollbackInternal(RollbackInfo rollback,
            String callerPackageName, IntentSender statusReceiver) {
        String targetPackageName = rollback.targetPackage.getPackageName();
        Log.i(TAG, "Initiating rollback of " + targetPackageName);
        Log.i(TAG, "Initiating rollback");

        // Get the latest RollbackData for the target package.
        final RollbackData data = getRollbackForPackage(targetPackageName);
        RollbackData data = getRollbackForId(rollback.getRollbackId());
        if (data == null) {
            sendFailure(statusReceiver, "No rollback available for package.");
            return;
        }

        if (data.rollbackId != rollback.getRollbackId()) {
            sendFailure(statusReceiver, "Rollback for package is out of date.");
            sendFailure(statusReceiver, "Rollback unavailable");
            return;
        }

@@ -335,14 +328,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
        PackageManager pm = context.getPackageManager();
        try {
            PackageInstaller packageInstaller = pm.getPackageInstaller();
            String installerPackageName = pm.getInstallerPackageName(targetPackageName);
            if (installerPackageName == null) {
                sendFailure(statusReceiver, "Cannot find installer package");
                return;
            }
            PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams(
                    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
            parentParams.setInstallerPackageName(installerPackageName);
            parentParams.setAllowDowngrade(true);
            parentParams.setMultiPackage();
            int parentSessionId = packageInstaller.createSession(parentParams);
@@ -351,6 +338,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
            for (PackageRollbackInfo info : data.packages) {
                PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                        PackageInstaller.SessionParams.MODE_FULL_INSTALL);
                String installerPackageName = pm.getInstallerPackageName(info.getPackageName());
                if (installerPackageName == null) {
                    sendFailure(statusReceiver, "Cannot find installer package");
                    return;
                }
                params.setInstallerPackageName(installerPackageName);
                params.setAllowDowngrade(true);
                int sessionId = packageInstaller.createSession(params);
@@ -406,7 +398,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
            data.inProgress = true;
            parentSession.commit(receiver.getIntentSender());
        } catch (IOException e) {
            Log.e(TAG, "Unable to roll back " + targetPackageName, e);
            Log.e(TAG, "Rollback failed", e);
            sendFailure(statusReceiver, "IOException: " + e.toString());
            return;
        }
@@ -537,9 +529,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
            boolean changed = false;
            while (iter.hasNext()) {
                RollbackInfo rollback = iter.next();
                if (packageName.equals(rollback.targetPackage.getPackageName())) {
                for (PackageRollbackInfo info : rollback.getPackages()) {
                    if (packageName.equals(info.getPackageName())) {
                        iter.remove();
                        changed = true;
                        break;
                    }
                }
            }

@@ -935,6 +930,25 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
        return null;
    }

    /*
     * Returns the RollbackData, if any, for an available rollback with the
     * given rollbackId.
     */
    private RollbackData getRollbackForId(int rollbackId) {
        synchronized (mLock) {
            // TODO: Have ensureRollbackDataLoadedLocked return the list of
            // available rollbacks, to hopefully avoid forgetting to call it?
            ensureRollbackDataLoadedLocked();
            for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
                RollbackData data = mAvailableRollbacks.get(i);
                if (data.rollbackId == rollbackId) {
                    return data;
                }
            }
        }
        return null;
    }

    @GuardedBy("mLock")
    private int allocateRollbackIdLocked() throws IOException {
        int n = 0;
+40 −35
Original line number Diff line number Diff line
@@ -114,13 +114,9 @@ class RollbackStore {
                for (int i = 0; i < array.length(); ++i) {
                    JSONObject element = array.getJSONObject(i);
                    int rollbackId = element.getInt("rollbackId");
                    String packageName = element.getString("packageName");
                    long higherVersionCode = element.getLong("higherVersionCode");
                    long lowerVersionCode = element.getLong("lowerVersionCode");
                    PackageRollbackInfo target = new PackageRollbackInfo(
                            new VersionedPackage(packageName, higherVersionCode),
                            new VersionedPackage(packageName, lowerVersionCode));
                    RollbackInfo rollback = new RollbackInfo(rollbackId, target);
                    List<PackageRollbackInfo> packages = packageRollbackInfosFromJson(
                            element.getJSONArray("packages"));
                    RollbackInfo rollback = new RollbackInfo(rollbackId, packages);
                    recentlyExecutedRollbacks.add(rollback);
                }
            } catch (IOException | JSONException e) {
@@ -155,18 +151,8 @@ class RollbackStore {
    void saveAvailableRollback(RollbackData data) throws IOException {
        try {
            JSONObject dataJson = new JSONObject();
            JSONArray packagesJson = new JSONArray();
            for (PackageRollbackInfo info : data.packages) {
                JSONObject infoJson = new JSONObject();
                infoJson.put("packageName", info.getPackageName());
                infoJson.put("higherVersionCode",
                        info.getVersionRolledBackFrom().getLongVersionCode());
                infoJson.put("lowerVersionCode",
                        info.getVersionRolledBackTo().getVersionCode());
                packagesJson.put(infoJson);
            }
            dataJson.put("rollbackId", data.rollbackId);
            dataJson.put("packages", packagesJson);
            dataJson.put("packages", toJson(data.packages));
            dataJson.put("timestamp", data.timestamp.toString());

            PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json"));
@@ -200,11 +186,7 @@ class RollbackStore {
                RollbackInfo rollback = recentlyExecutedRollbacks.get(i);
                JSONObject element = new JSONObject();
                element.put("rollbackId", rollback.getRollbackId());
                element.put("packageName", rollback.targetPackage.getPackageName());
                element.put("higherVersionCode",
                        rollback.targetPackage.getVersionRolledBackFrom().getLongVersionCode());
                element.put("lowerVersionCode",
                        rollback.targetPackage.getVersionRolledBackTo().getLongVersionCode());
                element.put("packages", toJson(rollback.getPackages()));
                array.put(element);
            }

@@ -229,18 +211,7 @@ class RollbackStore {

            int rollbackId = dataJson.getInt("rollbackId");
            RollbackData data = new RollbackData(rollbackId, backupDir);

            JSONArray packagesJson = dataJson.getJSONArray("packages");
            for (int i = 0; i < packagesJson.length(); ++i) {
                JSONObject infoJson = packagesJson.getJSONObject(i);
                String packageName = infoJson.getString("packageName");
                long higherVersionCode = infoJson.getLong("higherVersionCode");
                long lowerVersionCode = infoJson.getLong("lowerVersionCode");
                data.packages.add(new PackageRollbackInfo(
                        new VersionedPackage(packageName, higherVersionCode),
                        new VersionedPackage(packageName, lowerVersionCode)));
            }

            data.packages.addAll(packageRollbackInfosFromJson(dataJson.getJSONArray("packages")));
            data.timestamp = Instant.parse(dataJson.getString("timestamp"));
            return data;
        } catch (JSONException | DateTimeParseException e) {
@@ -248,6 +219,40 @@ class RollbackStore {
        }
    }

    private JSONObject toJson(PackageRollbackInfo info) throws JSONException {
        JSONObject json = new JSONObject();
        json.put("packageName", info.getPackageName());
        json.put("higherVersionCode", info.getVersionRolledBackFrom().getLongVersionCode());
        json.put("lowerVersionCode", info.getVersionRolledBackTo().getLongVersionCode());
        return json;
    }

    private PackageRollbackInfo packageRollbackInfoFromJson(JSONObject json) throws JSONException {
        String packageName = json.getString("packageName");
        long higherVersionCode = json.getLong("higherVersionCode");
        long lowerVersionCode = json.getLong("lowerVersionCode");
        return new PackageRollbackInfo(
                new VersionedPackage(packageName, higherVersionCode),
                new VersionedPackage(packageName, lowerVersionCode));
    }

    private JSONArray toJson(List<PackageRollbackInfo> infos) throws JSONException {
        JSONArray json = new JSONArray();
        for (PackageRollbackInfo info : infos) {
            json.put(toJson(info));
        }
        return json;
    }

    private List<PackageRollbackInfo> packageRollbackInfosFromJson(JSONArray json)
            throws JSONException {
        List<PackageRollbackInfo> infos = new ArrayList<>();
        for (int i = 0; i < json.length(); ++i) {
            infos.add(packageRollbackInfoFromJson(json.getJSONObject(i)));
        }
        return infos;
    }

    /**
     * Deletes a file completely.
     * If the file is a directory, its contents are deleted as well.
+86 −73

File changed.

Preview size limit exceeded, changes collapsed.