Squashed commit of the following:

Author: Christopher Tate <ctate@google.com>
Date:   Mon May 4 16:38:11 2009 -0700

    IBackupService now passes ParcelFileDescriptors rather than int fds

    The outlines of backup state file / data file handling are now in place as well
    in the BackupManagerService.

Author: Christopher Tate <ctate@google.com>
Date:   Thu Apr 30 12:40:19 2009 -0700

    Hide the backup stuff for now

    Also adjust based on comments:
    + changed service intent string to conform to usage guidelines
    + only publish the IBackupService binder when invoked with the right
      intent action
    + docs tweaks
This commit is contained in:
Christopher Tate
2009-05-04 16:41:53 -07:00
parent 636274185e
commit 22b8787ed4
3 changed files with 85 additions and 35 deletions

View File

@@ -22,6 +22,7 @@ import android.app.Service;
import android.backup.IBackupService; import android.backup.IBackupService;
import android.content.Intent; import android.content.Intent;
import android.os.IBinder; import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; 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 * The application is being asked to write any data changed since the
* last time it performed a backup operation. The state data recorded * last time it performed a backup operation. The state data recorded
* during the last backup pass is provided in the oldStateFd file descriptor. * during the last backup pass is provided in the oldStateFd file descriptor.
* If oldStateFd is negative, no old state is available and the application * If oldState.getStatSize() is zero or negative, no old state is available
* should perform a full backup. In both cases, a representation of the * and the application should perform a full backup. In both cases, a representation
* final backup state after this pass should be written to the file pointed * of the final backup state after this pass should be written to the file pointed
* to by the newStateFd file descriptor. * to by the newStateFd file descriptor.
* *
* @param oldStateFd An open, read-only file descriptor pointing to the last * @param oldState An open, read-only ParcelFileDescriptor pointing to the last backup
* backup state provided by the application. May be negative, * state provided by the application. May be empty or invalid, in which
* in which case no prior state is being provided and the * case no prior state is being provided and the application should
* application should perform a full backup. * perform a full backup.
* @param dataFd An open, read/write file descriptor pointing to the backup data * @param data An open, read/write ParcelFileDescriptor pointing to the backup data
* destination. Typically the application will use backup helper * destination. Typically the application will use backup helper
* classes to write to this file. * 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 * file. The application should record the final backup state
* here after writing the requested data to dataFd. * 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 * 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 * the restore is finished, the application should write a representation
* of the final state to the newStateFd file descriptor, * 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. * 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 * file. The application should record the final backup state
* here after restoring its data from dataFd. * 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 ----- // ----- Core implementation -----
@@ -110,17 +113,19 @@ public abstract class BackupService extends Service {
// ----- IBackupService binder interface ----- // ----- IBackupService binder interface -----
private class BackupServiceBinder extends IBackupService.Stub { private class BackupServiceBinder extends IBackupService.Stub {
public void doBackup(int oldStateFd, int dataFd, int newStateFd) public void doBackup(ParcelFileDescriptor oldState,
throws RemoteException { ParcelFileDescriptor data,
ParcelFileDescriptor newState) throws RemoteException {
// !!! TODO - real implementation; for now just invoke the callbacks directly // !!! TODO - real implementation; for now just invoke the callbacks directly
Log.v("BackupServiceBinder", "doBackup() invoked"); 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 // !!! TODO - real implementation; for now just invoke the callbacks directly
Log.v("BackupServiceBinder", "doRestore() invoked"); Log.v("BackupServiceBinder", "doRestore() invoked");
BackupService.this.onRestore(dataFd, newStateFd); BackupService.this.onRestore(data, newState);
} }
} }
} }

View File

@@ -16,38 +16,44 @@
package android.backup; package android.backup;
import android.os.ParcelFileDescriptor;
/** /**
* Interface presented by applications being asked to participate in the * Interface presented by applications being asked to participate in the
* backup & restore mechanism. End user code does not typically implement * backup & restore mechanism. End user code does not typically implement
* this interface; they subclass BackupService instead. * this interface; they subclass BackupService instead.
* *
* {@hide} * {@hide}
*/ */
interface IBackupService { interface IBackupService {
/** /**
* Request that the app perform an incremental backup. * 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. * 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. * 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. * 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. * 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 * app's backup. This is to be a <i>replacement</i> of the app's
* current data, not to be merged into it. * 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 * that is to be written with the state description that holds after
* the restore has been completed. * the restore has been completed.
*/ */
void doRestore(int dataFd, int newStateFd); void doRestore(in ParcelFileDescriptor data, in ParcelFileDescriptor newState);
} }

View File

@@ -26,15 +26,19 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.os.Binder; import android.os.Binder;
import android.os.Environment;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Message; import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import android.backup.IBackupManager; import android.backup.IBackupManager;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.String; import java.lang.String;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@@ -57,6 +61,7 @@ class BackupManagerService extends IBackupManager.Stub {
private HashSet<ServiceInfo> mPendingBackups = new HashSet<ServiceInfo>(); private HashSet<ServiceInfo> mPendingBackups = new HashSet<ServiceInfo>();
private final Object mQueueLock = new Object(); private final Object mQueueLock = new Object();
private File mStateDir;
// ----- Handler that runs the actual backup process asynchronously ----- // ----- Handler that runs the actual backup process asynchronously -----
@@ -99,12 +104,41 @@ class BackupManagerService extends IBackupManager.Stub {
if (mTargetService != null) { if (mTargetService != null) {
try { try {
Log.d(TAG, "invoking doBackup() on " + backupIntent); 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) { } catch (RemoteException e) {
Log.d(TAG, "Remote target " + backupIntent Log.d(TAG, "Remote target " + backupIntent
+ " threw during backup:"); + " threw during backup:");
e.printStackTrace(); e.printStackTrace();
} catch (Exception e) {
Log.w(TAG, "Final exception guard in backup: ");
e.printStackTrace();
} }
mContext.unbindService(this); mContext.unbindService(this);
} }
@@ -138,6 +172,11 @@ class BackupManagerService extends IBackupManager.Stub {
mContext = context; mContext = context;
mPackageManager = context.getPackageManager(); mPackageManager = context.getPackageManager();
// Set up our bookkeeping
File dataDir = Environment.getDataDirectory();
mStateDir = new File(dataDir, "backup");
mStateDir.mkdirs();
// Identify the backup participants // Identify the backup participants
// !!! TODO: also watch package-install to keep this up to date // !!! TODO: also watch package-install to keep this up to date
List<ResolveInfo> services = mPackageManager.queryIntentServices( List<ResolveInfo> services = mPackageManager.queryIntentServices(