diff --git a/core/java/android/backup/BackupService.java b/core/java/android/backup/BackupService.java index d912d8c6e7d0d..619718259812b 100644 --- a/core/java/android/backup/BackupService.java +++ b/core/java/android/backup/BackupService.java @@ -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; @@ -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 - * 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 - * file. The application should record the final backup state - * here after writing the requested data to dataFd. + * @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 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 @@ -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 - * of the application's data. - * @param newStateFd An open, read/write file descriptor pointing to an empty - * file. The application should record the final backup state - * here after restoring its data from dataFd. + * @param data An open, read-only ParcelFileDescriptor pointing to a full snapshot + * of the application's data. + * @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 ----- @@ -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); } } } diff --git a/core/java/android/backup/IBackupService.aidl b/core/java/android/backup/IBackupService.aidl index 24544bd26510e..1bde8eac9bdb1 100644 --- a/core/java/android/backup/IBackupService.aidl +++ b/core/java/android/backup/IBackupService.aidl @@ -16,38 +16,44 @@ 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 * this interface; they subclass BackupService instead. * * {@hide} - */ + */ 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 replacement 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); } diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 0f953180f8064..f5f35612679f7 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -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; @@ -57,6 +61,7 @@ class BackupManagerService extends IBackupManager.Stub { private HashSet mPendingBackups = new HashSet(); private final Object mQueueLock = new Object(); + private File mStateDir; // ----- Handler that runs the actual backup process asynchronously ----- @@ -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); } @@ -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 services = mPackageManager.queryIntentServices(