summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Tate <ctate@android.com>2009-07-15 16:45:50 -0700
committerChristopher Tate <ctate@android.com>2009-07-15 16:50:24 -0700
commite97e807a468bf64ad614fca77d350b016f3ce4a9 (patch)
treef9d71e526edd99f1e601f5cb786891f70079714a
parentf3ea3e09684c82016e13140d68019b968c793190 (diff)
downloadframeworks_base-e97e807a468bf64ad614fca77d350b016f3ce4a9.zip
frameworks_base-e97e807a468bf64ad614fca77d350b016f3ce4a9.tar.gz
frameworks_base-e97e807a468bf64ad614fca77d350b016f3ce4a9.tar.bz2
The rest of ever-backed-up tracking
When a package is uninstalled we now remove our notion of its having been backed up, thereby forcing a backup pass if it is reinstalled at some point in the future. Removal from the log means rewriting it and doing an atomic rename to the canonical version. The temporary existence used during the rewrite is *not* written synchronously; there's no need and it keeps the load on the flash part much lower. Because we might crash & reboot in the middle of the rewrite operation, there's now code during init that sanity-checks the contents of the ever-backed-up log and ensures that it's in a coherent state.
-rw-r--r--services/java/com/android/server/BackupManagerService.java76
1 files changed, 71 insertions, 5 deletions
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 6eba783..c493a12 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -285,27 +285,55 @@ class BackupManagerService extends IBackupManager.Stub {
private void initPackageTracking() {
if (DEBUG) Log.v(TAG, "Initializing package tracking");
- // Keep a log of what apps we've ever backed up
+ // Keep a log of what apps we've ever backed up. Because we might have
+ // rebooted in the middle of an operation that was removing something from
+ // this log, we sanity-check its contents here and reconstruct it.
mEverStored = new File(mBaseStateDir, "processed");
+ File tempProcessedFile = new File(mBaseStateDir, "processed.new");
try {
- mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
+ RandomAccessFile temp = new RandomAccessFile(tempProcessedFile, "rw");
+ mEverStoredStream = new RandomAccessFile(mEverStored, "r");
// parse its existing contents
mEverStoredStream.seek(0);
+ temp.seek(0);
try {
while (true) {
+ PackageInfo info;
String pkg = mEverStoredStream.readUTF();
- mEverStoredApps.add(pkg);
- if (DEBUG) Log.v(TAG, " + " + pkg);
+ try {
+ info = mPackageManager.getPackageInfo(pkg, 0);
+ mEverStoredApps.add(pkg);
+ temp.writeUTF(pkg);
+ if (DEBUG) Log.v(TAG, " + " + pkg);
+ } catch (NameNotFoundException e) {
+ // nope, this package was uninstalled; don't include it
+ if (DEBUG) Log.v(TAG, " - " + pkg);
+ }
}
} catch (EOFException e) {
// now we're at EOF
}
+
+ // Once we've rewritten the backup history log, atomically replace the
+ // old one with the new one then reopen the file for continuing use.
+ temp.close();
+ mEverStoredStream.close();
+ tempProcessedFile.renameTo(mEverStored);
+ mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
} catch (IOException e) {
Log.e(TAG, "Unable to open known-stored file!");
mEverStoredStream = null;
}
+ // If we were in the middle of removing something from the ever-backed-up
+ // file, there might be a transient "processed.new" file still present.
+ // We've reconstructed a coherent state at this point though, so we can
+ // safely discard that file now.
+ if (tempProcessedFile.exists()) {
+ tempProcessedFile.delete();
+ }
+
// Register for broadcasts about package install, etc., so we can
// update the provider list.
IntentFilter filter = new IntentFilter();
@@ -573,6 +601,7 @@ class BackupManagerService extends IBackupManager.Stub {
for (ApplicationInfo entry: set) {
if (entry.packageName.equals(pkg.packageName)) {
set.remove(entry);
+ removeEverBackedUp(pkg.packageName);
break;
}
}
@@ -618,7 +647,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Called from the backup thread: record that the given app has been successfully
// backed up at least once
void logBackupComplete(String packageName) {
- if (mEverStoredStream != null) {
+ if (mEverStoredStream != null && !packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
synchronized (mEverStoredApps) {
if (mEverStoredApps.add(packageName)) {
try {
@@ -637,6 +666,43 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ // Remove our awareness of having ever backed up the given package
+ void removeEverBackedUp(String packageName) {
+ if (DEBUG) Log.v(TAG, "Removing backed-up knowledge of " + packageName
+ + ", new set:");
+
+ if (mEverStoredStream != null) {
+ synchronized (mEverStoredApps) {
+ // Rewrite the file and rename to overwrite. If we reboot in the middle,
+ // we'll recognize on initialization time that the package no longer
+ // exists and fix it up then.
+ File tempKnownFile = new File(mBaseStateDir, "processed.new");
+ try {
+ mEverStoredStream.close();
+ RandomAccessFile known = new RandomAccessFile(tempKnownFile, "rw");
+ mEverStoredApps.remove(packageName);
+ for (String s : mEverStoredApps) {
+ known.writeUTF(s);
+ if (DEBUG) Log.v(TAG, " " + s);
+ }
+ known.close();
+ tempKnownFile.renameTo(mEverStored);
+ mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
+ } catch (IOException e) {
+ // Bad: we couldn't create the new copy. For safety's sake we
+ // abandon the whole process and remove all what's-backed-up
+ // state entirely, meaning we'll force a backup pass for every
+ // participant on the next boot or [re]install.
+ Log.w(TAG, "Error rewriting backed-up set; halting log");
+ mEverStoredStream = null;
+ mEverStoredApps.clear();
+ tempKnownFile.delete();
+ mEverStored.delete();
+ }
+ }
+ }
+ }
+
// Return the given transport
private IBackupTransport getTransport(String transportName) {
synchronized (mTransports) {