• 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.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.annotation.SystemApi;
24 import android.app.compat.CompatChanges;
25 import android.compat.annotation.ChangeId;
26 import android.compat.annotation.EnabledAfter;
27 import android.compat.annotation.UnsupportedAppUsage;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.os.Build;
32 import android.os.Bundle;
33 import android.os.Handler;
34 import android.os.Message;
35 import android.os.RemoteException;
36 import android.os.ServiceManager;
37 import android.os.UserHandle;
38 import android.util.Log;
39 import android.util.Pair;
40 
41 import java.lang.annotation.Retention;
42 import java.lang.annotation.RetentionPolicy;
43 import java.util.List;
44 
45 /**
46  * The interface through which an application interacts with the Android backup service to
47  * request backup and restore operations.
48  * Applications instantiate it using the constructor and issue calls through that instance.
49  * <p>
50  * When an application has made changes to data which should be backed up, a
51  * call to {@link #dataChanged()} will notify the backup service. The system
52  * will then schedule a backup operation to occur in the near future. Repeated
53  * calls to {@link #dataChanged()} have no further effect until the backup
54  * operation actually occurs.
55  * <p>
56  * A backup or restore operation for your application begins when the system launches the
57  * {@link android.app.backup.BackupAgent} subclass you've declared in your manifest. See the
58  * documentation for {@link android.app.backup.BackupAgent} for a detailed description
59  * of how the operation then proceeds.
60  * <p>
61  * Several attributes affecting the operation of the backup and restore mechanism
62  * can be set on the <code>
63  * <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
64  * tag in your application's AndroidManifest.xml file.
65  *
66  * <div class="special reference">
67  * <h3>Developer Guides</h3>
68  * <p>For more information about using BackupManager, read the
69  * <a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p></div>
70  *
71  * @attr ref android.R.styleable#AndroidManifestApplication_allowBackup
72  * @attr ref android.R.styleable#AndroidManifestApplication_backupAgent
73  * @attr ref android.R.styleable#AndroidManifestApplication_killAfterRestore
74  * @attr ref android.R.styleable#AndroidManifestApplication_restoreAnyVersion
75  */
76 public class BackupManager {
77     private static final String TAG = "BackupManager";
78 
79     // BackupObserver status codes
80     /**
81      * Indicates that backup succeeded.
82      *
83      * @hide
84      */
85     @SystemApi
86     public static final int SUCCESS = 0;
87 
88     /**
89      * Indicates that backup is either not enabled at all or
90      * backup for the package was rejected by backup service
91      * or backup transport,
92      *
93      * @hide
94      */
95     @SystemApi
96     public static final int ERROR_BACKUP_NOT_ALLOWED = -2001;
97 
98     /**
99      * The requested app is not installed on the device.
100      *
101      * @hide
102      */
103     @SystemApi
104     public static final int ERROR_PACKAGE_NOT_FOUND = -2002;
105 
106     /**
107      * The backup operation was cancelled.
108      *
109      * @hide
110      */
111     @SystemApi
112     public static final int ERROR_BACKUP_CANCELLED = -2003;
113 
114     /**
115      * The transport for some reason was not in a good state and
116      * aborted the entire backup request. This is a transient
117      * failure and should not be retried immediately.
118      *
119      * @hide
120      */
121     @SystemApi
122     public static final int ERROR_TRANSPORT_ABORTED = BackupTransport.TRANSPORT_ERROR;
123 
124     /**
125      * Returned when the transport was unable to process the
126      * backup request for a given package, for example if the
127      * transport hit a transient network failure. The remaining
128      * packages provided to {@link #requestBackup(String[], BackupObserver)}
129      * will still be attempted.
130      *
131      * @hide
132      */
133     @SystemApi
134     public static final int ERROR_TRANSPORT_PACKAGE_REJECTED =
135             BackupTransport.TRANSPORT_PACKAGE_REJECTED;
136 
137     /**
138      * Returned when the transport reject the attempt to backup because
139      * backup data size exceeded current quota limit for this package.
140      *
141      * @hide
142      */
143     @SystemApi
144     public static final int ERROR_TRANSPORT_QUOTA_EXCEEDED =
145             BackupTransport.TRANSPORT_QUOTA_EXCEEDED;
146 
147     /**
148      * The {@link BackupAgent} for the requested package failed for some reason
149      * and didn't provide appropriate backup data.
150      *
151      * @hide
152      */
153     @SystemApi
154     public static final int ERROR_AGENT_FAILURE = BackupTransport.AGENT_ERROR;
155 
156     /**
157      * Intent extra when any subsidiary backup-related UI is launched from Settings:  does
158      * device policy or configuration permit backup operations to run at all?
159      *
160      * @hide
161      */
162     public static final String EXTRA_BACKUP_SERVICES_AVAILABLE = "backup_services_available";
163 
164     /**
165      * If this flag is passed to {@link #requestBackup(String[], BackupObserver, int)},
166      * BackupManager will pass a blank old state to BackupAgents of requested packages.
167      *
168      * @hide
169      */
170     @SystemApi
171     public static final int FLAG_NON_INCREMENTAL_BACKUP = 1;
172 
173     /**
174      * Use with {@link #requestBackup} to force backup of
175      * package meta data. Typically you do not need to explicitly request this be backed up as it is
176      * handled internally by the BackupManager. If you are requesting backups with
177      * FLAG_NON_INCREMENTAL, this package won't automatically be backed up and you have to
178      * explicitly request for its backup.
179      *
180      * @hide
181      */
182     @SystemApi
183     public static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
184 
185 
186     /**
187      * This error code is passed to {@link SelectBackupTransportCallback#onFailure(int)}
188      * if the requested transport is unavailable.
189      *
190      * @hide
191      */
192     @SystemApi
193     public static final int ERROR_TRANSPORT_UNAVAILABLE = -1;
194 
195     /**
196      * This error code is passed to {@link SelectBackupTransportCallback#onFailure(int)} if the
197      * requested transport is not a valid BackupTransport.
198      *
199      * @hide
200      */
201     @SystemApi
202     public static final int ERROR_TRANSPORT_INVALID = -2;
203 
204     /** @hide */
205     @Retention(RetentionPolicy.SOURCE)
206     @IntDef({
207         OperationType.BACKUP,
208         OperationType.MIGRATION,
209         OperationType.ADB_BACKUP,
210     })
211     public @interface OperationType {
212         // A backup / restore to / from an off-device location, e.g. cloud.
213         int BACKUP = 0;
214         // A direct transfer to another device.
215         int MIGRATION = 1;
216         // Backup via adb, data saved on the host machine.
217         int ADB_BACKUP = 3;
218     }
219 
220     private Context mContext;
221     @UnsupportedAppUsage
222     private static IBackupManager sService;
223 
224     @UnsupportedAppUsage
checkServiceBinder()225     private static void checkServiceBinder() {
226         if (sService == null) {
227             sService = IBackupManager.Stub.asInterface(
228                     ServiceManager.getService(Context.BACKUP_SERVICE));
229         }
230     }
231 
232     /**
233      * Constructs a BackupManager object through which the application can
234      * communicate with the Android backup system.
235      *
236      * @param context The {@link android.content.Context} that was provided when
237      *                one of your application's {@link android.app.Activity Activities}
238      *                was created.
239      */
BackupManager(Context context)240     public BackupManager(Context context) {
241         mContext = context;
242     }
243 
244     /**
245      * Notifies the Android backup system that your application wishes to back up
246      * new changes to its data.  A backup operation using your application's
247      * {@link android.app.backup.BackupAgent} subclass will be scheduled when you
248      * call this method.
249      */
dataChanged()250     public void dataChanged() {
251         checkServiceBinder();
252         if (sService != null) {
253             try {
254                 sService.dataChanged(mContext.getPackageName());
255             } catch (RemoteException e) {
256                 Log.d(TAG, "dataChanged() couldn't connect");
257             }
258         }
259     }
260 
261     /**
262      * Convenience method for callers who need to indicate that some other package
263      * needs a backup pass.  This can be useful in the case of groups of packages
264      * that share a uid.
265      * <p>
266      * This method requires that the application hold the "android.permission.BACKUP"
267      * permission if the package named in the argument does not run under the same uid
268      * as the caller.
269      *
270      * @param packageName The package name identifying the application to back up.
271      */
dataChanged(String packageName)272     public static void dataChanged(String packageName) {
273         checkServiceBinder();
274         if (sService != null) {
275             try {
276                 sService.dataChanged(packageName);
277             } catch (RemoteException e) {
278                 Log.e(TAG, "dataChanged(pkg) couldn't connect");
279             }
280         }
281     }
282 
283     /**
284      * @deprecated Applications shouldn't request a restore operation using this method. In Android
285      * P and later, this method is a no-op.
286      *
287      * <p>Restore the calling application from backup. The data will be restored from the
288      * current backup dataset if the application has stored data there, or from
289      * the dataset used during the last full device setup operation if the current
290      * backup dataset has no matching data.  If no backup data exists for this application
291      * in either source, a non-zero value is returned.
292      *
293      * <p>If this method returns zero (meaning success), the OS attempts to retrieve a backed-up
294      * dataset from the remote transport, instantiate the application's backup agent, and pass the
295      * dataset to the agent's
296      * {@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
297      * method.
298      *
299      * <p class="caution">Unlike other restore operations, this method doesn't terminate the
300      * application after the restore. The application continues running to receive the
301      * {@link RestoreObserver} callbacks on the {@code observer} argument. Full backups use an
302      * {@link android.app.Application Application} base class while key-value backups use the
303      * application subclass declared in the AndroidManifest.xml {@code <application>} tag.
304      *
305      * @param observer The {@link RestoreObserver} to receive callbacks during the restore
306      * operation. This must not be null.
307      *
308      * @return Zero on success; nonzero on error.
309      */
310     @Deprecated
requestRestore(RestoreObserver observer)311     public int requestRestore(RestoreObserver observer) {
312         return requestRestore(observer, null);
313     }
314 
315     // system APIs start here
316 
317     /**
318      * @deprecated Since Android P app can no longer request restoring of its backup.
319      *
320      * <p>Restore the calling application from backup.  The data will be restored from the
321      * current backup dataset if the application has stored data there, or from
322      * the dataset used during the last full device setup operation if the current
323      * backup dataset has no matching data.  If no backup data exists for this application
324      * in either source, a nonzero value will be returned.
325      *
326      * <p>If this method returns zero (meaning success), the OS will attempt to retrieve
327      * a backed-up dataset from the remote transport, instantiate the application's
328      * backup agent, and pass the dataset to the agent's
329      * {@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
330      * method.
331      *
332      * @param observer The {@link RestoreObserver} to receive callbacks during the restore
333      * operation. This must not be null.
334      *
335      * @param monitor the {@link BackupManagerMonitor} to receive callbacks during the restore
336      * operation.
337      *
338      * @return Zero on success; nonzero on error.
339      *
340      * @hide
341      */
342     @Deprecated
343     @SystemApi
requestRestore(RestoreObserver observer, BackupManagerMonitor monitor)344     public int requestRestore(RestoreObserver observer, BackupManagerMonitor monitor) {
345         Log.w(TAG, "requestRestore(): Since Android P app can no longer request restoring"
346                 + " of its backup.");
347         return -1;
348     }
349 
350     /**
351      * Begin the process of restoring data from backup.  See the
352      * {@link android.app.backup.RestoreSession} class for documentation on that process.
353      * @hide
354      */
355     @SystemApi
356     @RequiresPermission(android.Manifest.permission.BACKUP)
beginRestoreSession()357     public RestoreSession beginRestoreSession() {
358         RestoreSession session = null;
359         checkServiceBinder();
360         if (sService != null) {
361             try {
362                 // All packages, current transport
363                 IRestoreSession binder =
364                         sService.beginRestoreSessionForUser(mContext.getUserId(), null, null);
365                 if (binder != null) {
366                     session = new RestoreSession(mContext, binder);
367                 }
368             } catch (RemoteException e) {
369                 Log.e(TAG, "beginRestoreSession() couldn't connect");
370             }
371         }
372         return session;
373     }
374 
375     /**
376      * Enable/disable the backup service entirely.  When disabled, no backup
377      * or restore operations will take place.  Data-changed notifications will
378      * still be observed and collected, however, so that changes made while the
379      * mechanism was disabled will still be backed up properly if it is enabled
380      * at some point in the future.
381      *
382      * @hide
383      */
384     @SystemApi
385     @RequiresPermission(android.Manifest.permission.BACKUP)
setBackupEnabled(boolean isEnabled)386     public void setBackupEnabled(boolean isEnabled) {
387         checkServiceBinder();
388         if (sService != null) {
389             try {
390                 sService.setBackupEnabled(isEnabled);
391             } catch (RemoteException e) {
392                 Log.e(TAG, "setBackupEnabled() couldn't connect");
393             }
394         }
395     }
396 
397     /**
398      * Report whether the backup mechanism is currently enabled.
399      *
400      * @hide
401      */
402     @SystemApi
403     @RequiresPermission(android.Manifest.permission.BACKUP)
isBackupEnabled()404     public boolean isBackupEnabled() {
405         checkServiceBinder();
406         if (sService != null) {
407             try {
408                 return sService.isBackupEnabled();
409             } catch (RemoteException e) {
410                 Log.e(TAG, "isBackupEnabled() couldn't connect");
411             }
412         }
413         return false;
414     }
415 
416 
417     /**
418      * If this change is enabled, the {@code BACKUP} permission needed for
419      * {@code isBackupServiceActive()} will be enforced on the service end
420      * rather than client-side in {@link BackupManager}.
421      * @hide
422      */
423     @ChangeId
424     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
425     public static final long IS_BACKUP_SERVICE_ACTIVE_ENFORCE_PERMISSION_IN_SERVICE = 158482162;
426 
427     /**
428      * Report whether the backup mechanism is currently active.
429      * When it is inactive, the device will not perform any backup operations, nor will it
430      * deliver data for restore, although clients can still safely call BackupManager methods.
431      *
432      * @hide
433      */
434     @SystemApi
435     @RequiresPermission(android.Manifest.permission.BACKUP)
isBackupServiceActive(UserHandle user)436     public boolean isBackupServiceActive(UserHandle user) {
437         if (!CompatChanges.isChangeEnabled(
438                 IS_BACKUP_SERVICE_ACTIVE_ENFORCE_PERMISSION_IN_SERVICE)) {
439             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
440                     "isBackupServiceActive");
441         }
442         checkServiceBinder();
443         if (sService != null) {
444             try {
445                 return sService.isBackupServiceActive(user.getIdentifier());
446             } catch (RemoteException e) {
447                 Log.e(TAG, "isBackupEnabled() couldn't connect");
448             }
449         }
450         return false;
451     }
452 
453     /**
454      * Enable/disable data restore at application install time.  When enabled, app
455      * installation will include an attempt to fetch the app's historical data from
456      * the archival restore dataset (if any).  When disabled, no such attempt will
457      * be made.
458      *
459      * @hide
460      */
461     @SystemApi
462     @RequiresPermission(android.Manifest.permission.BACKUP)
setAutoRestore(boolean isEnabled)463     public void setAutoRestore(boolean isEnabled) {
464         checkServiceBinder();
465         if (sService != null) {
466             try {
467                 sService.setAutoRestore(isEnabled);
468             } catch (RemoteException e) {
469                 Log.e(TAG, "setAutoRestore() couldn't connect");
470             }
471         }
472     }
473 
474     /**
475      * Identify the currently selected transport.
476      * @return The name of the currently active backup transport.  In case of
477      *   failure or if no transport is currently active, this method returns {@code null}.
478      *
479      * @hide
480      */
481     @SystemApi
482     @RequiresPermission(android.Manifest.permission.BACKUP)
getCurrentTransport()483     public String getCurrentTransport() {
484         checkServiceBinder();
485         if (sService != null) {
486             try {
487                 return sService.getCurrentTransport();
488             } catch (RemoteException e) {
489                 Log.e(TAG, "getCurrentTransport() couldn't connect");
490             }
491         }
492         return null;
493     }
494 
495     /**
496      * Returns the {@link ComponentName} of the host service of the selected transport or {@code
497      * null} if no transport selected or if the transport selected is not registered.
498      *
499      * @hide
500      */
501     @SystemApi
502     @RequiresPermission(android.Manifest.permission.BACKUP)
503     @Nullable
getCurrentTransportComponent()504     public ComponentName getCurrentTransportComponent() {
505         checkServiceBinder();
506         if (sService != null) {
507             try {
508                 return sService.getCurrentTransportComponentForUser(mContext.getUserId());
509             } catch (RemoteException e) {
510                 Log.e(TAG, "getCurrentTransportComponent() couldn't connect");
511             }
512         }
513         return null;
514     }
515 
516     /**
517      * Request a list of all available backup transports' names.
518      *
519      * @hide
520      */
521     @SystemApi
522     @RequiresPermission(android.Manifest.permission.BACKUP)
listAllTransports()523     public String[] listAllTransports() {
524         checkServiceBinder();
525         if (sService != null) {
526             try {
527                 return sService.listAllTransports();
528             } catch (RemoteException e) {
529                 Log.e(TAG, "listAllTransports() couldn't connect");
530             }
531         }
532         return null;
533     }
534 
535     /**
536      * Update the attributes of the transport identified by {@code transportComponent}. If the
537      * specified transport has not been bound at least once (for registration), this call will be
538      * ignored. Only the host process of the transport can change its description, otherwise a
539      * {@link SecurityException} will be thrown.
540      *
541      * @param transportComponent The identity of the transport being described.
542      * @param name A {@link String} with the new name for the transport. This is NOT for
543      *     identification. MUST NOT be {@code null}.
544      * @param configurationIntent An {@link Intent} that can be passed to {@link
545      *     Context#startActivity} in order to launch the transport's configuration UI. It may be
546      *     {@code null} if the transport does not offer any user-facing configuration UI.
547      * @param currentDestinationString A {@link String} describing the destination to which the
548      *     transport is currently sending data. MUST NOT be {@code null}.
549      * @param dataManagementIntent An {@link Intent} that can be passed to {@link
550      *     Context#startActivity} in order to launch the transport's data-management UI. It may be
551      *     {@code null} if the transport does not offer any user-facing data management UI.
552      * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
553      *     management affordance. This MUST be {@code null} when dataManagementIntent is {@code
554      *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
555      * @throws SecurityException If the UID of the calling process differs from the package UID of
556      *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
557      * @deprecated Since Android Q, please use the variant {@link
558      *     #updateTransportAttributes(ComponentName, String, Intent, String, Intent, CharSequence)}
559      *     instead.
560      * @hide
561      */
562     @Deprecated
563     @SystemApi
564     @RequiresPermission(android.Manifest.permission.BACKUP)
updateTransportAttributes( @onNull ComponentName transportComponent, @NonNull String name, @Nullable Intent configurationIntent, @NonNull String currentDestinationString, @Nullable Intent dataManagementIntent, @Nullable String dataManagementLabel)565     public void updateTransportAttributes(
566             @NonNull ComponentName transportComponent,
567             @NonNull String name,
568             @Nullable Intent configurationIntent,
569             @NonNull String currentDestinationString,
570             @Nullable Intent dataManagementIntent,
571             @Nullable String dataManagementLabel) {
572         updateTransportAttributes(
573                 transportComponent,
574                 name,
575                 configurationIntent,
576                 currentDestinationString,
577                 dataManagementIntent,
578                 (CharSequence) dataManagementLabel);
579     }
580 
581     /**
582      * Update the attributes of the transport identified by {@code transportComponent}. If the
583      * specified transport has not been bound at least once (for registration), this call will be
584      * ignored. Only the host process of the transport can change its description, otherwise a
585      * {@link SecurityException} will be thrown.
586      *
587      * @param transportComponent The identity of the transport being described.
588      * @param name A {@link String} with the new name for the transport. This is NOT for
589      *     identification. MUST NOT be {@code null}.
590      * @param configurationIntent An {@link Intent} that can be passed to {@link
591      *     Context#startActivity} in order to launch the transport's configuration UI. It may be
592      *     {@code null} if the transport does not offer any user-facing configuration UI.
593      * @param currentDestinationString A {@link String} describing the destination to which the
594      *     transport is currently sending data. MUST NOT be {@code null}.
595      * @param dataManagementIntent An {@link Intent} that can be passed to {@link
596      *     Context#startActivity} in order to launch the transport's data-management UI. It may be
597      *     {@code null} if the transport does not offer any user-facing data management UI.
598      * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
599      *     data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
600      *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
601      * @throws SecurityException If the UID of the calling process differs from the package UID of
602      *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
603      * @hide
604      */
605     @SystemApi
606     @RequiresPermission(android.Manifest.permission.BACKUP)
updateTransportAttributes( @onNull ComponentName transportComponent, @NonNull String name, @Nullable Intent configurationIntent, @NonNull String currentDestinationString, @Nullable Intent dataManagementIntent, @Nullable CharSequence dataManagementLabel)607     public void updateTransportAttributes(
608             @NonNull ComponentName transportComponent,
609             @NonNull String name,
610             @Nullable Intent configurationIntent,
611             @NonNull String currentDestinationString,
612             @Nullable Intent dataManagementIntent,
613             @Nullable CharSequence dataManagementLabel) {
614         checkServiceBinder();
615         if (sService != null) {
616             try {
617                 sService.updateTransportAttributesForUser(
618                         mContext.getUserId(),
619                         transportComponent,
620                         name,
621                         configurationIntent,
622                         currentDestinationString,
623                         dataManagementIntent,
624                         dataManagementLabel);
625             } catch (RemoteException e) {
626                 Log.e(TAG, "describeTransport() couldn't connect");
627             }
628         }
629     }
630 
631     /**
632      * Specify the current backup transport.
633      *
634      * @param transport The name of the transport to select.  This should be one
635      *   of the names returned by {@link #listAllTransports()}. This is the String returned by
636      *   {@link BackupTransport#name()} for the particular transport.
637      * @return The name of the previously selected transport.  If the given transport
638      *   name is not one of the currently available transports, no change is made to
639      *   the current transport setting and the method returns null.
640      *
641      * @hide
642      */
643     @Deprecated
644     @SystemApi
645     @RequiresPermission(android.Manifest.permission.BACKUP)
selectBackupTransport(String transport)646     public String selectBackupTransport(String transport) {
647         checkServiceBinder();
648         if (sService != null) {
649             try {
650                 return sService.selectBackupTransport(transport);
651             } catch (RemoteException e) {
652                 Log.e(TAG, "selectBackupTransport() couldn't connect");
653             }
654         }
655         return null;
656     }
657 
658     /**
659      * Specify the current backup transport and get notified when the transport is ready to be used.
660      * This method is async because BackupManager might need to bind to the specified transport
661      * which is in a separate process.
662      *
663      * @param transport ComponentName of the service hosting the transport. This is different from
664      *                  the transport's name that is returned by {@link BackupTransport#name()}.
665      * @param listener A listener object to get a callback on the transport being selected.
666      *
667      * @hide
668      */
669     @SystemApi
670     @RequiresPermission(android.Manifest.permission.BACKUP)
selectBackupTransport(ComponentName transport, SelectBackupTransportCallback listener)671     public void selectBackupTransport(ComponentName transport,
672             SelectBackupTransportCallback listener) {
673         checkServiceBinder();
674         if (sService != null) {
675             try {
676                 SelectTransportListenerWrapper wrapper = listener == null ?
677                         null : new SelectTransportListenerWrapper(mContext, listener);
678                 sService.selectBackupTransportAsyncForUser(
679                         mContext.getUserId(), transport, wrapper);
680             } catch (RemoteException e) {
681                 Log.e(TAG, "selectBackupTransportAsync() couldn't connect");
682             }
683         }
684     }
685 
686     /**
687      * Schedule an immediate backup attempt for all pending key/value updates.  This
688      * is primarily intended for transports to use when they detect a suitable
689      * opportunity for doing a backup pass.  If there are no pending updates to
690      * be sent, no action will be taken.  Even if some updates are pending, the
691      * transport will still be asked to confirm via the usual requestBackupTime()
692      * method.
693      *
694      * @hide
695      */
696     @SystemApi
697     @RequiresPermission(android.Manifest.permission.BACKUP)
backupNow()698     public void backupNow() {
699         checkServiceBinder();
700         if (sService != null) {
701             try {
702                 sService.backupNow();
703             } catch (RemoteException e) {
704                 Log.e(TAG, "backupNow() couldn't connect");
705             }
706         }
707     }
708 
709     /**
710      * Ask the framework which dataset, if any, the given package's data would be
711      * restored from if we were to install it right now.
712      *
713      * @param packageName The name of the package whose most-suitable dataset we
714      *     wish to look up
715      * @return The dataset token from which a restore should be attempted, or zero if
716      *     no suitable data is available.
717      *
718      * @hide
719      */
720     @SystemApi
721     @RequiresPermission(android.Manifest.permission.BACKUP)
getAvailableRestoreToken(String packageName)722     public long getAvailableRestoreToken(String packageName) {
723         checkServiceBinder();
724         if (sService != null) {
725             try {
726                 return sService.getAvailableRestoreTokenForUser(mContext.getUserId(), packageName);
727             } catch (RemoteException e) {
728                 Log.e(TAG, "getAvailableRestoreToken() couldn't connect");
729             }
730         }
731         return 0;
732     }
733 
734     /**
735      * Ask the framework whether this app is eligible for backup.
736      *
737      * @param packageName The name of the package.
738      * @return Whether this app is eligible for backup.
739      *
740      * @hide
741      */
742     @SystemApi
743     @RequiresPermission(android.Manifest.permission.BACKUP)
isAppEligibleForBackup(String packageName)744     public boolean isAppEligibleForBackup(String packageName) {
745         checkServiceBinder();
746         if (sService != null) {
747             try {
748                 return sService.isAppEligibleForBackupForUser(mContext.getUserId(), packageName);
749             } catch (RemoteException e) {
750                 Log.e(TAG, "isAppEligibleForBackup(pkg) couldn't connect");
751             }
752         }
753         return false;
754     }
755 
756     /**
757      * Request an immediate backup, providing an observer to which results of the backup operation
758      * will be published. The Android backup system will decide for each package whether it will
759      * be full app data backup or key/value-pair-based backup.
760      *
761      * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
762      * provided packages using the remote transport.
763      *
764      * @param packages List of package names to backup.
765      * @param observer The {@link BackupObserver} to receive callbacks during the backup
766      * operation. Could be {@code null}.
767      * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
768      * @exception  IllegalArgumentException on null or empty {@code packages} param.
769      *
770      * @hide
771      */
772     @SystemApi
773     @RequiresPermission(android.Manifest.permission.BACKUP)
requestBackup(String[] packages, BackupObserver observer)774     public int requestBackup(String[] packages, BackupObserver observer) {
775         return requestBackup(packages, observer, null, 0);
776     }
777 
778     /**
779      * Request an immediate backup, providing an observer to which results of the backup operation
780      * will be published. The Android backup system will decide for each package whether it will
781      * be full app data backup or key/value-pair-based backup.
782      *
783      * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
784      * provided packages using the remote transport.
785      *
786      * @param packages List of package names to backup.
787      * @param observer The {@link BackupObserver} to receive callbacks during the backup
788      *                 operation. Could be {@code null}.
789      * @param monitor  The {@link BackupManagerMonitorWrapper} to receive callbacks of important
790      *                 events during the backup operation. Could be {@code null}.
791      * @param flags    {@link #FLAG_NON_INCREMENTAL_BACKUP}.
792      * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
793      * @throws IllegalArgumentException on null or empty {@code packages} param.
794      * @hide
795      */
796     @SystemApi
797     @RequiresPermission(android.Manifest.permission.BACKUP)
requestBackup(String[] packages, BackupObserver observer, BackupManagerMonitor monitor, int flags)798     public int requestBackup(String[] packages, BackupObserver observer,
799             BackupManagerMonitor monitor, int flags) {
800         checkServiceBinder();
801         if (sService != null) {
802             try {
803                 BackupObserverWrapper observerWrapper = observer == null
804                         ? null
805                         : new BackupObserverWrapper(mContext, observer);
806                 BackupManagerMonitorWrapper monitorWrapper = monitor == null
807                         ? null
808                         : new BackupManagerMonitorWrapper(monitor);
809                 return sService.requestBackup(packages, observerWrapper, monitorWrapper, flags);
810             } catch (RemoteException e) {
811                 Log.e(TAG, "requestBackup() couldn't connect");
812             }
813         }
814         return -1;
815     }
816 
817     /**
818      * Cancel all running backups. After this call returns, no currently running backups will
819      * interact with the selected transport.
820      *
821      * @hide
822      */
823     @SystemApi
824     @RequiresPermission(android.Manifest.permission.BACKUP)
cancelBackups()825     public void cancelBackups() {
826         checkServiceBinder();
827         if (sService != null) {
828             try {
829                 sService.cancelBackups();
830             } catch (RemoteException e) {
831                 Log.e(TAG, "cancelBackups() couldn't connect.");
832             }
833         }
834     }
835 
836     /**
837      * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the
838      * serial number of the its ancestral work profile or {@code null} if there is none.
839      *
840      * <p> The ancestral serial number will have a corresponding {@link UserHandle} if the device
841      * has a work profile that was restored from another work profile with serial number
842      * {@code ancestralSerialNumber}.
843      *
844      * @see android.os.UserManager#getSerialNumberForUser(UserHandle)
845      */
846     @Nullable
getUserForAncestralSerialNumber(long ancestralSerialNumber)847     public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
848         checkServiceBinder();
849         if (sService != null) {
850             try {
851                 return sService.getUserForAncestralSerialNumber(ancestralSerialNumber);
852             } catch (RemoteException e) {
853                 Log.e(TAG, "getUserForAncestralSerialNumber() couldn't connect");
854             }
855         }
856         return null;
857     }
858 
859     /**
860      * Sets the ancestral work profile for the calling user.
861      *
862      * <p> The ancestral work profile corresponds to the profile that was used to restore to the
863      * callers profile.
864      * @hide
865      */
866     @SystemApi
867     @RequiresPermission(android.Manifest.permission.BACKUP)
setAncestralSerialNumber(long ancestralSerialNumber)868     public void setAncestralSerialNumber(long ancestralSerialNumber) {
869         checkServiceBinder();
870         if (sService != null) {
871             try {
872                 sService.setAncestralSerialNumber(ancestralSerialNumber);
873             } catch (RemoteException e) {
874                 Log.e(TAG, "setAncestralSerialNumber() couldn't connect");
875             }
876         }
877     }
878 
879     /**
880      * Returns an {@link Intent} for the specified transport's configuration UI.
881      * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
882      * Intent, CharSequence)}.
883      * @param transportName The name of the registered transport.
884      * @hide
885      */
886     @SystemApi
887     @RequiresPermission(android.Manifest.permission.BACKUP)
getConfigurationIntent(String transportName)888     public Intent getConfigurationIntent(String transportName) {
889         checkServiceBinder();
890         if (sService != null) {
891             try {
892                 return sService.getConfigurationIntentForUser(mContext.getUserId(), transportName);
893             } catch (RemoteException e) {
894                 Log.e(TAG, "getConfigurationIntent() couldn't connect");
895             }
896         }
897         return null;
898     }
899 
900     /**
901      * Returns a {@link String} describing where the specified transport is sending data.
902      * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
903      * Intent, CharSequence)}.
904      * @param transportName The name of the registered transport.
905      * @hide
906      */
907     @SystemApi
908     @RequiresPermission(android.Manifest.permission.BACKUP)
getDestinationString(String transportName)909     public String getDestinationString(String transportName) {
910         checkServiceBinder();
911         if (sService != null) {
912             try {
913                 return sService.getDestinationStringForUser(mContext.getUserId(), transportName);
914             } catch (RemoteException e) {
915                 Log.e(TAG, "getDestinationString() couldn't connect");
916             }
917         }
918         return null;
919     }
920 
921     /**
922      * Returns an {@link Intent} for the specified transport's data management UI.
923      * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
924      * Intent, CharSequence)}.
925      * @param transportName The name of the registered transport.
926      * @hide
927      */
928     @SystemApi
929     @RequiresPermission(android.Manifest.permission.BACKUP)
getDataManagementIntent(String transportName)930     public Intent getDataManagementIntent(String transportName) {
931         checkServiceBinder();
932         if (sService != null) {
933             try {
934                 return sService.getDataManagementIntentForUser(mContext.getUserId(), transportName);
935             } catch (RemoteException e) {
936                 Log.e(TAG, "getDataManagementIntent() couldn't connect");
937             }
938         }
939         return null;
940     }
941 
942     /**
943      * Returns a {@link String} describing what the specified transport's data management intent is
944      * used for. This value is set by {@link #updateTransportAttributes(ComponentName, String,
945      * Intent, String, Intent, CharSequence)}.
946      *
947      * @param transportName The name of the registered transport.
948      * @deprecated Since Android Q, please use the variant {@link
949      *     #getDataManagementIntentLabel(String)} instead.
950      * @hide
951      */
952     @Deprecated
953     @SystemApi
954     @RequiresPermission(android.Manifest.permission.BACKUP)
955     @Nullable
getDataManagementLabel(@onNull String transportName)956     public String getDataManagementLabel(@NonNull String transportName) {
957         CharSequence label = getDataManagementIntentLabel(transportName);
958         return label == null ? null : label.toString();
959     }
960 
961     /**
962      * Returns a {@link CharSequence} describing what the specified transport's data management
963      * intent is used for. This value is set by {@link #updateTransportAttributes(ComponentName,
964      * String, Intent, String, Intent, CharSequence)}.
965      *
966      * @param transportName The name of the registered transport.
967      * @hide
968      */
969     @SystemApi
970     @RequiresPermission(android.Manifest.permission.BACKUP)
971     @Nullable
getDataManagementIntentLabel(@onNull String transportName)972     public CharSequence getDataManagementIntentLabel(@NonNull String transportName) {
973         checkServiceBinder();
974         if (sService != null) {
975             try {
976                 return sService.getDataManagementLabelForUser(mContext.getUserId(), transportName);
977             } catch (RemoteException e) {
978                 Log.e(TAG, "getDataManagementIntentLabel() couldn't connect");
979             }
980         }
981         return null;
982     }
983 
984     /**
985      * Excludes keys from KV restore for a given package. The corresponding data will be excluded
986      * from the data set available the backup agent during restore. However,  final list  of keys
987      * that have been excluded will be passed to the agent to make it aware of the exclusions.
988      *
989      * @param packageName The name of the package for which to exclude keys.
990      * @param keys The list of keys to exclude.
991      *
992      * @hide
993      */
994     @SystemApi
995     @RequiresPermission(android.Manifest.permission.BACKUP)
excludeKeysFromRestore(@onNull String packageName, @NonNull List<String> keys)996     public void excludeKeysFromRestore(@NonNull String packageName, @NonNull List<String> keys) {
997         checkServiceBinder();
998         if (sService != null) {
999             try {
1000                 sService.excludeKeysFromRestore(packageName, keys);
1001             } catch (RemoteException e) {
1002                 Log.e(TAG, "excludeKeysFromRestore() couldn't connect");
1003             }
1004         }
1005     }
1006 
1007     /*
1008      * We wrap incoming binder calls with a private class implementation that
1009      * redirects them into main-thread actions.  This serializes the backup
1010      * progress callbacks nicely within the usual main-thread lifecycle pattern.
1011      */
1012     private class BackupObserverWrapper extends IBackupObserver.Stub {
1013         final Handler mHandler;
1014         final BackupObserver mObserver;
1015 
1016         static final int MSG_UPDATE = 1;
1017         static final int MSG_RESULT = 2;
1018         static final int MSG_FINISHED = 3;
1019 
BackupObserverWrapper(Context context, BackupObserver observer)1020         BackupObserverWrapper(Context context, BackupObserver observer) {
1021             mHandler = new Handler(context.getMainLooper()) {
1022                 @Override
1023                 public void handleMessage(Message msg) {
1024                     switch (msg.what) {
1025                         case MSG_UPDATE:
1026                             Pair<String, BackupProgress> obj =
1027                                 (Pair<String, BackupProgress>) msg.obj;
1028                             mObserver.onUpdate(obj.first, obj.second);
1029                             break;
1030                         case MSG_RESULT:
1031                             mObserver.onResult((String)msg.obj, msg.arg1);
1032                             break;
1033                         case MSG_FINISHED:
1034                             mObserver.backupFinished(msg.arg1);
1035                             break;
1036                         default:
1037                             Log.w(TAG, "Unknown message: " + msg);
1038                             break;
1039                     }
1040                 }
1041             };
1042             mObserver = observer;
1043         }
1044 
1045         // Binder calls into this object just enqueue on the main-thread handler
1046         @Override
onUpdate(String currentPackage, BackupProgress backupProgress)1047         public void onUpdate(String currentPackage, BackupProgress backupProgress) {
1048             mHandler.sendMessage(
1049                 mHandler.obtainMessage(MSG_UPDATE, Pair.create(currentPackage, backupProgress)));
1050         }
1051 
1052         @Override
onResult(String currentPackage, int status)1053         public void onResult(String currentPackage, int status) {
1054             mHandler.sendMessage(
1055                 mHandler.obtainMessage(MSG_RESULT, status, 0, currentPackage));
1056         }
1057 
1058         @Override
backupFinished(int status)1059         public void backupFinished(int status) {
1060             mHandler.sendMessage(
1061                 mHandler.obtainMessage(MSG_FINISHED, status, 0));
1062         }
1063     }
1064 
1065     private class SelectTransportListenerWrapper extends ISelectBackupTransportCallback.Stub {
1066 
1067         private final Handler mHandler;
1068         private final SelectBackupTransportCallback mListener;
1069 
SelectTransportListenerWrapper(Context context, SelectBackupTransportCallback listener)1070         SelectTransportListenerWrapper(Context context, SelectBackupTransportCallback listener) {
1071             mHandler = new Handler(context.getMainLooper());
1072             mListener = listener;
1073         }
1074 
1075         @Override
onSuccess(final String transportName)1076         public void onSuccess(final String transportName) {
1077             mHandler.post(new Runnable() {
1078                 @Override
1079                 public void run() {
1080                     mListener.onSuccess(transportName);
1081                 }
1082             });
1083         }
1084 
1085         @Override
onFailure(final int reason)1086         public void onFailure(final int reason) {
1087             mHandler.post(new Runnable() {
1088                 @Override
1089                 public void run() {
1090                     mListener.onFailure(reason);
1091                 }
1092             });
1093         }
1094     }
1095 
1096     private class BackupManagerMonitorWrapper extends IBackupManagerMonitor.Stub {
1097         final BackupManagerMonitor mMonitor;
1098 
BackupManagerMonitorWrapper(BackupManagerMonitor monitor)1099         BackupManagerMonitorWrapper(BackupManagerMonitor monitor) {
1100             mMonitor = monitor;
1101         }
1102 
1103         @Override
onEvent(final Bundle event)1104         public void onEvent(final Bundle event) throws RemoteException {
1105             mMonitor.onEvent(event);
1106         }
1107     }
1108 
1109 }
1110