diff options
Diffstat (limited to 'services/java')
| -rw-r--r-- | services/java/com/android/server/BackupManagerService.java | 28 | ||||
| -rw-r--r-- | services/java/com/android/server/PackageManagerBackupAgent.java | 227 |
2 files changed, 162 insertions, 93 deletions
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 9a8d740..c60f981 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -34,6 +34,7 @@ import android.content.pm.PackageManager; import android.content.pm.Signature; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; @@ -850,18 +851,27 @@ class BackupManagerService extends IBackupManager.Stub { if (app != null) { // Validate against the backed-up signature block, too Metadata info = pmAgent.getRestoredMetadata(app.packageName); - if (app.versionCode >= info.versionCode) { - if (DEBUG) Log.v(TAG, "Restore version " + info.versionCode - + " compatible with app version " + app.versionCode); - if (signaturesMatch(info.signatures, app.signatures)) { - appsToRestore.add(app); + if (info != null) { + if (app.versionCode >= info.versionCode) { + if (DEBUG) Log.v(TAG, "Restore version " + + info.versionCode + + " compatible with app version " + + app.versionCode); + if (signaturesMatch(info.signatures, app.signatures)) { + appsToRestore.add(app); + } else { + Log.w(TAG, "Sig mismatch restoring " + + app.packageName); + } } else { - Log.w(TAG, "Sig mismatch restoring " + app.packageName); + Log.i(TAG, "Restore set for " + app.packageName + + " is too new [" + info.versionCode + + "] for installed app version " + + app.versionCode); } } else { - Log.i(TAG, "Restore set for " + app.packageName - + " is too new [" + info.versionCode - + "] for installed app version " + app.versionCode); + Log.d(TAG, "Unable to get metadata for " + + app.packageName); } } } diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java index cc84430..9422878 100644 --- a/services/java/com/android/server/PackageManagerBackupAgent.java +++ b/services/java/com/android/server/PackageManagerBackupAgent.java @@ -24,6 +24,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; +import android.os.Build; import android.os.ParcelFileDescriptor; import android.util.Log; @@ -52,6 +53,10 @@ public class PackageManagerBackupAgent extends BackupAgent { private static final String TAG = "PMBA"; private static final boolean DEBUG = true; + // key under which we store global metadata (individual app metadata + // is stored using the package name as a key) + private static final String GLOBAL_METADATA_KEY = "@meta@"; + private List<ApplicationInfo> mAllApps; private PackageManager mPackageManager; private HashMap<String, Metadata> mRestoredSignatures; @@ -76,6 +81,7 @@ public class PackageManagerBackupAgent extends BackupAgent { public Metadata getRestoredMetadata(String packageName) { if (mRestoredSignatures == null) { + Log.w(TAG, "getRestoredMetadata() before metadata read!"); return null; } @@ -86,74 +92,97 @@ public class PackageManagerBackupAgent extends BackupAgent { // the package name. public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) { - HashSet<String> existing = parseStateFile(oldState); - - // 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. if (DEBUG) Log.v(TAG, "onBackup()"); + ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these DataOutputStream outWriter = new DataOutputStream(bufStream); - for (ApplicationInfo app : mAllApps) { - String packName = app.packageName; - if (!existing.contains(packName)) { - // We haven't stored this app's signatures yet, so we do that now - try { - PackageInfo info = mPackageManager.getPackageInfo(packName, - PackageManager.GET_SIGNATURES); - /* - * 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); - - // !!! TODO: take out this debugging - if (DEBUG) { - Log.v(TAG, "+ metadata for " + packName + " version=" + info.versionCode); - } - // 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); - } 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); - } catch (IOException e) { - // Real error writing data - Log.e(TAG, "Unable to write package backup data file!"); - return; - } + HashSet<String> existing = parseStateFile(oldState); + + 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. + */ + if (!existing.contains(GLOBAL_METADATA_KEY)) { + if (DEBUG) Log.v(TAG, "Storing global metadata key"); + outWriter.writeInt(Build.VERSION.SDK_INT); + byte[] metadata = bufStream.toByteArray(); + data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length); + data.writeEntityData(metadata, metadata.length); } 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!"); + if (DEBUG) Log.v(TAG, "Global metadata key already stored"); + } + + // 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. + for (ApplicationInfo app : mAllApps) { + String packName = app.packageName; + if (!existing.contains(packName)) { + // We haven't stored this app's signatures yet, so we do that now + try { + PackageInfo info = mPackageManager.getPackageInfo(packName, + PackageManager.GET_SIGNATURES); + /* + * 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); + + // !!! TODO: take out this debugging + if (DEBUG) { + Log.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); + } 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!"); + } } } - } - // 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) { - // !!! TODO: take out this msg - if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app); - try { - data.writeEntityHeader(app, -1); - } catch (IOException e) { - Log.e(TAG, "Unable to write package deletions!"); - return; + // 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) { + // !!! TODO: take out this msg + if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app); + try { + data.writeEntityHeader(app, -1); + } catch (IOException e) { + Log.e(TAG, "Unable to write package deletions!"); + return; + } } + } catch (IOException e) { + // Real error writing data + Log.e(TAG, "Unable to write package backup data file!"); + return; } // Finally, write the new state blob -- just the list of all apps we handled @@ -167,30 +196,53 @@ public class PackageManagerBackupAgent extends BackupAgent { throws IOException { List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); + if (DEBUG) Log.v(TAG, "onRestore()"); + int storedSystemVersion = -1; while (data.readNextHeader()) { + String key = data.getKey(); int dataSize = data.getDataSize(); - byte[] buf = new byte[dataSize]; - data.readEntityData(buf, 0, dataSize); - - ByteArrayInputStream bufStream = new ByteArrayInputStream(buf); - DataInputStream in = new DataInputStream(bufStream); - int versionCode = in.readInt(); - - Signature[] sigs = unflattenSignatureArray(in); - String pkg = data.getKey(); -// !!! TODO: take out this debugging - if (DEBUG) { - Log.i(TAG, "+ restored metadata for " + pkg - + " versionCode=" + versionCode + " sigs=" + sigs); - } - ApplicationInfo app = new ApplicationInfo(); - app.packageName = pkg; - restoredApps.add(app); - sigMap.put(pkg, new Metadata(versionCode, sigs)); + if (DEBUG) Log.v(TAG, " got key=" + key + " dataSize=" + dataSize); + + // generic setup to parse any entity data + byte[] dataBuf = new byte[dataSize]; + data.readEntityData(dataBuf, 0, dataSize); + ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf); + DataInputStream in = new DataInputStream(baStream); + + if (key.equals(GLOBAL_METADATA_KEY)) { + storedSystemVersion = 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; + } + // !!! TODO: remove this debugging output + if (DEBUG) { + Log.i(TAG, "Restore set version " + storedSystemVersion + + " is compatible with OS version " + Build.VERSION.SDK_INT); + } + } else { + // it's a file metadata record + int versionCode = in.readInt(); + Signature[] sigs = unflattenSignatureArray(in); +// !!! TODO: take out this debugging + if (DEBUG) { + Log.i(TAG, " restored metadata for " + key + + " dataSize=" + dataSize + + " versionCode=" + versionCode + " sigs=" + sigs); + } + + ApplicationInfo app = new ApplicationInfo(); + app.packageName = key; + restoredApps.add(app); + sigMap.put(key, new Metadata(versionCode, sigs)); + } } + // On successful completion, cache the signature map for the Backup Manager to use mRestoredSignatures = sigMap; } @@ -225,6 +277,7 @@ public class PackageManagerBackupAgent extends BackupAgent { try { int num = in.readInt(); + Log.v(TAG, " ... unflatten read " + num); sigs = new Signature[num]; for (int i = 0; i < num; i++) { int len = in.readInt(); @@ -273,20 +326,26 @@ public class PackageManagerBackupAgent extends BackupAgent { return set; } - // Util: write a set of names into a new state file + // Util: write out our new backup state file private void writeStateFile(List<ApplicationInfo> apps, ParcelFileDescriptor stateFile) { FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); DataOutputStream out = new DataOutputStream(outstream); - for (ApplicationInfo app : apps) { - try { + 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); + + // now write all the app names too + for (ApplicationInfo app : apps) { byte[] pkgNameBuf = app.packageName.getBytes(); out.writeInt(pkgNameBuf.length); out.write(pkgNameBuf); - } catch (IOException e) { - Log.e(TAG, "Unable to write package manager state file!"); - return; } + } catch (IOException e) { + Log.e(TAG, "Unable to write package manager state file!"); + return; } } } |
