From 0d043b0d4944422ed0167594094122faefdddfd4 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Fri, 13 Nov 2020 14:50:01 +0800 Subject: [PATCH] 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 --- .../rollback/RollbackManagerServiceImpl.java | 27 ++++++++----- .../server/rollback/RollbackStore.java | 39 ++++++++++++++++--- .../server/rollback/RollbackStoreTest.java | 24 ++++++++++-- 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index b34d46ff1a0ce..873f60d220fb8 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -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); + } } diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index 2ee87e67e467a..83976cc4076d6 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -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 loadRollbacks() { + private static List loadRollbacks(File rollbackDataDir) { List 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 loadRollbacks() { + return loadRollbacks(mRollbackDataDir); + } + + List loadHistorialRollbacks() { + return loadRollbacks(mRollbackHistoryDir); + } + /** * Converts a {@code JSONArray} of integers to a {@code List}. */ @@ -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. */ diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java index eedc9781aa400..96bfc98aaefc6 100644 --- a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java @@ -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 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());