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

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

Merge "Can now restore a subset of apps from historical dataset"

parents effa7523 284f1bb4
Loading
Loading
Loading
Loading
+26 −6
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import android.app.backup.IRestoreSession;
import android.os.RemoteException;
import android.os.ServiceManager;

import java.util.HashSet;

public final class Bmgr {
    IBackupManager mBmgr;
    IRestoreSession mRestore;
@@ -45,7 +47,6 @@ public final class Bmgr {
    }

    public void run(String[] args) {
        boolean validCommand = false;
        if (args.length < 1) {
            showUsage();
            return;
@@ -329,7 +330,13 @@ public final class Bmgr {
        } else {
            try {
                long token = Long.parseLong(arg, 16);
                doRestoreAll(token);
                HashSet<String> filter = null;
                while ((arg = nextArg()) != null) {
                    if (filter == null) filter = new HashSet<String>();
                    filter.add(arg);
                }

                doRestoreAll(token, filter);
            } catch (NumberFormatException e) {
                showUsage();
                return;
@@ -364,7 +371,7 @@ public final class Bmgr {
        }
    }

    private void doRestoreAll(long token) {
    private void doRestoreAll(long token, HashSet<String> filter) {
        RestoreObserver observer = new RestoreObserver();

        try {
@@ -383,7 +390,13 @@ public final class Bmgr {
                    for (RestoreSet s : sets) {
                        if (s.token == token) {
                            System.out.println("Scheduling restore: " + s.name);
                            if (filter == null) {
                                didRestore = (mRestore.restoreAll(token, observer) == 0);
                            } else {
                                String[] names = new String[filter.size()];
                                filter.toArray(names);
                                didRestore = (mRestore.restoreSome(token, observer, names) == 0);
                            }
                            break;
                        }
                    }
@@ -430,6 +443,7 @@ public final class Bmgr {
        System.err.println("       bmgr list sets");
        System.err.println("       bmgr transport WHICH");
        System.err.println("       bmgr restore TOKEN");
        System.err.println("       bmgr restore TOKEN PACKAGE...");
        System.err.println("       bmgr restore PACKAGE");
        System.err.println("       bmgr run");
        System.err.println("       bmgr wipe PACKAGE");
@@ -457,12 +471,18 @@ public final class Bmgr {
        System.err.println("The 'transport' command designates the named transport as the currently");
        System.err.println("active one.  This setting is persistent across reboots.");
        System.err.println("");
        System.err.println("The 'restore' command when given a restore token initiates a full-system");
        System.err.println("The 'restore' command when given just a restore token initiates a full-system");
        System.err.println("restore operation from the currently active transport.  It will deliver");
        System.err.println("the restore set designated by the TOKEN argument to each application");
        System.err.println("that had contributed data to that restore set.");
        System.err.println("");
        System.err.println("The 'restore' command when given a package name intiates a restore of");
        System.err.println("The 'restore' command when given a token and one or more package names");
        System.err.println("initiates a restore operation of just those given packages from the restore");
        System.err.println("set designated by the TOKEN argument.  It is effectively the same as the");
        System.err.println("'restore' operation supplying only a token, but applies a filter to the");
        System.err.println("set of applications to be restored.");
        System.err.println("");
        System.err.println("The 'restore' command when given just a package name intiates a restore of");
        System.err.println("just that one package according to the restore set selection algorithm");
        System.err.println("used by the RestoreSession.restorePackage() method.");
        System.err.println("");
+19 −0
Original line number Diff line number Diff line
@@ -51,6 +51,25 @@ interface IRestoreSession {
     */
    int restoreAll(long token, IRestoreObserver observer);

    /**
     * Restore select packages from the given set onto the device, replacing the
     * current data of any app contained in the set with the data previously
     * backed up.
     *
     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
     *
     * @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 binder points to an object that will receive
     *   progress callbacks during the restore operation.
     * @param packages The set of packages for which to attempt a restore.  Regardless of
     *   the contents of the actual back-end dataset named by {@code token}, only
     *   applications mentioned in this list will have their data restored.
     */
    int restoreSome(long token, IRestoreObserver observer, in String[] packages);

    /**
     * Restore a single application from backup.  The data will be restored from the
     * current backup dataset if the given package has stored data there, or from
+34 −0
Original line number Diff line number Diff line
@@ -86,6 +86,40 @@ public class RestoreSession {
        return err;
    }

    /**
     * Restore select packages from the given set onto the device, replacing the
     * current data of any app contained in the set with the data previously
     * backed up.
     *
     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
     *
     * @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 binder points to an object that will receive
     *   progress callbacks during the restore operation.
     * @param packages The set of packages for which to attempt a restore.  Regardless of
     *   the contents of the actual back-end dataset named by {@code token}, only
     *   applications mentioned in this list will have their data restored.
     *
     * @hide
     */
    public int restoreSome(long token, RestoreObserver observer, String[] packages) {
        int err = -1;
        if (mObserver != null) {
            Log.d(TAG, "restoreAll() called during active restore");
            return -1;
        }
        mObserver = new RestoreObserverWrapper(mContext, observer);
        try {
            err = mBinder.restoreSome(token, mObserver, packages);
        } catch (RemoteException e) {
            Log.d(TAG, "Can't contact server to restore packages");
        }
        return err;
    }

    /**
     * Restore a single application from backup.  The data will be restored from the
     * current backup dataset if the given package has stored data there, or from
+105 −3
Original line number Diff line number Diff line
@@ -224,6 +224,7 @@ class BackupManagerService extends IBackupManager.Stub {
        public PackageInfo pkgInfo;
        public int pmToken; // in post-install restore, the PM's token for this transaction
        public boolean needFullBackup;
        public String[] filterSet;

        RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
                long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
@@ -233,6 +234,7 @@ class BackupManagerService extends IBackupManager.Stub {
            pkgInfo = _pkg;
            pmToken = _pmToken;
            needFullBackup = _needFullBackup;
            filterSet = null;
        }

        RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
@@ -243,6 +245,18 @@ class BackupManagerService extends IBackupManager.Stub {
            pkgInfo = null;
            pmToken = 0;
            needFullBackup = _needFullBackup;
            filterSet = null;
        }

        RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
                String[] _filterSet, boolean _needFullBackup) {
            transport = _transport;
            observer = _obs;
            token = _token;
            pkgInfo = null;
            pmToken = 0;
            needFullBackup = _needFullBackup;
            filterSet = _filterSet;
        }
    }

@@ -404,7 +418,7 @@ class BackupManagerService extends IBackupManager.Stub {
                Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
                (new PerformRestoreTask(params.transport, params.observer,
                        params.token, params.pkgInfo, params.pmToken,
                        params.needFullBackup)).run();
                        params.needFullBackup, params.filterSet)).run();
                break;
            }

@@ -3020,6 +3034,7 @@ class BackupManagerService extends IBackupManager.Stub {
        private File mStateDir;
        private int mPmToken;
        private boolean mNeedFullBackup;
        private HashSet<String> mFilterSet;

        class RestoreRequest {
            public PackageInfo app;
@@ -3033,7 +3048,7 @@ class BackupManagerService extends IBackupManager.Stub {

        PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
                long restoreSetToken, PackageInfo targetPackage, int pmToken,
                boolean needFullBackup) {
                boolean needFullBackup, String[] filterSet) {
            mTransport = transport;
            mObserver = observer;
            mToken = restoreSetToken;
@@ -3041,6 +3056,15 @@ class BackupManagerService extends IBackupManager.Stub {
            mPmToken = pmToken;
            mNeedFullBackup = needFullBackup;

            if (filterSet != null) {
                mFilterSet = new HashSet<String>();
                for (String pkg : filterSet) {
                    mFilterSet.add(pkg);
                }
            } else {
                mFilterSet = null;
            }

            try {
                mStateDir = new File(mBaseStateDir, transport.transportDirName());
            } catch (RemoteException e) {
@@ -3052,7 +3076,8 @@ class BackupManagerService extends IBackupManager.Stub {
            long startRealtime = SystemClock.elapsedRealtime();
            if (DEBUG) Slog.v(TAG, "Beginning restore process mTransport=" + mTransport
                    + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken)
                    + " mTargetPackage=" + mTargetPackage + " mPmToken=" + mPmToken);
                    + " mTargetPackage=" + mTargetPackage + " mFilterSet=" + mFilterSet
                    + " mPmToken=" + mPmToken);

            PackageManagerBackupAgent pmAgent = null;
            int error = -1; // assume error
@@ -3071,6 +3096,22 @@ class BackupManagerService extends IBackupManager.Stub {

                List<PackageInfo> agentPackages = allAgentPackages();
                if (mTargetPackage == null) {
                    // if there's a filter set, strip out anything that isn't
                    // present before proceeding
                    if (mFilterSet != null) {
                        for (int i = agentPackages.size() - 1; i >= 0; i--) {
                            final PackageInfo pkg = agentPackages.get(i);
                            if (! mFilterSet.contains(pkg.packageName)) {
                                agentPackages.remove(i);
                            }
                        }
                        if (DEBUG) {
                            Slog.i(TAG, "Post-filter package set for restore:");
                            for (PackageInfo p : agentPackages) {
                                Slog.i(TAG, "    " + p);
                            }
                        }
                    }
                    restorePackages.addAll(agentPackages);
                } else {
                    // Just one package to attempt restore of
@@ -4266,6 +4307,67 @@ class BackupManagerService extends IBackupManager.Stub {
            return -1;
        }

        public synchronized int restoreSome(long token, IRestoreObserver observer,
                String[] packages) {
            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                    "performRestore");

            if (DEBUG) {
                StringBuilder b = new StringBuilder(128);
                b.append("restoreSome token=");
                b.append(Long.toHexString(token));
                b.append(" observer=");
                b.append(observer.toString());
                b.append(" packages=");
                if (packages == null) {
                    b.append("null");
                } else {
                    b.append('{');
                    boolean first = true;
                    for (String s : packages) {
                        if (!first) {
                            b.append(", ");
                        } else first = false;
                        b.append(s);
                    }
                    b.append('}');
                }
                Slog.d(TAG, b.toString());
            }

            if (mEnded) {
                throw new IllegalStateException("Restore session already ended");
            }

            if (mRestoreTransport == null || mRestoreSets == null) {
                Slog.e(TAG, "Ignoring restoreAll() with no restore set");
                return -1;
            }

            if (mPackageName != null) {
                Slog.e(TAG, "Ignoring restoreAll() on single-package session");
                return -1;
            }

            synchronized (mQueueLock) {
                for (int i = 0; i < mRestoreSets.length; i++) {
                    if (token == mRestoreSets[i].token) {
                        long oldId = Binder.clearCallingIdentity();
                        mWakelock.acquire();
                        Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
                        msg.obj = new RestoreParams(mRestoreTransport, observer, token,
                                packages, true);
                        mBackupHandler.sendMessage(msg);
                        Binder.restoreCallingIdentity(oldId);
                        return 0;
                    }
                }
            }

            Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
            return -1;
        }

        public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
            if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);