Merge "Make backup/restore asynchronous and enforce timeouts"
This commit is contained in:
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Reference in New Issue
Block a user