From 3dda518a4fd57cdded3afa50d8aa206501de7fc6 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Wed, 24 Feb 2010 16:06:18 -0800 Subject: [PATCH] Add 'restoreAnyVersion' attr for apps that want to restore "future" data If a backup-participating app sets android:restoreAnyVersion="true" in its manifest tag, then its agent will be invoked for restore even if the available dataset was created by a later version of the app than is currently installed on the device. This will not typically be a problem for third party applications, since for them the installation and initial data restore are tightly coupled, but it can cause serious problems for applications which are both preinstalled on the system partition and overridden by later updates. The primary difficulty that this new attribute addresses is this: 1. User buys a Nexus One, Market self-updates, and the user installs some apps. At this point the backup data on the server may indicate that the version of Market which originated its bookkeeping is newer than the stock N1 Market app. 2. User loses their phone, and buys a replacement N1. At setup time, Market has not yet had a chance to self-update, so when the restore comes in, it's tagged as being from "the future" and so the restore is refused. No apps get reinstalled. Bug: 2442127 Change-Id: I076a9553dc613e5c3189350e778315718ed1ed2b --- api/current.xml | 13 ++++++++- .../android/content/pm/ApplicationInfo.java | 13 +++++++++ .../android/content/pm/PackageParser.java | 9 +++++-- core/res/res/values/attrs_manifest.xml | 20 +++++++++++--- core/res/res/values/public.xml | 1 + .../android/server/BackupManagerService.java | 27 ++++++++++++++----- 6 files changed, 70 insertions(+), 13 deletions(-) diff --git a/api/current.xml b/api/current.xml index 3af1426b99681..031506b558e84 100644 --- a/api/current.xml +++ b/api/current.xml @@ -6785,6 +6785,17 @@ visibility="public" > + + - + diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 2e405c107cffc..8773f59de1001 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -247,6 +247,19 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int FLAG_NATIVE_DEBUGGABLE = 1<<21; + /** + * Value for {@link #flags}: Set to true if the application's backup + * agent claims to be able to handle restore data even "from the future," + * i.e. from versions of the application with a versionCode greater than + * the one currently installed on the device. + * + *

If android:allowBackup is set to false or no android:backupAgent + * is specified, this flag will be ignored. + * + * {@hide} + */ + public static final int FLAG_RESTORE_ANY_VERSION = 1<<22; + /** * Flags associated with the application. Any combination of * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE}, diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 582356013452e..98aacaacf2f79 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1369,8 +1369,8 @@ public class PackageParser { if (allowBackup) { ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; - // backupAgent, killAfterRestore, and restoreNeedsApplication are only relevant - // if backup is possible for the given application. + // backupAgent, killAfterRestore, restoreNeedsApplication, and restoreAnyVersion + // are only relevant if backup is possible for the given application. String backupAgent = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestApplication_backupAgent); if (backupAgent != null) { @@ -1390,6 +1390,11 @@ public class PackageParser { false)) { ai.flags |= ApplicationInfo.FLAG_RESTORE_NEEDS_APPLICATION; } + if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion, + false)) { + ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION; + } } } diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index b3adf49c46113..d66f513a66dc1 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -593,12 +593,15 @@ + infrastructure. If this attribute is set to false, no backup + of the application will ever be performed, even by a full-system backup that + would otherwise cause all application data to be saved via adb. The + default value of this attribute is true. --> + settings have been restored. The default is true, + which means to do so. --> + + + @@ -700,6 +713,7 @@ + diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index b3343375e90f1..5da8e8585f104 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1231,6 +1231,7 @@ + diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index f79a02a9166e8..d4b28e20cd8f3 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -1647,11 +1647,22 @@ class BackupManagerService extends IBackupManager.Stub { } if (metaInfo.versionCode > packageInfo.versionCode) { - String message = "Version " + metaInfo.versionCode - + " > installed version " + packageInfo.versionCode; - Log.w(TAG, "Package " + packageName + ": " + message); - EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, message); - continue; + // Data is from a "newer" version of the app than we have currently + // installed. If the app has not declared that it is prepared to + // handle this case, we do not attempt the restore. + if ((packageInfo.applicationInfo.flags + & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) { + String message = "Version " + metaInfo.versionCode + + " > installed version " + packageInfo.versionCode; + Log.w(TAG, "Package " + packageName + ": " + message); + EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, + packageName, message); + continue; + } else { + if (DEBUG) Log.v(TAG, "Version " + metaInfo.versionCode + + " > installed " + packageInfo.versionCode + + " but restoreAnyVersion"); + } } if (!signaturesMatch(metaInfo.signatures, packageInfo)) { @@ -1695,8 +1706,10 @@ class BackupManagerService extends IBackupManager.Stub { // The agent was probably running with a stub Application object, // which isn't a valid run mode for the main app logic. Shut // down the app so that next time it's launched, it gets the - // usual full initialization. - if ((packageInfo.applicationInfo.flags + // usual full initialization. Note that this is only done for + // full-system restores: when a single app has requested a restore, + // it is explicitly not killed following that operation. + if (mTargetPackage == null && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) { if (DEBUG) Log.d(TAG, "Restore complete, killing host process of " + packageInfo.applicationInfo.processName);