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:
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user