Merge change 4831 into donut
* changes: Add app version to the backup metadata
This commit is contained in:
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user