summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Tate <ctate@google.com>2009-06-30 12:47:33 -0700
committerChristopher Tate <ctate@google.com>2009-06-30 12:52:54 -0700
commit72d19aa51e90d45c7895629db78e548da2f6d469 (patch)
treef65c8bcf06246252d75f387bf647386a255466a3
parent91c91b74df12e40c31a50ecb807ac60bed2ccb58 (diff)
downloadframeworks_base-72d19aa51e90d45c7895629db78e548da2f6d469.zip
frameworks_base-72d19aa51e90d45c7895629db78e548da2f6d469.tar.gz
frameworks_base-72d19aa51e90d45c7895629db78e548da2f6d469.tar.bz2
Tighten up the metadata backup logic
We now store the app version codes and and global OS incremental version name in the PM backup state and the actual backup record. We then use that information to trigger a re-backup of the metadata if the OS revision changes in any way, or to back up single apps' metadata if we notice that they've been upgraded.
-rw-r--r--services/java/com/android/server/PackageManagerBackupAgent.java136
1 files changed, 94 insertions, 42 deletions
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
index 16f14e8..a1b4c26 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -59,7 +59,14 @@ public class PackageManagerBackupAgent extends BackupAgent {
private List<PackageInfo> mAllPackages;
private PackageManager mPackageManager;
+ // version & signature info of each app in a restore set
private HashMap<String, Metadata> mRestoredSignatures;
+ // The version info of each backed-up app as read from the state file
+ private HashMap<String, Metadata> mStateVersions = new HashMap<String, Metadata>();
+
+ private final HashSet<String> mExisting = new HashSet<String>();
+ private int mStoredSdkVersion;
+ private String mStoredIncrementalVersion;
public class Metadata {
public int versionCode;
@@ -96,24 +103,39 @@ public class PackageManagerBackupAgent extends BackupAgent {
ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these
DataOutputStream outWriter = new DataOutputStream(bufStream);
- HashSet<String> existing = parseStateFile(oldState);
+ parseStateFile(oldState);
+
+ // If the stored version string differs, we need to re-backup all
+ // of the metadata. We force this by removing everything from the
+ // "already backed up" map built by parseStateFile().
+ if (mStoredIncrementalVersion == null
+ || !mStoredIncrementalVersion.equals(Build.VERSION.INCREMENTAL)) {
+ Log.i(TAG, "Previous metadata " + mStoredIncrementalVersion + " mismatch vs "
+ + Build.VERSION.INCREMENTAL + " - rewriting");
+ mExisting.clear();
+ }
try {
/*
* Global metadata:
*
- * int version -- the SDK version of the OS itself on the device
- * that produced this backup set. Used to reject
- * backups from later OSes onto earlier ones.
+ * int SDKversion -- the SDK version of the OS itself on the device
+ * that produced this backup set. Used to reject
+ * backups from later OSes onto earlier ones.
+ * String incremental -- the incremental release name of the OS stored in
+ * the backup set.
*/
- if (!existing.contains(GLOBAL_METADATA_KEY)) {
+ if (!mExisting.contains(GLOBAL_METADATA_KEY)) {
if (DEBUG) Log.v(TAG, "Storing global metadata key");
outWriter.writeInt(Build.VERSION.SDK_INT);
+ outWriter.writeUTF(Build.VERSION.INCREMENTAL);
byte[] metadata = bufStream.toByteArray();
data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length);
data.writeEntityData(metadata, metadata.length);
} else {
if (DEBUG) Log.v(TAG, "Global metadata key already stored");
+ // don't consider it to have been skipped/deleted
+ mExisting.remove(GLOBAL_METADATA_KEY);
}
// For each app we have on device, see if we've backed it up yet. If not,
@@ -123,11 +145,36 @@ public class PackageManagerBackupAgent extends BackupAgent {
if (packName.equals(GLOBAL_METADATA_KEY)) {
// We've already handled the metadata key; skip it here
continue;
- } else if (!existing.contains(packName)) {
- // We haven't stored this app's signatures yet, so we do that now
+ } else {
+ PackageInfo info = null;
try {
- PackageInfo info = mPackageManager.getPackageInfo(packName,
+ info = mPackageManager.getPackageInfo(packName,
PackageManager.GET_SIGNATURES);
+ } catch (NameNotFoundException e) {
+ // Weird; we just found it, and now are told it doesn't exist.
+ // Treat it as having been removed from the device.
+ mExisting.add(packName);
+ continue;
+ }
+
+ boolean doBackup = false;
+ if (!mExisting.contains(packName)) {
+ // We haven't backed up this app before
+ doBackup = true;
+ } else {
+ // We *have* backed this one up before. Check whether the version
+ // of the backup matches the version of the current app; if they
+ // don't match, the app has been updated and we need to store its
+ // metadata again. In either case, take it out of mExisting so that
+ // we don't consider it deleted later.
+ if (info.versionCode != mStateVersions.get(packName).versionCode) {
+ doBackup = true;
+ }
+ mExisting.remove(packName);
+ }
+
+ if (doBackup) {
+ // We need to store this app's metadata
/*
* Metadata for each package:
*
@@ -135,7 +182,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
* byte[] signatures -- [len] flattened Signature[] of the package
*/
- // marshall the version code in a canonical form
+ // marshal the version code in a canonical form
bufStream.reset();
outWriter.writeInt(info.versionCode);
byte[] versionBuf = bufStream.toByteArray();
@@ -153,18 +200,6 @@ public class PackageManagerBackupAgent extends BackupAgent {
data.writeEntityHeader(packName, versionBuf.length + sigs.length);
data.writeEntityData(versionBuf, versionBuf.length);
data.writeEntityData(sigs, sigs.length);
- } catch (NameNotFoundException e) {
- // Weird; we just found it, and now are told it doesn't exist.
- // Treat it as having been removed from the device.
- existing.add(packName);
- }
- } else {
- // We've already backed up this app. Remove it from the set so
- // we can tell at the end what has disappeared from the device.
- // !!! TODO: take out the debugging message
- if (DEBUG) Log.v(TAG, "= already backed up metadata for " + packName);
- if (!existing.remove(packName)) {
- Log.d(TAG, "*** failed to remove " + packName + " from package set!");
}
}
}
@@ -172,7 +207,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
// At this point, the only entries in 'existing' are apps that were
// mentioned in the saved state file, but appear to no longer be present
// on the device. Write a deletion entity for them.
- for (String app : existing) {
+ for (String app : mExisting) {
// !!! TODO: take out this msg
if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app);
try {
@@ -215,17 +250,21 @@ public class PackageManagerBackupAgent extends BackupAgent {
DataInputStream in = new DataInputStream(baStream);
if (key.equals(GLOBAL_METADATA_KEY)) {
- storedSystemVersion = in.readInt();
+ int storedSdkVersion = in.readInt();
if (DEBUG) Log.v(TAG, " storedSystemVersion = " + storedSystemVersion);
if (storedSystemVersion > Build.VERSION.SDK_INT) {
// returning before setting the sig map means we rejected the restore set
Log.w(TAG, "Restore set was from a later version of Android; not restoring");
return;
}
+ mStoredSdkVersion = storedSdkVersion;
+ mStoredIncrementalVersion = in.readUTF();
// !!! TODO: remove this debugging output
if (DEBUG) {
Log.i(TAG, "Restore set version " + storedSystemVersion
- + " is compatible with OS version " + Build.VERSION.SDK_INT);
+ + " is compatible with OS version " + Build.VERSION.SDK_INT
+ + " (" + mStoredIncrementalVersion + " vs "
+ + Build.VERSION.INCREMENTAL + ")");
}
} else {
// it's a file metadata record
@@ -302,31 +341,45 @@ public class PackageManagerBackupAgent extends BackupAgent {
}
// Util: parse out an existing state file into a usable structure
- private HashSet<String> parseStateFile(ParcelFileDescriptor stateFile) {
- HashSet<String> set = new HashSet<String>();
+ private void parseStateFile(ParcelFileDescriptor stateFile) {
+ mExisting.clear();
+ mStateVersions.clear();
+ mStoredSdkVersion = 0;
+ mStoredIncrementalVersion = null;
+
// The state file is just the list of app names we have stored signatures for
+ // with the exception of the metadata block, to which is also appended the
+ // version numbers corresponding with the last time we wrote this PM block.
+ // If they mismatch the current system, we'll re-store the metadata key.
FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor());
DataInputStream in = new DataInputStream(instream);
int bufSize = 256;
byte[] buf = new byte[bufSize];
try {
- int nameSize = in.readInt();
- if (bufSize < nameSize) {
- bufSize = nameSize + 32;
- buf = new byte[bufSize];
+ String pkg = in.readUTF();
+ if (pkg.equals(GLOBAL_METADATA_KEY)) {
+ mStoredSdkVersion = in.readInt();
+ mStoredIncrementalVersion = in.readUTF();
+ mExisting.add(GLOBAL_METADATA_KEY);
+ } else {
+ Log.e(TAG, "No global metadata in state file!");
+ return;
+ }
+
+ // The global metadata was first; now read all the apps
+ while (true) {
+ pkg = in.readUTF();
+ int versionCode = in.readInt();
+ mExisting.add(pkg);
+ mStateVersions.put(pkg, new Metadata(versionCode, null));
}
- in.read(buf, 0, nameSize);
- String pkg = new String(buf, 0, nameSize);
- set.add(pkg);
} catch (EOFException eof) {
// safe; we're done
} catch (IOException e) {
// whoops, bad state file. abort.
- Log.e(TAG, "Unable to read Package Manager state file");
- return null;
+ Log.e(TAG, "Unable to read Package Manager state file: " + e);
}
- return set;
}
// Util: write out our new backup state file
@@ -336,15 +389,14 @@ public class PackageManagerBackupAgent extends BackupAgent {
try {
// by the time we get here we know we've stored the global metadata record
- byte[] metaNameBuf = GLOBAL_METADATA_KEY.getBytes();
- out.writeInt(metaNameBuf.length);
- out.write(metaNameBuf);
+ out.writeUTF(GLOBAL_METADATA_KEY);
+ out.writeInt(Build.VERSION.SDK_INT);
+ out.writeUTF(Build.VERSION.INCREMENTAL);
// now write all the app names too
for (PackageInfo pkg : pkgs) {
- byte[] pkgNameBuf = pkg.packageName.getBytes();
- out.writeInt(pkgNameBuf.length);
- out.write(pkgNameBuf);
+ out.writeUTF(pkg.packageName);
+ out.writeInt(pkg.versionCode);
}
} catch (IOException e) {
Log.e(TAG, "Unable to write package manager state file!");