• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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.RequiresPermission;
20 import android.annotation.SystemApi;
21 import android.content.ComponentName;
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.os.ServiceManager;
28 import android.util.Log;
29 import android.util.Pair;
30 
31 /**
32  * The interface through which an application interacts with the Android backup service to
33  * request backup and restore operations.
34  * Applications instantiate it using the constructor and issue calls through that instance.
35  * <p>
36  * When an application has made changes to data which should be backed up, a
37  * call to {@link #dataChanged()} will notify the backup service. The system
38  * will then schedule a backup operation to occur in the near future. Repeated
39  * calls to {@link #dataChanged()} have no further effect until the backup
40  * operation actually occurs.
41  * <p>
42  * A backup or restore operation for your application begins when the system launches the
43  * {@link android.app.backup.BackupAgent} subclass you've declared in your manifest. See the
44  * documentation for {@link android.app.backup.BackupAgent} for a detailed description
45  * of how the operation then proceeds.
46  * <p>
47  * Several attributes affecting the operation of the backup and restore mechanism
48  * can be set on the <code>
49  * <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
50  * tag in your application's AndroidManifest.xml file.
51  *
52  * <div class="special reference">
53  * <h3>Developer Guides</h3>
54  * <p>For more information about using BackupManager, read the
55  * <a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p></div>
56  *
57  * @attr ref android.R.styleable#AndroidManifestApplication_allowBackup
58  * @attr ref android.R.styleable#AndroidManifestApplication_backupAgent
59  * @attr ref android.R.styleable#AndroidManifestApplication_killAfterRestore
60  * @attr ref android.R.styleable#AndroidManifestApplication_restoreAnyVersion
61  */
62 public class BackupManager {
63     private static final String TAG = "BackupManager";
64 
65     // BackupObserver status codes
66     /**
67      * Indicates that backup succeeded.
68      *
69      * @hide
70      */
71     @SystemApi
72     public static final int SUCCESS = 0;
73 
74     /**
75      * Indicates that backup is either not enabled at all or
76      * backup for the package was rejected by backup service
77      * or backup transport,
78      *
79      * @hide
80      */
81     @SystemApi
82     public static final int ERROR_BACKUP_NOT_ALLOWED = -2001;
83 
84     /**
85      * The requested app is not installed on the device.
86      *
87      * @hide
88      */
89     @SystemApi
90     public static final int ERROR_PACKAGE_NOT_FOUND = -2002;
91 
92     /**
93      * The backup operation was cancelled.
94      *
95      * @hide
96      */
97     @SystemApi
98     public static final int ERROR_BACKUP_CANCELLED = -2003;
99 
100     /**
101      * The transport for some reason was not in a good state and
102      * aborted the entire backup request. This is a transient
103      * failure and should not be retried immediately.
104      *
105      * @hide
106      */
107     @SystemApi
108     public static final int ERROR_TRANSPORT_ABORTED = BackupTransport.TRANSPORT_ERROR;
109 
110     /**
111      * Returned when the transport was unable to process the
112      * backup request for a given package, for example if the
113      * transport hit a transient network failure. The remaining
114      * packages provided to {@link #requestBackup(String[], BackupObserver)}
115      * will still be attempted.
116      *
117      * @hide
118      */
119     @SystemApi
120     public static final int ERROR_TRANSPORT_PACKAGE_REJECTED =
121             BackupTransport.TRANSPORT_PACKAGE_REJECTED;
122 
123     /**
124      * Returned when the transport reject the attempt to backup because
125      * backup data size exceeded current quota limit for this package.
126      *
127      * @hide
128      */
129     @SystemApi
130     public static final int ERROR_TRANSPORT_QUOTA_EXCEEDED =
131             BackupTransport.TRANSPORT_QUOTA_EXCEEDED;
132 
133     /**
134      * The {@link BackupAgent} for the requested package failed for some reason
135      * and didn't provide appropriate backup data.
136      *
137      * @hide
138      */
139     @SystemApi
140     public static final int ERROR_AGENT_FAILURE = BackupTransport.AGENT_ERROR;
141 
142     /**
143      * Intent extra when any subsidiary backup-related UI is launched from Settings:  does
144      * device policy or configuration permit backup operations to run at all?
145      *
146      * @hide
147      */
148     public static final String EXTRA_BACKUP_SERVICES_AVAILABLE = "backup_services_available";
149 
150     /**
151      * If this flag is passed to {@link #requestBackup(String[], BackupObserver, int)},
152      * BackupManager will pass a blank old state to BackupAgents of requested packages.
153      *
154      * @hide
155      */
156     @SystemApi
157     public static final int FLAG_NON_INCREMENTAL_BACKUP = 1;
158 
159     /**
160      * Use with {@link #requestBackup} to force backup of
161      * package meta data. Typically you do not need to explicitly request this be backed up as it is
162      * handled internally by the BackupManager. If you are requesting backups with
163      * FLAG_NON_INCREMENTAL, this package won't automatically be backed up and you have to
164      * explicitly request for its backup.
165      *
166      * @hide
167      */
168     @SystemApi
169     public static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
170 
171 
172     /**
173      * This error code is passed to {@link SelectBackupTransportCallback#onFailure(int)}
174      * if the requested transport is unavailable.
175      *
176      * @hide
177      */
178     @SystemApi
179     public static final int ERROR_TRANSPORT_UNAVAILABLE = -1;
180 
181     /**
182      * This error code is passed to {@link SelectBackupTransportCallback#onFailure(int)} if the
183      * requested transport is not a valid BackupTransport.
184      *
185      * @hide
186      */
187     @SystemApi
188     public static final int ERROR_TRANSPORT_INVALID = -2;
189 
190     private Context mContext;
191     private static IBackupManager sService;
192 
checkServiceBinder()193     private static void checkServiceBinder() {
194         if (sService == null) {
195             sService = IBackupManager.Stub.asInterface(
196                     ServiceManager.getService(Context.BACKUP_SERVICE));
197         }
198     }
199 
200     /**
201      * Constructs a BackupManager object through which the application can
202      * communicate with the Android backup system.
203      *
204      * @param context The {@link android.content.Context} that was provided when
205      *                one of your application's {@link android.app.Activity Activities}
206      *                was created.
207      */
BackupManager(Context context)208     public BackupManager(Context context) {
209         mContext = context;
210     }
211 
212     /**
213      * Notifies the Android backup system that your application wishes to back up
214      * new changes to its data.  A backup operation using your application's
215      * {@link android.app.backup.BackupAgent} subclass will be scheduled when you
216      * call this method.
217      */
dataChanged()218     public void dataChanged() {
219         checkServiceBinder();
220         if (sService != null) {
221             try {
222                 sService.dataChanged(mContext.getPackageName());
223             } catch (RemoteException e) {
224                 Log.d(TAG, "dataChanged() couldn't connect");
225             }
226         }
227     }
228 
229     /**
230      * Convenience method for callers who need to indicate that some other package
231      * needs a backup pass.  This can be useful in the case of groups of packages
232      * that share a uid.
233      * <p>
234      * This method requires that the application hold the "android.permission.BACKUP"
235      * permission if the package named in the argument does not run under the same uid
236      * as the caller.
237      *
238      * @param packageName The package name identifying the application to back up.
239      */
dataChanged(String packageName)240     public static void dataChanged(String packageName) {
241         checkServiceBinder();
242         if (sService != null) {
243             try {
244                 sService.dataChanged(packageName);
245             } catch (RemoteException e) {
246                 Log.e(TAG, "dataChanged(pkg) couldn't connect");
247             }
248         }
249     }
250 
251     /**
252      * Restore the calling application from backup.  The data will be restored from the
253      * current backup dataset if the application 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 application
256      * in either source, a nonzero value will be returned.
257      *
258      * <p>If this method returns zero (meaning success), the OS will attempt to retrieve
259      * a backed-up dataset from the remote transport, instantiate the application's
260      * backup agent, and pass the dataset to the agent's
261      * {@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
262      * method.
263      *
264      * @param observer The {@link RestoreObserver} to receive callbacks during the restore
265      * operation. This must not be null.
266      *
267      * @return Zero on success; nonzero on error.
268      */
requestRestore(RestoreObserver observer)269     public int requestRestore(RestoreObserver observer) {
270         return requestRestore(observer, null);
271     }
272 
273     // system APIs start here
274 
275     /**
276      * Restore the calling application from backup.  The data will be restored from the
277      * current backup dataset if the application has stored data there, or from
278      * the dataset used during the last full device setup operation if the current
279      * backup dataset has no matching data.  If no backup data exists for this application
280      * in either source, a nonzero value will be returned.
281      *
282      * <p>If this method returns zero (meaning success), the OS will attempt to retrieve
283      * a backed-up dataset from the remote transport, instantiate the application's
284      * backup agent, and pass the dataset to the agent's
285      * {@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
286      * method.
287      *
288      * @param observer The {@link RestoreObserver} to receive callbacks during the restore
289      * operation. This must not be null.
290      *
291      * @param monitor the {@link BackupManagerMonitor} to receive callbacks during the restore
292      * operation.
293      *
294      * @return Zero on success; nonzero on error.
295      *
296      * @hide
297      */
298     @SystemApi
requestRestore(RestoreObserver observer, BackupManagerMonitor monitor)299     public int requestRestore(RestoreObserver observer, BackupManagerMonitor monitor) {
300         int result = -1;
301         checkServiceBinder();
302         if (sService != null) {
303             RestoreSession session = null;
304             try {
305                 IRestoreSession binder = sService.beginRestoreSession(mContext.getPackageName(),
306                     null);
307                 if (binder != null) {
308                     session = new RestoreSession(mContext, binder);
309                     result = session.restorePackage(mContext.getPackageName(), observer, monitor);
310                 }
311             } catch (RemoteException e) {
312                 Log.e(TAG, "restoreSelf() unable to contact service");
313             } finally {
314                 if (session != null) {
315                     session.endRestoreSession();
316                 }
317             }
318         }
319         return result;
320     }
321 
322     /**
323      * Begin the process of restoring data from backup.  See the
324      * {@link android.app.backup.RestoreSession} class for documentation on that process.
325      * @hide
326      */
327     @SystemApi
328     @RequiresPermission(android.Manifest.permission.BACKUP)
beginRestoreSession()329     public RestoreSession beginRestoreSession() {
330         RestoreSession session = null;
331         checkServiceBinder();
332         if (sService != null) {
333             try {
334                 // All packages, current transport
335                 IRestoreSession binder = sService.beginRestoreSession(null, null);
336                 if (binder != null) {
337                     session = new RestoreSession(mContext, binder);
338                 }
339             } catch (RemoteException e) {
340                 Log.e(TAG, "beginRestoreSession() couldn't connect");
341             }
342         }
343         return session;
344     }
345 
346     /**
347      * Enable/disable the backup service entirely.  When disabled, no backup
348      * or restore operations will take place.  Data-changed notifications will
349      * still be observed and collected, however, so that changes made while the
350      * mechanism was disabled will still be backed up properly if it is enabled
351      * at some point in the future.
352      *
353      * @hide
354      */
355     @SystemApi
356     @RequiresPermission(android.Manifest.permission.BACKUP)
setBackupEnabled(boolean isEnabled)357     public void setBackupEnabled(boolean isEnabled) {
358         checkServiceBinder();
359         if (sService != null) {
360             try {
361                 sService.setBackupEnabled(isEnabled);
362             } catch (RemoteException e) {
363                 Log.e(TAG, "setBackupEnabled() couldn't connect");
364             }
365         }
366     }
367 
368     /**
369      * Report whether the backup mechanism is currently enabled.
370      *
371      * @hide
372      */
373     @SystemApi
374     @RequiresPermission(android.Manifest.permission.BACKUP)
isBackupEnabled()375     public boolean isBackupEnabled() {
376         checkServiceBinder();
377         if (sService != null) {
378             try {
379                 return sService.isBackupEnabled();
380             } catch (RemoteException e) {
381                 Log.e(TAG, "isBackupEnabled() couldn't connect");
382             }
383         }
384         return false;
385     }
386 
387     /**
388      * Enable/disable data restore at application install time.  When enabled, app
389      * installation will include an attempt to fetch the app's historical data from
390      * the archival restore dataset (if any).  When disabled, no such attempt will
391      * be made.
392      *
393      * @hide
394      */
395     @SystemApi
396     @RequiresPermission(android.Manifest.permission.BACKUP)
setAutoRestore(boolean isEnabled)397     public void setAutoRestore(boolean isEnabled) {
398         checkServiceBinder();
399         if (sService != null) {
400             try {
401                 sService.setAutoRestore(isEnabled);
402             } catch (RemoteException e) {
403                 Log.e(TAG, "setAutoRestore() couldn't connect");
404             }
405         }
406     }
407 
408     /**
409      * Identify the currently selected transport.
410      * @return The name of the currently active backup transport.  In case of
411      *   failure or if no transport is currently active, this method returns {@code null}.
412      *
413      * @hide
414      */
415     @SystemApi
416     @RequiresPermission(android.Manifest.permission.BACKUP)
getCurrentTransport()417     public String getCurrentTransport() {
418         checkServiceBinder();
419         if (sService != null) {
420             try {
421                 return sService.getCurrentTransport();
422             } catch (RemoteException e) {
423                 Log.e(TAG, "getCurrentTransport() couldn't connect");
424             }
425         }
426         return null;
427     }
428 
429     /**
430      * Request a list of all available backup transports' names.
431      *
432      * @hide
433      */
434     @SystemApi
435     @RequiresPermission(android.Manifest.permission.BACKUP)
listAllTransports()436     public String[] listAllTransports() {
437         checkServiceBinder();
438         if (sService != null) {
439             try {
440                 return sService.listAllTransports();
441             } catch (RemoteException e) {
442                 Log.e(TAG, "listAllTransports() couldn't connect");
443             }
444         }
445         return null;
446     }
447 
448     /**
449      * Specify the current backup transport.
450      *
451      * @param transport The name of the transport to select.  This should be one
452      *   of the names returned by {@link #listAllTransports()}. This is the String returned by
453      *   {@link BackupTransport#name()} for the particular transport.
454      * @return The name of the previously selected transport.  If the given transport
455      *   name is not one of the currently available transports, no change is made to
456      *   the current transport setting and the method returns null.
457      *
458      * @hide
459      */
460     @Deprecated
461     @SystemApi
462     @RequiresPermission(android.Manifest.permission.BACKUP)
selectBackupTransport(String transport)463     public String selectBackupTransport(String transport) {
464         checkServiceBinder();
465         if (sService != null) {
466             try {
467                 return sService.selectBackupTransport(transport);
468             } catch (RemoteException e) {
469                 Log.e(TAG, "selectBackupTransport() couldn't connect");
470             }
471         }
472         return null;
473     }
474 
475     /**
476      * Specify the current backup transport and get notified when the transport is ready to be used.
477      * This method is async because BackupManager might need to bind to the specified transport
478      * which is in a separate process.
479      *
480      * @param transport ComponentName of the service hosting the transport. This is different from
481      *                  the transport's name that is returned by {@link BackupTransport#name()}.
482      * @param listener A listener object to get a callback on the transport being selected.
483      *
484      * @hide
485      */
486     @SystemApi
487     @RequiresPermission(android.Manifest.permission.BACKUP)
selectBackupTransport(ComponentName transport, SelectBackupTransportCallback listener)488     public void selectBackupTransport(ComponentName transport,
489             SelectBackupTransportCallback listener) {
490         checkServiceBinder();
491         if (sService != null) {
492             try {
493                 SelectTransportListenerWrapper wrapper = listener == null ?
494                         null : new SelectTransportListenerWrapper(mContext, listener);
495                 sService.selectBackupTransportAsync(transport, wrapper);
496             } catch (RemoteException e) {
497                 Log.e(TAG, "selectBackupTransportAsync() couldn't connect");
498             }
499         }
500     }
501 
502     /**
503      * Schedule an immediate backup attempt for all pending key/value updates.  This
504      * is primarily intended for transports to use when they detect a suitable
505      * opportunity for doing a backup pass.  If there are no pending updates to
506      * be sent, no action will be taken.  Even if some updates are pending, the
507      * transport will still be asked to confirm via the usual requestBackupTime()
508      * method.
509      *
510      * @hide
511      */
512     @SystemApi
513     @RequiresPermission(android.Manifest.permission.BACKUP)
backupNow()514     public void backupNow() {
515         checkServiceBinder();
516         if (sService != null) {
517             try {
518                 sService.backupNow();
519             } catch (RemoteException e) {
520                 Log.e(TAG, "backupNow() couldn't connect");
521             }
522         }
523     }
524 
525     /**
526      * Ask the framework which dataset, if any, the given package's data would be
527      * restored from if we were to install it right now.
528      *
529      * @param packageName The name of the package whose most-suitable dataset we
530      *     wish to look up
531      * @return The dataset token from which a restore should be attempted, or zero if
532      *     no suitable data is available.
533      *
534      * @hide
535      */
536     @SystemApi
537     @RequiresPermission(android.Manifest.permission.BACKUP)
getAvailableRestoreToken(String packageName)538     public long getAvailableRestoreToken(String packageName) {
539         checkServiceBinder();
540         if (sService != null) {
541             try {
542                 return sService.getAvailableRestoreToken(packageName);
543             } catch (RemoteException e) {
544                 Log.e(TAG, "getAvailableRestoreToken() couldn't connect");
545             }
546         }
547         return 0;
548     }
549 
550     /**
551      * Ask the framework whether this app is eligible for backup.
552      *
553      * @param packageName The name of the package.
554      * @return Whether this app is eligible for backup.
555      *
556      * @hide
557      */
558     @SystemApi
559     @RequiresPermission(android.Manifest.permission.BACKUP)
isAppEligibleForBackup(String packageName)560     public boolean isAppEligibleForBackup(String packageName) {
561         checkServiceBinder();
562         if (sService != null) {
563             try {
564                 return sService.isAppEligibleForBackup(packageName);
565             } catch (RemoteException e) {
566                 Log.e(TAG, "isAppEligibleForBackup(pkg) couldn't connect");
567             }
568         }
569         return false;
570     }
571 
572     /**
573      * Request an immediate backup, providing an observer to which results of the backup operation
574      * will be published. The Android backup system will decide for each package whether it will
575      * be full app data backup or key/value-pair-based backup.
576      *
577      * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
578      * provided packages using the remote transport.
579      *
580      * @param packages List of package names to backup.
581      * @param observer The {@link BackupObserver} to receive callbacks during the backup
582      * operation. Could be {@code null}.
583      * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
584      * @exception  IllegalArgumentException on null or empty {@code packages} param.
585      *
586      * @hide
587      */
588     @SystemApi
589     @RequiresPermission(android.Manifest.permission.BACKUP)
requestBackup(String[] packages, BackupObserver observer)590     public int requestBackup(String[] packages, BackupObserver observer) {
591         return requestBackup(packages, observer, null, 0);
592     }
593 
594     /**
595      * Request an immediate backup, providing an observer to which results of the backup operation
596      * will be published. The Android backup system will decide for each package whether it will
597      * be full app data backup or key/value-pair-based backup.
598      *
599      * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
600      * provided packages using the remote transport.
601      *
602      * @param packages List of package names to backup.
603      * @param observer The {@link BackupObserver} to receive callbacks during the backup
604      *                 operation. Could be {@code null}.
605      * @param monitor  The {@link BackupManagerMonitorWrapper} to receive callbacks of important
606      *                 events during the backup operation. Could be {@code null}.
607      * @param flags    {@link #FLAG_NON_INCREMENTAL_BACKUP}.
608      * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
609      * @throws IllegalArgumentException on null or empty {@code packages} param.
610      * @hide
611      */
612     @SystemApi
613     @RequiresPermission(android.Manifest.permission.BACKUP)
requestBackup(String[] packages, BackupObserver observer, BackupManagerMonitor monitor, int flags)614     public int requestBackup(String[] packages, BackupObserver observer,
615             BackupManagerMonitor monitor, int flags) {
616         checkServiceBinder();
617         if (sService != null) {
618             try {
619                 BackupObserverWrapper observerWrapper = observer == null
620                         ? null
621                         : new BackupObserverWrapper(mContext, observer);
622                 BackupManagerMonitorWrapper monitorWrapper = monitor == null
623                         ? null
624                         : new BackupManagerMonitorWrapper(monitor);
625                 return sService.requestBackup(packages, observerWrapper, monitorWrapper, flags);
626             } catch (RemoteException e) {
627                 Log.e(TAG, "requestBackup() couldn't connect");
628             }
629         }
630         return -1;
631     }
632 
633     /**
634      * Cancel all running backups. After this call returns, no currently running backups will
635      * interact with the selected transport.
636      *
637      * @hide
638      */
639     @SystemApi
640     @RequiresPermission(android.Manifest.permission.BACKUP)
cancelBackups()641     public void cancelBackups() {
642         checkServiceBinder();
643         if (sService != null) {
644             try {
645                 sService.cancelBackups();
646             } catch (RemoteException e) {
647                 Log.e(TAG, "cancelBackups() couldn't connect.");
648             }
649         }
650     }
651 
652     /*
653      * We wrap incoming binder calls with a private class implementation that
654      * redirects them into main-thread actions.  This serializes the backup
655      * progress callbacks nicely within the usual main-thread lifecycle pattern.
656      */
657     @SystemApi
658     private class BackupObserverWrapper extends IBackupObserver.Stub {
659         final Handler mHandler;
660         final BackupObserver mObserver;
661 
662         static final int MSG_UPDATE = 1;
663         static final int MSG_RESULT = 2;
664         static final int MSG_FINISHED = 3;
665 
BackupObserverWrapper(Context context, BackupObserver observer)666         BackupObserverWrapper(Context context, BackupObserver observer) {
667             mHandler = new Handler(context.getMainLooper()) {
668                 @Override
669                 public void handleMessage(Message msg) {
670                     switch (msg.what) {
671                         case MSG_UPDATE:
672                             Pair<String, BackupProgress> obj =
673                                 (Pair<String, BackupProgress>) msg.obj;
674                             mObserver.onUpdate(obj.first, obj.second);
675                             break;
676                         case MSG_RESULT:
677                             mObserver.onResult((String)msg.obj, msg.arg1);
678                             break;
679                         case MSG_FINISHED:
680                             mObserver.backupFinished(msg.arg1);
681                             break;
682                         default:
683                             Log.w(TAG, "Unknown message: " + msg);
684                             break;
685                     }
686                 }
687             };
688             mObserver = observer;
689         }
690 
691         // Binder calls into this object just enqueue on the main-thread handler
692         @Override
onUpdate(String currentPackage, BackupProgress backupProgress)693         public void onUpdate(String currentPackage, BackupProgress backupProgress) {
694             mHandler.sendMessage(
695                 mHandler.obtainMessage(MSG_UPDATE, Pair.create(currentPackage, backupProgress)));
696         }
697 
698         @Override
onResult(String currentPackage, int status)699         public void onResult(String currentPackage, int status) {
700             mHandler.sendMessage(
701                 mHandler.obtainMessage(MSG_RESULT, status, 0, currentPackage));
702         }
703 
704         @Override
backupFinished(int status)705         public void backupFinished(int status) {
706             mHandler.sendMessage(
707                 mHandler.obtainMessage(MSG_FINISHED, status, 0));
708         }
709     }
710 
711     private class SelectTransportListenerWrapper extends ISelectBackupTransportCallback.Stub {
712 
713         private final Handler mHandler;
714         private final SelectBackupTransportCallback mListener;
715 
SelectTransportListenerWrapper(Context context, SelectBackupTransportCallback listener)716         SelectTransportListenerWrapper(Context context, SelectBackupTransportCallback listener) {
717             mHandler = new Handler(context.getMainLooper());
718             mListener = listener;
719         }
720 
721         @Override
onSuccess(final String transportName)722         public void onSuccess(final String transportName) {
723             mHandler.post(new Runnable() {
724                 @Override
725                 public void run() {
726                     mListener.onSuccess(transportName);
727                 }
728             });
729         }
730 
731         @Override
onFailure(final int reason)732         public void onFailure(final int reason) {
733             mHandler.post(new Runnable() {
734                 @Override
735                 public void run() {
736                     mListener.onFailure(reason);
737                 }
738             });
739         }
740     }
741 
742     private class BackupManagerMonitorWrapper extends IBackupManagerMonitor.Stub {
743         final BackupManagerMonitor mMonitor;
744 
BackupManagerMonitorWrapper(BackupManagerMonitor monitor)745         BackupManagerMonitorWrapper(BackupManagerMonitor monitor) {
746             mMonitor = monitor;
747         }
748 
749         @Override
onEvent(final Bundle event)750         public void onEvent(final Bundle event) throws RemoteException {
751             mMonitor.onEvent(event);
752         }
753     }
754 
755 }
756