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

Commit 0d043b0d authored by JW Wang's avatar JW Wang
Browse files

Save deleted rollbacks for debugging purpose (2/n)

The rollbacks will be saved to /data/rollback-history before deletion.

Bug: 172644981
Test: atest RollbackStoreTest
Change-Id: I608316d2260ce8970d0f625eb8ba286d33d730c9
parent 85e86853
Loading
Loading
Loading
Loading
+18 −9
Original line number Diff line number Diff line
@@ -179,7 +179,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
        mInstaller = new Installer(mContext);
        mInstaller.onStart();

        mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
        mRollbackStore = new RollbackStore(
                new File(Environment.getDataDirectory(), "rollback"),
                new File(Environment.getDataDirectory(), "rollback-history"));

        mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
        mAppDataRollbackHelper = new AppDataRollbackHelper(mInstaller);
@@ -201,7 +203,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
            } else {
                // Delete rollbacks when build fingerprint has changed.
                for (Rollback rollback : mRollbacks) {
                    rollback.delete(mAppDataRollbackHelper);
                    deleteRollback(rollback);
                }
                mRollbacks.clear();
            }
@@ -271,7 +273,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
                    Rollback rollback = getRollbackForSession(sessionId);
                    if (rollback != null && rollback.isEnabling()) {
                        mRollbacks.remove(rollback);
                        rollback.delete(mAppDataRollbackHelper);
                        deleteRollback(rollback);
                    }
                }
            }
@@ -484,7 +486,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
            Rollback rollback = iter.next();
            if (rollback.includesPackage(packageName)) {
                iter.remove();
                rollback.delete(mAppDataRollbackHelper);
                deleteRollback(rollback);
            }
        }
    }
@@ -612,7 +614,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
                        .getPackageInstaller().getSessionInfo(rollback.getStagedSessionId());
                if (session == null || session.isStagedSessionFailed()) {
                    iter.remove();
                    rollback.delete(mAppDataRollbackHelper);
                    deleteRollback(rollback);
                    continue;
                }

@@ -666,7 +668,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
                    && rollback.includesPackageWithDifferentVersion(packageName,
                    installedVersion)) {
                iter.remove();
                rollback.delete(mAppDataRollbackHelper);
                deleteRollback(rollback);
            }
        }
    }
@@ -720,7 +722,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
            if (!now.isBefore(rollbackTimestamp.plusMillis(mRollbackLifetimeDurationInMillis))) {
                Slog.i(TAG, "runExpiration id=" + rollback.info.getRollbackId());
                iter.remove();
                rollback.delete(mAppDataRollbackHelper);
                deleteRollback(rollback);
            } else if (oldest == null || oldest.isAfter(rollbackTimestamp)) {
                oldest = rollbackTimestamp;
            }
@@ -1132,7 +1134,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
                    Slog.w(TAG, "Delete rollback id=" + rollback.info.getRollbackId()
                            + " for failed session id=" + sessionId);
                    mRollbacks.remove(rollback);
                    rollback.delete(mAppDataRollbackHelper);
                    deleteRollback(rollback);
                }
            }
        }
@@ -1159,7 +1161,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
        if (!rollback.allPackagesEnabled()) {
            Slog.e(TAG, "Failed to enable rollback for all packages in session.");
            mRollbacks.remove(rollback);
            rollback.delete(mAppDataRollbackHelper);
            deleteRollback(rollback);
            return false;
        }

@@ -1329,4 +1331,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
        }
        return null;
    }

    @WorkerThread
    private void deleteRollback(Rollback rollback) {
        assertInWorkerThread();
        mRollbackStore.saveRollbackToHistory(rollback);
        rollback.delete(mAppDataRollbackHelper);
    }
}
+33 −6
Original line number Diff line number Diff line
@@ -69,18 +69,20 @@ class RollbackStore {
    // * XXX, YYY are the rollbackIds for the corresponding rollbacks.
    // * rollback.json contains all relevant metadata for the rollback.
    private final File mRollbackDataDir;
    private final File mRollbackHistoryDir;

    RollbackStore(File rollbackDataDir) {
    RollbackStore(File rollbackDataDir, File rollbackHistoryDir) {
        mRollbackDataDir = rollbackDataDir;
        mRollbackHistoryDir = rollbackHistoryDir;
    }

    /**
     * Reads the rollbacks from persistent storage.
     */
    List<Rollback> loadRollbacks() {
    private static List<Rollback> loadRollbacks(File rollbackDataDir) {
        List<Rollback> rollbacks = new ArrayList<>();
        mRollbackDataDir.mkdirs();
        for (File rollbackDir : mRollbackDataDir.listFiles()) {
        rollbackDataDir.mkdirs();
        for (File rollbackDir : rollbackDataDir.listFiles()) {
            if (rollbackDir.isDirectory()) {
                try {
                    rollbacks.add(loadRollback(rollbackDir));
@@ -93,6 +95,14 @@ class RollbackStore {
        return rollbacks;
    }

    List<Rollback> loadRollbacks() {
        return loadRollbacks(mRollbackDataDir);
    }

    List<Rollback> loadHistorialRollbacks() {
        return loadRollbacks(mRollbackHistoryDir);
    }

    /**
     * Converts a {@code JSONArray} of integers to a {@code List<Integer>}.
     */
@@ -258,10 +268,11 @@ class RollbackStore {
    /**
     * Saves the given rollback to persistent storage.
     */
    static void saveRollback(Rollback rollback) {
    private static void saveRollback(Rollback rollback, File backDir) {
        FileOutputStream fos = null;
        AtomicFile file = new AtomicFile(new File(rollback.getBackupDir(), "rollback.json"));
        AtomicFile file = new AtomicFile(new File(backDir, "rollback.json"));
        try {
            backDir.mkdirs();
            JSONObject dataJson = new JSONObject();
            dataJson.put("info", rollbackInfoToJson(rollback.info));
            dataJson.put("timestamp", rollback.getTimestamp().toString());
@@ -286,6 +297,22 @@ class RollbackStore {
        }
    }

    static void saveRollback(Rollback rollback) {
        saveRollback(rollback, rollback.getBackupDir());
    }

    /**
     * Saves the rollback to mRollbackHistoryDir/ROLLBACKID-HEX for debugging purpose.
     */
    void saveRollbackToHistory(Rollback rollback) {
        // The same id might be allocated to different historical rollbacks.
        // Let's add a suffix to avoid naming collision.
        String suffix = Long.toHexString(rollback.getTimestamp().getEpochSecond());
        String dirName = Integer.toString(rollback.info.getRollbackId());
        File backupDir = new File(mRollbackHistoryDir, dirName + "-" + suffix);
        saveRollback(rollback, backupDir);
    }

    /**
     * Removes all persistent storage associated with the given rollback.
     */
+21 −3
Original line number Diff line number Diff line
@@ -110,6 +110,8 @@ public class RollbackStoreTest {

    @Rule
    public TemporaryFolder mFolder = new TemporaryFolder();
    @Rule
    public TemporaryFolder mHistoryDir = new TemporaryFolder();

    private File mRollbackDir;

@@ -117,7 +119,7 @@ public class RollbackStoreTest {

    @Before
    public void setUp() throws Exception {
        mRollbackStore = new RollbackStore(mFolder.getRoot());
        mRollbackStore = new RollbackStore(mFolder.getRoot(), mHistoryDir.getRoot());
        mRollbackDir = mFolder.newFolder(ID + "");
        mFolder.newFile("rollback.json");
    }
@@ -324,10 +326,26 @@ public class RollbackStoreTest {
        assertThat(expectedFile.exists()).isFalse();
    }

    private void assertRollbacksAreEquivalent(Rollback b, Rollback a) {
        assertThat(b.info.getRollbackId()).isEqualTo(ID);
    @Test
    public void saveToHistoryAndLoad() {
        Rollback origRb = mRollbackStore.createNonStagedRollback(
                ID, USER, INSTALLER, null, new SparseIntArray(0));
        mRollbackStore.saveRollbackToHistory(origRb);

        List<Rollback> loadedRollbacks = mRollbackStore.loadHistorialRollbacks();
        assertThat(loadedRollbacks).hasSize(1);
        Rollback loadedRb = loadedRollbacks.get(0);

        assertRollbacksAreEquivalentExcludingBackupDir(loadedRb, origRb);
    }

    private void assertRollbacksAreEquivalent(Rollback b, Rollback a) {
        assertThat(b.getBackupDir()).isEqualTo(a.getBackupDir());
        assertRollbacksAreEquivalentExcludingBackupDir(b, a);
    }

    private void assertRollbacksAreEquivalentExcludingBackupDir(Rollback b, Rollback a) {
        assertThat(b.info.getRollbackId()).isEqualTo(ID);

        assertThat(b.isRestoreUserDataInProgress())
                .isEqualTo(a.isRestoreUserDataInProgress());