summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/BackupManagerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/BackupManagerService.java')
-rw-r--r--services/java/com/android/server/BackupManagerService.java516
1 files changed, 265 insertions, 251 deletions
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 197404e..bbebba3 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -47,6 +47,7 @@ import android.util.Log;
import android.util.SparseArray;
import android.backup.IBackupManager;
+import android.backup.IRestoreObserver;
import android.backup.IRestoreSession;
import android.backup.BackupManager;
import android.backup.RestoreSet;
@@ -76,12 +77,12 @@ class BackupManagerService extends IBackupManager.Stub {
private static final boolean DEBUG = true;
// Default time to wait after data changes before we back up the data
- private static final long COLLECTION_INTERVAL = 1000;
- //private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
+ private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
private static final int MSG_RUN_BACKUP = 1;
private static final int MSG_RUN_FULL_BACKUP = 2;
private static final int MSG_RUN_RESTORE = 3;
+ private static final String RESTORE_OBSERVER_KEY = "_resOb";
// Timeout interval for deciding that a bind or clear-data has taken too long
static final long TIMEOUT_INTERVAL = 10 * 1000;
@@ -110,8 +111,8 @@ class BackupManagerService extends IBackupManager.Stub {
// Backups that we haven't started yet.
private HashMap<ApplicationInfo,BackupRequest> mPendingBackups
= new HashMap<ApplicationInfo,BackupRequest>();
- // Do we need to back up the package manager metadata on the next pass?
- private boolean mDoPackageManager;
+
+ // Pseudoname that we use for the Package Manager metadata "package"
private static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
// locking around the pending-backup management
@@ -134,7 +135,20 @@ class BackupManagerService extends IBackupManager.Stub {
private IBackupTransport mLocalTransport, mGoogleTransport;
private RestoreSession mActiveRestoreSession;
- private File mStateDir;
+ private class RestoreParams {
+ public IBackupTransport transport;
+ public IRestoreObserver observer;
+ public long token;
+
+ RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token) {
+ transport = _transport;
+ observer = _obs;
+ token = _token;
+ }
+ }
+
+ // Where we keep our journal files and other bookkeeping
+ private File mBaseStateDir;
private File mDataDir;
private File mJournalDir;
private File mJournal;
@@ -146,13 +160,12 @@ class BackupManagerService extends IBackupManager.Stub {
mActivityManager = ActivityManagerNative.getDefault();
// Set up our bookkeeping
- mStateDir = new File(Environment.getDataDirectory(), "backup");
- mStateDir.mkdirs();
+ mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
mDataDir = Environment.getDownloadCacheDirectory();
// Set up the backup-request journaling
- mJournalDir = new File(mStateDir, "pending");
- mJournalDir.mkdirs();
+ mJournalDir = new File(mBaseStateDir, "pending");
+ mJournalDir.mkdirs(); // creates mBaseStateDir along the way
makeJournalLocked(); // okay because no other threads are running yet
// Build our mapping of uid to backup client services. This implicitly
@@ -165,8 +178,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Set up our transport options and initialize the default transport
// TODO: Have transports register themselves somehow?
// TODO: Don't create transports that we don't need to?
- mTransportId = BackupManager.TRANSPORT_LOCAL;
- //mTransportId = BackupManager.TRANSPORT_GOOGLE;
+ mTransportId = BackupManager.TRANSPORT_GOOGLE;
mLocalTransport = new LocalTransport(context); // This is actually pretty cheap
mGoogleTransport = null;
@@ -337,9 +349,8 @@ class BackupManagerService extends IBackupManager.Stub {
case MSG_RUN_RESTORE:
{
- int token = msg.arg1;
- IBackupTransport transport = (IBackupTransport)msg.obj;
- (new PerformRestoreThread(transport, token)).start();
+ RestoreParams params = (RestoreParams)msg.obj;
+ (new PerformRestoreThread(params.transport, params.observer, params.token)).start();
break;
}
}
@@ -351,29 +362,29 @@ class BackupManagerService extends IBackupManager.Stub {
void addPackageParticipantsLocked(String packageName) {
// Look for apps that define the android:backupAgent attribute
if (DEBUG) Log.v(TAG, "addPackageParticipantsLocked: " + packageName);
- List<ApplicationInfo> targetApps = allAgentApps();
+ List<PackageInfo> targetApps = allAgentPackages();
addPackageParticipantsLockedInner(packageName, targetApps);
}
private void addPackageParticipantsLockedInner(String packageName,
- List<ApplicationInfo> targetApps) {
+ List<PackageInfo> targetPkgs) {
if (DEBUG) {
- Log.v(TAG, "Adding " + targetApps.size() + " backup participants:");
- for (ApplicationInfo a : targetApps) {
- Log.v(TAG, " " + a + " agent=" + a.backupAgentName);
+ Log.v(TAG, "Adding " + targetPkgs.size() + " backup participants:");
+ for (PackageInfo p : targetPkgs) {
+ Log.v(TAG, " " + p + " agent=" + p.applicationInfo.backupAgentName
+ + " uid=" + p.applicationInfo.uid);
}
}
- for (ApplicationInfo app : targetApps) {
- if (packageName == null || app.packageName.equals(packageName)) {
- int uid = app.uid;
+ for (PackageInfo pkg : targetPkgs) {
+ if (packageName == null || pkg.packageName.equals(packageName)) {
+ int uid = pkg.applicationInfo.uid;
HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
if (set == null) {
set = new HashSet<ApplicationInfo>();
mBackupParticipants.put(uid, set);
}
- set.add(app);
- backUpPackageManagerData();
+ set.add(pkg.applicationInfo);
}
}
}
@@ -382,67 +393,66 @@ class BackupManagerService extends IBackupManager.Stub {
// 'packageName' is null, *all* participating apps will be removed.
void removePackageParticipantsLocked(String packageName) {
if (DEBUG) Log.v(TAG, "removePackageParticipantsLocked: " + packageName);
- List<ApplicationInfo> allApps = null;
+ List<PackageInfo> allApps = null;
if (packageName != null) {
- allApps = new ArrayList<ApplicationInfo>();
+ allApps = new ArrayList<PackageInfo>();
try {
- ApplicationInfo app = mPackageManager.getApplicationInfo(packageName, 0);
- allApps.add(app);
+ int flags = PackageManager.GET_SIGNATURES;
+ allApps.add(mPackageManager.getPackageInfo(packageName, flags));
} catch (Exception e) {
- // just skip it
+ // just skip it (???)
}
} else {
// all apps with agents
- allApps = allAgentApps();
+ allApps = allAgentPackages();
}
removePackageParticipantsLockedInner(packageName, allApps);
}
private void removePackageParticipantsLockedInner(String packageName,
- List<ApplicationInfo> agents) {
+ List<PackageInfo> agents) {
if (DEBUG) {
Log.v(TAG, "removePackageParticipantsLockedInner (" + packageName
+ ") removing " + agents.size() + " entries");
- for (ApplicationInfo a : agents) {
- Log.v(TAG, " - " + a);
+ for (PackageInfo p : agents) {
+ Log.v(TAG, " - " + p);
}
}
- for (ApplicationInfo app : agents) {
- if (packageName == null || app.packageName.equals(packageName)) {
- int uid = app.uid;
+ for (PackageInfo pkg : agents) {
+ if (packageName == null || pkg.packageName.equals(packageName)) {
+ int uid = pkg.applicationInfo.uid;
HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
if (set != null) {
// Find the existing entry with the same package name, and remove it.
// We can't just remove(app) because the instances are different.
for (ApplicationInfo entry: set) {
- if (entry.packageName.equals(app.packageName)) {
+ if (entry.packageName.equals(pkg.packageName)) {
set.remove(entry);
- backUpPackageManagerData();
break;
}
}
if (set.size() == 0) {
- mBackupParticipants.delete(uid); }
+ mBackupParticipants.delete(uid);
+ }
}
}
}
}
// Returns the set of all applications that define an android:backupAgent attribute
- private List<ApplicationInfo> allAgentApps() {
+ private List<PackageInfo> allAgentPackages() {
// !!! TODO: cache this and regenerate only when necessary
- List<ApplicationInfo> allApps = mPackageManager.getInstalledApplications(0);
- int N = allApps.size();
- if (N > 0) {
- for (int a = N-1; a >= 0; a--) {
- ApplicationInfo app = allApps.get(a);
- if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
- || app.backupAgentName == null) {
- allApps.remove(a);
- }
+ int flags = PackageManager.GET_SIGNATURES;
+ List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
+ int N = packages.size();
+ for (int a = N-1; a >= 0; a--) {
+ ApplicationInfo app = packages.get(a).applicationInfo;
+ if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
+ || app.backupAgentName == null) {
+ packages.remove(a);
}
}
- return allApps;
+ return packages;
}
// Reset the given package's known backup participants. Unlike add/remove, the update
@@ -455,19 +465,11 @@ class BackupManagerService extends IBackupManager.Stub {
if (DEBUG) Log.v(TAG, "updatePackageParticipantsLocked: " + packageName);
// brute force but small code size
- List<ApplicationInfo> allApps = allAgentApps();
+ List<PackageInfo> allApps = allAgentPackages();
removePackageParticipantsLockedInner(packageName, allApps);
addPackageParticipantsLockedInner(packageName, allApps);
}
- private void backUpPackageManagerData() {
- // No need to schedule a backup just for the metadata; just piggyback on
- // the next actual data backup.
- synchronized(this) {
- mDoPackageManager = true;
- }
- }
-
// The queue lock should be held when scheduling a backup pass
private void scheduleBackupPassLocked(long timeFromNowMillis) {
mBackupHandler.removeMessages(MSG_RUN_BACKUP);
@@ -565,6 +567,7 @@ class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "PerformBackupThread";
IBackupTransport mTransport;
ArrayList<BackupRequest> mQueue;
+ File mStateDir;
File mJournal;
public PerformBackupThread(IBackupTransport transport, ArrayList<BackupRequest> queue,
@@ -572,52 +575,43 @@ class BackupManagerService extends IBackupManager.Stub {
mTransport = transport;
mQueue = queue;
mJournal = journal;
+
+ try {
+ mStateDir = new File(mBaseStateDir, transport.transportDirName());
+ } catch (RemoteException e) {
+ // can't happen; the transport is local
+ }
+ mStateDir.mkdirs();
}
@Override
public void run() {
if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
- // start up the transport
- try {
- mTransport.startSession();
- } catch (Exception e) {
- Log.e(TAG, "Error session transport");
- e.printStackTrace();
- return;
- }
-
- // The transport is up and running. First, back up the package manager
- // metadata if necessary
- boolean doPackageManager;
- synchronized (BackupManagerService.this) {
- doPackageManager = mDoPackageManager;
- mDoPackageManager = false;
- }
- if (doPackageManager) {
- // The package manager doesn't have a proper <application> etc, but since
- // it's running here in the system process we can just set up its agent
- // directly and use a synthetic BackupRequest.
- if (DEBUG) Log.i(TAG, "Running PM backup pass as well");
-
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
- mPackageManager, allAgentApps());
- BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
- pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
- processOneBackup(pmRequest,
- IBackupAgent.Stub.asInterface(pmAgent.onBind()),
- mTransport);
- }
+ // The package manager doesn't have a proper <application> etc, but since
+ // it's running here in the system process we can just set up its agent
+ // directly and use a synthetic BackupRequest. We always run this pass
+ // because it's cheap and this way we guarantee that we don't get out of
+ // step even if we're selecting among various transports at run time.
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ mPackageManager, allAgentPackages());
+ BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
+ pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
+ processOneBackup(pmRequest,
+ IBackupAgent.Stub.asInterface(pmAgent.onBind()),
+ mTransport);
// Now run all the backups in our queue
doQueuedBackups(mTransport);
// Finally, tear down the transport
try {
- mTransport.endSession();
- } catch (Exception e) {
- Log.e(TAG, "Error ending transport");
- e.printStackTrace();
+ if (!mTransport.finishBackup()) {
+ // STOPSHIP TODO: handle errors
+ Log.e(TAG, "Backup failure in finishBackup()");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in finishBackup()", e);
}
if (!mJournal.delete()) {
@@ -712,24 +706,18 @@ class BackupManagerService extends IBackupManager.Stub {
if (DEBUG) Log.v(TAG, "doBackup() success; calling transport");
backupData =
ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY);
- int error = transport.performBackup(packInfo, backupData);
+ if (!transport.performBackup(packInfo, backupData)) {
+ // STOPSHIP TODO: handle errors
+ Log.e(TAG, "Backup failure in performBackup()");
+ }
// !!! TODO: After successful transport, delete the now-stale data
// and juggle the files so that next time the new state is passed
//backupDataName.delete();
newStateName.renameTo(savedStateName);
}
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Package not found on backup: " + packageName);
- } catch (FileNotFoundException fnf) {
- Log.w(TAG, "File not found on backup: ");
- fnf.printStackTrace();
- } catch (RemoteException e) {
- Log.d(TAG, "Remote target " + request.appInfo.packageName + " threw during backup:");
- e.printStackTrace();
} catch (Exception e) {
- Log.w(TAG, "Final exception guard in backup: ");
- e.printStackTrace();
+ Log.e(TAG, "Error backing up " + packageName, e);
}
}
}
@@ -737,25 +725,6 @@ class BackupManagerService extends IBackupManager.Stub {
// ----- Restore handling -----
- // Is the given package restorable on this device? Returns the on-device app's
- // ApplicationInfo struct if it is; null if not.
- //
- // !!! TODO: also consider signatures
- PackageInfo isRestorable(PackageInfo packageInfo) {
- if (packageInfo.packageName != null) {
- try {
- PackageInfo app = mPackageManager.getPackageInfo(packageInfo.packageName,
- PackageManager.GET_SIGNATURES);
- if ((app.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
- return app;
- }
- } catch (Exception e) {
- // doesn't exist on this device, or other error -- just ignore it.
- }
- }
- return null;
- }
-
private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
// Allow unsigned apps, but not signed on one device and unsigned on the other
// !!! TODO: is this the right policy?
@@ -792,8 +761,10 @@ class BackupManagerService extends IBackupManager.Stub {
class PerformRestoreThread extends Thread {
private IBackupTransport mTransport;
- private int mToken;
+ private IRestoreObserver mObserver;
+ private long mToken;
private RestoreSet mImage;
+ private File mStateDir;
class RestoreRequest {
public PackageInfo app;
@@ -805,9 +776,18 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- PerformRestoreThread(IBackupTransport transport, int restoreSetToken) {
+ PerformRestoreThread(IBackupTransport transport, IRestoreObserver observer,
+ long restoreSetToken) {
mTransport = transport;
+ mObserver = observer;
mToken = restoreSetToken;
+
+ try {
+ mStateDir = new File(mBaseStateDir, transport.transportDirName());
+ } catch (RemoteException e) {
+ // can't happen; the transport is local
+ }
+ mStateDir.mkdirs();
}
@Override
@@ -816,130 +796,175 @@ class BackupManagerService extends IBackupManager.Stub {
/**
* Restore sequence:
*
- * 1. start up the transport session
- * 2. get the restore set description for our identity
- * 3. for each app in the restore set:
+ * 1. get the restore set description for our identity
+ * 2. for each app in the restore set:
* 3.a. if it's restorable on this device, add it to the restore queue
- * 4. for each app in the restore queue:
- * 4.a. clear the app data
- * 4.b. get the restore data for the app from the transport
- * 4.c. launch the backup agent for the app
- * 4.d. agent.doRestore() with the data from the server
- * 4.e. unbind the agent [and kill the app?]
- * 5. shut down the transport
+ * 3. for each app in the restore queue:
+ * 3.a. clear the app data
+ * 3.b. get the restore data for the app from the transport
+ * 3.c. launch the backup agent for the app
+ * 3.d. agent.doRestore() with the data from the server
+ * 3.e. unbind the agent [and kill the app?]
+ * 4. shut down the transport
*/
- int err = -1;
+ int error = -1; // assume error
+
+ // build the set of apps to restore
try {
- err = mTransport.startSession();
- } catch (Exception e) {
- Log.e(TAG, "Error starting transport for restore");
- e.printStackTrace();
- }
+ RestoreSet[] images = mTransport.getAvailableRestoreSets();
+ if (images == null) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error getting restore sets");
+ return;
+ }
- if (err == 0) {
- // build the set of apps to restore
- try {
- RestoreSet[] images = mTransport.getAvailableRestoreSets();
- if (images.length > 0) {
- // !!! TODO: pick out the set for this token
- mImage = images[0];
-
- // Pull the Package Manager metadata from the restore set first
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
- mPackageManager, allAgentApps());
- PackageInfo pmApp = new PackageInfo();
- pmApp.packageName = PACKAGE_MANAGER_SENTINEL;
- // !!! 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<RestoreRequest> appsToRestore = new HashSet<RestoreRequest>();
- for (PackageInfo pkg: packages) {
- // get the real PackageManager idea of the package
- PackageInfo app = isRestorable(pkg);
- if (app != null) {
- // Validate against the backed-up signature block, too
- Metadata info = pmAgent.getRestoredMetadata(app.packageName);
- if (info != null) {
- if (app.versionCode >= info.versionCode) {
- if (DEBUG) Log.v(TAG, "Restore version "
- + info.versionCode
- + " compatible with app version "
- + app.versionCode);
- if (signaturesMatch(info.signatures, app.signatures)) {
- appsToRestore.add(
- new RestoreRequest(app, info.versionCode));
- } else {
- Log.w(TAG, "Sig mismatch restoring "
- + app.packageName);
- }
- } else {
- Log.i(TAG, "Restore set for " + app.packageName
- + " is too new [" + info.versionCode
- + "] for installed app version "
- + app.versionCode);
- }
- } else {
- Log.d(TAG, "Unable to get metadata for "
- + app.packageName);
- }
- }
- }
+ if (images.length == 0) {
+ Log.i(TAG, "No restore sets available");
+ return;
+ }
+
+ mImage = images[0];
+
+ // Get the list of all packages which have backup enabled.
+ // (Include the Package Manager metadata pseudo-package first.)
+ ArrayList<PackageInfo> restorePackages = new ArrayList<PackageInfo>();
+ PackageInfo omPackage = new PackageInfo();
+ omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
+ restorePackages.add(omPackage);
- // now run the restore queue
- doQueuedRestores(appsToRestore);
+ List<PackageInfo> agentPackages = allAgentPackages();
+ restorePackages.addAll(agentPackages);
+
+ // let the observer know that we're running
+ if (mObserver != null) {
+ try {
+ // !!! TODO: get an actual count from the transport after
+ // its startRestore() runs?
+ mObserver.restoreStarting(restorePackages.size());
+ } catch (RemoteException e) {
+ Log.d(TAG, "Restore observer died at restoreStarting");
+ mObserver = null;
}
- } catch (RemoteException e) {
- // can't happen; transports run locally
}
- // done; shut down the transport
- try {
- mTransport.endSession();
- } catch (Exception e) {
- Log.e(TAG, "Error ending transport for restore");
- e.printStackTrace();
+ if (!mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0]))) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error starting restore operation");
+ return;
}
- }
- // even if the initial session startup failed, report that we're done here
- }
+ String packageName = mTransport.nextRestorePackage();
+ if (packageName == null) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error getting first restore package");
+ return;
+ } else if (packageName.equals("")) {
+ Log.i(TAG, "No restore data available");
+ return;
+ } else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
+ Log.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
+ + "\", found only \"" + packageName + "\"");
+ return;
+ }
+
+ // Pull the Package Manager metadata from the restore set first
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ mPackageManager, agentPackages);
+ processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+
+ int count = 0;
+ for (;;) {
+ packageName = mTransport.nextRestorePackage();
+ if (packageName == null) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error getting next restore package");
+ return;
+ } else if (packageName.equals("")) {
+ break;
+ }
- // restore each app in the queue
- void doQueuedRestores(HashSet<RestoreRequest> appsToRestore) {
- for (RestoreRequest req : appsToRestore) {
- PackageInfo app = req.app;
- Log.d(TAG, "starting agent for restore of " + app);
+ if (mObserver != null) {
+ ++count;
+ try {
+ mObserver.onUpdate(count);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Restore observer died in onUpdate");
+ mObserver = null;
+ }
+ }
- try {
- // Remove the app's data first
- clearApplicationDataSynchronous(app.packageName);
+ Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
+ if (metaInfo == null) {
+ Log.e(TAG, "Missing metadata for " + packageName);
+ continue;
+ }
+
+ int flags = PackageManager.GET_SIGNATURES;
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+ if (metaInfo.versionCode > packageInfo.versionCode) {
+ Log.w(TAG, "Package " + packageName
+ + " restore version [" + metaInfo.versionCode
+ + "] is too new for installed version ["
+ + packageInfo.versionCode + "]");
+ continue;
+ }
+
+ if (!signaturesMatch(metaInfo.signatures, packageInfo.signatures)) {
+ Log.w(TAG, "Signature mismatch restoring " + packageName);
+ continue;
+ }
+
+ if (DEBUG) Log.v(TAG, "Package " + packageName
+ + " restore version [" + metaInfo.versionCode
+ + "] is compatible with installed version ["
+ + packageInfo.versionCode + "]");
- // Now perform the restore into the clean app
- IBackupAgent agent = bindToAgentSynchronous(app.applicationInfo,
+ // Now perform the actual restore
+ clearApplicationDataSynchronous(packageName);
+ IBackupAgent agent = bindToAgentSynchronous(
+ packageInfo.applicationInfo,
IApplicationThread.BACKUP_MODE_RESTORE);
- if (agent != null) {
- processOneRestore(app, req.storedAppVersion, agent);
+ if (agent == null) {
+ Log.w(TAG, "Can't find backup agent for " + packageName);
+ continue;
}
- // unbind even on timeout, just in case
- mActivityManager.unbindBackupAgent(app.applicationInfo);
- } catch (SecurityException ex) {
- // Try for the next one.
- Log.d(TAG, "error in bind", ex);
+ try {
+ processOneRestore(packageInfo, metaInfo.versionCode, agent);
+ } finally {
+ // unbind even on timeout or failure, just in case
+ mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
+ }
+ }
+
+ // if we get this far, report success to the observer
+ error = 0;
+ } catch (NameNotFoundException e) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Invalid paackage restoring data", e);
+ } catch (RemoteException e) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error restoring data", e);
+ } finally {
+ try {
+ mTransport.finishRestore();
} catch (RemoteException e) {
- // can't happen
+ Log.e(TAG, "Error finishing restore", e);
}
+ if (mObserver != null) {
+ try {
+ mObserver.restoreFinished(error);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Restore observer died at restoreFinished");
+ }
+ }
}
}
- // Do the guts of a restore of one application, derived from the 'mImage'
- // restore set via the 'mTransport' transport.
- void processOneRestore(PackageInfo app, int storedAppVersion, IBackupAgent agent) {
+ // Do the guts of a restore of one application, using mTransport.getRestoreData().
+ void processOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent) {
// !!! TODO: actually run the restore through mTransport
final String packageName = app.packageName;
@@ -954,11 +979,12 @@ class BackupManagerService extends IBackupManager.Stub {
// Run the transport's restore pass
// Run the target's backup pass
- int err = -1;
try {
- err = mTransport.getRestoreData(mImage.token, app, backupData);
- } catch (RemoteException e) {
- // can't happen
+ if (!mTransport.getRestoreData(backupData)) {
+ // STOPSHIP TODO: Handle this error somehow?
+ Log.e(TAG, "Error getting restore data for " + packageName);
+ return;
+ }
} finally {
backupData.close();
}
@@ -973,30 +999,18 @@ class BackupManagerService extends IBackupManager.Stub {
backupData = ParcelFileDescriptor.open(backupDataName,
ParcelFileDescriptor.MODE_READ_ONLY);
- boolean success = false;
try {
- agent.doRestore(backupData, storedAppVersion, newState);
- success = true;
- } catch (Exception e) {
- Log.e(TAG, "Restore failed for " + packageName);
- e.printStackTrace();
+ agent.doRestore(backupData, appVersionCode, newState);
} finally {
newState.close();
backupData.close();
}
// if everything went okay, remember the recorded state now
- if (success) {
- File savedStateName = new File(mStateDir, packageName);
- newStateName.renameTo(savedStateName);
- }
- } catch (FileNotFoundException fnfe) {
- Log.v(TAG, "Couldn't open file for restore: " + fnfe);
- } catch (IOException ioe) {
- Log.e(TAG, "Unable to process restore file: " + ioe);
+ File savedStateName = new File(mStateDir, packageName);
+ newStateName.renameTo(savedStateName);
} catch (Exception e) {
- Log.e(TAG, "Final exception guard in restore:");
- e.printStackTrace();
+ Log.e(TAG, "Error restoring data for " + packageName, e);
}
}
}
@@ -1183,15 +1197,15 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- public int performRestore(int token) throws android.os.RemoteException {
+ public int performRestore(long token, IRestoreObserver observer)
+ throws android.os.RemoteException {
mContext.enforceCallingPermission("android.permission.BACKUP", "performRestore");
if (mRestoreSets != null) {
for (int i = 0; i < mRestoreSets.length; i++) {
if (token == mRestoreSets[i].token) {
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE,
- mRestoreTransport);
- msg.arg1 = token;
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(mRestoreTransport, observer, token);
mBackupHandler.sendMessage(msg);
return 0;
}
@@ -1206,7 +1220,7 @@ class BackupManagerService extends IBackupManager.Stub {
mContext.enforceCallingPermission("android.permission.BACKUP",
"endRestoreSession");
- mRestoreTransport.endSession();
+ mRestoreTransport.finishRestore();
mRestoreTransport = null;
synchronized(BackupManagerService.this) {
if (BackupManagerService.this.mActiveRestoreSession == this) {