Merge "Move towards a formal public API for backup and restore"

This commit is contained in:
Chris Tate
2010-01-26 12:29:13 -08:00
committed by Android (Google) Code Review
4 changed files with 242 additions and 8 deletions

View File

@@ -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;
}
}

View File

@@ -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) {
}
}

View File

@@ -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));
}
}
}

View File

@@ -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);
}