diff options
-rw-r--r-- | api/current.xml | 41 | ||||
-rw-r--r-- | cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java | 27 | ||||
-rw-r--r-- | core/java/android/app/backup/IRestoreObserver.aidl | 20 | ||||
-rw-r--r-- | core/java/android/app/backup/IRestoreSession.aidl | 10 | ||||
-rw-r--r-- | core/java/android/app/backup/RestoreObserver.java | 22 | ||||
-rw-r--r-- | core/java/android/app/backup/RestoreSession.java | 28 | ||||
-rw-r--r-- | services/java/com/android/server/BackupManagerService.java | 68 |
7 files changed, 181 insertions, 35 deletions
diff --git a/api/current.xml b/api/current.xml index cf46867..b0d9931 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 fa8a7c8..5612158 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 ec85683..449765e 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 58c21fe..1dddbb0 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 0a4ea17..dbddb78 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 da2778b..24ddb99 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 6c1fa60..ecf1a1d 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); } |