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