Loading core/java/android/backup/BackupService.java +30 −25 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.app.Service; import android.backup.IBackupService; import android.content.Intent; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; Loading Loading @@ -59,23 +60,25 @@ public abstract class BackupService extends Service { * The application is being asked to write any data changed since the * last time it performed a backup operation. The state data recorded * during the last backup pass is provided in the oldStateFd file descriptor. * If oldStateFd is negative, no old state is available and the application * should perform a full backup. In both cases, a representation of the * final backup state after this pass should be written to the file pointed * If oldState.getStatSize() is zero or negative, no old state is available * and the application should perform a full backup. In both cases, a representation * of the final backup state after this pass should be written to the file pointed * to by the newStateFd file descriptor. * * @param oldStateFd An open, read-only file descriptor pointing to the last * backup state provided by the application. May be negative, * in which case no prior state is being provided and the * application should perform a full backup. * @param dataFd An open, read/write file descriptor pointing to the backup data * @param oldState An open, read-only ParcelFileDescriptor pointing to the last backup * state provided by the application. May be empty or invalid, in which * case no prior state is being provided and the application should * perform a full backup. * @param data An open, read/write ParcelFileDescriptor pointing to the backup data * destination. Typically the application will use backup helper * classes to write to this file. * @param newStateFd An open, read/write file descriptor pointing to an empty * @param newState An open, read/write ParcelFileDescriptor pointing to an empty * file. The application should record the final backup state * here after writing the requested data to dataFd. */ public abstract void onBackup(int oldStateFd, int dataFd, int newStateFd); public abstract void onBackup(ParcelFileDescriptor oldState, ParcelFileDescriptor data, ParcelFileDescriptor newState); /** * The application is being restored from backup, and should replace any Loading @@ -84,13 +87,13 @@ public abstract class BackupService extends Service { * the restore is finished, the application should write a representation * of the final state to the newStateFd file descriptor, * * @param dataFd An open, read-only file descriptor pointing to a full snapshot * @param data An open, read-only ParcelFileDescriptor pointing to a full snapshot * of the application's data. * @param newStateFd An open, read/write file descriptor pointing to an empty * @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(int dataFd, int newStateFd); public abstract void onRestore(ParcelFileDescriptor data, ParcelFileDescriptor newState); // ----- Core implementation ----- Loading @@ -110,17 +113,19 @@ public abstract class BackupService extends Service { // ----- IBackupService binder interface ----- private class BackupServiceBinder extends IBackupService.Stub { public void doBackup(int oldStateFd, int dataFd, int newStateFd) throws RemoteException { public void doBackup(ParcelFileDescriptor oldState, ParcelFileDescriptor data, ParcelFileDescriptor newState) throws RemoteException { // !!! TODO - real implementation; for now just invoke the callbacks directly Log.v("BackupServiceBinder", "doBackup() invoked"); BackupService.this.onBackup(oldStateFd, dataFd, newStateFd); BackupService.this.onBackup(oldState, data, newState); } public void doRestore(int dataFd, int newStateFd) throws RemoteException { public void doRestore(ParcelFileDescriptor data, ParcelFileDescriptor newState) throws RemoteException { // !!! TODO - real implementation; for now just invoke the callbacks directly Log.v("BackupServiceBinder", "doRestore() invoked"); BackupService.this.onRestore(dataFd, newStateFd); BackupService.this.onRestore(data, newState); } } } core/java/android/backup/IBackupService.aidl +14 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.backup; import android.os.ParcelFileDescriptor; /** * Interface presented by applications being asked to participate in the * backup & restore mechanism. End user code does not typically implement Loading @@ -27,27 +29,31 @@ interface IBackupService { /** * Request that the app perform an incremental backup. * * @param oldStateFd Read-only file containing the description blob of the * @param oldState Read-only file containing the description blob of the * app's data state as of the last backup operation's completion. * This file is empty or invalid when a full backup is being * requested. * * @param dataFd Read-write file, empty when onBackup() is called, that * @param data Read-write file, empty when onBackup() is called, that * is the data destination for this backup pass's incrementals. * * @param newStateFd Read-write file, empty when onBackup() is called, * @param newState Read-write file, empty when onBackup() is called, * where the new state blob is to be recorded. */ void doBackup(int oldStateFd, int dataFd, int newStateFd); void doBackup(in ParcelFileDescriptor oldState, in ParcelFileDescriptor data, in ParcelFileDescriptor newState); /** * Restore an entire data snapshot to the application. * * @param dataFd Read-only file containing the full data snapshot of the * @param data Read-only file containing the full data snapshot of the * app's backup. This is to be a <i>replacement</i> of the app's * current data, not to be merged into it. * * @param newStateFd 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 * the restore has been completed. */ void doRestore(int dataFd, int newStateFd); void doRestore(in ParcelFileDescriptor data, in ParcelFileDescriptor newState); } services/java/com/android/server/BackupManagerService.java +41 −2 Original line number Diff line number Diff line Loading @@ -26,15 +26,19 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Binder; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; import android.util.SparseArray; import android.backup.IBackupManager; import java.io.File; import java.io.FileNotFoundException; import java.lang.String; import java.util.HashSet; import java.util.List; Loading @@ -57,6 +61,7 @@ class BackupManagerService extends IBackupManager.Stub { private HashSet<ServiceInfo> mPendingBackups = new HashSet<ServiceInfo>(); private final Object mQueueLock = new Object(); private File mStateDir; // ----- Handler that runs the actual backup process asynchronously ----- Loading Loading @@ -99,12 +104,41 @@ class BackupManagerService extends IBackupManager.Stub { if (mTargetService != null) { try { Log.d(TAG, "invoking doBackup() on " + backupIntent); // !!! TODO: set up files mTargetService.doBackup(-1, -1, -1); File savedStateName = new File(mStateDir, service.packageName); File backupDataName = new File(mStateDir, service.packageName + ".data"); File newStateName = new File(mStateDir, service.packageName + ".new"); ParcelFileDescriptor savedState = ParcelFileDescriptor.open(savedStateName, ParcelFileDescriptor.MODE_READ_ONLY | ParcelFileDescriptor.MODE_CREATE); ParcelFileDescriptor backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); ParcelFileDescriptor newState = ParcelFileDescriptor.open(newStateName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); mTargetService.doBackup(savedState, backupData, newState); // !!! TODO: Now propagate the newly-backed-up data to the transport // !!! TODO: After successful transport, juggle the files so that // next time the new state is used as the old state } catch (FileNotFoundException fnf) { Log.d(TAG, "File not found on backup: "); fnf.printStackTrace(); } catch (RemoteException e) { Log.d(TAG, "Remote target " + backupIntent + " threw during backup:"); e.printStackTrace(); } catch (Exception e) { Log.w(TAG, "Final exception guard in backup: "); e.printStackTrace(); } mContext.unbindService(this); } Loading Loading @@ -138,6 +172,11 @@ class BackupManagerService extends IBackupManager.Stub { mContext = context; mPackageManager = context.getPackageManager(); // Set up our bookkeeping File dataDir = Environment.getDataDirectory(); mStateDir = new File(dataDir, "backup"); mStateDir.mkdirs(); // Identify the backup participants // !!! TODO: also watch package-install to keep this up to date List<ResolveInfo> services = mPackageManager.queryIntentServices( Loading Loading
core/java/android/backup/BackupService.java +30 −25 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.app.Service; import android.backup.IBackupService; import android.content.Intent; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; Loading Loading @@ -59,23 +60,25 @@ public abstract class BackupService extends Service { * The application is being asked to write any data changed since the * last time it performed a backup operation. The state data recorded * during the last backup pass is provided in the oldStateFd file descriptor. * If oldStateFd is negative, no old state is available and the application * should perform a full backup. In both cases, a representation of the * final backup state after this pass should be written to the file pointed * If oldState.getStatSize() is zero or negative, no old state is available * and the application should perform a full backup. In both cases, a representation * of the final backup state after this pass should be written to the file pointed * to by the newStateFd file descriptor. * * @param oldStateFd An open, read-only file descriptor pointing to the last * backup state provided by the application. May be negative, * in which case no prior state is being provided and the * application should perform a full backup. * @param dataFd An open, read/write file descriptor pointing to the backup data * @param oldState An open, read-only ParcelFileDescriptor pointing to the last backup * state provided by the application. May be empty or invalid, in which * case no prior state is being provided and the application should * perform a full backup. * @param data An open, read/write ParcelFileDescriptor pointing to the backup data * destination. Typically the application will use backup helper * classes to write to this file. * @param newStateFd An open, read/write file descriptor pointing to an empty * @param newState An open, read/write ParcelFileDescriptor pointing to an empty * file. The application should record the final backup state * here after writing the requested data to dataFd. */ public abstract void onBackup(int oldStateFd, int dataFd, int newStateFd); public abstract void onBackup(ParcelFileDescriptor oldState, ParcelFileDescriptor data, ParcelFileDescriptor newState); /** * The application is being restored from backup, and should replace any Loading @@ -84,13 +87,13 @@ public abstract class BackupService extends Service { * the restore is finished, the application should write a representation * of the final state to the newStateFd file descriptor, * * @param dataFd An open, read-only file descriptor pointing to a full snapshot * @param data An open, read-only ParcelFileDescriptor pointing to a full snapshot * of the application's data. * @param newStateFd An open, read/write file descriptor pointing to an empty * @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(int dataFd, int newStateFd); public abstract void onRestore(ParcelFileDescriptor data, ParcelFileDescriptor newState); // ----- Core implementation ----- Loading @@ -110,17 +113,19 @@ public abstract class BackupService extends Service { // ----- IBackupService binder interface ----- private class BackupServiceBinder extends IBackupService.Stub { public void doBackup(int oldStateFd, int dataFd, int newStateFd) throws RemoteException { public void doBackup(ParcelFileDescriptor oldState, ParcelFileDescriptor data, ParcelFileDescriptor newState) throws RemoteException { // !!! TODO - real implementation; for now just invoke the callbacks directly Log.v("BackupServiceBinder", "doBackup() invoked"); BackupService.this.onBackup(oldStateFd, dataFd, newStateFd); BackupService.this.onBackup(oldState, data, newState); } public void doRestore(int dataFd, int newStateFd) throws RemoteException { public void doRestore(ParcelFileDescriptor data, ParcelFileDescriptor newState) throws RemoteException { // !!! TODO - real implementation; for now just invoke the callbacks directly Log.v("BackupServiceBinder", "doRestore() invoked"); BackupService.this.onRestore(dataFd, newStateFd); BackupService.this.onRestore(data, newState); } } }
core/java/android/backup/IBackupService.aidl +14 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.backup; import android.os.ParcelFileDescriptor; /** * Interface presented by applications being asked to participate in the * backup & restore mechanism. End user code does not typically implement Loading @@ -27,27 +29,31 @@ interface IBackupService { /** * Request that the app perform an incremental backup. * * @param oldStateFd Read-only file containing the description blob of the * @param oldState Read-only file containing the description blob of the * app's data state as of the last backup operation's completion. * This file is empty or invalid when a full backup is being * requested. * * @param dataFd Read-write file, empty when onBackup() is called, that * @param data Read-write file, empty when onBackup() is called, that * is the data destination for this backup pass's incrementals. * * @param newStateFd Read-write file, empty when onBackup() is called, * @param newState Read-write file, empty when onBackup() is called, * where the new state blob is to be recorded. */ void doBackup(int oldStateFd, int dataFd, int newStateFd); void doBackup(in ParcelFileDescriptor oldState, in ParcelFileDescriptor data, in ParcelFileDescriptor newState); /** * Restore an entire data snapshot to the application. * * @param dataFd Read-only file containing the full data snapshot of the * @param data Read-only file containing the full data snapshot of the * app's backup. This is to be a <i>replacement</i> of the app's * current data, not to be merged into it. * * @param newStateFd 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 * the restore has been completed. */ void doRestore(int dataFd, int newStateFd); void doRestore(in ParcelFileDescriptor data, in ParcelFileDescriptor newState); }
services/java/com/android/server/BackupManagerService.java +41 −2 Original line number Diff line number Diff line Loading @@ -26,15 +26,19 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Binder; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; import android.util.SparseArray; import android.backup.IBackupManager; import java.io.File; import java.io.FileNotFoundException; import java.lang.String; import java.util.HashSet; import java.util.List; Loading @@ -57,6 +61,7 @@ class BackupManagerService extends IBackupManager.Stub { private HashSet<ServiceInfo> mPendingBackups = new HashSet<ServiceInfo>(); private final Object mQueueLock = new Object(); private File mStateDir; // ----- Handler that runs the actual backup process asynchronously ----- Loading Loading @@ -99,12 +104,41 @@ class BackupManagerService extends IBackupManager.Stub { if (mTargetService != null) { try { Log.d(TAG, "invoking doBackup() on " + backupIntent); // !!! TODO: set up files mTargetService.doBackup(-1, -1, -1); File savedStateName = new File(mStateDir, service.packageName); File backupDataName = new File(mStateDir, service.packageName + ".data"); File newStateName = new File(mStateDir, service.packageName + ".new"); ParcelFileDescriptor savedState = ParcelFileDescriptor.open(savedStateName, ParcelFileDescriptor.MODE_READ_ONLY | ParcelFileDescriptor.MODE_CREATE); ParcelFileDescriptor backupData = ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); ParcelFileDescriptor newState = ParcelFileDescriptor.open(newStateName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE); mTargetService.doBackup(savedState, backupData, newState); // !!! TODO: Now propagate the newly-backed-up data to the transport // !!! TODO: After successful transport, juggle the files so that // next time the new state is used as the old state } catch (FileNotFoundException fnf) { Log.d(TAG, "File not found on backup: "); fnf.printStackTrace(); } catch (RemoteException e) { Log.d(TAG, "Remote target " + backupIntent + " threw during backup:"); e.printStackTrace(); } catch (Exception e) { Log.w(TAG, "Final exception guard in backup: "); e.printStackTrace(); } mContext.unbindService(this); } Loading Loading @@ -138,6 +172,11 @@ class BackupManagerService extends IBackupManager.Stub { mContext = context; mPackageManager = context.getPackageManager(); // Set up our bookkeeping File dataDir = Environment.getDataDirectory(); mStateDir = new File(dataDir, "backup"); mStateDir.mkdirs(); // Identify the backup participants // !!! TODO: also watch package-install to keep this up to date List<ResolveInfo> services = mPackageManager.queryIntentServices( Loading