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.SystemApi;
     20 import android.content.Context;
     21 import android.os.Handler;
     22 import android.os.Message;
     23 import android.os.RemoteException;
     24 import android.os.ServiceManager;
     25 import android.util.Log;
     26 import android.util.Pair;
     27 
     28 /**
     29  * The interface through which an application interacts with the Android backup service to
     30  * request backup and restore operations.
     31  * Applications instantiate it using the constructor and issue calls through that instance.
     32  * <p>
     33  * When an application has made changes to data which should be backed up, a
     34  * call to {@link #dataChanged()} will notify the backup service. The system
     35  * will then schedule a backup operation to occur in the near future. Repeated
     36  * calls to {@link #dataChanged()} have no further effect until the backup
     37  * operation actually occurs.
     38  * <p>
     39  * A backup or restore operation for your application begins when the system launches the
     40  * {@link android.app.backup.BackupAgent} subclass you've declared in your manifest. See the
     41  * documentation for {@link android.app.backup.BackupAgent} for a detailed description
     42  * of how the operation then proceeds.
     43  * <p>
     44  * Several attributes affecting the operation of the backup and restore mechanism
     45  * can be set on the <code>
     46  * <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
     47  * tag in your application's AndroidManifest.xml file.
     48  *
     49  * <div class="special reference">
     50  * <h3>Developer Guides</h3>
     51  * <p>For more information about using BackupManager, read the
     52  * <a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p></div>
     53  *
     54  * @attr ref android.R.styleable#AndroidManifestApplication_allowBackup
     55  * @attr ref android.R.styleable#AndroidManifestApplication_backupAgent
     56  * @attr ref android.R.styleable#AndroidManifestApplication_killAfterRestore
     57  * @attr ref android.R.styleable#AndroidManifestApplication_restoreAnyVersion
     58  */
     59 public class BackupManager {
     60     private static final String TAG = "BackupManager";
     61 
     62     // BackupObserver status codes
     63     /**
     64      * Indicates that backup succeeded.
     65      *
     66      * @hide
     67      */
     68     @SystemApi
     69     public static final int SUCCESS = 0;
     70 
     71     /**
     72      * Indicates that backup is either not enabled at all or
     73      * backup for the package was rejected by backup service
     74      * or backup transport,
     75      *
     76      * @hide
     77      */
     78     @SystemApi
     79     public static final int ERROR_BACKUP_NOT_ALLOWED = -2001;
     80 
     81     /**
     82      * The requested app is not installed on the device.
     83      *
     84      * @hide
     85      */
     86     @SystemApi
     87     public static final int ERROR_PACKAGE_NOT_FOUND = -2002;
     88 
     89     /**
     90      * The transport for some reason was not in a good state and
     91      * aborted the entire backup request. This is a transient
     92      * failure and should not be retried immediately.
     93      *
     94      * @hide
     95      */
     96     @SystemApi
     97     public static final int ERROR_TRANSPORT_ABORTED = BackupTransport.TRANSPORT_ERROR;
     98 
     99     /**
    100      * Returned when the transport was unable to process the
    101      * backup request for a given package, for example if the
    102      * transport hit a transient network failure. The remaining
    103      * packages provided to {@link #requestBackup(String[], BackupObserver)}
    104      * will still be attempted.
    105      *
    106      * @hide
    107      */
    108     @SystemApi
    109     public static final int ERROR_TRANSPORT_PACKAGE_REJECTED =
    110             BackupTransport.TRANSPORT_PACKAGE_REJECTED;
    111 
    112     /**
    113      * Returned when the transport reject the attempt to backup because
    114      * backup data size exceeded current quota limit for this package.
    115      *
    116      * @hide
    117      */
    118     @SystemApi
    119     public static final int ERROR_TRANSPORT_QUOTA_EXCEEDED =
    120             BackupTransport.TRANSPORT_QUOTA_EXCEEDED;
    121 
    122     /**
    123      * The {@link BackupAgent} for the requested package failed for some reason
    124      * and didn't provide appropriate backup data.
    125      *
    126      * @hide
    127      */
    128     @SystemApi
    129     public static final int ERROR_AGENT_FAILURE = BackupTransport.AGENT_ERROR;
    130 
    131     private Context mContext;
    132     private static IBackupManager sService;
    133 
    134     private static void checkServiceBinder() {
    135         if (sService == null) {
    136             sService = IBackupManager.Stub.asInterface(
    137                     ServiceManager.getService(Context.BACKUP_SERVICE));
    138         }
    139     }
    140 
    141     /**
    142      * Constructs a BackupManager object through which the application can
    143      * communicate with the Android backup system.
    144      *
    145      * @param context The {@link android.content.Context} that was provided when
    146      *                one of your application's {@link android.app.Activity Activities}
    147      *                was created.
    148      */
    149     public BackupManager(Context context) {
    150         mContext = context;
    151     }
    152 
    153     /**
    154      * Notifies the Android backup system that your application wishes to back up
    155      * new changes to its data.  A backup operation using your application's
    156      * {@link android.app.backup.BackupAgent} subclass will be scheduled when you
    157      * call this method.
    158      */
    159     public void dataChanged() {
    160         checkServiceBinder();
    161         if (sService != null) {
    162             try {
    163                 sService.dataChanged(mContext.getPackageName());
    164             } catch (RemoteException e) {
    165                 Log.d(TAG, "dataChanged() couldn't connect");
    166             }
    167         }
    168     }
    169 
    170     /**
    171      * Convenience method for callers who need to indicate that some other package
    172      * needs a backup pass.  This can be useful in the case of groups of packages
    173      * that share a uid.
    174      * <p>
    175      * This method requires that the application hold the "android.permission.BACKUP"
    176      * permission if the package named in the argument does not run under the same uid
    177      * as the caller.
    178      *
    179      * @param packageName The package name identifying the application to back up.
    180      */
    181     public static void dataChanged(String packageName) {
    182         checkServiceBinder();
    183         if (sService != null) {
    184             try {
    185                 sService.dataChanged(packageName);
    186             } catch (RemoteException e) {
    187                 Log.e(TAG, "dataChanged(pkg) couldn't connect");
    188             }
    189         }
    190     }
    191 
    192     /**
    193      * Restore the calling application from backup.  The data will be restored from the
    194      * current backup dataset if the application has stored data there, or from
    195      * the dataset used during the last full device setup operation if the current
    196      * backup dataset has no matching data.  If no backup data exists for this application
    197      * in either source, a nonzero value will be returned.
    198      *
    199      * <p>If this method returns zero (meaning success), the OS will attempt to retrieve
    200      * a backed-up dataset from the remote transport, instantiate the application's
    201      * backup agent, and pass the dataset to the agent's
    202      * {@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
    203      * method.
    204      *
    205      * @param observer The {@link RestoreObserver} to receive callbacks during the restore
    206      * operation. This must not be null.
    207      *
    208      * @return Zero on success; nonzero on error.
    209      */
    210     public int requestRestore(RestoreObserver observer) {
    211         int result = -1;
    212         checkServiceBinder();
    213         if (sService != null) {
    214             RestoreSession session = null;
    215             try {
    216                 IRestoreSession binder = sService.beginRestoreSession(mContext.getPackageName(),
    217                         null);
    218                 if (binder != null) {
    219                     session = new RestoreSession(mContext, binder);
    220                     result = session.restorePackage(mContext.getPackageName(), observer);
    221                 }
    222             } catch (RemoteException e) {
    223                 Log.e(TAG, "restoreSelf() unable to contact service");
    224             } finally {
    225                 if (session != null) {
    226                     session.endRestoreSession();
    227                 }
    228             }
    229         }
    230         return result;
    231     }
    232 
    233     // system APIs start here
    234 
    235     /**
    236      * Begin the process of restoring data from backup.  See the
    237      * {@link android.app.backup.RestoreSession} class for documentation on that process.
    238      * @hide
    239      */
    240     @SystemApi
    241     public RestoreSession beginRestoreSession() {
    242         RestoreSession session = null;
    243         checkServiceBinder();
    244         if (sService != null) {
    245             try {
    246                 // All packages, current transport
    247                 IRestoreSession binder = sService.beginRestoreSession(null, null);
    248                 if (binder != null) {
    249                     session = new RestoreSession(mContext, binder);
    250                 }
    251             } catch (RemoteException e) {
    252                 Log.e(TAG, "beginRestoreSession() couldn't connect");
    253             }
    254         }
    255         return session;
    256     }
    257 
    258     /**
    259      * Enable/disable the backup service entirely.  When disabled, no backup
    260      * or restore operations will take place.  Data-changed notifications will
    261      * still be observed and collected, however, so that changes made while the
    262      * mechanism was disabled will still be backed up properly if it is enabled
    263      * at some point in the future.
    264      *
    265      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
    266      *
    267      * @hide
    268      */
    269     @SystemApi
    270     public void setBackupEnabled(boolean isEnabled) {
    271         checkServiceBinder();
    272         if (sService != null) {
    273             try {
    274                 sService.setBackupEnabled(isEnabled);
    275             } catch (RemoteException e) {
    276                 Log.e(TAG, "setBackupEnabled() couldn't connect");
    277             }
    278         }
    279     }
    280 
    281     /**
    282      * Report whether the backup mechanism is currently enabled.
    283      *
    284      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
    285      *
    286      * @hide
    287      */
    288     @SystemApi
    289     public boolean isBackupEnabled() {
    290         checkServiceBinder();
    291         if (sService != null) {
    292             try {
    293                 return sService.isBackupEnabled();
    294             } catch (RemoteException e) {
    295                 Log.e(TAG, "isBackupEnabled() couldn't connect");
    296             }
    297         }
    298         return false;
    299     }
    300 
    301     /**
    302      * Enable/disable data restore at application install time.  When enabled, app
    303      * installation will include an attempt to fetch the app's historical data from
    304      * the archival restore dataset (if any).  When disabled, no such attempt will
    305      * be made.
    306      *
    307      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
    308      *
    309      * @hide
    310      */
    311     @SystemApi
    312     public void setAutoRestore(boolean isEnabled) {
    313         checkServiceBinder();
    314         if (sService != null) {
    315             try {
    316                 sService.setAutoRestore(isEnabled);
    317             } catch (RemoteException e) {
    318                 Log.e(TAG, "setAutoRestore() couldn't connect");
    319             }
    320         }
    321     }
    322 
    323     /**
    324      * Identify the currently selected transport.  Callers must hold the
    325      * android.permission.BACKUP permission to use this method.
    326      * @return The name of the currently active backup transport.  In case of
    327      *   failure or if no transport is currently active, this method returns {@code null}.
    328      *
    329      * @hide
    330      */
    331     @SystemApi
    332     public String getCurrentTransport() {
    333         checkServiceBinder();
    334         if (sService != null) {
    335             try {
    336                 return sService.getCurrentTransport();
    337             } catch (RemoteException e) {
    338                 Log.e(TAG, "getCurrentTransport() couldn't connect");
    339             }
    340         }
    341         return null;
    342     }
    343 
    344     /**
    345      * Request a list of all available backup transports' names.  Callers must
    346      * hold the android.permission.BACKUP permission to use this method.
    347      *
    348      * @hide
    349      */
    350     @SystemApi
    351     public String[] listAllTransports() {
    352         checkServiceBinder();
    353         if (sService != null) {
    354             try {
    355                 return sService.listAllTransports();
    356             } catch (RemoteException e) {
    357                 Log.e(TAG, "listAllTransports() couldn't connect");
    358             }
    359         }
    360         return null;
    361     }
    362 
    363     /**
    364      * Specify the current backup transport.  Callers must hold the
    365      * android.permission.BACKUP permission to use this method.
    366      *
    367      * @param transport The name of the transport to select.  This should be one
    368      *   of the names returned by {@link #listAllTransports()}.
    369      * @return The name of the previously selected transport.  If the given transport
    370      *   name is not one of the currently available transports, no change is made to
    371      *   the current transport setting and the method returns null.
    372      *
    373      * @hide
    374      */
    375     @SystemApi
    376     public String selectBackupTransport(String transport) {
    377         checkServiceBinder();
    378         if (sService != null) {
    379             try {
    380                 return sService.selectBackupTransport(transport);
    381             } catch (RemoteException e) {
    382                 Log.e(TAG, "selectBackupTransport() couldn't connect");
    383             }
    384         }
    385         return null;
    386     }
    387 
    388     /**
    389      * Schedule an immediate backup attempt for all pending key/value updates.  This
    390      * is primarily intended for transports to use when they detect a suitable
    391      * opportunity for doing a backup pass.  If there are no pending updates to
    392      * be sent, no action will be taken.  Even if some updates are pending, the
    393      * transport will still be asked to confirm via the usual requestBackupTime()
    394      * method.
    395      *
    396      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
    397      *
    398      * @hide
    399      */
    400     @SystemApi
    401     public void backupNow() {
    402         checkServiceBinder();
    403         if (sService != null) {
    404             try {
    405                 sService.backupNow();
    406             } catch (RemoteException e) {
    407                 Log.e(TAG, "backupNow() couldn't connect");
    408             }
    409         }
    410     }
    411 
    412     /**
    413      * Ask the framework which dataset, if any, the given package's data would be
    414      * restored from if we were to install it right now.
    415      *
    416      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
    417      *
    418      * @param packageName The name of the package whose most-suitable dataset we
    419      *     wish to look up
    420      * @return The dataset token from which a restore should be attempted, or zero if
    421      *     no suitable data is available.
    422      *
    423      * @hide
    424      */
    425     @SystemApi
    426     public long getAvailableRestoreToken(String packageName) {
    427         checkServiceBinder();
    428         if (sService != null) {
    429             try {
    430                 return sService.getAvailableRestoreToken(packageName);
    431             } catch (RemoteException e) {
    432                 Log.e(TAG, "getAvailableRestoreToken() couldn't connect");
    433             }
    434         }
    435         return 0;
    436     }
    437 
    438     /**
    439      * Ask the framework whether this app is eligible for backup.
    440      *
    441      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
    442      *
    443      * @param packageName The name of the package.
    444      * @return Whether this app is eligible for backup.
    445      *
    446      * @hide
    447      */
    448     @SystemApi
    449     public boolean isAppEligibleForBackup(String packageName) {
    450         checkServiceBinder();
    451         if (sService != null) {
    452             try {
    453                 return sService.isAppEligibleForBackup(packageName);
    454             } catch (RemoteException e) {
    455                 Log.e(TAG, "isAppEligibleForBackup(pkg) couldn't connect");
    456             }
    457         }
    458         return false;
    459     }
    460 
    461     /**
    462      * Request an immediate backup, providing an observer to which results of the backup operation
    463      * will be published. The Android backup system will decide for each package whether it will
    464      * be full app data backup or key/value-pair-based backup.
    465      *
    466      * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
    467      * provided packages using the remote transport.
    468      *
    469      * @param packages List of package names to backup.
    470      * @param observer The {@link BackupObserver} to receive callbacks during the backup
    471      * operation. Could be {@code null}.
    472      * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
    473      * @exception  IllegalArgumentException on null or empty {@code packages} param.
    474      *
    475      * @hide
    476      */
    477     @SystemApi
    478     public int requestBackup(String[] packages, BackupObserver observer) {
    479         checkServiceBinder();
    480         if (sService != null) {
    481             try {
    482                 BackupObserverWrapper observerWrapper = observer == null
    483                         ? null
    484                         : new BackupObserverWrapper(mContext, observer);
    485                 return sService.requestBackup(packages, observerWrapper);
    486             } catch (RemoteException e) {
    487                 Log.e(TAG, "requestBackup() couldn't connect");
    488             }
    489         }
    490         return -1;
    491     }
    492 
    493     /*
    494      * We wrap incoming binder calls with a private class implementation that
    495      * redirects them into main-thread actions.  This serializes the backup
    496      * progress callbacks nicely within the usual main-thread lifecycle pattern.
    497      */
    498     @SystemApi
    499     private class BackupObserverWrapper extends IBackupObserver.Stub {
    500         final Handler mHandler;
    501         final BackupObserver mObserver;
    502 
    503         static final int MSG_UPDATE = 1;
    504         static final int MSG_RESULT = 2;
    505         static final int MSG_FINISHED = 3;
    506 
    507         BackupObserverWrapper(Context context, BackupObserver observer) {
    508             mHandler = new Handler(context.getMainLooper()) {
    509                 @Override
    510                 public void handleMessage(Message msg) {
    511                     switch (msg.what) {
    512                         case MSG_UPDATE:
    513                             Pair<String, BackupProgress> obj =
    514                                 (Pair<String, BackupProgress>) msg.obj;
    515                             mObserver.onUpdate(obj.first, obj.second);
    516                             break;
    517                         case MSG_RESULT:
    518                             mObserver.onResult((String)msg.obj, msg.arg1);
    519                             break;
    520                         case MSG_FINISHED:
    521                             mObserver.backupFinished(msg.arg1);
    522                             break;
    523                         default:
    524                             Log.w(TAG, "Unknown message: " + msg);
    525                             break;
    526                     }
    527                 }
    528             };
    529             mObserver = observer;
    530         }
    531 
    532         // Binder calls into this object just enqueue on the main-thread handler
    533         @Override
    534         public void onUpdate(String currentPackage, BackupProgress backupProgress) {
    535             mHandler.sendMessage(
    536                 mHandler.obtainMessage(MSG_UPDATE, Pair.create(currentPackage, backupProgress)));
    537         }
    538 
    539         @Override
    540         public void onResult(String currentPackage, int status) {
    541             mHandler.sendMessage(
    542                 mHandler.obtainMessage(MSG_RESULT, status, 0, currentPackage));
    543         }
    544 
    545         @Override
    546         public void backupFinished(int status) {
    547             mHandler.sendMessage(
    548                 mHandler.obtainMessage(MSG_FINISHED, status, 0));
    549         }
    550     }
    551 }
    552