Loading services/backup/java/com/android/server/backup/BackupManagerService.java +5 −1 Original line number Original line Diff line number Diff line Loading @@ -4690,7 +4690,11 @@ public class BackupManagerService extends IBackupManager.Stub { // ----- Restore handling ----- // ----- Restore handling ----- private boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) { static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) { if (target == null) { return false; } // If the target resides on the system partition, we allow it to restore // If the target resides on the system partition, we allow it to restore // data from the like-named package in a restore set even if the signatures // data from the like-named package in a restore set even if the signatures // do not match. (Unlike general applications, those flashed to the system // do not match. (Unlike general applications, those flashed to the system Loading services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java +115 −9 Original line number Original line Diff line number Diff line Loading @@ -19,15 +19,19 @@ package com.android.server.backup; import android.app.backup.BackupAgent; import android.app.backup.BackupAgent; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.BackupDataOutput; import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.content.pm.Signature; import android.os.Build; import android.os.Build; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; import android.util.Slog; import android.util.Slog; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataInputStream; Loading @@ -42,6 +46,8 @@ import java.util.HashSet; import java.util.List; import java.util.List; import java.util.Set; import java.util.Set; import java.util.Objects; /** /** * 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 Loading @@ -58,6 +64,9 @@ public class PackageManagerBackupAgent extends BackupAgent { // is stored using the package name as a key) // is stored using the package name as a key) private static final String GLOBAL_METADATA_KEY = "@meta@"; private static final String GLOBAL_METADATA_KEY = "@meta@"; // key under which we store the identity of the user's chosen default home app private static final String DEFAULT_HOME_KEY = "@home@"; private List<PackageInfo> mAllPackages; private List<PackageInfo> mAllPackages; private PackageManager mPackageManager; private PackageManager mPackageManager; // version & signature info of each app in a restore set // version & signature info of each app in a restore set Loading @@ -68,7 +77,15 @@ public class PackageManagerBackupAgent extends BackupAgent { private final HashSet<String> mExisting = new HashSet<String>(); private final HashSet<String> mExisting = new HashSet<String>(); private int mStoredSdkVersion; private int mStoredSdkVersion; private String mStoredIncrementalVersion; private String mStoredIncrementalVersion; private ComponentName mStoredHomeComponent; private long mStoredHomeVersion; private Signature[] mStoredHomeSigs; private boolean mHasMetadata; private boolean mHasMetadata; private ComponentName mRestoredHome; private long mRestoredHomeVersion; private String mRestoredHomeInstaller; private Signature[] mRestoredHomeSignatures; public class Metadata { public class Metadata { public int versionCode; public int versionCode; Loading Loading @@ -136,7 +153,50 @@ public class PackageManagerBackupAgent extends BackupAgent { mExisting.clear(); mExisting.clear(); } } long homeVersion = 0; Signature[] homeSigs = null; PackageInfo homeInfo = null; String homeInstaller = null; ComponentName home = getPreferredHomeComponent(); if (home != null) { try { try { homeInfo = mPackageManager.getPackageInfo(home.getPackageName(), PackageManager.GET_SIGNATURES); homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName()); homeVersion = homeInfo.versionCode; homeSigs = homeInfo.signatures; } catch (NameNotFoundException e) { Slog.w(TAG, "Can't access preferred home info"); // proceed as though there were no preferred home set home = null; } } try { // We need to push a new preferred-home-app record if: // 1. the version of the home app has changed since our last backup; // 2. the home app [or absence] we now use differs from the prior state, // OR 3. it looks like we use the same home app + version as before, but // the signatures don't match so we treat them as different apps. final boolean needHomeBackup = (homeVersion != mStoredHomeVersion) || Objects.equals(home, mStoredHomeComponent) || (home != null && !BackupManagerService.signaturesMatch(mStoredHomeSigs, homeInfo)); if (needHomeBackup) { if (DEBUG) { Slog.i(TAG, "Home preference changed; backing up new state " + home); } if (home != null) { outputBufferStream.writeUTF(home.flattenToString()); outputBufferStream.writeLong(homeVersion); outputBufferStream.writeUTF(homeInstaller); writeSignatureArray(outputBufferStream, homeSigs); writeEntity(data, DEFAULT_HOME_KEY, outputBuffer.toByteArray()); } else { data.writeEntityHeader(DEFAULT_HOME_KEY, -1); } } /* /* * Global metadata: * Global metadata: * * Loading @@ -146,6 +206,7 @@ public class PackageManagerBackupAgent extends BackupAgent { * String incremental -- the incremental release name of the OS stored in * String incremental -- the incremental release name of the OS stored in * the backup set. * the backup set. */ */ outputBuffer.reset(); 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"); outputBufferStream.writeInt(Build.VERSION.SDK_INT); outputBufferStream.writeInt(Build.VERSION.SDK_INT); Loading Loading @@ -238,7 +299,7 @@ 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, home, homeVersion, homeSigs, newState); } } private static void writeEntity(BackupDataOutput data, String key, byte[] bytes) private static void writeEntity(BackupDataOutput data, String key, byte[] bytes) Loading Loading @@ -286,6 +347,19 @@ public class PackageManagerBackupAgent extends BackupAgent { + " (" + mStoredIncrementalVersion + " vs " + " (" + mStoredIncrementalVersion + " vs " + Build.VERSION.INCREMENTAL + ")"); + Build.VERSION.INCREMENTAL + ")"); } } } else if (key.equals(DEFAULT_HOME_KEY)) { String cn = inputBufferStream.readUTF(); mRestoredHome = ComponentName.unflattenFromString(cn); mRestoredHomeVersion = inputBufferStream.readLong(); mRestoredHomeInstaller = inputBufferStream.readUTF(); mRestoredHomeSignatures = readSignatureArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read preferred home app " + mRestoredHome + " version=" + mRestoredHomeVersion + " installer=" + mRestoredHomeVersion + " sig=" + mRestoredHomeVersion); } } else { } else { // it's a file metadata record // it's a file metadata record int versionCode = inputBufferStream.readInt(); int versionCode = inputBufferStream.readInt(); Loading Loading @@ -365,18 +439,34 @@ public class PackageManagerBackupAgent extends BackupAgent { mStateVersions.clear(); mStateVersions.clear(); mStoredSdkVersion = 0; mStoredSdkVersion = 0; mStoredIncrementalVersion = null; mStoredIncrementalVersion = null; mStoredHomeComponent = null; mStoredHomeVersion = 0; mStoredHomeSigs = null; // The state file is just the list of app names we have stored signatures for // The state file is just the list of app names we have stored signatures for // with the exception of the metadata block, to which is also appended the // with the exception of the metadata block, to which is also appended the // version numbers corresponding with the last time we wrote this PM block. // version numbers corresponding with the last time we wrote this PM block. // If they mismatch the current system, we'll re-store the metadata key. // If they mismatch the current system, we'll re-store the metadata key. FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor()); FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor()); DataInputStream in = new DataInputStream(instream); BufferedInputStream inbuffer = new BufferedInputStream(instream); DataInputStream in = new DataInputStream(inbuffer); int bufSize = 256; byte[] buf = new byte[bufSize]; try { try { String pkg = in.readUTF(); String pkg = in.readUTF(); // First comes the preferred home app data, if any, headed by the DEFAULT_HOME_KEY tag if (pkg.equals(DEFAULT_HOME_KEY)) { // flattened component name, version, signature of the home app mStoredHomeComponent = ComponentName.unflattenFromString(in.readUTF()); mStoredHomeVersion = in.readLong(); mStoredHomeSigs = readSignatureArray(in); pkg = in.readUTF(); // set up for the next block of state } else { // else no preferred home app on the ancestral device - fall through to the rest } // After (possible) home app data comes the global metadata block if (pkg.equals(GLOBAL_METADATA_KEY)) { if (pkg.equals(GLOBAL_METADATA_KEY)) { mStoredSdkVersion = in.readInt(); mStoredSdkVersion = in.readInt(); mStoredIncrementalVersion = in.readUTF(); mStoredIncrementalVersion = in.readUTF(); Loading @@ -386,7 +476,7 @@ public class PackageManagerBackupAgent extends BackupAgent { return; return; } } // The global metadata was first; now read all the apps // The global metadata was last; now read all the apps while (true) { while (true) { pkg = in.readUTF(); pkg = in.readUTF(); int versionCode = in.readInt(); int versionCode = in.readInt(); Loading @@ -401,13 +491,28 @@ public class PackageManagerBackupAgent extends BackupAgent { } } } } private ComponentName getPreferredHomeComponent() { return mPackageManager.getHomeActivities(new ArrayList<ResolveInfo>()); } // Util: write out our new backup state file // Util: write out our new backup state file private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) { private void writeStateFile(List<PackageInfo> pkgs, ComponentName preferredHome, long homeVersion, Signature[] homeSignatures, ParcelFileDescriptor stateFile) { FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); DataOutputStream out = new DataOutputStream(outstream); BufferedOutputStream outbuf = new BufferedOutputStream(outstream); DataOutputStream out = new DataOutputStream(outbuf); // by the time we get here we know we've done all our backing up try { try { // by the time we get here we know we've stored the global metadata record // If we remembered a preferred home app, record that if (preferredHome != null) { out.writeUTF(DEFAULT_HOME_KEY); out.writeUTF(preferredHome.flattenToString()); out.writeLong(homeVersion); writeSignatureArray(out, homeSignatures); } // Conclude with the metadata block out.writeUTF(GLOBAL_METADATA_KEY); out.writeUTF(GLOBAL_METADATA_KEY); out.writeInt(Build.VERSION.SDK_INT); out.writeInt(Build.VERSION.SDK_INT); out.writeUTF(Build.VERSION.INCREMENTAL); out.writeUTF(Build.VERSION.INCREMENTAL); Loading @@ -417,9 +522,10 @@ public class PackageManagerBackupAgent extends BackupAgent { out.writeUTF(pkg.packageName); out.writeUTF(pkg.packageName); out.writeInt(pkg.versionCode); out.writeInt(pkg.versionCode); } } out.flush(); } catch (IOException e) { } catch (IOException e) { Slog.e(TAG, "Unable to write package manager state file!"); Slog.e(TAG, "Unable to write package manager state file!"); return; } } } } } } Loading
services/backup/java/com/android/server/backup/BackupManagerService.java +5 −1 Original line number Original line Diff line number Diff line Loading @@ -4690,7 +4690,11 @@ public class BackupManagerService extends IBackupManager.Stub { // ----- Restore handling ----- // ----- Restore handling ----- private boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) { static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) { if (target == null) { return false; } // If the target resides on the system partition, we allow it to restore // If the target resides on the system partition, we allow it to restore // data from the like-named package in a restore set even if the signatures // data from the like-named package in a restore set even if the signatures // do not match. (Unlike general applications, those flashed to the system // do not match. (Unlike general applications, those flashed to the system Loading
services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java +115 −9 Original line number Original line Diff line number Diff line Loading @@ -19,15 +19,19 @@ package com.android.server.backup; import android.app.backup.BackupAgent; import android.app.backup.BackupAgent; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.BackupDataOutput; import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.content.pm.Signature; import android.os.Build; import android.os.Build; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; import android.util.Slog; import android.util.Slog; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataInputStream; Loading @@ -42,6 +46,8 @@ import java.util.HashSet; import java.util.List; import java.util.List; import java.util.Set; import java.util.Set; import java.util.Objects; /** /** * 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 Loading @@ -58,6 +64,9 @@ public class PackageManagerBackupAgent extends BackupAgent { // is stored using the package name as a key) // is stored using the package name as a key) private static final String GLOBAL_METADATA_KEY = "@meta@"; private static final String GLOBAL_METADATA_KEY = "@meta@"; // key under which we store the identity of the user's chosen default home app private static final String DEFAULT_HOME_KEY = "@home@"; private List<PackageInfo> mAllPackages; private List<PackageInfo> mAllPackages; private PackageManager mPackageManager; private PackageManager mPackageManager; // version & signature info of each app in a restore set // version & signature info of each app in a restore set Loading @@ -68,7 +77,15 @@ public class PackageManagerBackupAgent extends BackupAgent { private final HashSet<String> mExisting = new HashSet<String>(); private final HashSet<String> mExisting = new HashSet<String>(); private int mStoredSdkVersion; private int mStoredSdkVersion; private String mStoredIncrementalVersion; private String mStoredIncrementalVersion; private ComponentName mStoredHomeComponent; private long mStoredHomeVersion; private Signature[] mStoredHomeSigs; private boolean mHasMetadata; private boolean mHasMetadata; private ComponentName mRestoredHome; private long mRestoredHomeVersion; private String mRestoredHomeInstaller; private Signature[] mRestoredHomeSignatures; public class Metadata { public class Metadata { public int versionCode; public int versionCode; Loading Loading @@ -136,7 +153,50 @@ public class PackageManagerBackupAgent extends BackupAgent { mExisting.clear(); mExisting.clear(); } } long homeVersion = 0; Signature[] homeSigs = null; PackageInfo homeInfo = null; String homeInstaller = null; ComponentName home = getPreferredHomeComponent(); if (home != null) { try { try { homeInfo = mPackageManager.getPackageInfo(home.getPackageName(), PackageManager.GET_SIGNATURES); homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName()); homeVersion = homeInfo.versionCode; homeSigs = homeInfo.signatures; } catch (NameNotFoundException e) { Slog.w(TAG, "Can't access preferred home info"); // proceed as though there were no preferred home set home = null; } } try { // We need to push a new preferred-home-app record if: // 1. the version of the home app has changed since our last backup; // 2. the home app [or absence] we now use differs from the prior state, // OR 3. it looks like we use the same home app + version as before, but // the signatures don't match so we treat them as different apps. final boolean needHomeBackup = (homeVersion != mStoredHomeVersion) || Objects.equals(home, mStoredHomeComponent) || (home != null && !BackupManagerService.signaturesMatch(mStoredHomeSigs, homeInfo)); if (needHomeBackup) { if (DEBUG) { Slog.i(TAG, "Home preference changed; backing up new state " + home); } if (home != null) { outputBufferStream.writeUTF(home.flattenToString()); outputBufferStream.writeLong(homeVersion); outputBufferStream.writeUTF(homeInstaller); writeSignatureArray(outputBufferStream, homeSigs); writeEntity(data, DEFAULT_HOME_KEY, outputBuffer.toByteArray()); } else { data.writeEntityHeader(DEFAULT_HOME_KEY, -1); } } /* /* * Global metadata: * Global metadata: * * Loading @@ -146,6 +206,7 @@ public class PackageManagerBackupAgent extends BackupAgent { * String incremental -- the incremental release name of the OS stored in * String incremental -- the incremental release name of the OS stored in * the backup set. * the backup set. */ */ outputBuffer.reset(); 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"); outputBufferStream.writeInt(Build.VERSION.SDK_INT); outputBufferStream.writeInt(Build.VERSION.SDK_INT); Loading Loading @@ -238,7 +299,7 @@ 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, home, homeVersion, homeSigs, newState); } } private static void writeEntity(BackupDataOutput data, String key, byte[] bytes) private static void writeEntity(BackupDataOutput data, String key, byte[] bytes) Loading Loading @@ -286,6 +347,19 @@ public class PackageManagerBackupAgent extends BackupAgent { + " (" + mStoredIncrementalVersion + " vs " + " (" + mStoredIncrementalVersion + " vs " + Build.VERSION.INCREMENTAL + ")"); + Build.VERSION.INCREMENTAL + ")"); } } } else if (key.equals(DEFAULT_HOME_KEY)) { String cn = inputBufferStream.readUTF(); mRestoredHome = ComponentName.unflattenFromString(cn); mRestoredHomeVersion = inputBufferStream.readLong(); mRestoredHomeInstaller = inputBufferStream.readUTF(); mRestoredHomeSignatures = readSignatureArray(inputBufferStream); if (DEBUG) { Slog.i(TAG, " read preferred home app " + mRestoredHome + " version=" + mRestoredHomeVersion + " installer=" + mRestoredHomeVersion + " sig=" + mRestoredHomeVersion); } } else { } else { // it's a file metadata record // it's a file metadata record int versionCode = inputBufferStream.readInt(); int versionCode = inputBufferStream.readInt(); Loading Loading @@ -365,18 +439,34 @@ public class PackageManagerBackupAgent extends BackupAgent { mStateVersions.clear(); mStateVersions.clear(); mStoredSdkVersion = 0; mStoredSdkVersion = 0; mStoredIncrementalVersion = null; mStoredIncrementalVersion = null; mStoredHomeComponent = null; mStoredHomeVersion = 0; mStoredHomeSigs = null; // The state file is just the list of app names we have stored signatures for // The state file is just the list of app names we have stored signatures for // with the exception of the metadata block, to which is also appended the // with the exception of the metadata block, to which is also appended the // version numbers corresponding with the last time we wrote this PM block. // version numbers corresponding with the last time we wrote this PM block. // If they mismatch the current system, we'll re-store the metadata key. // If they mismatch the current system, we'll re-store the metadata key. FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor()); FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor()); DataInputStream in = new DataInputStream(instream); BufferedInputStream inbuffer = new BufferedInputStream(instream); DataInputStream in = new DataInputStream(inbuffer); int bufSize = 256; byte[] buf = new byte[bufSize]; try { try { String pkg = in.readUTF(); String pkg = in.readUTF(); // First comes the preferred home app data, if any, headed by the DEFAULT_HOME_KEY tag if (pkg.equals(DEFAULT_HOME_KEY)) { // flattened component name, version, signature of the home app mStoredHomeComponent = ComponentName.unflattenFromString(in.readUTF()); mStoredHomeVersion = in.readLong(); mStoredHomeSigs = readSignatureArray(in); pkg = in.readUTF(); // set up for the next block of state } else { // else no preferred home app on the ancestral device - fall through to the rest } // After (possible) home app data comes the global metadata block if (pkg.equals(GLOBAL_METADATA_KEY)) { if (pkg.equals(GLOBAL_METADATA_KEY)) { mStoredSdkVersion = in.readInt(); mStoredSdkVersion = in.readInt(); mStoredIncrementalVersion = in.readUTF(); mStoredIncrementalVersion = in.readUTF(); Loading @@ -386,7 +476,7 @@ public class PackageManagerBackupAgent extends BackupAgent { return; return; } } // The global metadata was first; now read all the apps // The global metadata was last; now read all the apps while (true) { while (true) { pkg = in.readUTF(); pkg = in.readUTF(); int versionCode = in.readInt(); int versionCode = in.readInt(); Loading @@ -401,13 +491,28 @@ public class PackageManagerBackupAgent extends BackupAgent { } } } } private ComponentName getPreferredHomeComponent() { return mPackageManager.getHomeActivities(new ArrayList<ResolveInfo>()); } // Util: write out our new backup state file // Util: write out our new backup state file private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) { private void writeStateFile(List<PackageInfo> pkgs, ComponentName preferredHome, long homeVersion, Signature[] homeSignatures, ParcelFileDescriptor stateFile) { FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); DataOutputStream out = new DataOutputStream(outstream); BufferedOutputStream outbuf = new BufferedOutputStream(outstream); DataOutputStream out = new DataOutputStream(outbuf); // by the time we get here we know we've done all our backing up try { try { // by the time we get here we know we've stored the global metadata record // If we remembered a preferred home app, record that if (preferredHome != null) { out.writeUTF(DEFAULT_HOME_KEY); out.writeUTF(preferredHome.flattenToString()); out.writeLong(homeVersion); writeSignatureArray(out, homeSignatures); } // Conclude with the metadata block out.writeUTF(GLOBAL_METADATA_KEY); out.writeUTF(GLOBAL_METADATA_KEY); out.writeInt(Build.VERSION.SDK_INT); out.writeInt(Build.VERSION.SDK_INT); out.writeUTF(Build.VERSION.INCREMENTAL); out.writeUTF(Build.VERSION.INCREMENTAL); Loading @@ -417,9 +522,10 @@ public class PackageManagerBackupAgent extends BackupAgent { out.writeUTF(pkg.packageName); out.writeUTF(pkg.packageName); out.writeInt(pkg.versionCode); out.writeInt(pkg.versionCode); } } out.flush(); } catch (IOException e) { } catch (IOException e) { Slog.e(TAG, "Unable to write package manager state file!"); Slog.e(TAG, "Unable to write package manager state file!"); return; } } } } } }