Loading core/java/com/android/internal/backup/AdbTransport.java +4 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,10 @@ import android.os.RemoteException; public class AdbTransport extends IBackupTransport.Stub { public long requestBackupTime() throws RemoteException { return 0; } public int startSession() throws RemoteException { // TODO Auto-generated method stub return 0; Loading core/java/com/android/internal/backup/GoogleTransport.java +4 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,10 @@ import android.os.RemoteException; public class GoogleTransport extends IBackupTransport.Stub { public long requestBackupTime() throws RemoteException { return 0; // !!! TODO: implement real backoff policy } public int startSession() throws RemoteException { // TODO Auto-generated method stub return 0; Loading core/java/com/android/internal/backup/IBackupTransport.aidl +16 −9 Original line number Diff line number Diff line Loading @@ -40,6 +40,16 @@ interface IBackupTransport { - cloud: tear down connection etc - adb: close the file */ /** * Verify that this is a suitable time for a backup pass. This should return zero * if a backup is reasonable right now, false otherwise. This method will be called * outside of the {@link #startSession}/{@link #endSession} pair. * * <p>If this is not a suitable time for a backup, the transport should suggest a * backoff delay, in milliseconds, after which the Backup Manager should try again. */ long requestBackupTime(); /** * Establish a connection to the back-end data repository, if necessary. If the transport * needs to initialize state that is not tied to individual applications' backup operations, Loading @@ -64,33 +74,30 @@ interface IBackupTransport { /** * Get the set of backups currently available over this transport. * * @return A bundle containing two elements: an int array under the key * "tokens" whose entries are a transport-private identifier for each backup set; * and a String array under the key "names" whose entries are the user-meaningful * names corresponding to the backup sets at each index in the tokens array. * @return Descriptions of the set of restore images available for this device. **/ RestoreSet[] getAvailableRestoreSets(); /** * Get the set of applications from a given backup image. * Get the set of applications from a given restore image. * * @param token A backup token as returned by {@link availableBackups}. * @param token A backup token as returned by {@link #getAvailableRestoreSets}. * @return An array of PackageInfo objects describing all of the applications * available for restore from the given backup set. This should include the list * available for restore from this restore image. This should include the list * of signatures for each package so that the Backup Manager can filter using that * information. */ PackageInfo[] getAppSet(int token); /** * Retrieve one application's data from the backup destination. * Retrieve one application's data from the backing store. * * @param token The backup record from which a restore is being requested. * @param packageInfo The identity of the application whose data is being restored. * This must include the signature list for the package; it is up to the transport * to verify that the requested app's signatures match the saved backup record * because the transport cannot necessarily trust the client device. * @param data An open, writeable file into which the backup image should be stored. * @param data An open, writable file into which the backup image should be stored. * @return Zero on success; a nonzero error code on failure. */ int getRestoreData(int token, in PackageInfo packageInfo, in ParcelFileDescriptor data); Loading services/java/com/android/server/BackupManagerService.java +174 −43 Original line number Diff line number Diff line Loading @@ -215,7 +215,8 @@ class BackupManagerService extends IBackupManager.Stub { // Look up the package info & signatures. This is first so that if it // throws an exception, there's no file setup yet that would need to // be unraveled. PackageInfo packInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); PackageInfo packInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); // !!! TODO: get the state file dir from the transport File savedStateName = new File(mStateDir, packageName); Loading Loading @@ -367,7 +368,8 @@ class BackupManagerService extends IBackupManager.Stub { if (N > 0) { for (int a = N-1; a >= 0; a--) { ApplicationInfo app = allApps.get(a); if (app.backupAgentName == null) { if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) || app.backupAgentName == null) { allApps.remove(a); } } Loading Loading @@ -411,6 +413,40 @@ class BackupManagerService extends IBackupManager.Stub { return transport; } // fire off a backup agent, blocking until it attaches or times out IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) { IBackupAgent agent = null; synchronized(mAgentConnectLock) { mConnecting = true; mConnectedAgent = null; try { if (mActivityManager.bindBackupAgent(app, mode)) { Log.d(TAG, "awaiting agent for " + app); // success; wait for the agent to arrive while (mConnecting && mConnectedAgent == null) { try { mAgentConnectLock.wait(10000); } catch (InterruptedException e) { // just retry return null; } } // if we timed out with no connect, abort and move on if (mConnecting == true) { Log.w(TAG, "Timeout waiting for agent " + app); return null; } agent = mConnectedAgent; } } catch (RemoteException e) { // can't happen } } return agent; } // ----- Back up a set of applications via a worker thread ----- class PerformBackupThread extends Thread { Loading @@ -425,15 +461,6 @@ class BackupManagerService extends IBackupManager.Stub { @Override public void run() { /* * 1. start up the current transport * 2. for each item in the queue: * 2a. bind the agent [wait for async attach] * 2b. set up the files and call doBackup() * 2c. unbind the agent * 3. tear down the transport * 4. done! */ if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets"); // stand up the current transport Loading @@ -442,6 +469,15 @@ class BackupManagerService extends IBackupManager.Stub { return; } // start up the transport try { transport.startSession(); } catch (Exception e) { Log.e(TAG, "Error session transport"); e.printStackTrace(); return; } // The transport is up and running; now run all the backups in our queue doQueuedBackups(transport); Loading @@ -456,60 +492,153 @@ class BackupManagerService extends IBackupManager.Stub { private void doQueuedBackups(IBackupTransport transport) { for (BackupRequest request : mQueue) { Log.d(TAG, "starting agent for " + request); // !!! TODO: need to handle the restore case? Log.d(TAG, "starting agent for backup of " + request); IBackupAgent agent = null; int mode = (request.fullBackup) ? IApplicationThread.BACKUP_MODE_FULL : IApplicationThread.BACKUP_MODE_INCREMENTAL; try { synchronized(mAgentConnectLock) { mConnecting = true; mConnectedAgent = null; if (mActivityManager.bindBackupAgent(request.appInfo, mode)) { Log.d(TAG, "awaiting agent for " + request); agent = bindToAgentSynchronous(request.appInfo, mode); if (agent != null) { processOneBackup(request, agent, transport); } // success; wait for the agent to arrive while (mConnecting && mConnectedAgent == null) { // unbind even on timeout, just in case mActivityManager.unbindBackupAgent(request.appInfo); } catch (SecurityException ex) { // Try for the next one. Log.d(TAG, "error in bind", ex); } catch (RemoteException e) { // can't happen } } } } // ----- 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 ApplicationInfo isRestorable(PackageInfo packageInfo) { if (packageInfo.packageName != null) { try { mAgentConnectLock.wait(10000); } catch (InterruptedException e) { // just retry continue; ApplicationInfo app = mPackageManager.getApplicationInfo(packageInfo.packageName, PackageManager.GET_SIGNATURES); if ((app.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; } // if we timed out with no connect, abort and move on if (mConnecting == true) { Log.w(TAG, "Timeout waiting for agent " + request); continue; class PerformRestoreThread extends Thread { private IBackupTransport mTransport; PerformRestoreThread(IBackupTransport transport) { mTransport = transport; } agent = mConnectedAgent; @Override public void run() { /** * 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: * 3.a. if it's restorable on this device, add it to the restore queue * 4. for each app in the restore queue: * 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 */ int err = -1; try { err = mTransport.startSession(); } catch (Exception e) { Log.e(TAG, "Error starting transport for restore"); e.printStackTrace(); } if (err == 0) { // build the set of apps to restore try { RestoreSet[] images = mTransport.getAvailableRestoreSets(); if (images.length > 0) { // !!! for now we always take the first set RestoreSet image = images[0]; // build the set of apps we will attempt to restore PackageInfo[] packages = mTransport.getAppSet(image.token); HashSet<ApplicationInfo> appsToRestore = new HashSet<ApplicationInfo>(); for (PackageInfo pkg: packages) { ApplicationInfo app = isRestorable(pkg); if (app != null) { appsToRestore.add(app); } } // now run the restore queue doQueuedRestores(appsToRestore); } } catch (RemoteException e) { // can't happen; activity manager is local } catch (SecurityException ex) { // Try for the next one. Log.d(TAG, "error in bind", ex); // can't happen; transports run locally } // successful bind? run the backup for this agent if (agent != null) { processOneBackup(request, agent, transport); // done; shut down the transport try { mTransport.endSession(); } catch (Exception e) { Log.e(TAG, "Error ending transport for restore"); e.printStackTrace(); } } // send the unbind even on timeout, just in case // even if the initial session startup failed, report that we're done here } // restore each app in the queue void doQueuedRestores(HashSet<ApplicationInfo> appsToRestore) { for (ApplicationInfo app : appsToRestore) { Log.d(TAG, "starting agent for restore of " + app); IBackupAgent agent = null; try { mActivityManager.unbindBackupAgent(request.appInfo); agent = bindToAgentSynchronous(app, IApplicationThread.BACKUP_MODE_RESTORE); if (agent != null) { processOneRestore(app, agent); } // unbind even on timeout, just in case mActivityManager.unbindBackupAgent(app); } catch (SecurityException ex) { // Try for the next one. Log.d(TAG, "error in bind", ex); } catch (RemoteException e) { // can't happen } } } // do the guts of a restore void processOneRestore(ApplicationInfo app, IBackupAgent agent) { // !!! TODO: actually run the restore through mTransport } } // ----- IBackupManager binder interface ----- public void dataChanged(String packageName) throws RemoteException { Loading Loading @@ -548,6 +677,8 @@ class BackupManagerService extends IBackupManager.Stub { mBackupHandler.removeMessages(MSG_RUN_BACKUP); mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, COLLECTION_INTERVAL); } } else { Log.w(TAG, "dataChanged but no participant pkg " + packageName); } } Loading Loading
core/java/com/android/internal/backup/AdbTransport.java +4 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,10 @@ import android.os.RemoteException; public class AdbTransport extends IBackupTransport.Stub { public long requestBackupTime() throws RemoteException { return 0; } public int startSession() throws RemoteException { // TODO Auto-generated method stub return 0; Loading
core/java/com/android/internal/backup/GoogleTransport.java +4 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,10 @@ import android.os.RemoteException; public class GoogleTransport extends IBackupTransport.Stub { public long requestBackupTime() throws RemoteException { return 0; // !!! TODO: implement real backoff policy } public int startSession() throws RemoteException { // TODO Auto-generated method stub return 0; Loading
core/java/com/android/internal/backup/IBackupTransport.aidl +16 −9 Original line number Diff line number Diff line Loading @@ -40,6 +40,16 @@ interface IBackupTransport { - cloud: tear down connection etc - adb: close the file */ /** * Verify that this is a suitable time for a backup pass. This should return zero * if a backup is reasonable right now, false otherwise. This method will be called * outside of the {@link #startSession}/{@link #endSession} pair. * * <p>If this is not a suitable time for a backup, the transport should suggest a * backoff delay, in milliseconds, after which the Backup Manager should try again. */ long requestBackupTime(); /** * Establish a connection to the back-end data repository, if necessary. If the transport * needs to initialize state that is not tied to individual applications' backup operations, Loading @@ -64,33 +74,30 @@ interface IBackupTransport { /** * Get the set of backups currently available over this transport. * * @return A bundle containing two elements: an int array under the key * "tokens" whose entries are a transport-private identifier for each backup set; * and a String array under the key "names" whose entries are the user-meaningful * names corresponding to the backup sets at each index in the tokens array. * @return Descriptions of the set of restore images available for this device. **/ RestoreSet[] getAvailableRestoreSets(); /** * Get the set of applications from a given backup image. * Get the set of applications from a given restore image. * * @param token A backup token as returned by {@link availableBackups}. * @param token A backup token as returned by {@link #getAvailableRestoreSets}. * @return An array of PackageInfo objects describing all of the applications * available for restore from the given backup set. This should include the list * available for restore from this restore image. This should include the list * of signatures for each package so that the Backup Manager can filter using that * information. */ PackageInfo[] getAppSet(int token); /** * Retrieve one application's data from the backup destination. * Retrieve one application's data from the backing store. * * @param token The backup record from which a restore is being requested. * @param packageInfo The identity of the application whose data is being restored. * This must include the signature list for the package; it is up to the transport * to verify that the requested app's signatures match the saved backup record * because the transport cannot necessarily trust the client device. * @param data An open, writeable file into which the backup image should be stored. * @param data An open, writable file into which the backup image should be stored. * @return Zero on success; a nonzero error code on failure. */ int getRestoreData(int token, in PackageInfo packageInfo, in ParcelFileDescriptor data); Loading
services/java/com/android/server/BackupManagerService.java +174 −43 Original line number Diff line number Diff line Loading @@ -215,7 +215,8 @@ class BackupManagerService extends IBackupManager.Stub { // Look up the package info & signatures. This is first so that if it // throws an exception, there's no file setup yet that would need to // be unraveled. PackageInfo packInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); PackageInfo packInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); // !!! TODO: get the state file dir from the transport File savedStateName = new File(mStateDir, packageName); Loading Loading @@ -367,7 +368,8 @@ class BackupManagerService extends IBackupManager.Stub { if (N > 0) { for (int a = N-1; a >= 0; a--) { ApplicationInfo app = allApps.get(a); if (app.backupAgentName == null) { if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) || app.backupAgentName == null) { allApps.remove(a); } } Loading Loading @@ -411,6 +413,40 @@ class BackupManagerService extends IBackupManager.Stub { return transport; } // fire off a backup agent, blocking until it attaches or times out IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) { IBackupAgent agent = null; synchronized(mAgentConnectLock) { mConnecting = true; mConnectedAgent = null; try { if (mActivityManager.bindBackupAgent(app, mode)) { Log.d(TAG, "awaiting agent for " + app); // success; wait for the agent to arrive while (mConnecting && mConnectedAgent == null) { try { mAgentConnectLock.wait(10000); } catch (InterruptedException e) { // just retry return null; } } // if we timed out with no connect, abort and move on if (mConnecting == true) { Log.w(TAG, "Timeout waiting for agent " + app); return null; } agent = mConnectedAgent; } } catch (RemoteException e) { // can't happen } } return agent; } // ----- Back up a set of applications via a worker thread ----- class PerformBackupThread extends Thread { Loading @@ -425,15 +461,6 @@ class BackupManagerService extends IBackupManager.Stub { @Override public void run() { /* * 1. start up the current transport * 2. for each item in the queue: * 2a. bind the agent [wait for async attach] * 2b. set up the files and call doBackup() * 2c. unbind the agent * 3. tear down the transport * 4. done! */ if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets"); // stand up the current transport Loading @@ -442,6 +469,15 @@ class BackupManagerService extends IBackupManager.Stub { return; } // start up the transport try { transport.startSession(); } catch (Exception e) { Log.e(TAG, "Error session transport"); e.printStackTrace(); return; } // The transport is up and running; now run all the backups in our queue doQueuedBackups(transport); Loading @@ -456,60 +492,153 @@ class BackupManagerService extends IBackupManager.Stub { private void doQueuedBackups(IBackupTransport transport) { for (BackupRequest request : mQueue) { Log.d(TAG, "starting agent for " + request); // !!! TODO: need to handle the restore case? Log.d(TAG, "starting agent for backup of " + request); IBackupAgent agent = null; int mode = (request.fullBackup) ? IApplicationThread.BACKUP_MODE_FULL : IApplicationThread.BACKUP_MODE_INCREMENTAL; try { synchronized(mAgentConnectLock) { mConnecting = true; mConnectedAgent = null; if (mActivityManager.bindBackupAgent(request.appInfo, mode)) { Log.d(TAG, "awaiting agent for " + request); agent = bindToAgentSynchronous(request.appInfo, mode); if (agent != null) { processOneBackup(request, agent, transport); } // success; wait for the agent to arrive while (mConnecting && mConnectedAgent == null) { // unbind even on timeout, just in case mActivityManager.unbindBackupAgent(request.appInfo); } catch (SecurityException ex) { // Try for the next one. Log.d(TAG, "error in bind", ex); } catch (RemoteException e) { // can't happen } } } } // ----- 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 ApplicationInfo isRestorable(PackageInfo packageInfo) { if (packageInfo.packageName != null) { try { mAgentConnectLock.wait(10000); } catch (InterruptedException e) { // just retry continue; ApplicationInfo app = mPackageManager.getApplicationInfo(packageInfo.packageName, PackageManager.GET_SIGNATURES); if ((app.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; } // if we timed out with no connect, abort and move on if (mConnecting == true) { Log.w(TAG, "Timeout waiting for agent " + request); continue; class PerformRestoreThread extends Thread { private IBackupTransport mTransport; PerformRestoreThread(IBackupTransport transport) { mTransport = transport; } agent = mConnectedAgent; @Override public void run() { /** * 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: * 3.a. if it's restorable on this device, add it to the restore queue * 4. for each app in the restore queue: * 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 */ int err = -1; try { err = mTransport.startSession(); } catch (Exception e) { Log.e(TAG, "Error starting transport for restore"); e.printStackTrace(); } if (err == 0) { // build the set of apps to restore try { RestoreSet[] images = mTransport.getAvailableRestoreSets(); if (images.length > 0) { // !!! for now we always take the first set RestoreSet image = images[0]; // build the set of apps we will attempt to restore PackageInfo[] packages = mTransport.getAppSet(image.token); HashSet<ApplicationInfo> appsToRestore = new HashSet<ApplicationInfo>(); for (PackageInfo pkg: packages) { ApplicationInfo app = isRestorable(pkg); if (app != null) { appsToRestore.add(app); } } // now run the restore queue doQueuedRestores(appsToRestore); } } catch (RemoteException e) { // can't happen; activity manager is local } catch (SecurityException ex) { // Try for the next one. Log.d(TAG, "error in bind", ex); // can't happen; transports run locally } // successful bind? run the backup for this agent if (agent != null) { processOneBackup(request, agent, transport); // done; shut down the transport try { mTransport.endSession(); } catch (Exception e) { Log.e(TAG, "Error ending transport for restore"); e.printStackTrace(); } } // send the unbind even on timeout, just in case // even if the initial session startup failed, report that we're done here } // restore each app in the queue void doQueuedRestores(HashSet<ApplicationInfo> appsToRestore) { for (ApplicationInfo app : appsToRestore) { Log.d(TAG, "starting agent for restore of " + app); IBackupAgent agent = null; try { mActivityManager.unbindBackupAgent(request.appInfo); agent = bindToAgentSynchronous(app, IApplicationThread.BACKUP_MODE_RESTORE); if (agent != null) { processOneRestore(app, agent); } // unbind even on timeout, just in case mActivityManager.unbindBackupAgent(app); } catch (SecurityException ex) { // Try for the next one. Log.d(TAG, "error in bind", ex); } catch (RemoteException e) { // can't happen } } } // do the guts of a restore void processOneRestore(ApplicationInfo app, IBackupAgent agent) { // !!! TODO: actually run the restore through mTransport } } // ----- IBackupManager binder interface ----- public void dataChanged(String packageName) throws RemoteException { Loading Loading @@ -548,6 +677,8 @@ class BackupManagerService extends IBackupManager.Stub { mBackupHandler.removeMessages(MSG_RUN_BACKUP); mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, COLLECTION_INTERVAL); } } else { Log.w(TAG, "dataChanged but no participant pkg " + packageName); } } Loading