summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Tate <ctate@google.com>2010-03-29 19:14:24 -0700
committerChristopher Tate <ctate@google.com>2010-03-30 12:42:35 -0700
commit2d449afe3d075020bdd1115bcc15c9383cbce122 (patch)
treed7c71c9a74e317319de947f3e3fe3ee673f0c559
parentae405d56215e4ab43e8210b66e741a0bf9d5edcf (diff)
downloadframeworks_base-2d449afe3d075020bdd1115bcc15c9383cbce122.tar.gz
frameworks_base-2d449afe3d075020bdd1115bcc15c9383cbce122.tar.bz2
frameworks_base-2d449afe3d075020bdd1115bcc15c9383cbce122.zip
Make RestoreSession.getAvailableRestoreSets() asynchronous
This transaction can involve the transport having to query a remote backend over the wire, so it can take a Long Time(tm). Make it main-thread-safe by making it asynchronous, with the results passed as a callback to the invoker's RestoreObserver. We also make the IRestoreObserver callback interface properly oneway. Bug #2550665 Bug #2549422 Change-Id: If18a233a0a3d54c7b55101715c9e6195b762c5a0
-rw-r--r--api/current.xml41
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java27
-rw-r--r--core/java/android/app/backup/IRestoreObserver.aidl20
-rw-r--r--core/java/android/app/backup/IRestoreSession.aidl10
-rw-r--r--core/java/android/app/backup/RestoreObserver.java22
-rw-r--r--core/java/android/app/backup/RestoreSession.java28
-rw-r--r--services/java/com/android/server/BackupManagerService.java68
7 files changed, 181 insertions, 35 deletions
diff --git a/api/current.xml b/api/current.xml
index cf4686765d0..b0d99317284 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -27381,6 +27381,47 @@
visibility="public"
>
</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 name="SharedPreferencesBackupHelper"
extends="android.app.backup.FileBackupHelperBase"
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index fa8a7c8c478..5612158021d 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -254,11 +254,13 @@ public final class Bmgr {
private void doListRestoreSets() {
try {
- RestoreSet[] sets = mRestore.getAvailableRestoreSets();
- if (sets == null || sets.length == 0) {
- System.out.println("No restore sets available");
+ RestoreObserver observer = new RestoreObserver();
+ int err = mRestore.getAvailableRestoreSets(observer);
+ if (err != 0) {
+ System.out.println("Unable to request restore sets");
} else {
- printRestoreSets(sets);
+ observer.waitForCompletion();
+ printRestoreSets(observer.sets);
}
} catch (RemoteException e) {
System.err.println(e.toString());
@@ -274,6 +276,16 @@ public final class Bmgr {
class RestoreObserver extends IRestoreObserver.Stub {
boolean done;
+ RestoreSet[] sets = null;
+
+ public void restoreSetsAvailable(RestoreSet[] result) {
+ synchronized (this) {
+ sets = result;
+ done = true;
+ this.notify();
+ }
+ }
+
public void restoreStarting(int numPackages) {
System.out.println("restoreStarting: " + numPackages + " packages");
}
@@ -359,8 +371,11 @@ public final class Bmgr {
System.err.println(BMGR_NOT_RUNNING_ERR);
return;
}
- RestoreSet[] sets = mRestore.getAvailableRestoreSets();
- if (sets != null) {
+ RestoreSet[] sets = null;
+ int err = mRestore.getAvailableRestoreSets(observer);
+ if (err != 0) {
+ observer.waitForCompletion();
+ sets = observer.sets;
for (RestoreSet s : sets) {
if (s.token == token) {
System.out.println("Scheduling restore: " + s.name);
diff --git a/core/java/android/app/backup/IRestoreObserver.aidl b/core/java/android/app/backup/IRestoreObserver.aidl
index ec856839cb3..449765ec475 100644
--- a/core/java/android/app/backup/IRestoreObserver.aidl
+++ b/core/java/android/app/backup/IRestoreObserver.aidl
@@ -16,12 +16,26 @@
package android.app.backup;
+import android.app.backup.RestoreSet;
+
/**
* Callback class for receiving progress reports during a restore operation.
*
* @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.
*
@@ -32,8 +46,8 @@ interface IRestoreObserver {
/**
* An indication of which package is being restored currently, out of the
- * total number provided in the restoreStarting() callback. This method
- * is not guaranteed to be called.
+ * total number provided in the {@link #restoreStarting(int numPackages)} callback.
+ * This method is not guaranteed to be called.
*
* @param nowBeingRestored The index, between 1 and the numPackages parameter
* to the restoreStarting() callback, of the package now being restored.
diff --git a/core/java/android/app/backup/IRestoreSession.aidl b/core/java/android/app/backup/IRestoreSession.aidl
index 58c21fea40a..1dddbb02c8b 100644
--- a/core/java/android/app/backup/IRestoreSession.aidl
+++ b/core/java/android/app/backup/IRestoreSession.aidl
@@ -29,12 +29,12 @@ interface IRestoreSession {
/**
* Ask the current transport what the available restore sets are.
*
- * @return A bundle containing two elements: an int array under the key
- * "tokens" whose entries are a transport-private identifier for each backup set;
- * and a String array under the key "names" whose entries are the user-meaningful
- * text corresponding to the backup sets at each index in the tokens array.
+ * @param observer This binder points to an object whose onRestoreSetsAvailable()
+ * method will be called to supply the results of the transport's lookup.
+ * @return Zero on success; nonzero on error. The observer will only receive a
+ * 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
diff --git a/core/java/android/app/backup/RestoreObserver.java b/core/java/android/app/backup/RestoreObserver.java
index 0a4ea176d10..dbddb788cc7 100644
--- a/core/java/android/app/backup/RestoreObserver.java
+++ b/core/java/android/app/backup/RestoreObserver.java
@@ -17,6 +17,7 @@
package android.app.backup;
import java.lang.String;
+import android.app.backup.RestoreSet;
/**
* Callback class for receiving progress reports during a restore operation. These
@@ -24,12 +25,27 @@ import java.lang.String;
*/
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.
*
* @param numPackages The total number of packages being processed in
* 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.
* @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
* as a whole failed.
*/
- void restoreFinished(int error) {
+ public void restoreFinished(int error) {
}
}
diff --git a/core/java/android/app/backup/RestoreSession.java b/core/java/android/app/backup/RestoreSession.java
index da2778b6135..24ddb99725e 100644
--- a/core/java/android/app/backup/RestoreSession.java
+++ b/core/java/android/app/backup/RestoreSession.java
@@ -40,19 +40,22 @@ public class RestoreSession {
/**
* Ask the current transport what the available restore sets are.
*
- * @return A bundle containing two elements: an int array under the key
- * "tokens" whose entries are a transport-private identifier for each backup set;
- * and a String array under the key "names" whose entries are the user-meaningful
- * text corresponding to the backup sets at each index in the tokens array.
- * On error, returns null.
+ * @param observer a RestoreObserver object whose restoreSetsAvailable() method will
+ * be called on the application's main thread in order to supply the results of
+ * the restore set lookup by the backup transport. This parameter must not be
+ * 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 {
- return mBinder.getAvailableRestoreSets();
+ err = mBinder.getAvailableRestoreSets(obsWrapper);
} catch (RemoteException e) {
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_UPDATE = 2;
static final int MSG_RESTORE_FINISHED = 3;
+ static final int MSG_RESTORE_SETS_AVAILABLE = 4;
RestoreObserverWrapper(Context context, RestoreObserver appObserver) {
mHandler = new Handler(context.getMainLooper()) {
@@ -166,6 +170,9 @@ public class RestoreSession {
case MSG_RESTORE_FINISHED:
mAppObserver.restoreFinished(msg.arg1);
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
+ public void restoreSetsAvailable(RestoreSet[] result) {
+ mHandler.sendMessage(
+ mHandler.obtainMessage(MSG_RESTORE_SETS_AVAILABLE, result));
+ }
+
public void restoreStarting(int numPackages) {
mHandler.sendMessage(
mHandler.obtainMessage(MSG_RESTORE_STARTING, numPackages, 0));
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 6c1fa60298f..ecf1a1d1cd7 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -104,7 +104,8 @@ class BackupManagerService extends IBackupManager.Stub {
private static final int MSG_RUN_RESTORE = 3;
private static final int MSG_RUN_CLEAR = 4;
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
static final long TIMEOUT_INTERVAL = 10 * 1000;
@@ -177,6 +178,19 @@ class BackupManagerService extends IBackupManager.Stub {
IBackupTransport mLocalTransport, mGoogleTransport;
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 {
public IBackupTransport transport;
public IRestoreObserver observer;
@@ -333,6 +347,36 @@ class BackupManagerService extends IBackupManager.Stub {
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:
{
synchronized (mCurrentOpLock) {
@@ -2343,24 +2387,28 @@ class BackupManagerService extends IBackupManager.Stub {
}
// --- Binder interface ---
- public synchronized RestoreSet[] getAvailableRestoreSets() {
+ public synchronized int getAvailableRestoreSets(IRestoreObserver observer) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getAvailableRestoreSets");
+ if (observer == null) {
+ throw new IllegalArgumentException("Observer must not be null");
+ }
long oldId = Binder.clearCallingIdentity();
try {
if (mRestoreTransport == null) {
Slog.w(TAG, "Null transport getting restore sets");
- return null;
- }
- if (mRestoreSets == null) { // valid transport; do the one-time fetch
- mRestoreSets = mRestoreTransport.getAvailableRestoreSets();
- if (mRestoreSets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
- }
- return mRestoreSets;
+ return -1;
+ }
+ // spin off the transport request to our service thread
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS,
+ new RestoreGetSetsParams(mRestoreTransport, this, observer));
+ mBackupHandler.sendMessage(msg);
+ return 0;
} catch (Exception e) {
Slog.e(TAG, "Error in getAvailableRestoreSets", e);
- return null;
+ return -1;
} finally {
Binder.restoreCallingIdentity(oldId);
}