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