1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.backup;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.content.Context;
23 import android.os.Bundle;
24 import android.os.Handler;
25 import android.os.Message;
26 import android.os.RemoteException;
27 import android.util.Log;
28 
29 import java.util.Arrays;
30 import java.util.HashSet;
31 import java.util.Set;
32 
33 /**
34  * Interface for managing a restore session.
35  * @hide
36  */
37 @SystemApi
38 public class RestoreSession {
39     static final String TAG = "RestoreSession";
40 
41     final Context mContext;
42     IRestoreSession mBinder;
43     RestoreObserverWrapper mObserver = null;
44 
45     /**
46      * Ask the current transport what the available restore sets are.
47      *
48      * @param observer a RestoreObserver object whose restoreSetsAvailable() method will
49      *   be called on the application's main thread in order to supply the results of
50      *   the restore set lookup by the backup transport.  This parameter must not be
51      *   null.
52      * @param monitor a BackupManagerMonitor object will supply data about important events.
53      * @return Zero on success, nonzero on error.  The observer's restoreSetsAvailable()
54      *   method will only be called if this method returned zero.
55      */
getAvailableRestoreSets(RestoreObserver observer, BackupManagerMonitor monitor)56     public int getAvailableRestoreSets(RestoreObserver observer, BackupManagerMonitor monitor) {
57         int err = -1;
58         RestoreObserverWrapper obsWrapper = new RestoreObserverWrapper(mContext, observer);
59         BackupManagerMonitorWrapper monitorWrapper = monitor == null
60                 ? null
61                 : new BackupManagerMonitorWrapper(monitor);
62         try {
63             err = mBinder.getAvailableRestoreSets(obsWrapper, monitorWrapper);
64         } catch (RemoteException e) {
65             Log.d(TAG, "Can't contact server to get available sets");
66         }
67         return err;
68     }
69 
70     /**
71      * Ask the current transport what the available restore sets are.
72      *
73      * @param observer a RestoreObserver object whose restoreSetsAvailable() method will
74      *   be called on the application's main thread in order to supply the results of
75      *   the restore set lookup by the backup transport.  This parameter must not be
76      *   null.
77      * @return Zero on success, nonzero on error.  The observer's restoreSetsAvailable()
78      *   method will only be called if this method returned zero.
79      */
getAvailableRestoreSets(RestoreObserver observer)80     public int getAvailableRestoreSets(RestoreObserver observer) {
81         return getAvailableRestoreSets(observer, null);
82     }
83 
84     /**
85      * Restore the given set onto the device, replacing the current data of any app
86      * contained in the restore set with the data previously backed up.
87      *
88      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
89      *
90      * @return Zero on success; nonzero on error.  The observer will only receive
91      *   progress callbacks if this method returned zero.
92      * @param token The token from {@link #getAvailableRestoreSets()} corresponding to
93      *   the restore set that should be used.
94      * @param observer If non-null, this binder points to an object that will receive
95      *   progress callbacks during the restore operation.
96      * @param monitor If non-null, this binder points to an object that will receive
97      *   progress callbacks during the restore operation.
98      */
restoreAll(long token, RestoreObserver observer, BackupManagerMonitor monitor)99     public int restoreAll(long token, RestoreObserver observer, BackupManagerMonitor monitor) {
100         int err = -1;
101         if (mObserver != null) {
102             Log.d(TAG, "restoreAll() called during active restore");
103             return -1;
104         }
105         mObserver = new RestoreObserverWrapper(mContext, observer);
106         BackupManagerMonitorWrapper monitorWrapper = monitor == null
107                 ? null
108                 : new BackupManagerMonitorWrapper(monitor);
109         try {
110             err = mBinder.restoreAll(token, mObserver, monitorWrapper);
111         } catch (RemoteException e) {
112             Log.d(TAG, "Can't contact server to restore");
113         }
114         return err;
115     }
116 
117     /**
118      * Restore the given set onto the device, replacing the current data of any app
119      * contained in the restore set with the data previously backed up.
120      *
121      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
122      *
123      * @return Zero on success; nonzero on error.  The observer will only receive
124      *   progress callbacks if this method returned zero.
125      * @param token The token from {@link #getAvailableRestoreSets()} corresponding to
126      *   the restore set that should be used.
127      * @param observer If non-null, this binder points to an object that will receive
128      *   progress callbacks during the restore operation.
129      */
restoreAll(long token, RestoreObserver observer)130     public int restoreAll(long token, RestoreObserver observer) {
131         return restoreAll(token, observer, null);
132     }
133 
134     /**
135      * Restore select packages from the given set onto the device, replacing the
136      * current data of any app contained in the set with the data previously
137      * backed up.
138      *
139      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
140      *
141      * @return Zero on success, nonzero on error. The observer will only receive
142      *   progress callbacks if this method returned zero.
143      * @param token The token from {@link getAvailableRestoreSets()} corresponding to
144      *   the restore set that should be used.
145      * @param observer If non-null, this binder points to an object that will receive
146      *   progress callbacks during the restore operation.
147      * @param packages The set of packages for which to attempt a restore.  Regardless of
148      *   the contents of the actual back-end dataset named by {@code token}, only
149      *   applications mentioned in this list will have their data restored.
150      * @param monitor If non-null, this binder points to an object that will receive
151      *   progress callbacks during the restore operation containing detailed information on any
152      *   failures or important decisions made by {@link BackupManager}.
153      */
restorePackages(long token, @Nullable RestoreObserver observer, @NonNull Set<String> packages, @Nullable BackupManagerMonitor monitor)154     public int restorePackages(long token, @Nullable RestoreObserver observer,
155             @NonNull Set<String> packages, @Nullable BackupManagerMonitor monitor) {
156         int err = -1;
157         if (mObserver != null) {
158             Log.d(TAG, "restoreAll() called during active restore");
159             return -1;
160         }
161         mObserver = new RestoreObserverWrapper(mContext, observer);
162         BackupManagerMonitorWrapper monitorWrapper = monitor == null
163                 ? null
164                 : new BackupManagerMonitorWrapper(monitor);
165         try {
166             err = mBinder.restorePackages(token, mObserver, packages.toArray(new String[] {}),
167                     monitorWrapper);
168         } catch (RemoteException e) {
169             Log.d(TAG, "Can't contact server to restore packages");
170         }
171         return err;
172     }
173 
174     /**
175      * Restore select packages from the given set onto the device, replacing the
176      * current data of any app contained in the set with the data previously
177      * backed up.
178      *
179      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
180      *
181      * @return Zero on success, nonzero on error. The observer will only receive
182      *   progress callbacks if this method returned zero.
183      * @param token The token from {@link getAvailableRestoreSets()} corresponding to
184      *   the restore set that should be used.
185      * @param observer If non-null, this binder points to an object that will receive
186      *   progress callbacks during the restore operation.
187      * @param packages The set of packages for which to attempt a restore.  Regardless of
188      *   the contents of the actual back-end dataset named by {@code token}, only
189      *   applications mentioned in this list will have their data restored.
190      */
restorePackages(long token, @Nullable RestoreObserver observer, @NonNull Set<String> packages)191     public int restorePackages(long token, @Nullable RestoreObserver observer,
192             @NonNull Set<String> packages) {
193         return restorePackages(token, observer, packages, null);
194     }
195 
196     /**
197      * Restore select packages from the given set onto the device, replacing the
198      * current data of any app contained in the set with the data previously
199      * backed up.
200      *
201      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
202      *
203      * @return Zero on success, nonzero on error. The observer will only receive
204      *   progress callbacks if this method returned zero.
205      * @param token The token from {@link getAvailableRestoreSets()} corresponding to
206      *   the restore set that should be used.
207      * @param observer If non-null, this binder points to an object that will receive
208      *   progress callbacks during the restore operation.
209      * @param monitor If non-null, this binder points to an object that will receive
210      *   progress callbacks during the restore operation.
211      * @param packages The set of packages for which to attempt a restore.  Regardless of
212      *   the contents of the actual back-end dataset named by {@code token}, only
213      *   applications mentioned in this list will have their data restored.
214      *
215      * @deprecated use {@link RestoreSession#restorePackages(long, RestoreObserver,
216      *   BackupManagerMonitor, Set)} instead.
217      * @removed
218      */
219     @Deprecated
restoreSome(long token, RestoreObserver observer, BackupManagerMonitor monitor, String[] packages)220     public int restoreSome(long token, RestoreObserver observer, BackupManagerMonitor monitor,
221             String[] packages) {
222         return restorePackages(token, observer, new HashSet<>(Arrays.asList(packages)), monitor);
223     }
224 
225     /**
226      * Restore select packages from the given set onto the device, replacing the
227      * current data of any app contained in the set with the data previously
228      * backed up.
229      *
230      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
231      *
232      * @return Zero on success, nonzero on error. The observer will only receive
233      *   progress callbacks if this method returned zero.
234      * @param token The token from {@link getAvailableRestoreSets()} corresponding to
235      *   the restore set that should be used.
236      * @param observer If non-null, this binder points to an object that will receive
237      *   progress callbacks during the restore operation.
238      * @param packages The set of packages for which to attempt a restore.  Regardless of
239      *   the contents of the actual back-end dataset named by {@code token}, only
240      *   applications mentioned in this list will have their data restored.
241      *
242      * @deprecated use {@link RestoreSession#restorePackages(long, RestoreObserver, Set)}
243      *   instead.
244      * @removed
245      */
246     @Deprecated
restoreSome(long token, RestoreObserver observer, String[] packages)247     public int restoreSome(long token, RestoreObserver observer, String[] packages) {
248         return restoreSome(token, observer, null, packages);
249     }
250 
251     /**
252      * Restore a single application from backup.  The data will be restored from the
253      * current backup dataset if the given package has stored data there, or from
254      * the dataset used during the last full device setup operation if the current
255      * backup dataset has no matching data.  If no backup data exists for this package
256      * in either source, a nonzero value will be returned.
257      *
258      * <p class="caution">Note: Unlike other restore operations, this method doesn't terminate the
259      * application after the restore. The application continues running to receive the
260      * {@link RestoreObserver} callbacks on the {@code observer} argument.
261      *
262      * @return Zero on success; nonzero on error.  The observer will only receive
263      *   progress callbacks if this method returned zero.
264      * @param packageName The name of the package whose data to restore.  If this is
265      *   not the name of the caller's own package, then the android.permission.BACKUP
266      *   permission must be held.
267      * @param observer If non-null, this binder points to an object that will receive
268      *   progress callbacks during the restore operation.
269      *
270      * @param monitor If non-null, this binder points to an object that will receive
271      *   event callbacks during the restore operation.
272      */
restorePackage(String packageName, RestoreObserver observer, BackupManagerMonitor monitor)273     public int restorePackage(String packageName, RestoreObserver observer,
274             BackupManagerMonitor monitor) {
275         int err = -1;
276         if (mObserver != null) {
277             Log.d(TAG, "restorePackage() called during active restore");
278             return -1;
279         }
280         mObserver = new RestoreObserverWrapper(mContext, observer);
281         BackupManagerMonitorWrapper monitorWrapper = monitor == null
282                 ? null
283                 : new BackupManagerMonitorWrapper(monitor);
284         try {
285             err = mBinder.restorePackage(packageName, mObserver, monitorWrapper);
286         } catch (RemoteException e) {
287             Log.d(TAG, "Can't contact server to restore package");
288         }
289         return err;
290     }
291 
292 
293     /**
294      * Restore a single application from backup.  The data will be restored from the
295      * current backup dataset if the given package has stored data there, or from
296      * the dataset used during the last full device setup operation if the current
297      * backup dataset has no matching data.  If no backup data exists for this package
298      * in either source, a nonzero value will be returned.
299      *
300      * @return Zero on success; nonzero on error.  The observer will only receive
301      *   progress callbacks if this method returned zero.
302      * @param packageName The name of the package whose data to restore.  If this is
303      *   not the name of the caller's own package, then the android.permission.BACKUP
304      *   permission must be held.
305      * @param observer If non-null, this binder points to an object that will receive
306      *   progress callbacks during the restore operation.
307      */
restorePackage(String packageName, RestoreObserver observer)308     public int restorePackage(String packageName, RestoreObserver observer) {
309         return restorePackage(packageName, observer, null);
310     }
311 
312     /**
313      * End this restore session.  After this method is called, the RestoreSession
314      * object is no longer valid.
315      *
316      * <p><b>Note:</b> The caller <i>must</i> invoke this method to end the restore session,
317      *   even if {@link #restorePackage(String, RestoreObserver)} failed.
318      */
endRestoreSession()319     public void endRestoreSession() {
320         try {
321             mBinder.endRestoreSession();
322         } catch (RemoteException e) {
323             Log.d(TAG, "Can't contact server to get available sets");
324         } finally {
325             mBinder = null;
326         }
327     }
328 
329     /*
330      * Nonpublic implementation here
331      */
332 
RestoreSession(Context context, IRestoreSession binder)333     RestoreSession(Context context, IRestoreSession binder) {
334         mContext = context;
335         mBinder = binder;
336     }
337 
338     /*
339      * We wrap incoming binder calls with a private class implementation that
340      * redirects them into main-thread actions.  This serializes the restore
341      * progress callbacks nicely within the usual main-thread lifecycle pattern.
342      */
343     private class RestoreObserverWrapper extends IRestoreObserver.Stub {
344         final Handler mHandler;
345         final RestoreObserver mAppObserver;
346 
347         static final int MSG_RESTORE_STARTING = 1;
348         static final int MSG_UPDATE = 2;
349         static final int MSG_RESTORE_FINISHED = 3;
350         static final int MSG_RESTORE_SETS_AVAILABLE = 4;
351 
RestoreObserverWrapper(Context context, RestoreObserver appObserver)352         RestoreObserverWrapper(Context context, RestoreObserver appObserver) {
353             mHandler = new Handler(context.getMainLooper()) {
354                 @Override
355                 public void handleMessage(Message msg) {
356                     switch (msg.what) {
357                     case MSG_RESTORE_STARTING:
358                         mAppObserver.restoreStarting(msg.arg1);
359                         break;
360                     case MSG_UPDATE:
361                         mAppObserver.onUpdate(msg.arg1, (String)msg.obj);
362                         break;
363                     case MSG_RESTORE_FINISHED:
364                         mAppObserver.restoreFinished(msg.arg1);
365                         break;
366                     case MSG_RESTORE_SETS_AVAILABLE:
367                         mAppObserver.restoreSetsAvailable((RestoreSet[])msg.obj);
368                         break;
369                     }
370                 }
371             };
372             mAppObserver = appObserver;
373         }
374 
375         // Binder calls into this object just enqueue on the main-thread handler
restoreSetsAvailable(RestoreSet[] result)376         public void restoreSetsAvailable(RestoreSet[] result) {
377             mHandler.sendMessage(
378                     mHandler.obtainMessage(MSG_RESTORE_SETS_AVAILABLE, result));
379         }
380 
restoreStarting(int numPackages)381         public void restoreStarting(int numPackages) {
382             mHandler.sendMessage(
383                     mHandler.obtainMessage(MSG_RESTORE_STARTING, numPackages, 0));
384         }
385 
onUpdate(int nowBeingRestored, String currentPackage)386         public void onUpdate(int nowBeingRestored, String currentPackage) {
387             mHandler.sendMessage(
388                     mHandler.obtainMessage(MSG_UPDATE, nowBeingRestored, 0, currentPackage));
389         }
390 
restoreFinished(int error)391         public void restoreFinished(int error) {
392             mHandler.sendMessage(
393                     mHandler.obtainMessage(MSG_RESTORE_FINISHED, error, 0));
394         }
395     }
396 
397     private class BackupManagerMonitorWrapper extends IBackupManagerMonitor.Stub {
398         final BackupManagerMonitor mMonitor;
399 
BackupManagerMonitorWrapper(BackupManagerMonitor monitor)400         BackupManagerMonitorWrapper(BackupManagerMonitor monitor) {
401             mMonitor = monitor;
402         }
403 
404         @Override
onEvent(final Bundle event)405         public void onEvent(final Bundle event) throws RemoteException {
406             mMonitor.onEvent(event);
407         }
408     }
409 }
410