Merge change 4831 into donut

* changes:
  Add app version to the backup metadata
This commit is contained in:
Android (Google) Code Review
2009-06-19 15:38:41 -07:00
2 changed files with 75 additions and 43 deletions

View File

@@ -54,6 +54,7 @@ import com.android.internal.backup.LocalTransport;
import com.android.internal.backup.IBackupTransport; import com.android.internal.backup.IBackupTransport;
import com.android.server.PackageManagerBackupAgent; import com.android.server.PackageManagerBackupAgent;
import com.android.server.PackageManagerBackupAgent.Metadata;
import java.io.EOFException; import java.io.EOFException;
import java.io.File; import java.io.File;
@@ -111,9 +112,8 @@ class BackupManagerService extends IBackupManager.Stub {
// Do we need to back up the package manager metadata on the next pass? // Do we need to back up the package manager metadata on the next pass?
private boolean mDoPackageManager; private boolean mDoPackageManager;
private static final String PACKAGE_MANAGER_SENTINEL = "@pm@"; private static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
// Backups that we have started. These are separate to prevent starvation
// if an app keeps re-enqueuing itself. // locking around the pending-backup management
private ArrayList<BackupRequest> mBackupQueue;
private final Object mQueueLock = new Object(); private final Object mQueueLock = new Object();
// The thread performing the sequence of queued backups binds to each app's agent // The thread performing the sequence of queued backups binds to each app's agent
@@ -296,6 +296,7 @@ class BackupManagerService extends IBackupManager.Stub {
} }
// snapshot the pending-backup set and work on that // snapshot the pending-backup set and work on that
ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
File oldJournal = mJournal; File oldJournal = mJournal;
synchronized (mQueueLock) { synchronized (mQueueLock) {
if (mPendingBackups.size() == 0) { if (mPendingBackups.size() == 0) {
@@ -303,13 +304,11 @@ class BackupManagerService extends IBackupManager.Stub {
break; break;
} }
if (mBackupQueue == null) { for (BackupRequest b: mPendingBackups.values()) {
mBackupQueue = new ArrayList<BackupRequest>(); queue.add(b);
for (BackupRequest b: mPendingBackups.values()) {
mBackupQueue.add(b);
}
mPendingBackups = new HashMap<ApplicationInfo,BackupRequest>();
} }
Log.v(TAG, "clearing pending backups");
mPendingBackups.clear();
// Start a new backup-queue journal file too // Start a new backup-queue journal file too
if (mJournalStream != null) { if (mJournalStream != null) {
@@ -328,7 +327,7 @@ class BackupManagerService extends IBackupManager.Stub {
// at next boot and the journaled requests fulfilled. // at next boot and the journaled requests fulfilled.
} }
(new PerformBackupThread(transport, mBackupQueue, oldJournal)).start(); (new PerformBackupThread(transport, queue, oldJournal)).start();
break; break;
} }
@@ -759,6 +758,8 @@ class BackupManagerService extends IBackupManager.Stub {
private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) { private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
// Allow unsigned apps, but not signed on one device and unsigned on the other // Allow unsigned apps, but not signed on one device and unsigned on the other
// !!! TODO: is this the right policy? // !!! TODO: is this the right policy?
if (DEBUG) Log.v(TAG, "signaturesMatch(): stored=" + storedSigs
+ " device=" + deviceSigs);
if ((storedSigs == null || storedSigs.length == 0) if ((storedSigs == null || storedSigs.length == 0)
&& (deviceSigs == null || deviceSigs.length == 0)) { && (deviceSigs == null || deviceSigs.length == 0)) {
return true; return true;
@@ -800,6 +801,7 @@ class BackupManagerService extends IBackupManager.Stub {
@Override @Override
public void run() { public void run() {
if (DEBUG) Log.v(TAG, "Beginning restore process");
/** /**
* Restore sequence: * Restore sequence:
* *
@@ -847,13 +849,19 @@ class BackupManagerService extends IBackupManager.Stub {
PackageInfo app = isRestorable(pkg); PackageInfo app = isRestorable(pkg);
if (app != null) { if (app != null) {
// Validate against the backed-up signature block, too // Validate against the backed-up signature block, too
Signature[] storedSigs Metadata info = pmAgent.getRestoredMetadata(app.packageName);
= pmAgent.getRestoredSignatures(app.packageName); if (app.versionCode >= info.versionCode) {
// !!! TODO: check app version here as well if (DEBUG) Log.v(TAG, "Restore version " + info.versionCode
if (signaturesMatch(storedSigs, app.signatures)) { + " compatible with app version " + app.versionCode);
appsToRestore.add(app); if (signaturesMatch(info.signatures, app.signatures)) {
appsToRestore.add(app);
} else {
Log.w(TAG, "Sig mismatch restoring " + app.packageName);
}
} else { } else {
Log.w(TAG, "Sig mismatch on restore of " + app.packageName); Log.i(TAG, "Restore set for " + app.packageName
+ " is too new [" + info.versionCode
+ "] for installed app version " + app.versionCode);
} }
} }
} }
@@ -1202,11 +1210,10 @@ class BackupManagerService extends IBackupManager.Stub {
pw.println(app.toString()); pw.println(app.toString());
} }
} }
pw.println("Pending:"); pw.println("Pending: " + mPendingBackups.size());
Iterator<BackupRequest> br = mPendingBackups.values().iterator(); for (BackupRequest req : mPendingBackups.values()) {
while (br.hasNext()) { pw.print(" ");
pw.print(" "); pw.println(req);
pw.println(br);
} }
} }
} }

View File

@@ -40,9 +40,6 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
// !!!TODO: take this out
import java.util.zip.CRC32;
/** /**
* We back up the signatures of each package so that during a system restore, * We back up the signatures of each package so that during a system restore,
* we can verify that the app whose data we think we have matches the app * we can verify that the app whose data we think we have matches the app
@@ -57,7 +54,17 @@ public class PackageManagerBackupAgent extends BackupAgent {
private List<ApplicationInfo> mAllApps; private List<ApplicationInfo> mAllApps;
private PackageManager mPackageManager; private PackageManager mPackageManager;
private HashMap<String, Signature[]> mRestoredSignatures; private HashMap<String, Metadata> mRestoredSignatures;
public class Metadata {
public int versionCode;
public Signature[] signatures;
Metadata(int version, Signature[] sigs) {
versionCode = version;
signatures = sigs;
}
}
// We're constructed with the set of applications that are participating // We're constructed with the set of applications that are participating
// in backup. This set changes as apps are installed & removed. // in backup. This set changes as apps are installed & removed.
@@ -67,7 +74,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
mRestoredSignatures = null; mRestoredSignatures = null;
} }
public Signature[] getRestoredSignatures(String packageName) { public Metadata getRestoredMetadata(String packageName) {
if (mRestoredSignatures == null) { if (mRestoredSignatures == null) {
return null; return null;
} }
@@ -83,6 +90,9 @@ public class PackageManagerBackupAgent extends BackupAgent {
// For each app we have on device, see if we've backed it up yet. If not, // For each app we have on device, see if we've backed it up yet. If not,
// write its signature block to the output, keyed on the package name. // write its signature block to the output, keyed on the package name.
if (DEBUG) Log.v(TAG, "onBackup()");
ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these
DataOutputStream outWriter = new DataOutputStream(bufStream);
for (ApplicationInfo app : mAllApps) { for (ApplicationInfo app : mAllApps) {
String packName = app.packageName; String packName = app.packageName;
if (!existing.contains(packName)) { if (!existing.contains(packName)) {
@@ -90,16 +100,27 @@ public class PackageManagerBackupAgent extends BackupAgent {
try { try {
PackageInfo info = mPackageManager.getPackageInfo(packName, PackageInfo info = mPackageManager.getPackageInfo(packName,
PackageManager.GET_SIGNATURES); PackageManager.GET_SIGNATURES);
// build a byte array out of the signature list /*
* Metadata for each package:
*
* int version -- [4] the package's versionCode
* byte[] signatures -- [len] flattened Signature[] of the package
*/
// marshall the version code in a canonical form
bufStream.reset();
outWriter.writeInt(info.versionCode);
byte[] versionBuf = bufStream.toByteArray();
byte[] sigs = flattenSignatureArray(info.signatures); byte[] sigs = flattenSignatureArray(info.signatures);
// !!! TODO: take out this debugging
// !!! TODO: take out this debugging
if (DEBUG) { if (DEBUG) {
CRC32 crc = new CRC32(); Log.v(TAG, "+ metadata for " + packName + " version=" + info.versionCode);
crc.update(sigs);
Log.i(TAG, "+ flat sig array for " + packName + " : "
+ crc.getValue());
} }
data.writeEntityHeader(packName, sigs.length); // Now we can write the backup entity for this package
data.writeEntityHeader(packName, versionBuf.length + sigs.length);
data.writeEntityData(versionBuf, versionBuf.length);
data.writeEntityData(sigs, sigs.length); data.writeEntityData(sigs, sigs.length);
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
// Weird; we just found it, and now are told it doesn't exist. // Weird; we just found it, and now are told it doesn't exist.
@@ -113,6 +134,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
} else { } else {
// We've already backed up this app. Remove it from the set so // 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. // 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)) { if (!existing.remove(packName)) {
Log.d(TAG, "*** failed to remove " + packName + " from package set!"); Log.d(TAG, "*** failed to remove " + packName + " from package set!");
} }
@@ -123,6 +146,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
// mentioned in the saved state file, but appear to no longer be present // mentioned in the saved state file, but appear to no longer be present
// on the device. Write a deletion entity for them. // on the device. Write a deletion entity for them.
for (String app : existing) { for (String app : existing) {
// !!! TODO: take out this msg
if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app);
try { try {
data.writeEntityHeader(app, -1); data.writeEntityHeader(app, -1);
} catch (IOException e) { } catch (IOException e) {
@@ -141,27 +166,29 @@ public class PackageManagerBackupAgent extends BackupAgent {
public void onRestore(BackupDataInput data, ParcelFileDescriptor newState) public void onRestore(BackupDataInput data, ParcelFileDescriptor newState)
throws IOException { throws IOException {
List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
HashMap<String, Signature[]> sigMap = new HashMap<String, Signature[]>(); HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();
while (data.readNextHeader()) { while (data.readNextHeader()) {
int dataSize = data.getDataSize(); int dataSize = data.getDataSize();
byte[] buf = new byte[dataSize]; byte[] buf = new byte[dataSize];
data.readEntityData(buf, 0, dataSize); data.readEntityData(buf, 0, dataSize);
Signature[] sigs = unflattenSignatureArray(buf); ByteArrayInputStream bufStream = new ByteArrayInputStream(buf);
DataInputStream in = new DataInputStream(bufStream);
int versionCode = in.readInt();
Signature[] sigs = unflattenSignatureArray(in);
String pkg = data.getKey(); String pkg = data.getKey();
// !!! TODO: take out this debugging // !!! TODO: take out this debugging
if (DEBUG) { if (DEBUG) {
CRC32 crc = new CRC32(); Log.i(TAG, "+ restored metadata for " + pkg
crc.update(buf); + " versionCode=" + versionCode + " sigs=" + sigs);
Log.i(TAG, "- unflat sig array for " + pkg + " : "
+ crc.getValue());
} }
ApplicationInfo app = new ApplicationInfo(); ApplicationInfo app = new ApplicationInfo();
app.packageName = pkg; app.packageName = pkg;
restoredApps.add(app); restoredApps.add(app);
sigMap.put(pkg, sigs); sigMap.put(pkg, new Metadata(versionCode, sigs));
} }
mRestoredSignatures = sigMap; mRestoredSignatures = sigMap;
@@ -193,9 +220,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
return outBuf.toByteArray(); return outBuf.toByteArray();
} }
private Signature[] unflattenSignatureArray(byte[] buffer) { private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) {
ByteArrayInputStream inBufStream = new ByteArrayInputStream(buffer);
DataInputStream in = new DataInputStream(inBufStream);
Signature[] sigs = null; Signature[] sigs = null;
try { try {