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      * Convenience method for callers who need to indicate that some other package or
285      * some other user needs a backup pass. This can be useful in the case of groups of
286      * packages that share a uid and/or have user-specific data.
287      * <p>
288      * This method requires that the application hold the "android.permission.BACKUP"
289      * permission if the package named in the package argument does not run under the
290      * same uid as the caller. This method also requires that the application hold the
291      * "android.permission.INTERACT_ACROSS_USERS_FULL" if the user argument is not the
292      * same as the user the caller is running under.
293      * @param userId The user to back up
294      * @param packageName The package name identifying the application to back up.
295      *
296      * @hide
297      */
dataChangedForUser(int userId, String packageName)298     public static void dataChangedForUser(int userId, String packageName) {
299         checkServiceBinder();
300         if (sService != null) {
301             try {
302                 sService.dataChangedForUser(userId, packageName);
303             } catch (RemoteException e) {
304                 Log.e(TAG, "dataChanged(userId,pkg) couldn't connect");
305             }
306         }
307     }
308 
309     /**
310      * @deprecated Applications shouldn't request a restore operation using this method. In Android
311      * P and later, this method is a no-op.
312      *
313      * <p>Restore the calling application from backup. The data will be restored from the
314      * current backup dataset if the application has stored data there, or from
315      * the dataset used during the last full device setup operation if the current
316      * backup dataset has no matching data.  If no backup data exists for this application
317      * in either source, a non-zero value is returned.
318      *
319      * <p>If this method returns zero (meaning success), the OS attempts to retrieve a backed-up
320      * dataset from the remote transport, instantiate the application's backup agent, and pass the
321      * dataset to the agent's
322      * {@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
323      * method.
324      *
325      * <p class="caution">Unlike other restore operations, this method doesn't terminate the
326      * application after the restore. The application continues running to receive the
327      * {@link RestoreObserver} callbacks on the {@code observer} argument. Full backups use an
328      * {@link android.app.Application Application} base class while key-value backups use the
329      * application subclass declared in the AndroidManifest.xml {@code <application>} tag.
330      *
331      * @param observer The {@link RestoreObserver} to receive callbacks during the restore
332      * operation. This must not be null.
333      *
334      * @return Zero on success; nonzero on error.
335      */
336     @Deprecated
requestRestore(RestoreObserver observer)337     public int requestRestore(RestoreObserver observer) {
338         return requestRestore(observer, null);
339     }
340 
341     // system APIs start here
342 
343     /**
344      * @deprecated Since Android P app can no longer request restoring of its backup.
345      *
346      * <p>Restore the calling application from backup.  The data will be restored from the
347      * current backup dataset if the application has stored data there, or from
348      * the dataset used during the last full device setup operation if the current
349      * backup dataset has no matching data.  If no backup data exists for this application
350      * in either source, a nonzero value will be returned.
351      *
352      * <p>If this method returns zero (meaning success), the OS will attempt to retrieve
353      * a backed-up dataset from the remote transport, instantiate the application's
354      * backup agent, and pass the dataset to the agent's
355      * {@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
356      * method.
357      *
358      * @param observer The {@link RestoreObserver} to receive callbacks during the restore
359      * operation. This must not be null.
360      *
361      * @param monitor the {@link BackupManagerMonitor} to receive callbacks during the restore
362      * operation.
363      *
364      * @return Zero on success; nonzero on error.
365      *
366      * @hide
367      */
368     @Deprecated
369     @SystemApi
requestRestore(RestoreObserver observer, BackupManagerMonitor monitor)370     public int requestRestore(RestoreObserver observer, BackupManagerMonitor monitor) {
371         Log.w(TAG, "requestRestore(): Since Android P app can no longer request restoring"
372                 + " of its backup.");
373         return -1;
374     }
375 
376     /**
377      * Begin the process of restoring data from backup.  See the
378      * {@link android.app.backup.RestoreSession} class for documentation on that process.
379      * @hide
380      */
381     @SystemApi
382     @RequiresPermission(android.Manifest.permission.BACKUP)
beginRestoreSession()383     public RestoreSession beginRestoreSession() {
384         RestoreSession session = null;
385         checkServiceBinder();
386         if (sService != null) {
387             try {
388                 // All packages, current transport
389                 IRestoreSession binder =
390                         sService.beginRestoreSessionForUser(mContext.getUserId(), null, null);
391                 if (binder != null) {
392                     session = new RestoreSession(mContext, binder);
393                 }
394             } catch (RemoteException e) {
395                 Log.e(TAG, "beginRestoreSession() couldn't connect");
396             }
397         }
398         return session;
399     }
400 
401     /**
402      * Enable/disable the backup service entirely.  When disabled, no backup
403      * or restore operations will take place.  Data-changed notifications will
404      * still be observed and collected, however, so that changes made while the
405      * mechanism was disabled will still be backed up properly if it is enabled
406      * at some point in the future.
407      *
408      * @hide
409      */
410     @SystemApi
411     @RequiresPermission(android.Manifest.permission.BACKUP)
setBackupEnabled(boolean isEnabled)412     public void setBackupEnabled(boolean isEnabled) {
413         checkServiceBinder();
414         if (sService != null) {
415             try {
416                 sService.setBackupEnabled(isEnabled);
417             } catch (RemoteException e) {
418                 Log.e(TAG, "setBackupEnabled() couldn't connect");
419             }
420         }
421     }
422 
423     /**
424      * Report whether the backup mechanism is currently enabled.
425      *
426      * @hide
427      */
428     @SystemApi
429     @RequiresPermission(android.Manifest.permission.BACKUP)
isBackupEnabled()430     public boolean isBackupEnabled() {
431         checkServiceBinder();
432         if (sService != null) {
433             try {
434                 return sService.isBackupEnabled();
435             } catch (RemoteException e) {
436                 Log.e(TAG, "isBackupEnabled() couldn't connect");
437             }
438         }
439         return false;
440     }
441 
442 
443     /**
444      * If this change is enabled, the {@code BACKUP} permission needed for
445      * {@code isBackupServiceActive()} will be enforced on the service end
446      * rather than client-side in {@link BackupManager}.
447      * @hide
448      */
449     @ChangeId
450     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
451     public static final long IS_BACKUP_SERVICE_ACTIVE_ENFORCE_PERMISSION_IN_SERVICE = 158482162;
452 
453     /**
454      * Report whether the backup mechanism is currently active.
455      * When it is inactive, the device will not perform any backup operations, nor will it
456      * deliver data for restore, although clients can still safely call BackupManager methods.
457      *
458      * @hide
459      */
460     @SystemApi
461     @RequiresPermission(android.Manifest.permission.BACKUP)
isBackupServiceActive(UserHandle user)462     public boolean isBackupServiceActive(UserHandle user) {
463         if (!CompatChanges.isChangeEnabled(
464                 IS_BACKUP_SERVICE_ACTIVE_ENFORCE_PERMISSION_IN_SERVICE)) {
465             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
466                     "isBackupServiceActive");
467         }
468         checkServiceBinder();
469         if (sService != null) {
470             try {
471                 return sService.isBackupServiceActive(user.getIdentifier());
472             } catch (RemoteException e) {
473                 Log.e(TAG, "isBackupEnabled() couldn't connect");
474             }
475         }
476         return false;
477     }
478 
479     /**
480      * Enable/disable data restore at application install time.  When enabled, app
481      * installation will include an attempt to fetch the app's historical data from
482      * the archival restore dataset (if any).  When disabled, no such attempt will
483      * be made.
484      *
485      * @hide
486      */
487     @SystemApi
488     @RequiresPermission(android.Manifest.permission.BACKUP)
setAutoRestore(boolean isEnabled)489     public void setAutoRestore(boolean isEnabled) {
490         checkServiceBinder();
491         if (sService != null) {
492             try {
493                 sService.setAutoRestore(isEnabled);
494             } catch (RemoteException e) {
495                 Log.e(TAG, "setAutoRestore() couldn't connect");
496             }
497         }
498     }
499 
500     /**
501      * Identify the currently selected transport.
502      * @return The name of the currently active backup transport.  In case of
503      *   failure or if no transport is currently active, this method returns {@code null}.
504      *
505      * @hide
506      */
507     @SystemApi
508     @RequiresPermission(android.Manifest.permission.BACKUP)
getCurrentTransport()509     public String getCurrentTransport() {
510         checkServiceBinder();
511         if (sService != null) {
512             try {
513                 return sService.getCurrentTransport();
514             } catch (RemoteException e) {
515                 Log.e(TAG, "getCurrentTransport() couldn't connect");
516             }
517         }
518         return null;
519     }
520 
521     /**
522      * Returns the {@link ComponentName} of the host service of the selected transport or {@code
523      * null} if no transport selected or if the transport selected is not registered.
524      *
525      * @hide
526      */
527     @SystemApi
528     @RequiresPermission(android.Manifest.permission.BACKUP)
529     @Nullable
getCurrentTransportComponent()530     public ComponentName getCurrentTransportComponent() {
531         checkServiceBinder();
532         if (sService != null) {
533             try {
534                 return sService.getCurrentTransportComponentForUser(mContext.getUserId());
535             } catch (RemoteException e) {
536                 Log.e(TAG, "getCurrentTransportComponent() couldn't connect");
537             }
538         }
539         return null;
540     }
541 
542     /**
543      * Request a list of all available backup transports' names.
544      *
545      * @hide
546      */
547     @SystemApi
548     @RequiresPermission(android.Manifest.permission.BACKUP)
listAllTransports()549     public String[] listAllTransports() {
550         checkServiceBinder();
551         if (sService != null) {
552             try {
553                 return sService.listAllTransports();
554             } catch (RemoteException e) {
555                 Log.e(TAG, "listAllTransports() couldn't connect");
556             }
557         }
558         return null;
559     }
560 
561     /**
562      * Update the attributes of the transport identified by {@code transportComponent}. If the
563      * specified transport has not been bound at least once (for registration), this call will be
564      * ignored. Only the host process of the transport can change its description, otherwise a
565      * {@link SecurityException} will be thrown.
566      *
567      * @param transportComponent The identity of the transport being described.
568      * @param name A {@link String} with the new name for the transport. This is NOT for
569      *     identification. MUST NOT be {@code null}.
570      * @param configurationIntent An {@link Intent} that can be passed to {@link
571      *     Context#startActivity} in order to launch the transport's configuration UI. It may be
572      *     {@code null} if the transport does not offer any user-facing configuration UI.
573      * @param currentDestinationString A {@link String} describing the destination to which the
574      *     transport is currently sending data. MUST NOT be {@code null}.
575      * @param dataManagementIntent An {@link Intent} that can be passed to {@link
576      *     Context#startActivity} in order to launch the transport's data-management UI. It may be
577      *     {@code null} if the transport does not offer any user-facing data management UI.
578      * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
579      *     management affordance. This MUST be {@code null} when dataManagementIntent is {@code
580      *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
581      * @throws SecurityException If the UID of the calling process differs from the package UID of
582      *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
583      * @deprecated Since Android Q, please use the variant {@link
584      *     #updateTransportAttributes(ComponentName, String, Intent, String, Intent, CharSequence)}
585      *     instead.
586      * @hide
587      */
588     @Deprecated
589     @SystemApi
590     @RequiresPermission(android.Manifest.permission.BACKUP)
updateTransportAttributes( @onNull ComponentName transportComponent, @NonNull String name, @Nullable Intent configurationIntent, @NonNull String currentDestinationString, @Nullable Intent dataManagementIntent, @Nullable String dataManagementLabel)591     public void updateTransportAttributes(
592             @NonNull ComponentName transportComponent,
593             @NonNull String name,
594             @Nullable Intent configurationIntent,
595             @NonNull String currentDestinationString,
596             @Nullable Intent dataManagementIntent,
597             @Nullable String dataManagementLabel) {
598         updateTransportAttributes(
599                 transportComponent,
600                 name,
601                 configurationIntent,
602                 currentDestinationString,
603                 dataManagementIntent,
604                 (CharSequence) dataManagementLabel);
605     }
606 
607     /**
608      * Update the attributes of the transport identified by {@code transportComponent}. If the
609      * specified transport has not been bound at least once (for registration), this call will be
610      * ignored. Only the host process of the transport can change its description, otherwise a
611      * {@link SecurityException} will be thrown.
612      *
613      * @param transportComponent The identity of the transport being described.
614      * @param name A {@link String} with the new name for the transport. This is NOT for
615      *     identification. MUST NOT be {@code null}.
616      * @param configurationIntent An {@link Intent} that can be passed to {@link
617      *     Context#startActivity} in order to launch the transport's configuration UI. It may be
618      *     {@code null} if the transport does not offer any user-facing configuration UI.
619      * @param currentDestinationString A {@link String} describing the destination to which the
620      *     transport is currently sending data. MUST NOT be {@code null}.
621      * @param dataManagementIntent An {@link Intent} that can be passed to {@link
622      *     Context#startActivity} in order to launch the transport's data-management UI. It may be
623      *     {@code null} if the transport does not offer any user-facing data management UI.
624      * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
625      *     data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
626      *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
627      * @throws SecurityException If the UID of the calling process differs from the package UID of
628      *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
629      * @hide
630      */
631     @SystemApi
632     @RequiresPermission(android.Manifest.permission.BACKUP)
updateTransportAttributes( @onNull ComponentName transportComponent, @NonNull String name, @Nullable Intent configurationIntent, @NonNull String currentDestinationString, @Nullable Intent dataManagementIntent, @Nullable CharSequence dataManagementLabel)633     public void updateTransportAttributes(
634             @NonNull ComponentName transportComponent,
635             @NonNull String name,
636             @Nullable Intent configurationIntent,
637             @NonNull String currentDestinationString,
638             @Nullable Intent dataManagementIntent,
639             @Nullable CharSequence dataManagementLabel) {
640         checkServiceBinder();
641         if (sService != null) {
642             try {
643                 sService.updateTransportAttributesForUser(
644                         mContext.getUserId(),
645                         transportComponent,
646                         name,
647                         configurationIntent,
648                         currentDestinationString,
649                         dataManagementIntent,
650                         dataManagementLabel);
651             } catch (RemoteException e) {
652                 Log.e(TAG, "describeTransport() couldn't connect");
653             }
654         }
655     }
656 
657     /**
658      * Specify the current backup transport.
659      *
660      * @param transport The name of the transport to select.  This should be one
661      *   of the names returned by {@link #listAllTransports()}. This is the String returned by
662      *   {@link BackupTransport#name()} for the particular transport.
663      * @return The name of the previously selected transport.  If the given transport
664      *   name is not one of the currently available transports, no change is made to
665      *   the current transport setting and the method returns null.
666      *
667      * @hide
668      */
669     @Deprecated
670     @SystemApi
671     @RequiresPermission(android.Manifest.permission.BACKUP)
selectBackupTransport(String transport)672     public String selectBackupTransport(String transport) {
673         checkServiceBinder();
674         if (sService != null) {
675             try {
676                 return sService.selectBackupTransport(transport);
677             } catch (RemoteException e) {
678                 Log.e(TAG, "selectBackupTransport() couldn't connect");
679             }
680         }
681         return null;
682     }
683 
684     /**
685      * Specify the current backup transport and get notified when the transport is ready to be used.
686      * This method is async because BackupManager might need to bind to the specified transport
687      * which is in a separate process.
688      *
689      * @param transport ComponentName of the service hosting the transport. This is different from
690      *                  the transport's name that is returned by {@link BackupTransport#name()}.
691      * @param listener A listener object to get a callback on the transport being selected.
692      *
693      * @hide
694      */
695     @SystemApi
696     @RequiresPermission(android.Manifest.permission.BACKUP)
selectBackupTransport(ComponentName transport, SelectBackupTransportCallback listener)697     public void selectBackupTransport(ComponentName transport,
698             SelectBackupTransportCallback listener) {
699         checkServiceBinder();
700         if (sService != null) {
701             try {
702                 SelectTransportListenerWrapper wrapper = listener == null ?
703                         null : new SelectTransportListenerWrapper(mContext, listener);
704                 sService.selectBackupTransportAsyncForUser(
705                         mContext.getUserId(), transport, wrapper);
706             } catch (RemoteException e) {
707                 Log.e(TAG, "selectBackupTransportAsync() couldn't connect");
708             }
709         }
710     }
711 
712     /**
713      * Schedule an immediate backup attempt for all pending key/value updates.  This
714      * is primarily intended for transports to use when they detect a suitable
715      * opportunity for doing a backup pass.  If there are no pending updates to
716      * be sent, no action will be taken.  Even if some updates are pending, the
717      * transport will still be asked to confirm via the usual requestBackupTime()
718      * method.
719      *
720      * @hide
721      */
722     @SystemApi
723     @RequiresPermission(android.Manifest.permission.BACKUP)
backupNow()724     public void backupNow() {
725         checkServiceBinder();
726         if (sService != null) {
727             try {
728                 sService.backupNow();
729             } catch (RemoteException e) {
730                 Log.e(TAG, "backupNow() couldn't connect");
731             }
732         }
733     }
734 
735     /**
736      * Ask the framework which dataset, if any, the given package's data would be
737      * restored from if we were to install it right now.
738      *
739      * @param packageName The name of the package whose most-suitable dataset we
740      *     wish to look up
741      * @return The dataset token from which a restore should be attempted, or zero if
742      *     no suitable data is available.
743      *
744      * @hide
745      */
746     @SystemApi
747     @RequiresPermission(android.Manifest.permission.BACKUP)
getAvailableRestoreToken(String packageName)748     public long getAvailableRestoreToken(String packageName) {
749         checkServiceBinder();
750         if (sService != null) {
751             try {
752                 return sService.getAvailableRestoreTokenForUser(mContext.getUserId(), packageName);
753             } catch (RemoteException e) {
754                 Log.e(TAG, "getAvailableRestoreToken() couldn't connect");
755             }
756         }
757         return 0;
758     }
759 
760     /**
761      * Ask the framework whether this app is eligible for backup.
762      *
763      * @param packageName The name of the package.
764      * @return Whether this app is eligible for backup.
765      *
766      * @hide
767      */
768     @SystemApi
769     @RequiresPermission(android.Manifest.permission.BACKUP)
isAppEligibleForBackup(String packageName)770     public boolean isAppEligibleForBackup(String packageName) {
771         checkServiceBinder();
772         if (sService != null) {
773             try {
774                 return sService.isAppEligibleForBackupForUser(mContext.getUserId(), packageName);
775             } catch (RemoteException e) {
776                 Log.e(TAG, "isAppEligibleForBackup(pkg) couldn't connect");
777             }
778         }
779         return false;
780     }
781 
782     /**
783      * Request an immediate backup, providing an observer to which results of the backup operation
784      * will be published. The Android backup system will decide for each package whether it will
785      * be full app data backup or key/value-pair-based backup.
786      *
787      * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
788      * provided packages using the remote transport.
789      *
790      * @param packages List of package names to backup.
791      * @param observer The {@link BackupObserver} to receive callbacks during the backup
792      * operation. Could be {@code null}.
793      * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
794      * @exception  IllegalArgumentException on null or empty {@code packages} param.
795      *
796      * @hide
797      */
798     @SystemApi
799     @RequiresPermission(android.Manifest.permission.BACKUP)
requestBackup(String[] packages, BackupObserver observer)800     public int requestBackup(String[] packages, BackupObserver observer) {
801         return requestBackup(packages, observer, null, 0);
802     }
803 
804     /**
805      * Request an immediate backup, providing an observer to which results of the backup operation
806      * will be published. The Android backup system will decide for each package whether it will
807      * be full app data backup or key/value-pair-based backup.
808      *
809      * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
810      * provided packages using the remote transport.
811      *
812      * @param packages List of package names to backup.
813      * @param observer The {@link BackupObserver} to receive callbacks during the backup
814      *                 operation. Could be {@code null}.
815      * @param monitor  The {@link BackupManagerMonitorWrapper} to receive callbacks of important
816      *                 events during the backup operation. Could be {@code null}.
817      * @param flags    {@link #FLAG_NON_INCREMENTAL_BACKUP}.
818      * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
819      * @throws IllegalArgumentException on null or empty {@code packages} param.
820      * @hide
821      */
822     @SystemApi
823     @RequiresPermission(android.Manifest.permission.BACKUP)
requestBackup(String[] packages, BackupObserver observer, BackupManagerMonitor monitor, int flags)824     public int requestBackup(String[] packages, BackupObserver observer,
825             BackupManagerMonitor monitor, int flags) {
826         checkServiceBinder();
827         if (sService != null) {
828             try {
829                 BackupObserverWrapper observerWrapper = observer == null
830                         ? null
831                         : new BackupObserverWrapper(mContext, observer);
832                 BackupManagerMonitorWrapper monitorWrapper = monitor == null
833                         ? null
834                         : new BackupManagerMonitorWrapper(monitor);
835                 return sService.requestBackup(packages, observerWrapper, monitorWrapper, flags);
836             } catch (RemoteException e) {
837                 Log.e(TAG, "requestBackup() couldn't connect");
838             }
839         }
840         return -1;
841     }
842 
843     /**
844      * Cancel all running backups. After this call returns, no currently running backups will
845      * interact with the selected transport.
846      *
847      * @hide
848      */
849     @SystemApi
850     @RequiresPermission(android.Manifest.permission.BACKUP)
cancelBackups()851     public void cancelBackups() {
852         checkServiceBinder();
853         if (sService != null) {
854             try {
855                 sService.cancelBackups();
856             } catch (RemoteException e) {
857                 Log.e(TAG, "cancelBackups() couldn't connect.");
858             }
859         }
860     }
861 
862     /**
863      * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the
864      * serial number of the its ancestral work profile or {@code null} if there is none.
865      *
866      * <p> The ancestral serial number will have a corresponding {@link UserHandle} if the device
867      * has a work profile that was restored from another work profile with serial number
868      * {@code ancestralSerialNumber}.
869      *
870      * @see android.os.UserManager#getSerialNumberForUser(UserHandle)
871      */
872     @Nullable
getUserForAncestralSerialNumber(long ancestralSerialNumber)873     public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
874         checkServiceBinder();
875         if (sService != null) {
876             try {
877                 return sService.getUserForAncestralSerialNumber(ancestralSerialNumber);
878             } catch (RemoteException e) {
879                 Log.e(TAG, "getUserForAncestralSerialNumber() couldn't connect");
880             }
881         }
882         return null;
883     }
884 
885     /**
886      * Sets the ancestral work profile for the calling user.
887      *
888      * <p> The ancestral work profile corresponds to the profile that was used to restore to the
889      * callers profile.
890      * @hide
891      */
892     @SystemApi
893     @RequiresPermission(android.Manifest.permission.BACKUP)
setAncestralSerialNumber(long ancestralSerialNumber)894     public void setAncestralSerialNumber(long ancestralSerialNumber) {
895         checkServiceBinder();
896         if (sService != null) {
897             try {
898                 sService.setAncestralSerialNumber(ancestralSerialNumber);
899             } catch (RemoteException e) {
900                 Log.e(TAG, "setAncestralSerialNumber() couldn't connect");
901             }
902         }
903     }
904 
905     /**
906      * Returns an {@link Intent} for the specified transport's configuration UI.
907      * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
908      * Intent, CharSequence)}.
909      * @param transportName The name of the registered transport.
910      * @hide
911      */
912     @SystemApi
913     @RequiresPermission(android.Manifest.permission.BACKUP)
getConfigurationIntent(String transportName)914     public Intent getConfigurationIntent(String transportName) {
915         checkServiceBinder();
916         if (sService != null) {
917             try {
918                 return sService.getConfigurationIntentForUser(mContext.getUserId(), transportName);
919             } catch (RemoteException e) {
920                 Log.e(TAG, "getConfigurationIntent() couldn't connect");
921             }
922         }
923         return null;
924     }
925 
926     /**
927      * Returns a {@link String} describing where the specified transport is sending data.
928      * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
929      * Intent, CharSequence)}.
930      * @param transportName The name of the registered transport.
931      * @hide
932      */
933     @SystemApi
934     @RequiresPermission(android.Manifest.permission.BACKUP)
getDestinationString(String transportName)935     public String getDestinationString(String transportName) {
936         checkServiceBinder();
937         if (sService != null) {
938             try {
939                 return sService.getDestinationStringForUser(mContext.getUserId(), transportName);
940             } catch (RemoteException e) {
941                 Log.e(TAG, "getDestinationString() couldn't connect");
942             }
943         }
944         return null;
945     }
946 
947     /**
948      * Returns an {@link Intent} for the specified transport's data management UI.
949      * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
950      * Intent, CharSequence)}.
951      * @param transportName The name of the registered transport.
952      * @hide
953      */
954     @SystemApi
955     @RequiresPermission(android.Manifest.permission.BACKUP)
getDataManagementIntent(String transportName)956     public Intent getDataManagementIntent(String transportName) {
957         checkServiceBinder();
958         if (sService != null) {
959             try {
960                 return sService.getDataManagementIntentForUser(mContext.getUserId(), transportName);
961             } catch (RemoteException e) {
962                 Log.e(TAG, "getDataManagementIntent() couldn't connect");
963             }
964         }
965         return null;
966     }
967 
968     /**
969      * Returns a {@link String} describing what the specified transport's data management intent is
970      * used for. This value is set by {@link #updateTransportAttributes(ComponentName, String,
971      * Intent, String, Intent, CharSequence)}.
972      *
973      * @param transportName The name of the registered transport.
974      * @deprecated Since Android Q, please use the variant {@link
975      *     #getDataManagementIntentLabel(String)} instead.
976      * @hide
977      */
978     @Deprecated
979     @SystemApi
980     @RequiresPermission(android.Manifest.permission.BACKUP)
981     @Nullable
getDataManagementLabel(@onNull String transportName)982     public String getDataManagementLabel(@NonNull String transportName) {
983         CharSequence label = getDataManagementIntentLabel(transportName);
984         return label == null ? null : label.toString();
985     }
986 
987     /**
988      * Returns a {@link CharSequence} describing what the specified transport's data management
989      * intent is used for. This value is set by {@link #updateTransportAttributes(ComponentName,
990      * String, Intent, String, Intent, CharSequence)}.
991      *
992      * @param transportName The name of the registered transport.
993      * @hide
994      */
995     @SystemApi
996     @RequiresPermission(android.Manifest.permission.BACKUP)
997     @Nullable
getDataManagementIntentLabel(@onNull String transportName)998     public CharSequence getDataManagementIntentLabel(@NonNull String transportName) {
999         checkServiceBinder();
1000         if (sService != null) {
1001             try {
1002                 return sService.getDataManagementLabelForUser(mContext.getUserId(), transportName);
1003             } catch (RemoteException e) {
1004                 Log.e(TAG, "getDataManagementIntentLabel() couldn't connect");
1005             }
1006         }
1007         return null;
1008     }
1009 
1010     /**
1011      * Excludes keys from KV restore for a given package. The corresponding data will be excluded
1012      * from the data set available the backup agent during restore. However,  final list  of keys
1013      * that have been excluded will be passed to the agent to make it aware of the exclusions.
1014      *
1015      * @param packageName The name of the package for which to exclude keys.
1016      * @param keys The list of keys to exclude.
1017      *
1018      * @hide
1019      */
1020     @SystemApi
1021     @RequiresPermission(android.Manifest.permission.BACKUP)
excludeKeysFromRestore(@onNull String packageName, @NonNull List<String> keys)1022     public void excludeKeysFromRestore(@NonNull String packageName, @NonNull List<String> keys) {
1023         checkServiceBinder();
1024         if (sService != null) {
1025             try {
1026                 sService.excludeKeysFromRestore(packageName, keys);
1027             } catch (RemoteException e) {
1028                 Log.e(TAG, "excludeKeysFromRestore() couldn't connect");
1029             }
1030         }
1031     }
1032 
1033     /*
1034      * We wrap incoming binder calls with a private class implementation that
1035      * redirects them into main-thread actions.  This serializes the backup
1036      * progress callbacks nicely within the usual main-thread lifecycle pattern.
1037      */
1038     private class BackupObserverWrapper extends IBackupObserver.Stub {
1039         final Handler mHandler;
1040         final BackupObserver mObserver;
1041 
1042         static final int MSG_UPDATE = 1;
1043         static final int MSG_RESULT = 2;
1044         static final int MSG_FINISHED = 3;
1045 
BackupObserverWrapper(Context context, BackupObserver observer)1046         BackupObserverWrapper(Context context, BackupObserver observer) {
1047             mHandler = new Handler(context.getMainLooper()) {
1048                 @Override
1049                 public void handleMessage(Message msg) {
1050                     switch (msg.what) {
1051                         case MSG_UPDATE:
1052                             Pair<String, BackupProgress> obj =
1053                                 (Pair<String, BackupProgress>) msg.obj;
1054                             mObserver.onUpdate(obj.first, obj.second);
1055                             break;
1056                         case MSG_RESULT:
1057                             mObserver.onResult((String)msg.obj, msg.arg1);
1058                             break;
1059                         case MSG_FINISHED:
1060                             mObserver.backupFinished(msg.arg1);
1061                             break;
1062                         default:
1063                             Log.w(TAG, "Unknown message: " + msg);
1064                             break;
1065                     }
1066                 }
1067             };
1068             mObserver = observer;
1069         }
1070 
1071         // Binder calls into this object just enqueue on the main-thread handler
1072         @Override
onUpdate(String currentPackage, BackupProgress backupProgress)1073         public void onUpdate(String currentPackage, BackupProgress backupProgress) {
1074             mHandler.sendMessage(
1075                 mHandler.obtainMessage(MSG_UPDATE, Pair.create(currentPackage, backupProgress)));
1076         }
1077 
1078         @Override
onResult(String currentPackage, int status)1079         public void onResult(String currentPackage, int status) {
1080             mHandler.sendMessage(
1081                 mHandler.obtainMessage(MSG_RESULT, status, 0, currentPackage));
1082         }
1083 
1084         @Override
backupFinished(int status)1085         public void backupFinished(int status) {
1086             mHandler.sendMessage(
1087                 mHandler.obtainMessage(MSG_FINISHED, status, 0));
1088         }
1089     }
1090 
1091     private class SelectTransportListenerWrapper extends ISelectBackupTransportCallback.Stub {
1092 
1093         private final Handler mHandler;
1094         private final SelectBackupTransportCallback mListener;
1095 
SelectTransportListenerWrapper(Context context, SelectBackupTransportCallback listener)1096         SelectTransportListenerWrapper(Context context, SelectBackupTransportCallback listener) {
1097             mHandler = new Handler(context.getMainLooper());
1098             mListener = listener;
1099         }
1100 
1101         @Override
onSuccess(final String transportName)1102         public void onSuccess(final String transportName) {
1103             mHandler.post(new Runnable() {
1104                 @Override
1105                 public void run() {
1106                     mListener.onSuccess(transportName);
1107                 }
1108             });
1109         }
1110 
1111         @Override
onFailure(final int reason)1112         public void onFailure(final int reason) {
1113             mHandler.post(new Runnable() {
1114                 @Override
1115                 public void run() {
1116                     mListener.onFailure(reason);
1117                 }
1118             });
1119         }
1120     }
1121 
1122     private class BackupManagerMonitorWrapper extends IBackupManagerMonitor.Stub {
1123         final BackupManagerMonitor mMonitor;
1124 
BackupManagerMonitorWrapper(BackupManagerMonitor monitor)1125         BackupManagerMonitorWrapper(BackupManagerMonitor monitor) {
1126             mMonitor = monitor;
1127         }
1128 
1129         @Override
onEvent(final Bundle event)1130         public void onEvent(final Bundle event) throws RemoteException {
1131             mMonitor.onEvent(event);
1132         }
1133     }
1134 
1135 }
1136