• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     /**
132      * Intent extra when any subsidiary backup-related UI is launched from Settings:  does
133      * device policy or configuration permit backup operations to run at all?
134      *
135      * @hide
136      */
137     public static final String EXTRA_BACKUP_SERVICES_AVAILABLE = "backup_services_available";
138 
139     private Context mContext;
140     private static IBackupManager sService;
141 
checkServiceBinder()142     private static void checkServiceBinder() {
143         if (sService == null) {
144             sService = IBackupManager.Stub.asInterface(
145                     ServiceManager.getService(Context.BACKUP_SERVICE));
146         }
147     }
148 
149     /**
150      * Constructs a BackupManager object through which the application can
151      * communicate with the Android backup system.
152      *
153      * @param context The {@link android.content.Context} that was provided when
154      *                one of your application's {@link android.app.Activity Activities}
155      *                was created.
156      */
BackupManager(Context context)157     public BackupManager(Context context) {
158         mContext = context;
159     }
160 
161     /**
162      * Notifies the Android backup system that your application wishes to back up
163      * new changes to its data.  A backup operation using your application's
164      * {@link android.app.backup.BackupAgent} subclass will be scheduled when you
165      * call this method.
166      */
dataChanged()167     public void dataChanged() {
168         checkServiceBinder();
169         if (sService != null) {
170             try {
171                 sService.dataChanged(mContext.getPackageName());
172             } catch (RemoteException e) {
173                 Log.d(TAG, "dataChanged() couldn't connect");
174             }
175         }
176     }
177 
178     /**
179      * Convenience method for callers who need to indicate that some other package
180      * needs a backup pass.  This can be useful in the case of groups of packages
181      * that share a uid.
182      * <p>
183      * This method requires that the application hold the "android.permission.BACKUP"
184      * permission if the package named in the argument does not run under the same uid
185      * as the caller.
186      *
187      * @param packageName The package name identifying the application to back up.
188      */
dataChanged(String packageName)189     public static void dataChanged(String packageName) {
190         checkServiceBinder();
191         if (sService != null) {
192             try {
193                 sService.dataChanged(packageName);
194             } catch (RemoteException e) {
195                 Log.e(TAG, "dataChanged(pkg) couldn't connect");
196             }
197         }
198     }
199 
200     /**
201      * Restore the calling application from backup.  The data will be restored from the
202      * current backup dataset if the application has stored data there, or from
203      * the dataset used during the last full device setup operation if the current
204      * backup dataset has no matching data.  If no backup data exists for this application
205      * in either source, a nonzero value will be returned.
206      *
207      * <p>If this method returns zero (meaning success), the OS will attempt to retrieve
208      * a backed-up dataset from the remote transport, instantiate the application's
209      * backup agent, and pass the dataset to the agent's
210      * {@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
211      * method.
212      *
213      * @param observer The {@link RestoreObserver} to receive callbacks during the restore
214      * operation. This must not be null.
215      *
216      * @return Zero on success; nonzero on error.
217      */
requestRestore(RestoreObserver observer)218     public int requestRestore(RestoreObserver observer) {
219         int result = -1;
220         checkServiceBinder();
221         if (sService != null) {
222             RestoreSession session = null;
223             try {
224                 IRestoreSession binder = sService.beginRestoreSession(mContext.getPackageName(),
225                         null);
226                 if (binder != null) {
227                     session = new RestoreSession(mContext, binder);
228                     result = session.restorePackage(mContext.getPackageName(), observer);
229                 }
230             } catch (RemoteException e) {
231                 Log.e(TAG, "restoreSelf() unable to contact service");
232             } finally {
233                 if (session != null) {
234                     session.endRestoreSession();
235                 }
236             }
237         }
238         return result;
239     }
240 
241     // system APIs start here
242 
243     /**
244      * Begin the process of restoring data from backup.  See the
245      * {@link android.app.backup.RestoreSession} class for documentation on that process.
246      * @hide
247      */
248     @SystemApi
beginRestoreSession()249     public RestoreSession beginRestoreSession() {
250         RestoreSession session = null;
251         checkServiceBinder();
252         if (sService != null) {
253             try {
254                 // All packages, current transport
255                 IRestoreSession binder = sService.beginRestoreSession(null, null);
256                 if (binder != null) {
257                     session = new RestoreSession(mContext, binder);
258                 }
259             } catch (RemoteException e) {
260                 Log.e(TAG, "beginRestoreSession() couldn't connect");
261             }
262         }
263         return session;
264     }
265 
266     /**
267      * Enable/disable the backup service entirely.  When disabled, no backup
268      * or restore operations will take place.  Data-changed notifications will
269      * still be observed and collected, however, so that changes made while the
270      * mechanism was disabled will still be backed up properly if it is enabled
271      * at some point in the future.
272      *
273      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
274      *
275      * @hide
276      */
277     @SystemApi
setBackupEnabled(boolean isEnabled)278     public void setBackupEnabled(boolean isEnabled) {
279         checkServiceBinder();
280         if (sService != null) {
281             try {
282                 sService.setBackupEnabled(isEnabled);
283             } catch (RemoteException e) {
284                 Log.e(TAG, "setBackupEnabled() couldn't connect");
285             }
286         }
287     }
288 
289     /**
290      * Report whether the backup mechanism is currently enabled.
291      *
292      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
293      *
294      * @hide
295      */
296     @SystemApi
isBackupEnabled()297     public boolean isBackupEnabled() {
298         checkServiceBinder();
299         if (sService != null) {
300             try {
301                 return sService.isBackupEnabled();
302             } catch (RemoteException e) {
303                 Log.e(TAG, "isBackupEnabled() couldn't connect");
304             }
305         }
306         return false;
307     }
308 
309     /**
310      * Enable/disable data restore at application install time.  When enabled, app
311      * installation will include an attempt to fetch the app's historical data from
312      * the archival restore dataset (if any).  When disabled, no such attempt will
313      * be made.
314      *
315      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
316      *
317      * @hide
318      */
319     @SystemApi
setAutoRestore(boolean isEnabled)320     public void setAutoRestore(boolean isEnabled) {
321         checkServiceBinder();
322         if (sService != null) {
323             try {
324                 sService.setAutoRestore(isEnabled);
325             } catch (RemoteException e) {
326                 Log.e(TAG, "setAutoRestore() couldn't connect");
327             }
328         }
329     }
330 
331     /**
332      * Identify the currently selected transport.  Callers must hold the
333      * android.permission.BACKUP permission to use this method.
334      * @return The name of the currently active backup transport.  In case of
335      *   failure or if no transport is currently active, this method returns {@code null}.
336      *
337      * @hide
338      */
339     @SystemApi
getCurrentTransport()340     public String getCurrentTransport() {
341         checkServiceBinder();
342         if (sService != null) {
343             try {
344                 return sService.getCurrentTransport();
345             } catch (RemoteException e) {
346                 Log.e(TAG, "getCurrentTransport() couldn't connect");
347             }
348         }
349         return null;
350     }
351 
352     /**
353      * Request a list of all available backup transports' names.  Callers must
354      * hold the android.permission.BACKUP permission to use this method.
355      *
356      * @hide
357      */
358     @SystemApi
listAllTransports()359     public String[] listAllTransports() {
360         checkServiceBinder();
361         if (sService != null) {
362             try {
363                 return sService.listAllTransports();
364             } catch (RemoteException e) {
365                 Log.e(TAG, "listAllTransports() couldn't connect");
366             }
367         }
368         return null;
369     }
370 
371     /**
372      * Specify the current backup transport.  Callers must hold the
373      * android.permission.BACKUP permission to use this method.
374      *
375      * @param transport The name of the transport to select.  This should be one
376      *   of the names returned by {@link #listAllTransports()}.
377      * @return The name of the previously selected transport.  If the given transport
378      *   name is not one of the currently available transports, no change is made to
379      *   the current transport setting and the method returns null.
380      *
381      * @hide
382      */
383     @SystemApi
selectBackupTransport(String transport)384     public String selectBackupTransport(String transport) {
385         checkServiceBinder();
386         if (sService != null) {
387             try {
388                 return sService.selectBackupTransport(transport);
389             } catch (RemoteException e) {
390                 Log.e(TAG, "selectBackupTransport() couldn't connect");
391             }
392         }
393         return null;
394     }
395 
396     /**
397      * Schedule an immediate backup attempt for all pending key/value updates.  This
398      * is primarily intended for transports to use when they detect a suitable
399      * opportunity for doing a backup pass.  If there are no pending updates to
400      * be sent, no action will be taken.  Even if some updates are pending, the
401      * transport will still be asked to confirm via the usual requestBackupTime()
402      * method.
403      *
404      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
405      *
406      * @hide
407      */
408     @SystemApi
backupNow()409     public void backupNow() {
410         checkServiceBinder();
411         if (sService != null) {
412             try {
413                 sService.backupNow();
414             } catch (RemoteException e) {
415                 Log.e(TAG, "backupNow() couldn't connect");
416             }
417         }
418     }
419 
420     /**
421      * Ask the framework which dataset, if any, the given package's data would be
422      * restored from if we were to install it right now.
423      *
424      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
425      *
426      * @param packageName The name of the package whose most-suitable dataset we
427      *     wish to look up
428      * @return The dataset token from which a restore should be attempted, or zero if
429      *     no suitable data is available.
430      *
431      * @hide
432      */
433     @SystemApi
getAvailableRestoreToken(String packageName)434     public long getAvailableRestoreToken(String packageName) {
435         checkServiceBinder();
436         if (sService != null) {
437             try {
438                 return sService.getAvailableRestoreToken(packageName);
439             } catch (RemoteException e) {
440                 Log.e(TAG, "getAvailableRestoreToken() couldn't connect");
441             }
442         }
443         return 0;
444     }
445 
446     /**
447      * Ask the framework whether this app is eligible for backup.
448      *
449      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
450      *
451      * @param packageName The name of the package.
452      * @return Whether this app is eligible for backup.
453      *
454      * @hide
455      */
456     @SystemApi
isAppEligibleForBackup(String packageName)457     public boolean isAppEligibleForBackup(String packageName) {
458         checkServiceBinder();
459         if (sService != null) {
460             try {
461                 return sService.isAppEligibleForBackup(packageName);
462             } catch (RemoteException e) {
463                 Log.e(TAG, "isAppEligibleForBackup(pkg) couldn't connect");
464             }
465         }
466         return false;
467     }
468 
469     /**
470      * Request an immediate backup, providing an observer to which results of the backup operation
471      * will be published. The Android backup system will decide for each package whether it will
472      * be full app data backup or key/value-pair-based backup.
473      *
474      * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
475      * provided packages using the remote transport.
476      *
477      * @param packages List of package names to backup.
478      * @param observer The {@link BackupObserver} to receive callbacks during the backup
479      * operation. Could be {@code null}.
480      * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
481      * @exception  IllegalArgumentException on null or empty {@code packages} param.
482      *
483      * @hide
484      */
485     @SystemApi
requestBackup(String[] packages, BackupObserver observer)486     public int requestBackup(String[] packages, BackupObserver observer) {
487         checkServiceBinder();
488         if (sService != null) {
489             try {
490                 BackupObserverWrapper observerWrapper = observer == null
491                         ? null
492                         : new BackupObserverWrapper(mContext, observer);
493                 return sService.requestBackup(packages, observerWrapper);
494             } catch (RemoteException e) {
495                 Log.e(TAG, "requestBackup() couldn't connect");
496             }
497         }
498         return -1;
499     }
500 
501     /*
502      * We wrap incoming binder calls with a private class implementation that
503      * redirects them into main-thread actions.  This serializes the backup
504      * progress callbacks nicely within the usual main-thread lifecycle pattern.
505      */
506     @SystemApi
507     private class BackupObserverWrapper extends IBackupObserver.Stub {
508         final Handler mHandler;
509         final BackupObserver mObserver;
510 
511         static final int MSG_UPDATE = 1;
512         static final int MSG_RESULT = 2;
513         static final int MSG_FINISHED = 3;
514 
BackupObserverWrapper(Context context, BackupObserver observer)515         BackupObserverWrapper(Context context, BackupObserver observer) {
516             mHandler = new Handler(context.getMainLooper()) {
517                 @Override
518                 public void handleMessage(Message msg) {
519                     switch (msg.what) {
520                         case MSG_UPDATE:
521                             Pair<String, BackupProgress> obj =
522                                 (Pair<String, BackupProgress>) msg.obj;
523                             mObserver.onUpdate(obj.first, obj.second);
524                             break;
525                         case MSG_RESULT:
526                             mObserver.onResult((String)msg.obj, msg.arg1);
527                             break;
528                         case MSG_FINISHED:
529                             mObserver.backupFinished(msg.arg1);
530                             break;
531                         default:
532                             Log.w(TAG, "Unknown message: " + msg);
533                             break;
534                     }
535                 }
536             };
537             mObserver = observer;
538         }
539 
540         // Binder calls into this object just enqueue on the main-thread handler
541         @Override
onUpdate(String currentPackage, BackupProgress backupProgress)542         public void onUpdate(String currentPackage, BackupProgress backupProgress) {
543             mHandler.sendMessage(
544                 mHandler.obtainMessage(MSG_UPDATE, Pair.create(currentPackage, backupProgress)));
545         }
546 
547         @Override
onResult(String currentPackage, int status)548         public void onResult(String currentPackage, int status) {
549             mHandler.sendMessage(
550                 mHandler.obtainMessage(MSG_RESULT, status, 0, currentPackage));
551         }
552 
553         @Override
backupFinished(int status)554         public void backupFinished(int status) {
555             mHandler.sendMessage(
556                 mHandler.obtainMessage(MSG_FINISHED, status, 0));
557         }
558     }
559 }
560