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