am 22375e4a: Merge "Make RestoreSession.getAvailableRestoreSets() asynchronous" into froyo

Merge commit '22375e4a736c0d646c3cf0905c15126f7f4107c2' into froyo-plus-aosp

* commit '22375e4a736c0d646c3cf0905c15126f7f4107c2':
  Make RestoreSession.getAvailableRestoreSets() asynchronous
This commit is contained in:
Christopher Tate
2010-03-30 13:13:52 -07:00
committed by Android Git Automerger
7 changed files with 180 additions and 34 deletions

View File

@@ -27381,6 +27381,47 @@
visibility="public" visibility="public"
> >
</constructor> </constructor>
<method name="onUpdate"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="nowBeingRestored" type="int">
</parameter>
<parameter name="currentPackage" type="java.lang.String">
</parameter>
</method>
<method name="restoreFinished"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="error" type="int">
</parameter>
</method>
<method name="restoreStarting"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="numPackages" type="int">
</parameter>
</method>
</class> </class>
<class name="SharedPreferencesBackupHelper" <class name="SharedPreferencesBackupHelper"
extends="android.app.backup.FileBackupHelperBase" extends="android.app.backup.FileBackupHelperBase"

View File

@@ -254,11 +254,13 @@ public final class Bmgr {
private void doListRestoreSets() { private void doListRestoreSets() {
try { try {
RestoreSet[] sets = mRestore.getAvailableRestoreSets(); RestoreObserver observer = new RestoreObserver();
if (sets == null || sets.length == 0) { int err = mRestore.getAvailableRestoreSets(observer);
System.out.println("No restore sets available"); if (err != 0) {
System.out.println("Unable to request restore sets");
} else { } else {
printRestoreSets(sets); observer.waitForCompletion();
printRestoreSets(observer.sets);
} }
} catch (RemoteException e) { } catch (RemoteException e) {
System.err.println(e.toString()); System.err.println(e.toString());
@@ -274,6 +276,16 @@ public final class Bmgr {
class RestoreObserver extends IRestoreObserver.Stub { class RestoreObserver extends IRestoreObserver.Stub {
boolean done; boolean done;
RestoreSet[] sets = null;
public void restoreSetsAvailable(RestoreSet[] result) {
synchronized (this) {
sets = result;
done = true;
this.notify();
}
}
public void restoreStarting(int numPackages) { public void restoreStarting(int numPackages) {
System.out.println("restoreStarting: " + numPackages + " packages"); System.out.println("restoreStarting: " + numPackages + " packages");
} }
@@ -359,8 +371,11 @@ public final class Bmgr {
System.err.println(BMGR_NOT_RUNNING_ERR); System.err.println(BMGR_NOT_RUNNING_ERR);
return; return;
} }
RestoreSet[] sets = mRestore.getAvailableRestoreSets(); RestoreSet[] sets = null;
if (sets != null) { int err = mRestore.getAvailableRestoreSets(observer);
if (err != 0) {
observer.waitForCompletion();
sets = observer.sets;
for (RestoreSet s : sets) { for (RestoreSet s : sets) {
if (s.token == token) { if (s.token == token) {
System.out.println("Scheduling restore: " + s.name); System.out.println("Scheduling restore: " + s.name);

View File

@@ -16,12 +16,26 @@
package android.app.backup; package android.app.backup;
import android.app.backup.RestoreSet;
/** /**
* Callback class for receiving progress reports during a restore operation. * Callback class for receiving progress reports during a restore operation.
* *
* @hide * @hide
*/ */
interface IRestoreObserver { oneway interface IRestoreObserver {
/**
* Supply a list of the restore datasets available from the current transport. This
* method is invoked as a callback following the application's use of the
* {@link android.app.backup.IRestoreSession.getAvailableRestoreSets} method.
*
* @param result An array of {@link android.app.backup.RestoreSet RestoreSet} objects
* describing all of the available datasets that are candidates for restoring to
* the current device. If no applicable datasets exist, {@code result} will be
* {@code null}.
*/
void restoreSetsAvailable(in RestoreSet[] result);
/** /**
* The restore operation has begun. * The restore operation has begun.
* *
@@ -32,8 +46,8 @@ interface IRestoreObserver {
/** /**
* An indication of which package is being restored currently, out of the * An indication of which package is being restored currently, out of the
* total number provided in the restoreStarting() callback. This method * total number provided in the {@link #restoreStarting(int numPackages)} callback.
* is not guaranteed to be called. * This method is not guaranteed to be called.
* *
* @param nowBeingRestored The index, between 1 and the numPackages parameter * @param nowBeingRestored The index, between 1 and the numPackages parameter
* to the restoreStarting() callback, of the package now being restored. * to the restoreStarting() callback, of the package now being restored.

View File

@@ -29,12 +29,12 @@ interface IRestoreSession {
/** /**
* Ask the current transport what the available restore sets are. * Ask the current transport what the available restore sets are.
* *
* @return A bundle containing two elements: an int array under the key * @param observer This binder points to an object whose onRestoreSetsAvailable()
* "tokens" whose entries are a transport-private identifier for each backup set; * method will be called to supply the results of the transport's lookup.
* and a String array under the key "names" whose entries are the user-meaningful * @return Zero on success; nonzero on error. The observer will only receive a
* text corresponding to the backup sets at each index in the tokens array. * result callback if this method returned zero.
*/ */
RestoreSet[] getAvailableRestoreSets(); int getAvailableRestoreSets(IRestoreObserver observer);
/** /**
* Restore the given set onto the device, replacing the current data of any app * Restore the given set onto the device, replacing the current data of any app

View File

@@ -17,19 +17,35 @@
package android.app.backup; package android.app.backup;
import java.lang.String; import java.lang.String;
import android.app.backup.RestoreSet;
/** /**
* Callback class for receiving progress reports during a restore operation. These * Callback class for receiving progress reports during a restore operation. These
* methods will all be called on your application's main thread. * methods will all be called on your application's main thread.
*/ */
public abstract class RestoreObserver { public abstract class RestoreObserver {
/**
* Supply a list of the restore datasets available from the current transport. This
* method is invoked as a callback following the application's use of the
* {@link android.app.backup.IRestoreSession.getAvailableRestoreSets} method.
*
* @param result An array of {@link android.app.backup.RestoreSet RestoreSet} objects
* describing all of the available datasets that are candidates for restoring to
* the current device. If no applicable datasets exist, {@code result} will be
* {@code null}.
*
* @hide
*/
public void restoreSetsAvailable(RestoreSet[] result) {
}
/** /**
* The restore operation has begun. * The restore operation has begun.
* *
* @param numPackages The total number of packages being processed in * @param numPackages The total number of packages being processed in
* this restore operation. * this restore operation.
*/ */
void restoreStarting(int numPackages) { public void restoreStarting(int numPackages) {
} }
/** /**
@@ -45,7 +61,7 @@ public abstract class RestoreObserver {
* indication of the backup manager's progress through the overall restore process. * indication of the backup manager's progress through the overall restore process.
* @param currentPackage The name of the package now being restored. * @param currentPackage The name of the package now being restored.
*/ */
void onUpdate(int nowBeingRestored, String currentPackage) { public void onUpdate(int nowBeingRestored, String currentPackage) {
} }
/** /**
@@ -55,6 +71,6 @@ public abstract class RestoreObserver {
* @param error Zero on success; a nonzero error code if the restore operation * @param error Zero on success; a nonzero error code if the restore operation
* as a whole failed. * as a whole failed.
*/ */
void restoreFinished(int error) { public void restoreFinished(int error) {
} }
} }

View File

@@ -40,19 +40,22 @@ public class RestoreSession {
/** /**
* Ask the current transport what the available restore sets are. * Ask the current transport what the available restore sets are.
* *
* @return A bundle containing two elements: an int array under the key * @param observer a RestoreObserver object whose restoreSetsAvailable() method will
* "tokens" whose entries are a transport-private identifier for each backup set; * be called on the application's main thread in order to supply the results of
* and a String array under the key "names" whose entries are the user-meaningful * the restore set lookup by the backup transport. This parameter must not be
* text corresponding to the backup sets at each index in the tokens array. * null.
* On error, returns null. * @return Zero on success, nonzero on error. The observer's restoreSetsAvailable()
* method will only be called if this method returned zero.
*/ */
public RestoreSet[] getAvailableRestoreSets() { public int getAvailableRestoreSets(RestoreObserver observer) {
int err = -1;
RestoreObserverWrapper obsWrapper = new RestoreObserverWrapper(mContext, observer);
try { try {
return mBinder.getAvailableRestoreSets(); err = mBinder.getAvailableRestoreSets(obsWrapper);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.d(TAG, "Can't contact server to get available sets"); Log.d(TAG, "Can't contact server to get available sets");
return null;
} }
return err;
} }
/** /**
@@ -151,6 +154,7 @@ public class RestoreSession {
static final int MSG_RESTORE_STARTING = 1; static final int MSG_RESTORE_STARTING = 1;
static final int MSG_UPDATE = 2; static final int MSG_UPDATE = 2;
static final int MSG_RESTORE_FINISHED = 3; static final int MSG_RESTORE_FINISHED = 3;
static final int MSG_RESTORE_SETS_AVAILABLE = 4;
RestoreObserverWrapper(Context context, RestoreObserver appObserver) { RestoreObserverWrapper(Context context, RestoreObserver appObserver) {
mHandler = new Handler(context.getMainLooper()) { mHandler = new Handler(context.getMainLooper()) {
@@ -166,6 +170,9 @@ public class RestoreSession {
case MSG_RESTORE_FINISHED: case MSG_RESTORE_FINISHED:
mAppObserver.restoreFinished(msg.arg1); mAppObserver.restoreFinished(msg.arg1);
break; break;
case MSG_RESTORE_SETS_AVAILABLE:
mAppObserver.restoreSetsAvailable((RestoreSet[])msg.obj);
break;
} }
} }
}; };
@@ -173,6 +180,11 @@ public class RestoreSession {
} }
// Binder calls into this object just enqueue on the main-thread handler // Binder calls into this object just enqueue on the main-thread handler
public void restoreSetsAvailable(RestoreSet[] result) {
mHandler.sendMessage(
mHandler.obtainMessage(MSG_RESTORE_SETS_AVAILABLE, result));
}
public void restoreStarting(int numPackages) { public void restoreStarting(int numPackages) {
mHandler.sendMessage( mHandler.sendMessage(
mHandler.obtainMessage(MSG_RESTORE_STARTING, numPackages, 0)); mHandler.obtainMessage(MSG_RESTORE_STARTING, numPackages, 0));

View File

@@ -104,7 +104,8 @@ class BackupManagerService extends IBackupManager.Stub {
private static final int MSG_RUN_RESTORE = 3; private static final int MSG_RUN_RESTORE = 3;
private static final int MSG_RUN_CLEAR = 4; private static final int MSG_RUN_CLEAR = 4;
private static final int MSG_RUN_INITIALIZE = 5; private static final int MSG_RUN_INITIALIZE = 5;
private static final int MSG_TIMEOUT = 6; private static final int MSG_RUN_GET_RESTORE_SETS = 6;
private static final int MSG_TIMEOUT = 7;
// Timeout interval for deciding that a bind or clear-data has taken too long // Timeout interval for deciding that a bind or clear-data has taken too long
static final long TIMEOUT_INTERVAL = 10 * 1000; static final long TIMEOUT_INTERVAL = 10 * 1000;
@@ -177,6 +178,19 @@ class BackupManagerService extends IBackupManager.Stub {
IBackupTransport mLocalTransport, mGoogleTransport; IBackupTransport mLocalTransport, mGoogleTransport;
ActiveRestoreSession mActiveRestoreSession; ActiveRestoreSession mActiveRestoreSession;
class RestoreGetSetsParams {
public IBackupTransport transport;
public ActiveRestoreSession session;
public IRestoreObserver observer;
RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
IRestoreObserver _observer) {
transport = _transport;
session = _session;
observer = _observer;
}
}
class RestoreParams { class RestoreParams {
public IBackupTransport transport; public IBackupTransport transport;
public IRestoreObserver observer; public IRestoreObserver observer;
@@ -333,6 +347,36 @@ class BackupManagerService extends IBackupManager.Stub {
break; break;
} }
case MSG_RUN_GET_RESTORE_SETS:
{
// Like other async operations, this is entered with the wakelock held
RestoreSet[] sets = null;
RestoreGetSetsParams params = (RestoreGetSetsParams)msg.obj;
try {
sets = params.transport.getAvailableRestoreSets();
// cache the result in the active session
synchronized (params.session) {
params.session.mRestoreSets = sets;
}
if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
} catch (Exception e) {
Slog.e(TAG, "Error from transport getting set list");
} finally {
if (params.observer != null) {
try {
params.observer.restoreSetsAvailable(sets);
} catch (RemoteException re) {
Slog.e(TAG, "Unable to report listing to observer");
} catch (Exception e) {
Slog.e(TAG, "Restore observer threw", e);
}
}
mWakelock.release();
}
break;
}
case MSG_TIMEOUT: case MSG_TIMEOUT:
{ {
synchronized (mCurrentOpLock) { synchronized (mCurrentOpLock) {
@@ -2343,24 +2387,28 @@ class BackupManagerService extends IBackupManager.Stub {
} }
// --- Binder interface --- // --- Binder interface ---
public synchronized RestoreSet[] getAvailableRestoreSets() { public synchronized int getAvailableRestoreSets(IRestoreObserver observer) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getAvailableRestoreSets"); "getAvailableRestoreSets");
if (observer == null) {
throw new IllegalArgumentException("Observer must not be null");
}
long oldId = Binder.clearCallingIdentity(); long oldId = Binder.clearCallingIdentity();
try { try {
if (mRestoreTransport == null) { if (mRestoreTransport == null) {
Slog.w(TAG, "Null transport getting restore sets"); Slog.w(TAG, "Null transport getting restore sets");
return null; return -1;
} }
if (mRestoreSets == null) { // valid transport; do the one-time fetch // spin off the transport request to our service thread
mRestoreSets = mRestoreTransport.getAvailableRestoreSets(); mWakelock.acquire();
if (mRestoreSets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS,
} new RestoreGetSetsParams(mRestoreTransport, this, observer));
return mRestoreSets; mBackupHandler.sendMessage(msg);
return 0;
} catch (Exception e) { } catch (Exception e) {
Slog.e(TAG, "Error in getAvailableRestoreSets", e); Slog.e(TAG, "Error in getAvailableRestoreSets", e);
return null; return -1;
} finally { } finally {
Binder.restoreCallingIdentity(oldId); Binder.restoreCallingIdentity(oldId);
} }