Loading packages/BackupRestoreConfirmation/AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ <uses-permission android:name="android.permission.BACKUP" /> <application android:allowClearUserData="false" android:killAfterRestore="false" android:allowBackup="false" android:permission="android.permission.CONFIRM_FULL_BACKUP" > <activity android:name=".BackupRestoreConfirmation" Loading services/java/com/android/server/BackupManagerService.java +118 −21 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; Loading Loading @@ -1709,6 +1710,16 @@ class BackupManagerService extends IBackupManager.Stub { } } // Cull any packages that have indicated that backups are not permitted. for (int i = 0; i < packagesToBackup.size(); ) { PackageInfo info = packagesToBackup.get(i); if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { packagesToBackup.remove(i); } else { i++; } } // Now back up the app data via the agent mechanism PackageInfo pkg = null; try { Loading Loading @@ -1937,7 +1948,6 @@ class BackupManagerService extends IBackupManager.Stub { // Which packages we've already wiped data on. We prepopulate this // with a whitelist of packages known to be unclearable. mClearedPackages.add("android"); mClearedPackages.add("com.android.backupconfirm"); mClearedPackages.add("com.android.providers.settings"); } Loading Loading @@ -2314,6 +2324,7 @@ class BackupManagerService extends IBackupManager.Stub { class RestoreInstallObserver extends IPackageInstallObserver.Stub { final AtomicBoolean mDone = new AtomicBoolean(); String mPackageName; int mResult; public void reset() { Loading Loading @@ -2341,12 +2352,45 @@ class BackupManagerService extends IBackupManager.Stub { throws RemoteException { synchronized (mDone) { mResult = returnCode; mPackageName = packageName; mDone.set(true); mDone.notifyAll(); } } } class RestoreDeleteObserver extends IPackageDeleteObserver.Stub { final AtomicBoolean mDone = new AtomicBoolean(); int mResult; public void reset() { synchronized (mDone) { mDone.set(false); } } public void waitForCompletion() { synchronized (mDone) { while (mDone.get() == false) { try { mDone.wait(); } catch (InterruptedException e) { } } } } @Override public void packageDeleted(String packageName, int returnCode) throws RemoteException { synchronized (mDone) { mResult = returnCode; mDone.set(true); mDone.notifyAll(); } } } final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver(); final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver(); boolean installApk(FileMetadata info, String installerPackage, InputStream instream) { boolean okay = true; Loading Loading @@ -2385,6 +2429,49 @@ class BackupManagerService extends IBackupManager.Stub { if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) { okay = false; } } else { // Okay, the install succeeded. Make sure it was the right app. boolean uninstall = false; if (!mInstallObserver.mPackageName.equals(info.packageName)) { Slog.w(TAG, "Restore stream claimed to include apk for " + info.packageName + " but apk was really " + mInstallObserver.mPackageName); // delete the package we just put in place; it might be fraudulent okay = false; uninstall = true; } else { try { PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName, PackageManager.GET_SIGNATURES); if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { Slog.w(TAG, "Restore stream contains apk of package " + info.packageName + " but it disallows backup/restore"); okay = false; } else { // So far so good -- do the signatures match the manifest? Signature[] sigs = mManifestSignatures.get(info.packageName); if (!signaturesMatch(sigs, pkg)) { Slog.w(TAG, "Installed app " + info.packageName + " signatures do not match restore manifest"); okay = false; uninstall = true; } } } catch (NameNotFoundException e) { Slog.w(TAG, "Install of package " + info.packageName + " succeeded but now not found"); okay = false; } } // If we're not okay at this point, we need to delete the package // that we just installed. if (uninstall) { mDeleteObserver.reset(); mPackageManager.deletePackage(mInstallObserver.mPackageName, mDeleteObserver, 0); mDeleteObserver.waitForCompletion(); } } } catch (IOException e) { Slog.e(TAG, "Unable to transcribe restored apk for install"); Loading Loading @@ -2441,16 +2528,21 @@ class BackupManagerService extends IBackupManager.Stub { boolean hasApk = str[0].equals("1"); offset = extractLine(buffer, offset, str); int numSigs = Integer.parseInt(str[0]); Signature[] sigs = null; if (numSigs > 0) { sigs = new Signature[numSigs]; Signature[] sigs = new Signature[numSigs]; for (int i = 0; i < numSigs; i++) { offset = extractLine(buffer, offset, str); sigs[i] = new Signature(str[0]); } mManifestSignatures.put(info.packageName, sigs); // Okay, got the manifest info we need... try { PackageInfo pkgInfo = mPackageManager.getPackageInfo( info.packageName, PackageManager.GET_SIGNATURES); // Fall through to IGNORE if the app explicitly disallows backup final int flags = pkgInfo.applicationInfo.flags; if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { // Verify signatures against any installed version; if they // don't match, then we fall though and ignore the data. The // signatureMatch() method explicitly ignores the signature Loading @@ -2458,8 +2550,6 @@ class BackupManagerService extends IBackupManager.Stub { // such packages are signed with the platform cert instead of // the app developer's cert, so they're different on every // device. PackageInfo pkgInfo = mPackageManager.getPackageInfo( info.packageName, PackageManager.GET_SIGNATURES); if (signaturesMatch(sigs, pkgInfo)) { if (pkgInfo.versionCode >= version) { Slog.i(TAG, "Sig + version match; taking data"); Loading @@ -2473,6 +2563,13 @@ class BackupManagerService extends IBackupManager.Stub { + pkgInfo.versionCode + " - requiring apk"); policy = RestorePolicy.ACCEPT_IF_APK; } } else { Slog.w(TAG, "Restore manifest signatures do not match " + "installed application for " + info.packageName); } } else { if (DEBUG) Slog.i(TAG, "Restore manifest from " + info.packageName + " but allowBackup=false"); } } catch (NameNotFoundException e) { // Okay, the target app isn't installed. We can process Loading Loading
packages/BackupRestoreConfirmation/AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ <uses-permission android:name="android.permission.BACKUP" /> <application android:allowClearUserData="false" android:killAfterRestore="false" android:allowBackup="false" android:permission="android.permission.CONFIRM_FULL_BACKUP" > <activity android:name=".BackupRestoreConfirmation" Loading
services/java/com/android/server/BackupManagerService.java +118 −21 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; Loading Loading @@ -1709,6 +1710,16 @@ class BackupManagerService extends IBackupManager.Stub { } } // Cull any packages that have indicated that backups are not permitted. for (int i = 0; i < packagesToBackup.size(); ) { PackageInfo info = packagesToBackup.get(i); if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { packagesToBackup.remove(i); } else { i++; } } // Now back up the app data via the agent mechanism PackageInfo pkg = null; try { Loading Loading @@ -1937,7 +1948,6 @@ class BackupManagerService extends IBackupManager.Stub { // Which packages we've already wiped data on. We prepopulate this // with a whitelist of packages known to be unclearable. mClearedPackages.add("android"); mClearedPackages.add("com.android.backupconfirm"); mClearedPackages.add("com.android.providers.settings"); } Loading Loading @@ -2314,6 +2324,7 @@ class BackupManagerService extends IBackupManager.Stub { class RestoreInstallObserver extends IPackageInstallObserver.Stub { final AtomicBoolean mDone = new AtomicBoolean(); String mPackageName; int mResult; public void reset() { Loading Loading @@ -2341,12 +2352,45 @@ class BackupManagerService extends IBackupManager.Stub { throws RemoteException { synchronized (mDone) { mResult = returnCode; mPackageName = packageName; mDone.set(true); mDone.notifyAll(); } } } class RestoreDeleteObserver extends IPackageDeleteObserver.Stub { final AtomicBoolean mDone = new AtomicBoolean(); int mResult; public void reset() { synchronized (mDone) { mDone.set(false); } } public void waitForCompletion() { synchronized (mDone) { while (mDone.get() == false) { try { mDone.wait(); } catch (InterruptedException e) { } } } } @Override public void packageDeleted(String packageName, int returnCode) throws RemoteException { synchronized (mDone) { mResult = returnCode; mDone.set(true); mDone.notifyAll(); } } } final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver(); final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver(); boolean installApk(FileMetadata info, String installerPackage, InputStream instream) { boolean okay = true; Loading Loading @@ -2385,6 +2429,49 @@ class BackupManagerService extends IBackupManager.Stub { if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) { okay = false; } } else { // Okay, the install succeeded. Make sure it was the right app. boolean uninstall = false; if (!mInstallObserver.mPackageName.equals(info.packageName)) { Slog.w(TAG, "Restore stream claimed to include apk for " + info.packageName + " but apk was really " + mInstallObserver.mPackageName); // delete the package we just put in place; it might be fraudulent okay = false; uninstall = true; } else { try { PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName, PackageManager.GET_SIGNATURES); if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { Slog.w(TAG, "Restore stream contains apk of package " + info.packageName + " but it disallows backup/restore"); okay = false; } else { // So far so good -- do the signatures match the manifest? Signature[] sigs = mManifestSignatures.get(info.packageName); if (!signaturesMatch(sigs, pkg)) { Slog.w(TAG, "Installed app " + info.packageName + " signatures do not match restore manifest"); okay = false; uninstall = true; } } } catch (NameNotFoundException e) { Slog.w(TAG, "Install of package " + info.packageName + " succeeded but now not found"); okay = false; } } // If we're not okay at this point, we need to delete the package // that we just installed. if (uninstall) { mDeleteObserver.reset(); mPackageManager.deletePackage(mInstallObserver.mPackageName, mDeleteObserver, 0); mDeleteObserver.waitForCompletion(); } } } catch (IOException e) { Slog.e(TAG, "Unable to transcribe restored apk for install"); Loading Loading @@ -2441,16 +2528,21 @@ class BackupManagerService extends IBackupManager.Stub { boolean hasApk = str[0].equals("1"); offset = extractLine(buffer, offset, str); int numSigs = Integer.parseInt(str[0]); Signature[] sigs = null; if (numSigs > 0) { sigs = new Signature[numSigs]; Signature[] sigs = new Signature[numSigs]; for (int i = 0; i < numSigs; i++) { offset = extractLine(buffer, offset, str); sigs[i] = new Signature(str[0]); } mManifestSignatures.put(info.packageName, sigs); // Okay, got the manifest info we need... try { PackageInfo pkgInfo = mPackageManager.getPackageInfo( info.packageName, PackageManager.GET_SIGNATURES); // Fall through to IGNORE if the app explicitly disallows backup final int flags = pkgInfo.applicationInfo.flags; if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { // Verify signatures against any installed version; if they // don't match, then we fall though and ignore the data. The // signatureMatch() method explicitly ignores the signature Loading @@ -2458,8 +2550,6 @@ class BackupManagerService extends IBackupManager.Stub { // such packages are signed with the platform cert instead of // the app developer's cert, so they're different on every // device. PackageInfo pkgInfo = mPackageManager.getPackageInfo( info.packageName, PackageManager.GET_SIGNATURES); if (signaturesMatch(sigs, pkgInfo)) { if (pkgInfo.versionCode >= version) { Slog.i(TAG, "Sig + version match; taking data"); Loading @@ -2473,6 +2563,13 @@ class BackupManagerService extends IBackupManager.Stub { + pkgInfo.versionCode + " - requiring apk"); policy = RestorePolicy.ACCEPT_IF_APK; } } else { Slog.w(TAG, "Restore manifest signatures do not match " + "installed application for " + info.packageName); } } else { if (DEBUG) Slog.i(TAG, "Restore manifest from " + info.packageName + " but allowBackup=false"); } } catch (NameNotFoundException e) { // Okay, the target app isn't installed. We can process Loading