Loading services/java/com/android/server/BackupManagerService.java +203 −94 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; Loading Loading @@ -53,6 +54,7 @@ import com.android.internal.backup.IBackupTransport; import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.lang.String; import java.util.ArrayList; Loading @@ -71,6 +73,9 @@ class BackupManagerService extends IBackupManager.Stub { private static final int MSG_RUN_BACKUP = 1; private static final int MSG_RUN_FULL_BACKUP = 2; // Timeout interval for deciding that a bind or clear-data has taken too long static final long TIMEOUT_INTERVAL = 10 * 1000; private Context mContext; private PackageManager mPackageManager; private final IActivityManager mActivityManager; Loading Loading @@ -108,6 +113,10 @@ class BackupManagerService extends IBackupManager.Stub { private IBackupAgent mConnectedAgent; private volatile boolean mConnecting; // A similar synchronicity mechanism around clearing apps' data for restore private final Object mClearDataLock = new Object(); private volatile boolean mClearingData; private int mTransportId; private File mStateDir; Loading Loading @@ -207,80 +216,6 @@ class BackupManagerService extends IBackupManager.Stub { } } void processOneBackup(BackupRequest request, IBackupAgent agent, IBackupTransport transport) { final String packageName = request.appInfo.packageName; Log.d(TAG, "processOneBackup doBackup() on " + packageName); try { // 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); // !!! TODO: get the state file dir from the transport File savedStateName = new File(mStateDir, packageName); File backupDataName = new File(mDataDir, packageName + ".data"); File newStateName = new File(mStateDir, packageName + ".new"); // In a full backup, we pass a null ParcelFileDescriptor as // the saved-state "file" ParcelFileDescriptor savedState = (request.fullBackup) ? null : ParcelFileDescriptor.open(savedStateName, ParcelFileDescriptor.MODE_READ_ONLY | ParcelFileDescriptor.MODE_CREATE); backupDataName.delete(); ParcelFileDescriptor backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); newStateName.delete(); ParcelFileDescriptor newState = ParcelFileDescriptor.open(newStateName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); // Run the target's backup pass boolean success = false; try { agent.doBackup(savedState, backupData, newState); success = true; } finally { if (savedState != null) { savedState.close(); } backupData.close(); newState.close(); } // Now propagate the newly-backed-up data to the transport if (success) { if (DEBUG) Log.v(TAG, "doBackup() success; calling transport"); backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY); int error = transport.performBackup(packInfo, backupData); // !!! 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(); } } // Add the backup agents in the given package to our set of known backup participants. // If 'packageName' is null, adds all backup agents in the whole system. void addPackageParticipantsLocked(String packageName) { Loading Loading @@ -424,11 +359,14 @@ class BackupManagerService extends IBackupManager.Stub { Log.d(TAG, "awaiting agent for " + app); // success; wait for the agent to arrive while (mConnecting && mConnectedAgent == null) { // only wait 10 seconds for the clear data to happen long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL; while (mConnecting && mConnectedAgent == null && (System.currentTimeMillis() < timeoutMark)) { try { mAgentConnectLock.wait(10000); mAgentConnectLock.wait(5000); } catch (InterruptedException e) { // just retry // just bail return null; } } Loading @@ -447,6 +385,37 @@ class BackupManagerService extends IBackupManager.Stub { return agent; } // clear an application's data, blocking until the operation completes or times out void clearApplicationDataSynchronous(String packageName) { ClearDataObserver observer = new ClearDataObserver(); synchronized(mClearDataLock) { mClearingData = true; mPackageManager.clearApplicationUserData(packageName, observer); // only wait 10 seconds for the clear data to happen long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL; while (mClearingData && (System.currentTimeMillis() < timeoutMark)) { try { mClearDataLock.wait(5000); } catch (InterruptedException e) { // won't happen, but still. mClearingData = false; } } } } class ClearDataObserver extends IPackageDataObserver.Stub { public void onRemoveCompleted(String packageName, boolean succeeded) throws android.os.RemoteException { synchronized(mClearDataLock) { mClearingData = false; notifyAll(); } } } // ----- Back up a set of applications via a worker thread ----- class PerformBackupThread extends Thread { Loading Loading @@ -508,13 +477,88 @@ class BackupManagerService extends IBackupManager.Stub { mActivityManager.unbindBackupAgent(request.appInfo); } catch (SecurityException ex) { // Try for the next one. Log.d(TAG, "error in bind", ex); Log.d(TAG, "error in bind/backup", ex); } catch (RemoteException e) { // can't happen Log.v(TAG, "bind/backup threw"); e.printStackTrace(); } } } void processOneBackup(BackupRequest request, IBackupAgent agent, IBackupTransport transport) { final String packageName = request.appInfo.packageName; Log.d(TAG, "processOneBackup doBackup() on " + packageName); try { // 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); // !!! TODO: get the state file dir from the transport File savedStateName = new File(mStateDir, packageName); File backupDataName = new File(mDataDir, packageName + ".data"); File newStateName = new File(mStateDir, packageName + ".new"); // In a full backup, we pass a null ParcelFileDescriptor as // the saved-state "file" ParcelFileDescriptor savedState = (request.fullBackup) ? null : ParcelFileDescriptor.open(savedStateName, ParcelFileDescriptor.MODE_READ_ONLY | ParcelFileDescriptor.MODE_CREATE); backupDataName.delete(); ParcelFileDescriptor backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); newStateName.delete(); ParcelFileDescriptor newState = ParcelFileDescriptor.open(newStateName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); // Run the target's backup pass boolean success = false; try { agent.doBackup(savedState, backupData, newState); success = true; } finally { if (savedState != null) { savedState.close(); } backupData.close(); newState.close(); } // Now propagate the newly-backed-up data to the transport if (success) { if (DEBUG) Log.v(TAG, "doBackup() success; calling transport"); backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY); int error = transport.performBackup(packInfo, backupData); // !!! 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(); } } } Loading @@ -524,12 +568,12 @@ class BackupManagerService extends IBackupManager.Stub { // ApplicationInfo struct if it is; null if not. // // !!! TODO: also consider signatures ApplicationInfo isRestorable(PackageInfo packageInfo) { PackageInfo isRestorable(PackageInfo packageInfo) { if (packageInfo.packageName != null) { try { ApplicationInfo app = mPackageManager.getApplicationInfo(packageInfo.packageName, PackageInfo app = mPackageManager.getPackageInfo(packageInfo.packageName, PackageManager.GET_SIGNATURES); if ((app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { if ((app.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { return app; } } catch (Exception e) { Loading @@ -541,6 +585,7 @@ class BackupManagerService extends IBackupManager.Stub { class PerformRestoreThread extends Thread { private IBackupTransport mTransport; private RestoreSet mImage; PerformRestoreThread(IBackupTransport transport) { mTransport = transport; Loading @@ -556,6 +601,7 @@ class BackupManagerService extends IBackupManager.Stub { * 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.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 Loading @@ -577,13 +623,14 @@ class BackupManagerService extends IBackupManager.Stub { RestoreSet[] images = mTransport.getAvailableRestoreSets(); if (images.length > 0) { // !!! for now we always take the first set RestoreSet image = images[0]; mImage = images[0]; // build the set of apps we will attempt to restore PackageInfo[] packages = mTransport.getAppSet(image.token); HashSet<ApplicationInfo> appsToRestore = new HashSet<ApplicationInfo>(); PackageInfo[] packages = mTransport.getAppSet(mImage.token); HashSet<PackageInfo> appsToRestore = new HashSet<PackageInfo>(); for (PackageInfo pkg: packages) { ApplicationInfo app = isRestorable(pkg); // get the real PackageManager idea of the package PackageInfo app = isRestorable(pkg); if (app != null) { appsToRestore.add(app); } Loading @@ -609,19 +656,23 @@ class BackupManagerService extends IBackupManager.Stub { } // restore each app in the queue void doQueuedRestores(HashSet<ApplicationInfo> appsToRestore) { for (ApplicationInfo app : appsToRestore) { void doQueuedRestores(HashSet<PackageInfo> appsToRestore) { for (PackageInfo app : appsToRestore) { Log.d(TAG, "starting agent for restore of " + app); IBackupAgent agent = null; try { agent = bindToAgentSynchronous(app, IApplicationThread.BACKUP_MODE_RESTORE); // Remove the app's data first clearApplicationDataSynchronous(app.packageName); // Now perform the restore into the clean app IBackupAgent agent = bindToAgentSynchronous(app.applicationInfo, IApplicationThread.BACKUP_MODE_RESTORE); if (agent != null) { processOneRestore(app, agent); } // unbind even on timeout, just in case mActivityManager.unbindBackupAgent(app); mActivityManager.unbindBackupAgent(app.applicationInfo); } catch (SecurityException ex) { // Try for the next one. Log.d(TAG, "error in bind", ex); Loading @@ -632,9 +683,67 @@ class BackupManagerService extends IBackupManager.Stub { } } // do the guts of a restore void processOneRestore(ApplicationInfo app, IBackupAgent agent) { // 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) { // !!! TODO: actually run the restore through mTransport final String packageName = app.packageName; // !!! TODO: get the dirs from the transport File backupDataName = new File(mDataDir, packageName + ".restore"); backupDataName.delete(); try { ParcelFileDescriptor backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); // 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 } finally { backupData.close(); } // Okay, we have the data. Now have the agent do the restore. File newStateName = new File(mStateDir, packageName + ".new"); ParcelFileDescriptor newState = ParcelFileDescriptor.open(newStateName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY); boolean success = false; try { agent.doRestore(backupData, newState); success = true; } catch (Exception e) { Log.e(TAG, "Restore failed for " + packageName); e.printStackTrace(); } 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); } catch (Exception e) { Log.e(TAG, "Final exception guard in restore:"); e.printStackTrace(); } } } Loading services/java/com/android/server/am/ActivityManagerService.java +8 −5 Original line number Diff line number Diff line Loading @@ -10422,6 +10422,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Not backing this app up any more; reset its OOM adjustment updateOomAdjLocked(proc); // If the app crashed during backup, 'thread' will be null here if (proc.thread != null) { try { proc.thread.scheduleDestroyBackupAgent(appInfo); } catch (Exception e) { Loading @@ -10430,6 +10432,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } } } // ========================================================= // BROADCASTS // ========================================================= Loading Loading
services/java/com/android/server/BackupManagerService.java +203 −94 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; Loading Loading @@ -53,6 +54,7 @@ import com.android.internal.backup.IBackupTransport; import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.lang.String; import java.util.ArrayList; Loading @@ -71,6 +73,9 @@ class BackupManagerService extends IBackupManager.Stub { private static final int MSG_RUN_BACKUP = 1; private static final int MSG_RUN_FULL_BACKUP = 2; // Timeout interval for deciding that a bind or clear-data has taken too long static final long TIMEOUT_INTERVAL = 10 * 1000; private Context mContext; private PackageManager mPackageManager; private final IActivityManager mActivityManager; Loading Loading @@ -108,6 +113,10 @@ class BackupManagerService extends IBackupManager.Stub { private IBackupAgent mConnectedAgent; private volatile boolean mConnecting; // A similar synchronicity mechanism around clearing apps' data for restore private final Object mClearDataLock = new Object(); private volatile boolean mClearingData; private int mTransportId; private File mStateDir; Loading Loading @@ -207,80 +216,6 @@ class BackupManagerService extends IBackupManager.Stub { } } void processOneBackup(BackupRequest request, IBackupAgent agent, IBackupTransport transport) { final String packageName = request.appInfo.packageName; Log.d(TAG, "processOneBackup doBackup() on " + packageName); try { // 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); // !!! TODO: get the state file dir from the transport File savedStateName = new File(mStateDir, packageName); File backupDataName = new File(mDataDir, packageName + ".data"); File newStateName = new File(mStateDir, packageName + ".new"); // In a full backup, we pass a null ParcelFileDescriptor as // the saved-state "file" ParcelFileDescriptor savedState = (request.fullBackup) ? null : ParcelFileDescriptor.open(savedStateName, ParcelFileDescriptor.MODE_READ_ONLY | ParcelFileDescriptor.MODE_CREATE); backupDataName.delete(); ParcelFileDescriptor backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); newStateName.delete(); ParcelFileDescriptor newState = ParcelFileDescriptor.open(newStateName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); // Run the target's backup pass boolean success = false; try { agent.doBackup(savedState, backupData, newState); success = true; } finally { if (savedState != null) { savedState.close(); } backupData.close(); newState.close(); } // Now propagate the newly-backed-up data to the transport if (success) { if (DEBUG) Log.v(TAG, "doBackup() success; calling transport"); backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY); int error = transport.performBackup(packInfo, backupData); // !!! 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(); } } // Add the backup agents in the given package to our set of known backup participants. // If 'packageName' is null, adds all backup agents in the whole system. void addPackageParticipantsLocked(String packageName) { Loading Loading @@ -424,11 +359,14 @@ class BackupManagerService extends IBackupManager.Stub { Log.d(TAG, "awaiting agent for " + app); // success; wait for the agent to arrive while (mConnecting && mConnectedAgent == null) { // only wait 10 seconds for the clear data to happen long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL; while (mConnecting && mConnectedAgent == null && (System.currentTimeMillis() < timeoutMark)) { try { mAgentConnectLock.wait(10000); mAgentConnectLock.wait(5000); } catch (InterruptedException e) { // just retry // just bail return null; } } Loading @@ -447,6 +385,37 @@ class BackupManagerService extends IBackupManager.Stub { return agent; } // clear an application's data, blocking until the operation completes or times out void clearApplicationDataSynchronous(String packageName) { ClearDataObserver observer = new ClearDataObserver(); synchronized(mClearDataLock) { mClearingData = true; mPackageManager.clearApplicationUserData(packageName, observer); // only wait 10 seconds for the clear data to happen long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL; while (mClearingData && (System.currentTimeMillis() < timeoutMark)) { try { mClearDataLock.wait(5000); } catch (InterruptedException e) { // won't happen, but still. mClearingData = false; } } } } class ClearDataObserver extends IPackageDataObserver.Stub { public void onRemoveCompleted(String packageName, boolean succeeded) throws android.os.RemoteException { synchronized(mClearDataLock) { mClearingData = false; notifyAll(); } } } // ----- Back up a set of applications via a worker thread ----- class PerformBackupThread extends Thread { Loading Loading @@ -508,13 +477,88 @@ class BackupManagerService extends IBackupManager.Stub { mActivityManager.unbindBackupAgent(request.appInfo); } catch (SecurityException ex) { // Try for the next one. Log.d(TAG, "error in bind", ex); Log.d(TAG, "error in bind/backup", ex); } catch (RemoteException e) { // can't happen Log.v(TAG, "bind/backup threw"); e.printStackTrace(); } } } void processOneBackup(BackupRequest request, IBackupAgent agent, IBackupTransport transport) { final String packageName = request.appInfo.packageName; Log.d(TAG, "processOneBackup doBackup() on " + packageName); try { // 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); // !!! TODO: get the state file dir from the transport File savedStateName = new File(mStateDir, packageName); File backupDataName = new File(mDataDir, packageName + ".data"); File newStateName = new File(mStateDir, packageName + ".new"); // In a full backup, we pass a null ParcelFileDescriptor as // the saved-state "file" ParcelFileDescriptor savedState = (request.fullBackup) ? null : ParcelFileDescriptor.open(savedStateName, ParcelFileDescriptor.MODE_READ_ONLY | ParcelFileDescriptor.MODE_CREATE); backupDataName.delete(); ParcelFileDescriptor backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); newStateName.delete(); ParcelFileDescriptor newState = ParcelFileDescriptor.open(newStateName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); // Run the target's backup pass boolean success = false; try { agent.doBackup(savedState, backupData, newState); success = true; } finally { if (savedState != null) { savedState.close(); } backupData.close(); newState.close(); } // Now propagate the newly-backed-up data to the transport if (success) { if (DEBUG) Log.v(TAG, "doBackup() success; calling transport"); backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY); int error = transport.performBackup(packInfo, backupData); // !!! 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(); } } } Loading @@ -524,12 +568,12 @@ class BackupManagerService extends IBackupManager.Stub { // ApplicationInfo struct if it is; null if not. // // !!! TODO: also consider signatures ApplicationInfo isRestorable(PackageInfo packageInfo) { PackageInfo isRestorable(PackageInfo packageInfo) { if (packageInfo.packageName != null) { try { ApplicationInfo app = mPackageManager.getApplicationInfo(packageInfo.packageName, PackageInfo app = mPackageManager.getPackageInfo(packageInfo.packageName, PackageManager.GET_SIGNATURES); if ((app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { if ((app.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { return app; } } catch (Exception e) { Loading @@ -541,6 +585,7 @@ class BackupManagerService extends IBackupManager.Stub { class PerformRestoreThread extends Thread { private IBackupTransport mTransport; private RestoreSet mImage; PerformRestoreThread(IBackupTransport transport) { mTransport = transport; Loading @@ -556,6 +601,7 @@ class BackupManagerService extends IBackupManager.Stub { * 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.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 Loading @@ -577,13 +623,14 @@ class BackupManagerService extends IBackupManager.Stub { RestoreSet[] images = mTransport.getAvailableRestoreSets(); if (images.length > 0) { // !!! for now we always take the first set RestoreSet image = images[0]; mImage = images[0]; // build the set of apps we will attempt to restore PackageInfo[] packages = mTransport.getAppSet(image.token); HashSet<ApplicationInfo> appsToRestore = new HashSet<ApplicationInfo>(); PackageInfo[] packages = mTransport.getAppSet(mImage.token); HashSet<PackageInfo> appsToRestore = new HashSet<PackageInfo>(); for (PackageInfo pkg: packages) { ApplicationInfo app = isRestorable(pkg); // get the real PackageManager idea of the package PackageInfo app = isRestorable(pkg); if (app != null) { appsToRestore.add(app); } Loading @@ -609,19 +656,23 @@ class BackupManagerService extends IBackupManager.Stub { } // restore each app in the queue void doQueuedRestores(HashSet<ApplicationInfo> appsToRestore) { for (ApplicationInfo app : appsToRestore) { void doQueuedRestores(HashSet<PackageInfo> appsToRestore) { for (PackageInfo app : appsToRestore) { Log.d(TAG, "starting agent for restore of " + app); IBackupAgent agent = null; try { agent = bindToAgentSynchronous(app, IApplicationThread.BACKUP_MODE_RESTORE); // Remove the app's data first clearApplicationDataSynchronous(app.packageName); // Now perform the restore into the clean app IBackupAgent agent = bindToAgentSynchronous(app.applicationInfo, IApplicationThread.BACKUP_MODE_RESTORE); if (agent != null) { processOneRestore(app, agent); } // unbind even on timeout, just in case mActivityManager.unbindBackupAgent(app); mActivityManager.unbindBackupAgent(app.applicationInfo); } catch (SecurityException ex) { // Try for the next one. Log.d(TAG, "error in bind", ex); Loading @@ -632,9 +683,67 @@ class BackupManagerService extends IBackupManager.Stub { } } // do the guts of a restore void processOneRestore(ApplicationInfo app, IBackupAgent agent) { // 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) { // !!! TODO: actually run the restore through mTransport final String packageName = app.packageName; // !!! TODO: get the dirs from the transport File backupDataName = new File(mDataDir, packageName + ".restore"); backupDataName.delete(); try { ParcelFileDescriptor backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); // 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 } finally { backupData.close(); } // Okay, we have the data. Now have the agent do the restore. File newStateName = new File(mStateDir, packageName + ".new"); ParcelFileDescriptor newState = ParcelFileDescriptor.open(newStateName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY); boolean success = false; try { agent.doRestore(backupData, newState); success = true; } catch (Exception e) { Log.e(TAG, "Restore failed for " + packageName); e.printStackTrace(); } 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); } catch (Exception e) { Log.e(TAG, "Final exception guard in restore:"); e.printStackTrace(); } } } Loading
services/java/com/android/server/am/ActivityManagerService.java +8 −5 Original line number Diff line number Diff line Loading @@ -10422,6 +10422,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Not backing this app up any more; reset its OOM adjustment updateOomAdjLocked(proc); // If the app crashed during backup, 'thread' will be null here if (proc.thread != null) { try { proc.thread.scheduleDestroyBackupAgent(appInfo); } catch (Exception e) { Loading @@ -10430,6 +10432,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } } } // ========================================================= // BROADCASTS // ========================================================= Loading