Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b91f4643 authored by Chris Tate's avatar Chris Tate Committed by Android (Google) Code Review
Browse files

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

parents 8aa2e893 80202c8c
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -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;
    }
}
+53 −0
Original line number Diff line number Diff line
/*
 * 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) {
    }
}
+178 −0
Original line number Diff line number Diff line
/*
 * 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));
        }
    }
}
+4 −4
Original line number Diff line number Diff line
@@ -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);
        }