Merge "Make backup/restore asynchronous and enforce timeouts"

This commit is contained in:
Chris Tate
2010-01-29 15:02:03 -08:00
committed by Android (Google) Code Review
5 changed files with 260 additions and 124 deletions

View File

@ -19,6 +19,7 @@ package android.app;
import android.app.IBackupAgent;
import android.backup.BackupDataInput;
import android.backup.BackupDataOutput;
import android.backup.IBackupManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.Binder;
@ -94,12 +95,9 @@ public abstract class BackupAgent extends ContextWrapper {
// ----- Core implementation -----
/**
* Returns the private interface called by the backup system. Applications will
* not typically override this.
*/
public IBinder onBind() {
/** @hide */
public final IBinder onBind() {
return mBinder;
}
@ -116,9 +114,10 @@ public abstract class BackupAgent extends ContextWrapper {
public void doBackup(ParcelFileDescriptor oldState,
ParcelFileDescriptor data,
ParcelFileDescriptor newState) throws RemoteException {
ParcelFileDescriptor newState,
int token, IBackupManager callbackBinder) throws RemoteException {
// Ensure that we're running with the app's normal permission level
long token = Binder.clearCallingIdentity();
long ident = Binder.clearCallingIdentity();
if (DEBUG) Log.v(TAG, "doBackup() invoked");
BackupDataOutput output = new BackupDataOutput(data.getFileDescriptor());
@ -131,14 +130,20 @@ public abstract class BackupAgent extends ContextWrapper {
Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
throw ex;
} finally {
Binder.restoreCallingIdentity(token);
Binder.restoreCallingIdentity(ident);
try {
callbackBinder.opComplete(token);
} catch (RemoteException e) {
// we'll time out anyway, so we're safe
}
}
}
public void doRestore(ParcelFileDescriptor data, int appVersionCode,
ParcelFileDescriptor newState) throws RemoteException {
ParcelFileDescriptor newState,
int token, IBackupManager callbackBinder) throws RemoteException {
// Ensure that we're running with the app's normal permission level
long token = Binder.clearCallingIdentity();
long ident = Binder.clearCallingIdentity();
if (DEBUG) Log.v(TAG, "doRestore() invoked");
BackupDataInput input = new BackupDataInput(data.getFileDescriptor());
@ -151,7 +156,12 @@ public abstract class BackupAgent extends ContextWrapper {
Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
throw ex;
} finally {
Binder.restoreCallingIdentity(token);
Binder.restoreCallingIdentity(ident);
try {
callbackBinder.opComplete(token);
} catch (RemoteException e) {
// we'll time out anyway, so we're safe
}
}
}
}

View File

@ -16,6 +16,7 @@
package android.app;
import android.backup.IBackupManager;
import android.os.ParcelFileDescriptor;
/**
@ -25,7 +26,7 @@ import android.os.ParcelFileDescriptor;
*
* {@hide}
*/
interface IBackupAgent {
oneway interface IBackupAgent {
/**
* Request that the app perform an incremental backup.
*
@ -39,10 +40,18 @@ interface IBackupAgent {
*
* @param newState Read-write file, empty when onBackup() is called,
* where the new state blob is to be recorded.
*
* @param token Opaque token identifying this transaction. This must
* be echoed back to the backup service binder once the new
* data has been written to the data and newState files.
*
* @param callbackBinder Binder on which to indicate operation completion,
* passed here as a convenience to the agent.
*/
void doBackup(in ParcelFileDescriptor oldState,
in ParcelFileDescriptor data,
in ParcelFileDescriptor newState);
in ParcelFileDescriptor newState,
int token, IBackupManager callbackBinder);
/**
* Restore an entire data snapshot to the application.
@ -58,7 +67,15 @@ interface IBackupAgent {
* @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.
*
* @param token Opaque token identifying this transaction. This must
* be echoed back to the backup service binder once the agent is
* finished restoring the application based on the restore data
* contents.
*
* @param callbackBinder Binder on which to indicate operation completion,
* passed here as a convenience to the agent.
*/
void doRestore(in ParcelFileDescriptor data, int appVersionCode,
in ParcelFileDescriptor newState);
in ParcelFileDescriptor newState, int token, IBackupManager callbackBinder);
}

View File

@ -130,4 +130,14 @@ interface IBackupManager {
* @return An interface to the restore session, or null on error.
*/
IRestoreSession beginRestoreSession(String transportID);
/**
* Notify the backup manager that a BackupAgent has completed the operation
* corresponding to the given token.
*
* @param token The transaction token passed to a BackupAgent's doBackup() or
* doRestore() method.
* {@hide}
*/
void opComplete(int token);
}

View File

@ -109,9 +109,7 @@ public class RestoreSession {
/*
* We wrap incoming binder calls with a private class implementation that
* redirects them into main-thread actions. This accomplishes two things:
* first, it ensures that the app's code is run on their own main thread,
* never with system Binder identity; and second, it serializes the restore
* redirects them into main-thread actions. This serializes the restore
* progress callbacks nicely within the usual main-thread lifecycle pattern.
*/
private class RestoreObserverWrapper extends IRestoreObserver.Stub {