diff options
| author | 2010-01-25 19:37:47 -0800 | |
|---|---|---|
| committer | 2010-01-25 19:41:23 -0800 | |
| commit | 80202c8cb8c8e4ab507079e79b864c61a8eeeee9 (patch) | |
| tree | 517c775feb878d11f2e10eec0074907cea724574 | |
| parent | da77d0a6e7fe70b7da229077039bcca1f232bd89 (diff) | |
Move towards a formal public API for backup and restore
This commit makes a few changes towards establishing a formal application
interface for interacting with the backup/restore mechanism:
1. Introduce public wrapper classes around the various binder interfaces; 3rd
party code will never see the binders directly.
2. Progress update callbacks during a restore sequence now occur on the main
thread, not in a binder thread [and not with system-process permissions!].
3. Rename the BackupManagerService's inner "RestoreSession" class to avoid
ambiguity with the new public "RestoreSession" class.
| -rw-r--r-- | core/java/android/backup/BackupManager.java | 11 | ||||
| -rw-r--r-- | core/java/android/backup/RestoreObserver.java | 53 | ||||
| -rw-r--r-- | core/java/android/backup/RestoreSession.java | 178 | ||||
| -rw-r--r-- | services/java/com/android/server/BackupManagerService.java | 8 |
4 files changed, 242 insertions, 8 deletions
diff --git a/core/java/android/backup/BackupManager.java b/core/java/android/backup/BackupManager.java index da1647a5abcb..0b27117d3f45 100644 --- a/core/java/android/backup/BackupManager.java +++ b/core/java/android/backup/BackupManager.java @@ -16,6 +16,7 @@ package android.backup; +import android.backup.RestoreSession; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; @@ -115,19 +116,21 @@ public class BackupManager { * * {@hide} */ - public IRestoreSession beginRestoreSession(String transport) { + public RestoreSession beginRestoreSession() { if (!EVEN_THINK_ABOUT_DOING_RESTORE) { return null; } - IRestoreSession binder = null; + RestoreSession session = null; checkServiceBinder(); if (sService != null) { try { - binder = sService.beginRestoreSession(transport); + String transport = sService.getCurrentTransport(); + IRestoreSession binder = sService.beginRestoreSession(transport); + session = new RestoreSession(mContext, binder); } catch (RemoteException e) { Log.d(TAG, "beginRestoreSession() couldn't connect"); } } - return binder; + return session; } } diff --git a/core/java/android/backup/RestoreObserver.java b/core/java/android/backup/RestoreObserver.java new file mode 100644 index 000000000000..3be8c086ab50 --- /dev/null +++ b/core/java/android/backup/RestoreObserver.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.backup; + +/** + * Callback class for receiving progress reports during a restore operation. These + * methods will all be called on your application's main thread. + * @hide + */ +public abstract class RestoreObserver { + /** + * The restore operation has begun. + * + * @param numPackages The total number of packages being processed in + * this restore operation. + */ + void restoreStarting(int numPackages) { + } + + /** + * 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. + * + * @param nowBeingRestored The index, between 1 and the numPackages parameter + * to the restoreStarting() callback, of the package now being restored. + */ + void onUpdate(int nowBeingRestored) { + } + + /** + * The restore operation has completed. + * + * @param error Zero on success; a nonzero error code if the restore operation + * as a whole failed. + */ + void restoreFinished(int error) { + } +} diff --git a/core/java/android/backup/RestoreSession.java b/core/java/android/backup/RestoreSession.java new file mode 100644 index 000000000000..119fc52e7433 --- /dev/null +++ b/core/java/android/backup/RestoreSession.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.backup; + +import android.backup.IRestoreSession; +import android.backup.RestoreObserver; +import android.backup.RestoreSet; +import android.content.Context; +import android.os.Handler; +import android.os.RemoteException; +import android.util.Log; + +/** + * Interface for applications to use when managing a restore session. + * @hide + */ +public class RestoreSession { + static final String TAG = "RestoreSession"; + + final Context mContext; + IRestoreSession mBinder; + RestoreObserverWrapper mObserver = null; + + /** + * 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. + */ + public RestoreSet[] getAvailableRestoreSets() { + try { + return mBinder.getAvailableRestoreSets(); + } catch (RemoteException e) { + Log.d(TAG, "Can't contact server to get available sets"); + return null; + } + } + + /** + * Restore the given set onto the device, replacing the current data of any app + * contained in the restore set with the data previously backed up. + * + * @return Zero on success; nonzero on error. The observer will only receive + * progress callbacks if this method returned zero. + * @param token The token from {@link #getAvailableRestoreSets()} corresponding to + * the restore set that should be used. + * @param observer If non-null, this argument points to an object that will receive + * progress callbacks during the restore operation. These callbacks will occur + * on the main thread of the application. + */ + public int performRestore(long token, RestoreObserver observer) { + int err = -1; + if (mObserver != null) { + Log.d(TAG, "performRestore() called during active restore"); + return -1; + } + mObserver = new RestoreObserverWrapper(mContext, observer); + try { + err = mBinder.performRestore(token, mObserver); + } catch (RemoteException e) { + Log.d(TAG, "Can't contact server to perform restore"); + } + return err; + } + + /** + * End this restore session. After this method is called, the RestoreSession + * object is no longer valid. + * + * <p><b>Note:</b> The caller <i>must</i> invoke this method to end the restore session, + * even if {@link #getAvailableRestoreSets()} or + * {@link #performRestore(long, RestoreObserver)} failed. + */ + public void endRestoreSession() { + try { + mBinder.endRestoreSession(); + } catch (RemoteException e) { + Log.d(TAG, "Can't contact server to get available sets"); + } finally { + mBinder = null; + } + } + + /* + * Nonpublic implementation here + */ + + RestoreSession(Context context, IRestoreSession binder) { + mContext = context; + mBinder = binder; + } + + /* + * 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 + * progress callbacks nicely within the usual main-thread lifecycle pattern. + */ + private class RestoreObserverWrapper extends IRestoreObserver.Stub { + final Handler mHandler; + final RestoreObserver mAppObserver; + + RestoreObserverWrapper(Context context, RestoreObserver appObserver) { + mHandler = new Handler(context.getMainLooper()); + mAppObserver = appObserver; + } + + // Wrap the IRestoreObserver -> RestoreObserver callthrough in Runnables + // posted to the app's main thread looper. + class RestoreStartingRunnable implements Runnable { + int mNumPackages; + + RestoreStartingRunnable(int numPackages) { + mNumPackages = numPackages; + } + + public void run() { + mAppObserver.restoreStarting(mNumPackages); + } + } + + class OnUpdateRunnable implements Runnable { + int mNowRestoring; + + OnUpdateRunnable(int nowRestoring) { + mNowRestoring = nowRestoring; + } + + public void run() { + mAppObserver.onUpdate(mNowRestoring); + } + } + + class RestoreFinishedRunnable implements Runnable { + int mError; + + RestoreFinishedRunnable(int error) { + mError = error; + } + + public void run() { + mAppObserver.restoreFinished(mError); + } + } + + // The actual redirection code is quite simple using just the + // above Runnable subclasses + public void restoreStarting(int numPackages) { + mHandler.post(new RestoreStartingRunnable(numPackages)); + } + + public void onUpdate(int nowBeingRestored) { + mHandler.post(new OnUpdateRunnable(nowBeingRestored)); + } + + public void restoreFinished(int error) { + mHandler.post(new RestoreFinishedRunnable(error)); + } + } +} diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 2e4551268a08..72e26f8775ae 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -161,7 +161,7 @@ class BackupManagerService extends IBackupManager.Stub { = new HashMap<String,IBackupTransport>(); String mCurrentTransport; IBackupTransport mLocalTransport, mGoogleTransport; - RestoreSession mActiveRestoreSession; + ActiveRestoreSession mActiveRestoreSession; class RestoreParams { public IBackupTransport transport; @@ -2068,20 +2068,20 @@ class BackupManagerService extends IBackupManager.Stub { Log.d(TAG, "Restore session requested but one already active"); return null; } - mActiveRestoreSession = new RestoreSession(transport); + mActiveRestoreSession = new ActiveRestoreSession(transport); } return mActiveRestoreSession; } // ----- Restore session ----- - class RestoreSession extends IRestoreSession.Stub { + class ActiveRestoreSession extends IRestoreSession.Stub { private static final String TAG = "RestoreSession"; private IBackupTransport mRestoreTransport = null; RestoreSet[] mRestoreSets = null; - RestoreSession(String transport) { + ActiveRestoreSession(String transport) { mRestoreTransport = getTransport(transport); } |