Loading services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java +248 −73 Original line number Diff line number Diff line Loading @@ -70,12 +70,28 @@ public class PackageManagerBackupAgent extends BackupAgent { private static final String DEFAULT_HOME_KEY = "@home@"; // Sentinel: start of state file, followed by a version number // Note that STATE_FILE_VERSION=2 is tied to UNDEFINED_ANCESTRAL_RECORD_VERSION=-1 *as well as* // ANCESTRAL_RECORD_VERSION=1 (introduced Android P). // Should the ANCESTRAL_RECORD_VERSION be bumped up in the future, STATE_FILE_VERSION will also // need bumping up, assuming more data needs saving to the state file. private static final String STATE_FILE_HEADER = "=state="; private static final int STATE_FILE_VERSION = 2; // Current version of the saved ancestral-dataset file format // key under which we store the saved ancestral-dataset format (starting from Android P) // IMPORTANT: this key needs to come first in the restore data stream (to find out // whether this version of Android knows how to restore the incoming data set), so it needs // to be always the first one in alphabetical order of all the keys private static final String ANCESTRAL_RECORD_KEY = "@ancestral_record@"; // Current version of the saved ancestral-dataset format // Note that this constant was not used until Android P, and started being used // to version @pm@ data for forwards-compatibility. private static final int ANCESTRAL_RECORD_VERSION = 1; // Undefined version of the saved ancestral-dataset file format means that the restore data // is coming from pre-Android P device. private static final int UNDEFINED_ANCESTRAL_RECORD_VERSION = -1; private List<PackageInfo> mAllPackages; private PackageManager mPackageManager; // version & signature info of each app in a restore set Loading Loading @@ -176,8 +192,7 @@ public class PackageManagerBackupAgent extends BackupAgent { return mRestoredSignatures.keySet(); } // The backed up data is the signature block for each app, keyed by // the package name. // The backed up data is the signature block for each app, keyed by the package name. public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) { if (DEBUG) Slog.v(TAG, "onBackup()"); Loading @@ -196,6 +211,22 @@ public class PackageManagerBackupAgent extends BackupAgent { mExisting.clear(); } /* * Ancestral record version: * * int ancestralRecordVersion -- the version of the format in which this backup set is * produced */ try { if (DEBUG) Slog.v(TAG, "Storing ancestral record version key"); outputBufferStream.writeInt(ANCESTRAL_RECORD_VERSION); writeEntity(data, ANCESTRAL_RECORD_KEY, outputBuffer.toByteArray()); } catch (IOException e) { // Real error writing data Slog.e(TAG, "Unable to write package backup data file!"); return; } long homeVersion = 0; ArrayList<byte[]> homeSigHashes = null; PackageInfo homeInfo = null; Loading Loading @@ -230,6 +261,7 @@ public class PackageManagerBackupAgent extends BackupAgent { Slog.i(TAG, "Home preference changed; backing up new state " + home); } if (home != null) { outputBuffer.reset(); outputBufferStream.writeUTF(home.flattenToString()); outputBufferStream.writeLong(homeVersion); outputBufferStream.writeUTF(homeInstaller != null ? homeInstaller : "" ); Loading @@ -244,8 +276,8 @@ public class PackageManagerBackupAgent extends BackupAgent { * Global metadata: * * 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. * that produced this backup set. Before Android P it was used to * reject backups from later OSes onto earlier ones. * String incremental -- the incremental release name of the OS stored in * the backup set. */ Loading Loading @@ -366,85 +398,59 @@ public class PackageManagerBackupAgent extends BackupAgent { // image. We'll use those later to determine what we can legitimately restore. public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException { List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); if (DEBUG) Slog.v(TAG, "onRestore()"); int storedSystemVersion = -1; while (data.readNextHeader()) { // we expect the ANCESTRAL_RECORD_KEY ("@ancestral_record@") to always come first in the // restore set - based on that value we use different mechanisms to consume the data; // if the ANCESTRAL_RECORD_KEY is missing in the restore set, it means that the data is // is coming from a pre-Android P device, and we consume the header data in the legacy way // TODO: add a CTS test to verify that backups of PMBA generated on Android P+ always // contain the ANCESTRAL_RECORD_KEY, and it's always the first key int ancestralRecordVersion = getAncestralRecordVersionValue(data); RestoreDataConsumer consumer = getRestoreDataConsumer(ancestralRecordVersion); if (consumer == null) { Slog.w(TAG, "Ancestral restore set version is unknown" + " to this Android version; not restoring"); return; } else { consumer.consumeRestoreData(data); } } private int getAncestralRecordVersionValue(BackupDataInput data) throws IOException { int ancestralRecordVersionValue = UNDEFINED_ANCESTRAL_RECORD_VERSION; if (data.readNextHeader()) { String key = data.getKey(); int dataSize = data.getDataSize(); if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize); if (ANCESTRAL_RECORD_KEY.equals(key)) { // generic setup to parse any entity data byte[] inputBytes = new byte[dataSize]; data.readEntityData(inputBytes, 0, dataSize); ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes); DataInputStream inputBufferStream = new DataInputStream(inputBuffer); if (key.equals(GLOBAL_METADATA_KEY)) { int storedSdkVersion = inputBufferStream.readInt(); if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion); if (storedSystemVersion > Build.VERSION.SDK_INT) { // returning before setting the sig map means we rejected the restore set Slog.w(TAG, "Restore set was from a later version of Android; not restoring"); return; } mStoredSdkVersion = storedSdkVersion; mStoredIncrementalVersion = inputBufferStream.readUTF(); mHasMetadata = true; if (DEBUG) { Slog.i(TAG, "Restore set version " + storedSystemVersion + " is compatible with OS version " + Build.VERSION.SDK_INT + " (" + mStoredIncrementalVersion + " vs " + Build.VERSION.INCREMENTAL + ")"); ancestralRecordVersionValue = inputBufferStream.readInt(); } } else if (key.equals(DEFAULT_HOME_KEY)) { String cn = inputBufferStream.readUTF(); mRestoredHome = ComponentName.unflattenFromString(cn); mRestoredHomeVersion = inputBufferStream.readLong(); mRestoredHomeInstaller = inputBufferStream.readUTF(); mRestoredHomeSigHashes = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read preferred home app " + mRestoredHome + " version=" + mRestoredHomeVersion + " installer=" + mRestoredHomeInstaller + " sig=" + mRestoredHomeSigHashes); } } else { // it's a file metadata record int versionCodeInt = inputBufferStream.readInt(); long versionCode; if (versionCodeInt == Integer.MIN_VALUE) { versionCode = inputBufferStream.readLong(); } else { versionCode = versionCodeInt; } ArrayList<byte[]> sigs = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read metadata for " + key + " dataSize=" + dataSize + " versionCode=" + versionCode + " sigs=" + sigs); } if (sigs == null || sigs.size() == 0) { Slog.w(TAG, "Not restoring package " + key + " since it appears to have no signatures."); continue; return ancestralRecordVersionValue; } ApplicationInfo app = new ApplicationInfo(); app.packageName = key; restoredApps.add(app); sigMap.put(key, new Metadata(versionCode, sigs)); private RestoreDataConsumer getRestoreDataConsumer(int ancestralRecordVersion) { switch (ancestralRecordVersion) { case UNDEFINED_ANCESTRAL_RECORD_VERSION: return new LegacyRestoreDataConsumer(); case 1: return new AncestralVersion1RestoreDataConsumer(); default: Slog.e(TAG, "Unrecognized ANCESTRAL_RECORD_VERSION: " + ancestralRecordVersion); return null; } } // On successful completion, cache the signature map for the Backup Manager to use mRestoredSignatures = sigMap; } private static void writeSignatureHashArray(DataOutputStream out, ArrayList<byte[]> hashes) throws IOException { // the number of entries in the array Loading Loading @@ -639,4 +645,173 @@ public class PackageManagerBackupAgent extends BackupAgent { Slog.e(TAG, "Unable to write package manager state file!"); } } interface RestoreDataConsumer { void consumeRestoreData(BackupDataInput data) throws IOException; } private class LegacyRestoreDataConsumer implements RestoreDataConsumer { public void consumeRestoreData(BackupDataInput data) throws IOException { List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); int storedSystemVersion = -1; if (DEBUG) Slog.i(TAG, "Using LegacyRestoreDataConsumer"); // we already have the first header read and "cached", since ANCESTRAL_RECORD_KEY // was missing while (true) { String key = data.getKey(); int dataSize = data.getDataSize(); if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize); // generic setup to parse any entity data byte[] inputBytes = new byte[dataSize]; data.readEntityData(inputBytes, 0, dataSize); ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes); DataInputStream inputBufferStream = new DataInputStream(inputBuffer); if (key.equals(GLOBAL_METADATA_KEY)) { int storedSdkVersion = inputBufferStream.readInt(); if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion); mStoredSdkVersion = storedSdkVersion; mStoredIncrementalVersion = inputBufferStream.readUTF(); mHasMetadata = true; if (DEBUG) { Slog.i(TAG, "Restore set version " + storedSystemVersion + " is compatible with OS version " + Build.VERSION.SDK_INT + " (" + mStoredIncrementalVersion + " vs " + Build.VERSION.INCREMENTAL + ")"); } } else if (key.equals(DEFAULT_HOME_KEY)) { String cn = inputBufferStream.readUTF(); mRestoredHome = ComponentName.unflattenFromString(cn); mRestoredHomeVersion = inputBufferStream.readLong(); mRestoredHomeInstaller = inputBufferStream.readUTF(); mRestoredHomeSigHashes = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read preferred home app " + mRestoredHome + " version=" + mRestoredHomeVersion + " installer=" + mRestoredHomeInstaller + " sig=" + mRestoredHomeSigHashes); } } else { // it's a file metadata record int versionCodeInt = inputBufferStream.readInt(); long versionCode; if (versionCodeInt == Integer.MIN_VALUE) { versionCode = inputBufferStream.readLong(); } else { versionCode = versionCodeInt; } ArrayList<byte[]> sigs = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read metadata for " + key + " dataSize=" + dataSize + " versionCode=" + versionCode + " sigs=" + sigs); } if (sigs == null || sigs.size() == 0) { Slog.w(TAG, "Not restoring package " + key + " since it appears to have no signatures."); continue; } ApplicationInfo app = new ApplicationInfo(); app.packageName = key; restoredApps.add(app); sigMap.put(key, new Metadata(versionCode, sigs)); } boolean readNextHeader = data.readNextHeader(); if (!readNextHeader) { if (DEBUG) Slog.v(TAG, "LegacyRestoreDataConsumer:" + " we're done reading all the headers"); break; } } // On successful completion, cache the signature map for the Backup Manager to use mRestoredSignatures = sigMap; } } private class AncestralVersion1RestoreDataConsumer implements RestoreDataConsumer { public void consumeRestoreData(BackupDataInput data) throws IOException { List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); int storedSystemVersion = -1; if (DEBUG) Slog.i(TAG, "Using AncestralVersion1RestoreDataConsumer"); while (data.readNextHeader()) { String key = data.getKey(); int dataSize = data.getDataSize(); if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize); // generic setup to parse any entity data byte[] inputBytes = new byte[dataSize]; data.readEntityData(inputBytes, 0, dataSize); ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes); DataInputStream inputBufferStream = new DataInputStream(inputBuffer); if (key.equals(GLOBAL_METADATA_KEY)) { int storedSdkVersion = inputBufferStream.readInt(); if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion); mStoredSdkVersion = storedSdkVersion; mStoredIncrementalVersion = inputBufferStream.readUTF(); mHasMetadata = true; if (DEBUG) { Slog.i(TAG, "Restore set version " + storedSystemVersion + " is compatible with OS version " + Build.VERSION.SDK_INT + " (" + mStoredIncrementalVersion + " vs " + Build.VERSION.INCREMENTAL + ")"); } } else if (key.equals(DEFAULT_HOME_KEY)) { String cn = inputBufferStream.readUTF(); mRestoredHome = ComponentName.unflattenFromString(cn); mRestoredHomeVersion = inputBufferStream.readLong(); mRestoredHomeInstaller = inputBufferStream.readUTF(); mRestoredHomeSigHashes = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read preferred home app " + mRestoredHome + " version=" + mRestoredHomeVersion + " installer=" + mRestoredHomeInstaller + " sig=" + mRestoredHomeSigHashes); } } else { // it's a file metadata record int versionCodeInt = inputBufferStream.readInt(); long versionCode; if (versionCodeInt == Integer.MIN_VALUE) { versionCode = inputBufferStream.readLong(); } else { versionCode = versionCodeInt; } ArrayList<byte[]> sigs = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read metadata for " + key + " dataSize=" + dataSize + " versionCode=" + versionCode + " sigs=" + sigs); } if (sigs == null || sigs.size() == 0) { Slog.w(TAG, "Not restoring package " + key + " since it appears to have no signatures."); continue; } 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; } } } Loading
services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java +248 −73 Original line number Diff line number Diff line Loading @@ -70,12 +70,28 @@ public class PackageManagerBackupAgent extends BackupAgent { private static final String DEFAULT_HOME_KEY = "@home@"; // Sentinel: start of state file, followed by a version number // Note that STATE_FILE_VERSION=2 is tied to UNDEFINED_ANCESTRAL_RECORD_VERSION=-1 *as well as* // ANCESTRAL_RECORD_VERSION=1 (introduced Android P). // Should the ANCESTRAL_RECORD_VERSION be bumped up in the future, STATE_FILE_VERSION will also // need bumping up, assuming more data needs saving to the state file. private static final String STATE_FILE_HEADER = "=state="; private static final int STATE_FILE_VERSION = 2; // Current version of the saved ancestral-dataset file format // key under which we store the saved ancestral-dataset format (starting from Android P) // IMPORTANT: this key needs to come first in the restore data stream (to find out // whether this version of Android knows how to restore the incoming data set), so it needs // to be always the first one in alphabetical order of all the keys private static final String ANCESTRAL_RECORD_KEY = "@ancestral_record@"; // Current version of the saved ancestral-dataset format // Note that this constant was not used until Android P, and started being used // to version @pm@ data for forwards-compatibility. private static final int ANCESTRAL_RECORD_VERSION = 1; // Undefined version of the saved ancestral-dataset file format means that the restore data // is coming from pre-Android P device. private static final int UNDEFINED_ANCESTRAL_RECORD_VERSION = -1; private List<PackageInfo> mAllPackages; private PackageManager mPackageManager; // version & signature info of each app in a restore set Loading Loading @@ -176,8 +192,7 @@ public class PackageManagerBackupAgent extends BackupAgent { return mRestoredSignatures.keySet(); } // The backed up data is the signature block for each app, keyed by // the package name. // The backed up data is the signature block for each app, keyed by the package name. public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) { if (DEBUG) Slog.v(TAG, "onBackup()"); Loading @@ -196,6 +211,22 @@ public class PackageManagerBackupAgent extends BackupAgent { mExisting.clear(); } /* * Ancestral record version: * * int ancestralRecordVersion -- the version of the format in which this backup set is * produced */ try { if (DEBUG) Slog.v(TAG, "Storing ancestral record version key"); outputBufferStream.writeInt(ANCESTRAL_RECORD_VERSION); writeEntity(data, ANCESTRAL_RECORD_KEY, outputBuffer.toByteArray()); } catch (IOException e) { // Real error writing data Slog.e(TAG, "Unable to write package backup data file!"); return; } long homeVersion = 0; ArrayList<byte[]> homeSigHashes = null; PackageInfo homeInfo = null; Loading Loading @@ -230,6 +261,7 @@ public class PackageManagerBackupAgent extends BackupAgent { Slog.i(TAG, "Home preference changed; backing up new state " + home); } if (home != null) { outputBuffer.reset(); outputBufferStream.writeUTF(home.flattenToString()); outputBufferStream.writeLong(homeVersion); outputBufferStream.writeUTF(homeInstaller != null ? homeInstaller : "" ); Loading @@ -244,8 +276,8 @@ public class PackageManagerBackupAgent extends BackupAgent { * Global metadata: * * 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. * that produced this backup set. Before Android P it was used to * reject backups from later OSes onto earlier ones. * String incremental -- the incremental release name of the OS stored in * the backup set. */ Loading Loading @@ -366,85 +398,59 @@ public class PackageManagerBackupAgent extends BackupAgent { // image. We'll use those later to determine what we can legitimately restore. public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException { List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); if (DEBUG) Slog.v(TAG, "onRestore()"); int storedSystemVersion = -1; while (data.readNextHeader()) { // we expect the ANCESTRAL_RECORD_KEY ("@ancestral_record@") to always come first in the // restore set - based on that value we use different mechanisms to consume the data; // if the ANCESTRAL_RECORD_KEY is missing in the restore set, it means that the data is // is coming from a pre-Android P device, and we consume the header data in the legacy way // TODO: add a CTS test to verify that backups of PMBA generated on Android P+ always // contain the ANCESTRAL_RECORD_KEY, and it's always the first key int ancestralRecordVersion = getAncestralRecordVersionValue(data); RestoreDataConsumer consumer = getRestoreDataConsumer(ancestralRecordVersion); if (consumer == null) { Slog.w(TAG, "Ancestral restore set version is unknown" + " to this Android version; not restoring"); return; } else { consumer.consumeRestoreData(data); } } private int getAncestralRecordVersionValue(BackupDataInput data) throws IOException { int ancestralRecordVersionValue = UNDEFINED_ANCESTRAL_RECORD_VERSION; if (data.readNextHeader()) { String key = data.getKey(); int dataSize = data.getDataSize(); if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize); if (ANCESTRAL_RECORD_KEY.equals(key)) { // generic setup to parse any entity data byte[] inputBytes = new byte[dataSize]; data.readEntityData(inputBytes, 0, dataSize); ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes); DataInputStream inputBufferStream = new DataInputStream(inputBuffer); if (key.equals(GLOBAL_METADATA_KEY)) { int storedSdkVersion = inputBufferStream.readInt(); if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion); if (storedSystemVersion > Build.VERSION.SDK_INT) { // returning before setting the sig map means we rejected the restore set Slog.w(TAG, "Restore set was from a later version of Android; not restoring"); return; } mStoredSdkVersion = storedSdkVersion; mStoredIncrementalVersion = inputBufferStream.readUTF(); mHasMetadata = true; if (DEBUG) { Slog.i(TAG, "Restore set version " + storedSystemVersion + " is compatible with OS version " + Build.VERSION.SDK_INT + " (" + mStoredIncrementalVersion + " vs " + Build.VERSION.INCREMENTAL + ")"); ancestralRecordVersionValue = inputBufferStream.readInt(); } } else if (key.equals(DEFAULT_HOME_KEY)) { String cn = inputBufferStream.readUTF(); mRestoredHome = ComponentName.unflattenFromString(cn); mRestoredHomeVersion = inputBufferStream.readLong(); mRestoredHomeInstaller = inputBufferStream.readUTF(); mRestoredHomeSigHashes = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read preferred home app " + mRestoredHome + " version=" + mRestoredHomeVersion + " installer=" + mRestoredHomeInstaller + " sig=" + mRestoredHomeSigHashes); } } else { // it's a file metadata record int versionCodeInt = inputBufferStream.readInt(); long versionCode; if (versionCodeInt == Integer.MIN_VALUE) { versionCode = inputBufferStream.readLong(); } else { versionCode = versionCodeInt; } ArrayList<byte[]> sigs = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read metadata for " + key + " dataSize=" + dataSize + " versionCode=" + versionCode + " sigs=" + sigs); } if (sigs == null || sigs.size() == 0) { Slog.w(TAG, "Not restoring package " + key + " since it appears to have no signatures."); continue; return ancestralRecordVersionValue; } ApplicationInfo app = new ApplicationInfo(); app.packageName = key; restoredApps.add(app); sigMap.put(key, new Metadata(versionCode, sigs)); private RestoreDataConsumer getRestoreDataConsumer(int ancestralRecordVersion) { switch (ancestralRecordVersion) { case UNDEFINED_ANCESTRAL_RECORD_VERSION: return new LegacyRestoreDataConsumer(); case 1: return new AncestralVersion1RestoreDataConsumer(); default: Slog.e(TAG, "Unrecognized ANCESTRAL_RECORD_VERSION: " + ancestralRecordVersion); return null; } } // On successful completion, cache the signature map for the Backup Manager to use mRestoredSignatures = sigMap; } private static void writeSignatureHashArray(DataOutputStream out, ArrayList<byte[]> hashes) throws IOException { // the number of entries in the array Loading Loading @@ -639,4 +645,173 @@ public class PackageManagerBackupAgent extends BackupAgent { Slog.e(TAG, "Unable to write package manager state file!"); } } interface RestoreDataConsumer { void consumeRestoreData(BackupDataInput data) throws IOException; } private class LegacyRestoreDataConsumer implements RestoreDataConsumer { public void consumeRestoreData(BackupDataInput data) throws IOException { List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); int storedSystemVersion = -1; if (DEBUG) Slog.i(TAG, "Using LegacyRestoreDataConsumer"); // we already have the first header read and "cached", since ANCESTRAL_RECORD_KEY // was missing while (true) { String key = data.getKey(); int dataSize = data.getDataSize(); if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize); // generic setup to parse any entity data byte[] inputBytes = new byte[dataSize]; data.readEntityData(inputBytes, 0, dataSize); ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes); DataInputStream inputBufferStream = new DataInputStream(inputBuffer); if (key.equals(GLOBAL_METADATA_KEY)) { int storedSdkVersion = inputBufferStream.readInt(); if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion); mStoredSdkVersion = storedSdkVersion; mStoredIncrementalVersion = inputBufferStream.readUTF(); mHasMetadata = true; if (DEBUG) { Slog.i(TAG, "Restore set version " + storedSystemVersion + " is compatible with OS version " + Build.VERSION.SDK_INT + " (" + mStoredIncrementalVersion + " vs " + Build.VERSION.INCREMENTAL + ")"); } } else if (key.equals(DEFAULT_HOME_KEY)) { String cn = inputBufferStream.readUTF(); mRestoredHome = ComponentName.unflattenFromString(cn); mRestoredHomeVersion = inputBufferStream.readLong(); mRestoredHomeInstaller = inputBufferStream.readUTF(); mRestoredHomeSigHashes = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read preferred home app " + mRestoredHome + " version=" + mRestoredHomeVersion + " installer=" + mRestoredHomeInstaller + " sig=" + mRestoredHomeSigHashes); } } else { // it's a file metadata record int versionCodeInt = inputBufferStream.readInt(); long versionCode; if (versionCodeInt == Integer.MIN_VALUE) { versionCode = inputBufferStream.readLong(); } else { versionCode = versionCodeInt; } ArrayList<byte[]> sigs = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read metadata for " + key + " dataSize=" + dataSize + " versionCode=" + versionCode + " sigs=" + sigs); } if (sigs == null || sigs.size() == 0) { Slog.w(TAG, "Not restoring package " + key + " since it appears to have no signatures."); continue; } ApplicationInfo app = new ApplicationInfo(); app.packageName = key; restoredApps.add(app); sigMap.put(key, new Metadata(versionCode, sigs)); } boolean readNextHeader = data.readNextHeader(); if (!readNextHeader) { if (DEBUG) Slog.v(TAG, "LegacyRestoreDataConsumer:" + " we're done reading all the headers"); break; } } // On successful completion, cache the signature map for the Backup Manager to use mRestoredSignatures = sigMap; } } private class AncestralVersion1RestoreDataConsumer implements RestoreDataConsumer { public void consumeRestoreData(BackupDataInput data) throws IOException { List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); int storedSystemVersion = -1; if (DEBUG) Slog.i(TAG, "Using AncestralVersion1RestoreDataConsumer"); while (data.readNextHeader()) { String key = data.getKey(); int dataSize = data.getDataSize(); if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize); // generic setup to parse any entity data byte[] inputBytes = new byte[dataSize]; data.readEntityData(inputBytes, 0, dataSize); ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes); DataInputStream inputBufferStream = new DataInputStream(inputBuffer); if (key.equals(GLOBAL_METADATA_KEY)) { int storedSdkVersion = inputBufferStream.readInt(); if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion); mStoredSdkVersion = storedSdkVersion; mStoredIncrementalVersion = inputBufferStream.readUTF(); mHasMetadata = true; if (DEBUG) { Slog.i(TAG, "Restore set version " + storedSystemVersion + " is compatible with OS version " + Build.VERSION.SDK_INT + " (" + mStoredIncrementalVersion + " vs " + Build.VERSION.INCREMENTAL + ")"); } } else if (key.equals(DEFAULT_HOME_KEY)) { String cn = inputBufferStream.readUTF(); mRestoredHome = ComponentName.unflattenFromString(cn); mRestoredHomeVersion = inputBufferStream.readLong(); mRestoredHomeInstaller = inputBufferStream.readUTF(); mRestoredHomeSigHashes = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read preferred home app " + mRestoredHome + " version=" + mRestoredHomeVersion + " installer=" + mRestoredHomeInstaller + " sig=" + mRestoredHomeSigHashes); } } else { // it's a file metadata record int versionCodeInt = inputBufferStream.readInt(); long versionCode; if (versionCodeInt == Integer.MIN_VALUE) { versionCode = inputBufferStream.readLong(); } else { versionCode = versionCodeInt; } ArrayList<byte[]> sigs = readSignatureHashArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read metadata for " + key + " dataSize=" + dataSize + " versionCode=" + versionCode + " sigs=" + sigs); } if (sigs == null || sigs.size() == 0) { Slog.w(TAG, "Not restoring package " + key + " since it appears to have no signatures."); continue; } 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; } } }