Can now restore a subset of apps from historical dataset

Adds the ability to filter a restore of an historical dataset so that it
only restores certain apps' data regardless of what is actually present
in the dataset.  This is currently only used by the bmgr command-line tool,
for debugging / developer support.

Bug 2021590

Change-Id: I7685e5d609b0f5506f71d70c26410602bb387659
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 6afccec..786f2fa 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -224,6 +224,7 @@
         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 @@
             pkgInfo = _pkg;
             pmToken = _pmToken;
             needFullBackup = _needFullBackup;
+            filterSet = null;
         }
 
         RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
@@ -243,6 +245,18 @@
             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 @@
                 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 @@
         private File mStateDir;
         private int mPmToken;
         private boolean mNeedFullBackup;
+        private HashSet<String> mFilterSet;
 
         class RestoreRequest {
             public PackageInfo app;
@@ -3033,7 +3048,7 @@
 
         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 @@
             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 @@
             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 @@
 
                 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 @@
             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);