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