am b059dc9c: am b00771aa: am 267f0a6b: Merge "Workaround NPE caused by packages missing signatures." into froyo

This commit is contained in:
Jeff Brown
2010-04-08 16:49:56 -07:00
committed by Android Git Automerger

View File

@@ -122,8 +122,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
ParcelFileDescriptor newState) { ParcelFileDescriptor newState) {
if (DEBUG) Slog.v(TAG, "onBackup()"); if (DEBUG) Slog.v(TAG, "onBackup()");
ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream(); // we'll reuse these
DataOutputStream outWriter = new DataOutputStream(bufStream); DataOutputStream outputBufferStream = new DataOutputStream(outputBuffer);
parseStateFile(oldState); parseStateFile(oldState);
// If the stored version string differs, we need to re-backup all // If the stored version string differs, we need to re-backup all
@@ -148,11 +148,9 @@ public class PackageManagerBackupAgent extends BackupAgent {
*/ */
if (!mExisting.contains(GLOBAL_METADATA_KEY)) { if (!mExisting.contains(GLOBAL_METADATA_KEY)) {
if (DEBUG) Slog.v(TAG, "Storing global metadata key"); if (DEBUG) Slog.v(TAG, "Storing global metadata key");
outWriter.writeInt(Build.VERSION.SDK_INT); outputBufferStream.writeInt(Build.VERSION.SDK_INT);
outWriter.writeUTF(Build.VERSION.INCREMENTAL); outputBufferStream.writeUTF(Build.VERSION.INCREMENTAL);
byte[] metadata = bufStream.toByteArray(); writeEntity(data, GLOBAL_METADATA_KEY, outputBuffer.toByteArray());
data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length);
data.writeEntityData(metadata, metadata.length);
} else { } else {
if (DEBUG) Slog.v(TAG, "Global metadata key already stored"); if (DEBUG) Slog.v(TAG, "Global metadata key already stored");
// don't consider it to have been skipped/deleted // don't consider it to have been skipped/deleted
@@ -178,49 +176,46 @@ public class PackageManagerBackupAgent extends BackupAgent {
continue; continue;
} }
boolean doBackup = false; if (mExisting.contains(packName)) {
if (!mExisting.contains(packName)) { // We have backed up this app before. Check whether the version
// 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 // 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 // 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 // metadata again. In either case, take it out of mExisting so that
// we don't consider it deleted later. // we don't consider it deleted later.
if (info.versionCode != mStateVersions.get(packName).versionCode) {
doBackup = true;
}
mExisting.remove(packName); mExisting.remove(packName);
} if (info.versionCode == mStateVersions.get(packName).versionCode) {
continue;
if (doBackup) {
// We need to store this app's metadata
/*
* Metadata for each package:
*
* int version -- [4] the package's versionCode
* byte[] signatures -- [len] flattened Signature[] of the package
*/
// marshal the version code in a canonical form
bufStream.reset();
outWriter.writeInt(info.versionCode);
byte[] versionBuf = bufStream.toByteArray();
byte[] sigs = flattenSignatureArray(info.signatures);
if (DEBUG) {
Slog.v(TAG, "+ metadata for " + packName
+ " version=" + info.versionCode
+ " versionLen=" + versionBuf.length
+ " sigsLen=" + 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);
} }
if (info.signatures == null || info.signatures.length == 0)
{
Slog.w(TAG, "Not backing up package " + packName
+ " since it appears to have no signatures.");
continue;
}
// We need to store this app's metadata
/*
* Metadata for each package:
*
* int version -- [4] the package's versionCode
* byte[] signatures -- [len] flattened Signature[] of the package
*/
// marshal the version code in a canonical form
outputBuffer.reset();
outputBufferStream.writeInt(info.versionCode);
writeSignatureArray(outputBufferStream, info.signatures);
if (DEBUG) {
Slog.v(TAG, "+ writing metadata for " + packName
+ " version=" + info.versionCode
+ " entityLen=" + outputBuffer.size());
}
// Now we can write the backup entity for this package
writeEntity(data, packName, outputBuffer.toByteArray());
} }
} }
@@ -245,6 +240,12 @@ public class PackageManagerBackupAgent extends BackupAgent {
// Finally, write the new state blob -- just the list of all apps we handled // Finally, write the new state blob -- just the list of all apps we handled
writeStateFile(mAllPackages, newState); writeStateFile(mAllPackages, newState);
} }
private static void writeEntity(BackupDataOutput data, String key, byte[] bytes)
throws IOException {
data.writeEntityHeader(key, bytes.length);
data.writeEntityData(bytes, bytes.length);
}
// "Restore" here is a misnomer. What we're really doing is reading back the // "Restore" here is a misnomer. What we're really doing is reading back the
// set of app signatures associated with each backed-up app in this restore // set of app signatures associated with each backed-up app in this restore
@@ -263,13 +264,13 @@ public class PackageManagerBackupAgent extends BackupAgent {
if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize); if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize);
// generic setup to parse any entity data // generic setup to parse any entity data
byte[] dataBuf = new byte[dataSize]; byte[] inputBytes = new byte[dataSize];
data.readEntityData(dataBuf, 0, dataSize); data.readEntityData(inputBytes, 0, dataSize);
ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf); ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes);
DataInputStream in = new DataInputStream(baStream); DataInputStream inputBufferStream = new DataInputStream(inputBuffer);
if (key.equals(GLOBAL_METADATA_KEY)) { if (key.equals(GLOBAL_METADATA_KEY)) {
int storedSdkVersion = in.readInt(); int storedSdkVersion = inputBufferStream.readInt();
if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion); if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion);
if (storedSystemVersion > Build.VERSION.SDK_INT) { if (storedSystemVersion > Build.VERSION.SDK_INT) {
// returning before setting the sig map means we rejected the restore set // returning before setting the sig map means we rejected the restore set
@@ -277,7 +278,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
return; return;
} }
mStoredSdkVersion = storedSdkVersion; mStoredSdkVersion = storedSdkVersion;
mStoredIncrementalVersion = in.readUTF(); mStoredIncrementalVersion = inputBufferStream.readUTF();
mHasMetadata = true; mHasMetadata = true;
if (DEBUG) { if (DEBUG) {
Slog.i(TAG, "Restore set version " + storedSystemVersion Slog.i(TAG, "Restore set version " + storedSystemVersion
@@ -287,13 +288,19 @@ public class PackageManagerBackupAgent extends BackupAgent {
} }
} else { } else {
// it's a file metadata record // it's a file metadata record
int versionCode = in.readInt(); int versionCode = inputBufferStream.readInt();
Signature[] sigs = unflattenSignatureArray(in); Signature[] sigs = readSignatureArray(inputBufferStream);
if (DEBUG) { if (DEBUG) {
Slog.i(TAG, " restored metadata for " + key Slog.i(TAG, " read metadata for " + key
+ " dataSize=" + dataSize + " dataSize=" + dataSize
+ " versionCode=" + versionCode + " sigs=" + sigs); + " versionCode=" + versionCode + " sigs=" + sigs);
} }
if (sigs == null || sigs.length == 0) {
Slog.w(TAG, "Not restoring package " + key
+ " since it appears to have no signatures.");
continue;
}
ApplicationInfo app = new ApplicationInfo(); ApplicationInfo app = new ApplicationInfo();
app.packageName = key; app.packageName = key;
@@ -306,63 +313,50 @@ public class PackageManagerBackupAgent extends BackupAgent {
mRestoredSignatures = sigMap; mRestoredSignatures = sigMap;
} }
private static void writeSignatureArray(DataOutputStream out, Signature[] sigs)
throws IOException {
// write the number of signatures in the array
out.writeInt(sigs.length);
// Util: convert an array of Signatures into a flattened byte buffer. The // write the signatures themselves, length + flattened buffer
// flattened format contains enough info to reconstruct the signature array. for (Signature sig : sigs) {
private byte[] flattenSignatureArray(Signature[] allSigs) { byte[] flat = sig.toByteArray();
ByteArrayOutputStream outBuf = new ByteArrayOutputStream(); out.writeInt(flat.length);
DataOutputStream out = new DataOutputStream(outBuf); out.write(flat);
// build the set of subsidiary buffers
try {
// first the # of signatures in the array
out.writeInt(allSigs.length);
// then the signatures themselves, length + flattened buffer
for (Signature sig : allSigs) {
byte[] flat = sig.toByteArray();
out.writeInt(flat.length);
out.write(flat);
}
} catch (IOException e) {
// very strange; we're writing to memory here. abort.
return null;
} }
return outBuf.toByteArray();
} }
private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) { private static Signature[] readSignatureArray(DataInputStream in) {
Signature[] sigs = null;
try { try {
int num = in.readInt(); int num;
try {
num = in.readInt();
} catch (EOFException e) {
// clean termination
Slog.w(TAG, "Read empty signature block");
return null;
}
if (DEBUG) Slog.v(TAG, " ... unflatten read " + num); if (DEBUG) Slog.v(TAG, " ... unflatten read " + num);
// Sensical? // Sensical?
if (num > 20) { if (num > 20) {
Slog.e(TAG, "Suspiciously large sig count in restore data; aborting"); Slog.e(TAG, "Suspiciously large sig count in restore data; aborting");
throw new IllegalStateException("Bad restore state"); throw new IllegalStateException("Bad restore state");
} }
sigs = new Signature[num]; Signature[] sigs = new Signature[num];
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
int len = in.readInt(); int len = in.readInt();
byte[] flatSig = new byte[len]; byte[] flatSig = new byte[len];
in.read(flatSig); in.read(flatSig);
sigs[i] = new Signature(flatSig); sigs[i] = new Signature(flatSig);
} }
} catch (EOFException e) { return sigs;
// clean termination
if (sigs == null) {
Slog.w(TAG, "Empty signature block found");
}
} catch (IOException e) { } catch (IOException e) {
Slog.e(TAG, "Unable to unflatten sigs"); Slog.e(TAG, "Unable to read signatures");
return null; return null;
} }
return sigs;
} }
// Util: parse out an existing state file into a usable structure // Util: parse out an existing state file into a usable structure