Pass the originating app's versionCode along with a restore set
This change amends the doRestore() / onRestore() interface to backup agents to provide the integer android:versionCode of the app that stored the backup set. This should help agents figure out how to handle whatever historical data set they're handed at restore time.
This commit is contained in:
@@ -78,11 +78,16 @@ public abstract class BackupAgent extends ContextWrapper {
|
||||
*
|
||||
* @param data An open, read-only ParcelFileDescriptor pointing to a full snapshot
|
||||
* 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
|
||||
* file. The application should record the final backup state
|
||||
* 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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
// !!! TODO - real implementation; for now just invoke the callbacks directly
|
||||
Log.v(TAG, "doRestore() invoked");
|
||||
BackupDataInput input = new BackupDataInput(data.getFileDescriptor());
|
||||
try {
|
||||
BackupAgent.this.onRestore(input, newState);
|
||||
BackupAgent.this.onRestore(input, appVersionCode, newState);
|
||||
} catch (IOException ex) {
|
||||
Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
|
||||
throw new RuntimeException(ex);
|
||||
|
||||
@@ -53,6 +53,6 @@ public class FullBackupAgent extends BackupAgent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestore(BackupDataInput data, ParcelFileDescriptor newState) {
|
||||
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,9 +51,14 @@ interface IBackupAgent {
|
||||
* app's backup. This is to be a <i>replacement</i> of the app's
|
||||
* 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,
|
||||
* that is to be written with the state description that holds after
|
||||
* the restore has been completed.
|
||||
*/
|
||||
void doRestore(in ParcelFileDescriptor data, in ParcelFileDescriptor newState);
|
||||
void doRestore(in ParcelFileDescriptor data, int appVersionCode,
|
||||
in ParcelFileDescriptor newState);
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ public class BackupHelperAgent extends BackupAgent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestore(BackupDataInput data, ParcelFileDescriptor newState)
|
||||
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
|
||||
throws IOException {
|
||||
mDispatcher.performRestore(data, newState);
|
||||
mDispatcher.performRestore(data, appVersionCode, newState);
|
||||
}
|
||||
|
||||
public BackupHelperDispatcher getDispatcher() {
|
||||
|
||||
@@ -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 {
|
||||
boolean alreadyComplained = false;
|
||||
|
||||
|
||||
@@ -33,19 +33,19 @@ interface IBackupManager {
|
||||
* Tell the system service that the caller has made changes to its
|
||||
* 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
|
||||
* 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.
|
||||
* 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
|
||||
@@ -57,7 +57,7 @@ interface IBackupManager {
|
||||
*
|
||||
* <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
|
||||
|
||||
@@ -795,6 +795,16 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
private int mToken;
|
||||
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) {
|
||||
mTransport = transport;
|
||||
mToken = restoreSetToken;
|
||||
@@ -840,11 +850,13 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
mPackageManager, allAgentApps());
|
||||
PackageInfo pmApp = new PackageInfo();
|
||||
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
|
||||
PackageInfo[] packages = mTransport.getAppSet(mImage.token);
|
||||
HashSet<PackageInfo> appsToRestore = new HashSet<PackageInfo>();
|
||||
HashSet<RestoreRequest> appsToRestore = new HashSet<RestoreRequest>();
|
||||
for (PackageInfo pkg: packages) {
|
||||
// get the real PackageManager idea of the package
|
||||
PackageInfo app = isRestorable(pkg);
|
||||
@@ -858,7 +870,8 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
+ " compatible with app version "
|
||||
+ app.versionCode);
|
||||
if (signaturesMatch(info.signatures, app.signatures)) {
|
||||
appsToRestore.add(app);
|
||||
appsToRestore.add(
|
||||
new RestoreRequest(app, info.versionCode));
|
||||
} else {
|
||||
Log.w(TAG, "Sig mismatch restoring "
|
||||
+ app.packageName);
|
||||
@@ -896,8 +909,9 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
}
|
||||
|
||||
// restore each app in the queue
|
||||
void doQueuedRestores(HashSet<PackageInfo> appsToRestore) {
|
||||
for (PackageInfo app : appsToRestore) {
|
||||
void doQueuedRestores(HashSet<RestoreRequest> appsToRestore) {
|
||||
for (RestoreRequest req : appsToRestore) {
|
||||
PackageInfo app = req.app;
|
||||
Log.d(TAG, "starting agent for restore of " + app);
|
||||
|
||||
try {
|
||||
@@ -908,7 +922,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
IBackupAgent agent = bindToAgentSynchronous(app.applicationInfo,
|
||||
IApplicationThread.BACKUP_MODE_RESTORE);
|
||||
if (agent != null) {
|
||||
processOneRestore(app, agent);
|
||||
processOneRestore(app, req.storedAppVersion, agent);
|
||||
}
|
||||
|
||||
// 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'
|
||||
// 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
|
||||
final String packageName = app.packageName;
|
||||
|
||||
@@ -961,7 +975,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
|
||||
boolean success = false;
|
||||
try {
|
||||
agent.doRestore(backupData, newState);
|
||||
agent.doRestore(backupData, storedAppVersion, newState);
|
||||
success = true;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Restore failed for " + packageName);
|
||||
|
||||
@@ -192,7 +192,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
|
||||
// "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
|
||||
// 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 {
|
||||
List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
|
||||
HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();
|
||||
|
||||
@@ -164,7 +164,8 @@ public class BackupTestActivity extends ListActivity
|
||||
new File(getFilesDir(), "restore_state"),
|
||||
ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE|
|
||||
ParcelFileDescriptor.MODE_TRUNCATE);
|
||||
dispatch.performRestore(data, state);
|
||||
// TODO: a more plausable synthetic stored-data version number
|
||||
dispatch.performRestore(data, 0, state);
|
||||
dataFile.close();
|
||||
state.close();
|
||||
} catch (IOException ex) {
|
||||
|
||||
Reference in New Issue
Block a user