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"><application></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 checkServiceBinder()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 */ BackupManager(Context context)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 */ dataChanged()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 */ dataChanged(String packageName)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 requestRestore(RestoreObserver observer)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 requestRestore(RestoreObserver observer, BackupManagerMonitor monitor)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) beginRestoreSession()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) setBackupEnabled(boolean isEnabled)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) isBackupEnabled()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) isBackupServiceActive(UserHandle user)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) setAutoRestore(boolean isEnabled)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) getCurrentTransport()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) listAllTransports()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) updateTransportAttributes( ComponentName transportComponent, String name, @Nullable Intent configurationIntent, String currentDestinationString, @Nullable Intent dataManagementIntent, @Nullable String dataManagementLabel)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) selectBackupTransport(String transport)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) selectBackupTransport(ComponentName transport, SelectBackupTransportCallback listener)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) backupNow()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) getAvailableRestoreToken(String packageName)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) isAppEligibleForBackup(String packageName)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) requestBackup(String[] packages, BackupObserver observer)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) requestBackup(String[] packages, BackupObserver observer, BackupManagerMonitor monitor, int flags)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) cancelBackups()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) getConfigurationIntent(String transportName)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) getDestinationString(String transportName)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) getDataManagementIntent(String transportName)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) getDataManagementLabel(String transportName)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 BackupObserverWrapper(Context context, BackupObserver observer)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 onUpdate(String currentPackage, BackupProgress backupProgress)852 public void onUpdate(String currentPackage, BackupProgress backupProgress) { 853 mHandler.sendMessage( 854 mHandler.obtainMessage(MSG_UPDATE, Pair.create(currentPackage, backupProgress))); 855 } 856 857 @Override onResult(String currentPackage, int status)858 public void onResult(String currentPackage, int status) { 859 mHandler.sendMessage( 860 mHandler.obtainMessage(MSG_RESULT, status, 0, currentPackage)); 861 } 862 863 @Override backupFinished(int status)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 SelectTransportListenerWrapper(Context context, SelectBackupTransportCallback listener)875 SelectTransportListenerWrapper(Context context, SelectBackupTransportCallback listener) { 876 mHandler = new Handler(context.getMainLooper()); 877 mListener = listener; 878 } 879 880 @Override onSuccess(final String transportName)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 onFailure(final int reason)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 BackupManagerMonitorWrapper(BackupManagerMonitor monitor)904 BackupManagerMonitorWrapper(BackupManagerMonitor monitor) { 905 mMonitor = monitor; 906 } 907 908 @Override onEvent(final Bundle event)909 public void onEvent(final Bundle event) throws RemoteException { 910 mMonitor.onEvent(event); 911 } 912 } 913 914 } 915