Merge change 5006 into donut

* changes:
  Pass the originating app's versionCode along with a restore set
This commit is contained in:
Android (Google) Code Review
2009-06-22 16:47:06 -07:00
9 changed files with 48 additions and 22 deletions

View File

@@ -78,11 +78,16 @@ public abstract class BackupAgent extends ContextWrapper {
* *
* @param data An open, read-only ParcelFileDescriptor pointing to a full snapshot * @param data An open, read-only ParcelFileDescriptor pointing to a full snapshot
* of the application's data. * of the application's data.
* @param appVersionCode The android:versionCode value of the application that backed
* up this particular data set. This makes it easier for an application's
* agent to distinguish among several possible older data versions when
* asked to perform the restore operation.
* @param newState An open, read/write ParcelFileDescriptor pointing to an empty * @param newState An open, read/write ParcelFileDescriptor pointing to an empty
* file. The application should record the final backup state * file. The application should record the final backup state
* here after restoring its data from dataFd. * here after restoring its data from dataFd.
*/ */
public abstract void onRestore(BackupDataInput data, ParcelFileDescriptor newState) public abstract void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState)
throws IOException; throws IOException;
@@ -121,13 +126,13 @@ public abstract class BackupAgent extends ContextWrapper {
} }
} }
public void doRestore(ParcelFileDescriptor data, public void doRestore(ParcelFileDescriptor data, int appVersionCode,
ParcelFileDescriptor newState) throws RemoteException { ParcelFileDescriptor newState) throws RemoteException {
// !!! TODO - real implementation; for now just invoke the callbacks directly // !!! TODO - real implementation; for now just invoke the callbacks directly
Log.v(TAG, "doRestore() invoked"); Log.v(TAG, "doRestore() invoked");
BackupDataInput input = new BackupDataInput(data.getFileDescriptor()); BackupDataInput input = new BackupDataInput(data.getFileDescriptor());
try { try {
BackupAgent.this.onRestore(input, newState); BackupAgent.this.onRestore(input, appVersionCode, newState);
} catch (IOException ex) { } catch (IOException ex) {
Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex); Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
throw new RuntimeException(ex); throw new RuntimeException(ex);

View File

@@ -53,6 +53,6 @@ public class FullBackupAgent extends BackupAgent {
} }
@Override @Override
public void onRestore(BackupDataInput data, ParcelFileDescriptor newState) { public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) {
} }
} }

View File

@@ -51,9 +51,14 @@ interface IBackupAgent {
* app's backup. This is to be a <i>replacement</i> of the app's * app's backup. This is to be a <i>replacement</i> of the app's
* current data, not to be merged into it. * current data, not to be merged into it.
* *
* @param appVersionCode The android:versionCode attribute of the application
* that created this data set. This can help the agent distinguish among
* various historical backup content possibilities.
*
* @param newState Read-write file, empty when onRestore() is called, * @param newState Read-write file, empty when onRestore() is called,
* that is to be written with the state description that holds after * that is to be written with the state description that holds after
* the restore has been completed. * the restore has been completed.
*/ */
void doRestore(in ParcelFileDescriptor data, in ParcelFileDescriptor newState); void doRestore(in ParcelFileDescriptor data, int appVersionCode,
in ParcelFileDescriptor newState);
} }

View File

@@ -39,9 +39,9 @@ public class BackupHelperAgent extends BackupAgent {
} }
@Override @Override
public void onRestore(BackupDataInput data, ParcelFileDescriptor newState) public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
throws IOException { throws IOException {
mDispatcher.performRestore(data, newState); mDispatcher.performRestore(data, appVersionCode, newState);
} }
public BackupHelperDispatcher getDispatcher() { public BackupHelperDispatcher getDispatcher() {

View File

@@ -46,7 +46,8 @@ public class BackupHelperDispatcher {
} }
} }
public void performRestore(BackupDataInput input, ParcelFileDescriptor newState) public void performRestore(BackupDataInput input, int appVersionCode,
ParcelFileDescriptor newState)
throws IOException { throws IOException {
boolean alreadyComplained = false; boolean alreadyComplained = false;

View File

@@ -33,19 +33,19 @@ interface IBackupManager {
* Tell the system service that the caller has made changes to its * Tell the system service that the caller has made changes to its
* data, and therefore needs to undergo an incremental backup pass. * data, and therefore needs to undergo an incremental backup pass.
*/ */
oneway void dataChanged(String packageName); void dataChanged(String packageName);
/** /**
* Notifies the Backup Manager Service that an agent has become available. This * Notifies the Backup Manager Service that an agent has become available. This
* method is only invoked by the Activity Manager. * method is only invoked by the Activity Manager.
*/ */
oneway void agentConnected(String packageName, IBinder agent); void agentConnected(String packageName, IBinder agent);
/** /**
* Notify the Backup Manager Service that an agent has unexpectedly gone away. * Notify the Backup Manager Service that an agent has unexpectedly gone away.
* This method is only invoked by the Activity Manager. * This method is only invoked by the Activity Manager.
*/ */
oneway void agentDisconnected(String packageName); void agentDisconnected(String packageName);
/** /**
* Schedule an immediate backup attempt for all pending updates. This is * Schedule an immediate backup attempt for all pending updates. This is
@@ -57,7 +57,7 @@ interface IBackupManager {
* *
* <p>Callers must hold the android.permission.BACKUP permission to use this method. * <p>Callers must hold the android.permission.BACKUP permission to use this method.
*/ */
oneway void backupNow(); void backupNow();
/** /**
* Identify the currently selected transport. Callers must hold the * Identify the currently selected transport. Callers must hold the

View File

@@ -795,6 +795,16 @@ class BackupManagerService extends IBackupManager.Stub {
private int mToken; private int mToken;
private RestoreSet mImage; private RestoreSet mImage;
class RestoreRequest {
public PackageInfo app;
public int storedAppVersion;
RestoreRequest(PackageInfo _app, int _version) {
app = _app;
storedAppVersion = _version;
}
}
PerformRestoreThread(IBackupTransport transport, int restoreSetToken) { PerformRestoreThread(IBackupTransport transport, int restoreSetToken) {
mTransport = transport; mTransport = transport;
mToken = restoreSetToken; mToken = restoreSetToken;
@@ -840,11 +850,13 @@ class BackupManagerService extends IBackupManager.Stub {
mPackageManager, allAgentApps()); mPackageManager, allAgentApps());
PackageInfo pmApp = new PackageInfo(); PackageInfo pmApp = new PackageInfo();
pmApp.packageName = PACKAGE_MANAGER_SENTINEL; pmApp.packageName = PACKAGE_MANAGER_SENTINEL;
processOneRestore(pmApp, IBackupAgent.Stub.asInterface(pmAgent.onBind())); // !!! TODO: version currently ignored when 'restoring' the PM metadata
processOneRestore(pmApp, 0,
IBackupAgent.Stub.asInterface(pmAgent.onBind()));
// build the set of apps we will attempt to restore // build the set of apps we will attempt to restore
PackageInfo[] packages = mTransport.getAppSet(mImage.token); PackageInfo[] packages = mTransport.getAppSet(mImage.token);
HashSet<PackageInfo> appsToRestore = new HashSet<PackageInfo>(); HashSet<RestoreRequest> appsToRestore = new HashSet<RestoreRequest>();
for (PackageInfo pkg: packages) { for (PackageInfo pkg: packages) {
// get the real PackageManager idea of the package // get the real PackageManager idea of the package
PackageInfo app = isRestorable(pkg); PackageInfo app = isRestorable(pkg);
@@ -858,7 +870,8 @@ class BackupManagerService extends IBackupManager.Stub {
+ " compatible with app version " + " compatible with app version "
+ app.versionCode); + app.versionCode);
if (signaturesMatch(info.signatures, app.signatures)) { if (signaturesMatch(info.signatures, app.signatures)) {
appsToRestore.add(app); appsToRestore.add(
new RestoreRequest(app, info.versionCode));
} else { } else {
Log.w(TAG, "Sig mismatch restoring " Log.w(TAG, "Sig mismatch restoring "
+ app.packageName); + app.packageName);
@@ -896,8 +909,9 @@ class BackupManagerService extends IBackupManager.Stub {
} }
// restore each app in the queue // restore each app in the queue
void doQueuedRestores(HashSet<PackageInfo> appsToRestore) { void doQueuedRestores(HashSet<RestoreRequest> appsToRestore) {
for (PackageInfo app : appsToRestore) { for (RestoreRequest req : appsToRestore) {
PackageInfo app = req.app;
Log.d(TAG, "starting agent for restore of " + app); Log.d(TAG, "starting agent for restore of " + app);
try { try {
@@ -908,7 +922,7 @@ class BackupManagerService extends IBackupManager.Stub {
IBackupAgent agent = bindToAgentSynchronous(app.applicationInfo, IBackupAgent agent = bindToAgentSynchronous(app.applicationInfo,
IApplicationThread.BACKUP_MODE_RESTORE); IApplicationThread.BACKUP_MODE_RESTORE);
if (agent != null) { if (agent != null) {
processOneRestore(app, agent); processOneRestore(app, req.storedAppVersion, agent);
} }
// unbind even on timeout, just in case // unbind even on timeout, just in case
@@ -925,7 +939,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Do the guts of a restore of one application, derived from the 'mImage' // Do the guts of a restore of one application, derived from the 'mImage'
// restore set via the 'mTransport' transport. // restore set via the 'mTransport' transport.
void processOneRestore(PackageInfo app, IBackupAgent agent) { void processOneRestore(PackageInfo app, int storedAppVersion, IBackupAgent agent) {
// !!! TODO: actually run the restore through mTransport // !!! TODO: actually run the restore through mTransport
final String packageName = app.packageName; final String packageName = app.packageName;
@@ -961,7 +975,7 @@ class BackupManagerService extends IBackupManager.Stub {
boolean success = false; boolean success = false;
try { try {
agent.doRestore(backupData, newState); agent.doRestore(backupData, storedAppVersion, newState);
success = true; success = true;
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Restore failed for " + packageName); Log.e(TAG, "Restore failed for " + packageName);

View File

@@ -192,7 +192,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
// "Restore" here is a misnomer. What we're really doing is reading back the // "Restore" here is a misnomer. What we're really doing is reading back the
// set of app signatures associated with each backed-up app in this restore // set of app signatures associated with each backed-up app in this restore
// image. We'll use those later to determine what we can legitimately restore. // image. We'll use those later to determine what we can legitimately restore.
public void onRestore(BackupDataInput data, ParcelFileDescriptor newState) public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
throws IOException { throws IOException {
List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();

View File

@@ -164,7 +164,8 @@ public class BackupTestActivity extends ListActivity
new File(getFilesDir(), "restore_state"), new File(getFilesDir(), "restore_state"),
ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE| ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE|
ParcelFileDescriptor.MODE_TRUNCATE); ParcelFileDescriptor.MODE_TRUNCATE);
dispatch.performRestore(data, state); // TODO: a more plausable synthetic stored-data version number
dispatch.performRestore(data, 0, state);
dataFile.close(); dataFile.close();
state.close(); state.close();
} catch (IOException ex) { } catch (IOException ex) {