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

Commit daa11006 authored by JW Wang's avatar JW Wang
Browse files

Give original session id to non-staged rollbacks (1/n)

* Reduce differences between staged and non-staged rollbacks
* Remove the possible conflicts between Rollback#mStagedSessionId and
  RollbackInfo#mIsStaged
* Now both staged and non-staged rollbacks can be searched using
  the original session ids.
* This is in preparation for unifying the flow of enabling rollback
  for both staged and non-staged rollbacks.

Bug: 183466803
Test: atest RollbackUnitTest RollbackStoreTest AppDataRollbackHelperTest
Test: atest RollbackTest CtsRollbackManagerTestCases
Test: atest MultiUserRollbackTest CtsRollbackManagerHostTestCases StagedRollbackTest

Change-Id: I54b737074c8b94780b54a0a552834f0a77f9c1a8
parent d42dbfc3
Loading
Loading
Loading
Loading
+15 −22
Original line number Diff line number Diff line
@@ -116,10 +116,10 @@ class Rollback {
    static final int ROLLBACK_STATE_DELETED = 4;

    /**
     * The session ID for the staged session if this rollback data represents a staged session,
     * {@code -1} otherwise.
     * The session ID associate with this rollback. This is the parent session ID in the case of
     * a multi-package session.
     */
    private final int mStagedSessionId;
    private final int mOriginalSessionId;

    /**
     * The rollback info for this rollback.
@@ -203,24 +203,25 @@ class Rollback {
     *
     * @param rollbackId the id of the rollback.
     * @param backupDir the directory where the rollback data is stored.
     * @param stagedSessionId the session id if this is a staged rollback, -1 otherwise.
     * @param originalSessionId the session id associated with this rollback.
     * @param isStaged true if this is a staged rollback.
     * @param userId the user that performed the install with rollback enabled.
     * @param installerPackageName the installer package name from the original install session.
     * @param packageSessionIds the session ids for all packages in the install.
     * @param extensionVersions the extension versions supported at the time of rollback creation
     */
    Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId,
    Rollback(int rollbackId, File backupDir, int originalSessionId, boolean isStaged, int userId,
            String installerPackageName, int[] packageSessionIds,
            SparseIntArray extensionVersions) {
        this.info = new RollbackInfo(rollbackId,
                /* packages */ new ArrayList<>(),
                /* isStaged */ stagedSessionId != -1,
                /* isStaged */ isStaged,
                /* causePackages */ new ArrayList<>(),
                /* committedSessionId */ -1);
        mUserId = userId;
        mInstallerPackageName = installerPackageName;
        mBackupDir = backupDir;
        mStagedSessionId = stagedSessionId;
        mOriginalSessionId = originalSessionId;
        mState = ROLLBACK_STATE_ENABLING;
        mTimestamp = Instant.now();
        mPackageSessionIds = packageSessionIds != null ? packageSessionIds : new int[0];
@@ -228,16 +229,10 @@ class Rollback {
        mHandler = Looper.myLooper() != null ? new Handler(Looper.myLooper()) : null;
    }

    Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId,
             String installerPackageName) {
        this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null,
                new SparseIntArray(0));
    }

    /**
     * Constructs a pre-populated Rollback instance.
     */
    Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
    Rollback(RollbackInfo info, File backupDir, Instant timestamp, int originalSessionId,
            @RollbackState int state, String stateDescription, boolean restoreUserDataInProgress,
            int userId, String installerPackageName, SparseIntArray extensionVersions) {
        this.info = info;
@@ -245,7 +240,7 @@ class Rollback {
        mInstallerPackageName = installerPackageName;
        mBackupDir = backupDir;
        mTimestamp = timestamp;
        mStagedSessionId = stagedSessionId;
        mOriginalSessionId = originalSessionId;
        mState = state;
        mStateDescription = stateDescription;
        mRestoreUserDataInProgress = restoreUserDataInProgress;
@@ -298,12 +293,11 @@ class Rollback {
    }

    /**
     * Returns the session ID for the staged session if this rollback data represents a staged
     * session, or {@code -1} otherwise.
     * Returns the session ID associated with this rollback, or {@code -1} if unknown.
     */
    @AnyThread
    int getStagedSessionId() {
        return mStagedSessionId;
    int getOriginalSessionId() {
        return mOriginalSessionId;
    }

    /**
@@ -954,9 +948,8 @@ class Rollback {
        ipw.println("-state: " + getStateAsString());
        ipw.println("-stateDescription: " + mStateDescription);
        ipw.println("-timestamp: " + getTimestamp());
        if (getStagedSessionId() != -1) {
            ipw.println("-stagedSessionId: " + getStagedSessionId());
        }
        ipw.println("-isStaged: " + isStaged());
        ipw.println("-originalSessionId: " + getOriginalSessionId());
        ipw.println("-packages:");
        ipw.increaseIndent();
        for (PackageRollbackInfo pkg : info.getPackages()) {
+4 −4
Original line number Diff line number Diff line
@@ -611,11 +611,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
                }

                PackageInstaller.SessionInfo session = mContext.getPackageManager()
                        .getPackageInstaller().getSessionInfo(rollback.getStagedSessionId());
                        .getPackageInstaller().getSessionInfo(rollback.getOriginalSessionId());
                if (session == null || session.isStagedSessionFailed()) {
                    if (rollback.isEnabling()) {
                        iter.remove();
                        deleteRollback(rollback, "Session " + rollback.getStagedSessionId()
                        deleteRollback(rollback, "Session " + rollback.getOriginalSessionId()
                                + " not existed or failed");
                    }
                    continue;
@@ -1307,7 +1307,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
            rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId,
                    installerPackageName, packageSessionIds, getExtensionVersions());
        } else {
            rollback = mRollbackStore.createNonStagedRollback(rollbackId, userId,
            rollback = mRollbackStore.createNonStagedRollback(rollbackId, parentSessionId, userId,
                    installerPackageName, packageSessionIds, getExtensionVersions());
        }

@@ -1339,7 +1339,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
        // We expect mRollbacks to be a very small list; linear search should be plenty fast.
        for (int i = 0; i < mRollbacks.size(); ++i) {
            Rollback rollback = mRollbacks.get(i);
            if (rollback.getStagedSessionId() == sessionId
            if (rollback.getOriginalSessionId() == sessionId
                    || rollback.containsSessionId(sessionId)) {
                return rollback;
            }
+12 −9
Original line number Diff line number Diff line
@@ -209,23 +209,24 @@ class RollbackStore {
     * Creates a new Rollback instance for a non-staged rollback with
     * backupDir assigned.
     */
    Rollback createNonStagedRollback(int rollbackId, int userId, String installerPackageName,
            int[] packageSessionIds, SparseIntArray extensionVersions) {
    Rollback createNonStagedRollback(int rollbackId, int originalSessionId, int userId,
            String installerPackageName, int[] packageSessionIds,
            SparseIntArray extensionVersions) {
        File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
        return new Rollback(rollbackId, backupDir, -1, userId, installerPackageName,
                packageSessionIds, extensionVersions);
        return new Rollback(rollbackId, backupDir, originalSessionId, /* isStaged */ false, userId,
                installerPackageName, packageSessionIds, extensionVersions);
    }

    /**
     * Creates a new Rollback instance for a staged rollback with
     * backupDir assigned.
     */
    Rollback createStagedRollback(int rollbackId, int stagedSessionId, int userId,
    Rollback createStagedRollback(int rollbackId, int originalSessionId, int userId,
            String installerPackageName, int[] packageSessionIds,
            SparseIntArray extensionVersions) {
        File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
        return new Rollback(rollbackId, backupDir, stagedSessionId, userId, installerPackageName,
                packageSessionIds, extensionVersions);
        return new Rollback(rollbackId, backupDir, originalSessionId, /* isStaged */ true, userId,
                installerPackageName, packageSessionIds, extensionVersions);
    }

    private static boolean isLinkPossible(File oldFile, File newFile) {
@@ -312,7 +313,7 @@ class RollbackStore {
            JSONObject dataJson = new JSONObject();
            dataJson.put("info", rollbackInfoToJson(rollback.info));
            dataJson.put("timestamp", rollback.getTimestamp().toString());
            dataJson.put("stagedSessionId", rollback.getStagedSessionId());
            dataJson.put("originalSessionId", rollback.getOriginalSessionId());
            dataJson.put("state", rollback.getStateAsString());
            dataJson.put("stateDescription", rollback.getStateDescription());
            dataJson.put("restoreUserDataInProgress", rollback.isRestoreUserDataInProgress());
@@ -380,7 +381,9 @@ class RollbackStore {
                rollbackInfoFromJson(dataJson.getJSONObject("info")),
                backupDir,
                Instant.parse(dataJson.getString("timestamp")),
                dataJson.getInt("stagedSessionId"),
                // Backward compatibility: Historical rollbacks are not erased upon OTA update.
                //  Need to load the old field 'stagedSessionId' as fallback.
                dataJson.optInt("originalSessionId", dataJson.optInt("stagedSessionId", -1)),
                rollbackStateFromString(dataJson.getString("state")),
                dataJson.optString("stateDescription"),
                dataJson.getBoolean("restoreUserDataInProgress"),
+4 −2
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static org.mockito.MockitoAnnotations.initMocks;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.util.SparseIntArray;

import com.android.server.pm.ApexManager;
import com.android.server.pm.Installer;
@@ -119,8 +120,9 @@ public class AppDataRollbackHelperTest {
    }

    private static Rollback createRollbackForId(int rollbackId) {
        return new Rollback(rollbackId, new File("/does/not/exist"), -1,
                0, "com.xyz");
        return new Rollback(rollbackId, new File("/does/not/exist"), -1, /* isStaged */ false, 0,
                "com.xyz", null, new SparseIntArray(0));

    }

    @Test
+11 −10
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ public class RollbackStoreTest {
            + "'ceSnapshotInodes':[]}],'isStaged':false,'causePackages':[{'packageName':'hello',"
            + "'longVersionCode':23},{'packageName':'something','longVersionCode':999}],"
            + "'committedSessionId':45654465},'timestamp':'2019-10-01T12:29:08.855Z',"
            + "'stagedSessionId':-1,'state':'enabling','apkSessionId':-1,"
            + "'originalSessionId':567,'state':'enabling','apkSessionId':-1,"
            + "'restoreUserDataInProgress':true, 'userId':0,"
            + "'installerPackageName':'some.installer'}";

@@ -102,7 +102,7 @@ public class RollbackStoreTest {
            + "'ceSnapshotInodes':[]}],'isStaged':false,'causePackages':[{'packageName':'hello',"
            + "'longVersionCode':23},{'packageName':'something','longVersionCode':999}],"
            + "'committedSessionId':45654465},'timestamp':'2019-10-01T12:29:08.855Z',"
            + "'stagedSessionId':-1,'state':'enabling','apkSessionId':-1,"
            + "'originalSessionId':567,'state':'enabling','apkSessionId':-1,"
            + "'restoreUserDataInProgress':true, 'userId':0,"
            + "'installerPackageName':'some.installer',"
            + "'extensionVersions':[{'sdkVersion':5,'extensionVersion':25},"
@@ -129,12 +129,13 @@ public class RollbackStoreTest {
        SparseIntArray extensionVersions = new SparseIntArray();
        extensionVersions.put(30, 71);
        Rollback rollback = mRollbackStore.createNonStagedRollback(
                ID, USER, INSTALLER, null, extensionVersions);
                ID, 567, USER, INSTALLER, null, extensionVersions);

        assertThat(rollback.getBackupDir().getAbsolutePath())
                .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID);

        assertThat(rollback.isStaged()).isFalse();
        assertThat(rollback.getOriginalSessionId()).isEqualTo(567);
        assertThat(rollback.info.getRollbackId()).isEqualTo(ID);
        assertThat(rollback.info.getPackages()).isEmpty();
        assertThat(rollback.isEnabling()).isTrue();
@@ -153,7 +154,7 @@ public class RollbackStoreTest {
                .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID);

        assertThat(rollback.isStaged()).isTrue();
        assertThat(rollback.getStagedSessionId()).isEqualTo(897);
        assertThat(rollback.getOriginalSessionId()).isEqualTo(897);

        assertThat(rollback.info.getRollbackId()).isEqualTo(ID);
        assertThat(rollback.info.getPackages()).isEmpty();
@@ -168,7 +169,7 @@ public class RollbackStoreTest {
        extensionVersions.put(5, 25);
        extensionVersions.put(30, 71);
        Rollback origRb = mRollbackStore.createNonStagedRollback(
                ID, USER, INSTALLER, null, extensionVersions);
                ID, 567, USER, INSTALLER, null, extensionVersions);

        origRb.setRestoreUserDataInProgress(true);
        origRb.info.getCausePackages().add(new VersionedPackage("com.made.up", 2));
@@ -218,7 +219,7 @@ public class RollbackStoreTest {
    @Test
    public void loadFromJsonNoExtensionVersions() throws Exception {
        Rollback expectedRb = mRollbackStore.createNonStagedRollback(
                ID, USER, INSTALLER, null, new SparseIntArray(0));
                ID, 567, USER, INSTALLER, null, new SparseIntArray(0));

        expectedRb.setTimestamp(Instant.parse("2019-10-01T12:29:08.855Z"));
        expectedRb.setRestoreUserDataInProgress(true);
@@ -268,7 +269,7 @@ public class RollbackStoreTest {
        extensionVersions.put(5, 25);
        extensionVersions.put(30, 71);
        Rollback expectedRb = mRollbackStore.createNonStagedRollback(
                ID, USER, INSTALLER, null, extensionVersions);
                ID, 567, USER, INSTALLER, null, extensionVersions);

        expectedRb.setTimestamp(Instant.parse("2019-10-01T12:29:08.855Z"));
        expectedRb.setRestoreUserDataInProgress(true);
@@ -315,7 +316,7 @@ public class RollbackStoreTest {
    @Test
    public void saveAndDelete() {
        Rollback rollback = mRollbackStore.createNonStagedRollback(
                ID, USER, INSTALLER, null, new SparseIntArray(0));
                ID, 567, USER, INSTALLER, null, new SparseIntArray(0));

        RollbackStore.saveRollback(rollback);

@@ -331,7 +332,7 @@ public class RollbackStoreTest {
    @Test
    public void saveToHistoryAndLoad() {
        Rollback origRb = mRollbackStore.createNonStagedRollback(
                ID, USER, INSTALLER, null, new SparseIntArray(0));
                ID, 567, USER, INSTALLER, null, new SparseIntArray(0));
        mRollbackStore.saveRollbackToHistory(origRb);

        List<Rollback> loadedRollbacks = mRollbackStore.loadHistorialRollbacks();
@@ -364,7 +365,7 @@ public class RollbackStoreTest {
        assertThat(b.getApexPackageNames())
                .containsExactlyElementsIn(a.getApexPackageNames());

        assertThat(b.getStagedSessionId()).isEqualTo(a.getStagedSessionId());
        assertThat(b.getOriginalSessionId()).isEqualTo(a.getOriginalSessionId());

        assertThat(b.info.getCommittedSessionId()).isEqualTo(a.info.getCommittedSessionId());

Loading