1 /* 2 * Copyright (C) 2014 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.SystemApi; 21 import android.content.Intent; 22 import android.content.pm.PackageInfo; 23 import android.os.IBinder; 24 import android.os.ParcelFileDescriptor; 25 import android.os.RemoteException; 26 27 import com.android.internal.backup.IBackupTransport; 28 import com.android.internal.backup.ITransportStatusCallback; 29 import com.android.internal.infra.AndroidFuture; 30 31 import java.util.Arrays; 32 import java.util.List; 33 34 /** 35 * Concrete class that provides a stable-API bridge between IBackupTransport 36 * and its implementations. 37 * 38 * @hide 39 */ 40 @SystemApi 41 public class BackupTransport { 42 // Zero return always means things are okay. If returned from 43 // getNextFullRestoreDataChunk(), it means that no data could be delivered at 44 // this time, but the restore is still running and the caller should simply 45 // retry. 46 public static final int TRANSPORT_OK = 0; 47 48 // -1 is special; it is used in getNextFullRestoreDataChunk() to indicate that 49 // we've delivered the entire data stream for the current restore target. 50 public static final int NO_MORE_DATA = -1; 51 52 // Result codes that indicate real errors are negative and not -1 53 public static final int TRANSPORT_ERROR = -1000; 54 public static final int TRANSPORT_NOT_INITIALIZED = -1001; 55 public static final int TRANSPORT_PACKAGE_REJECTED = -1002; 56 public static final int AGENT_ERROR = -1003; 57 public static final int AGENT_UNKNOWN = -1004; 58 public static final int TRANSPORT_QUOTA_EXCEEDED = -1005; 59 60 /** 61 * Indicates that the transport cannot accept a diff backup for this package. 62 * 63 * <p>Backup manager should clear its state for this package and immediately retry a 64 * non-incremental backup. This might be used if the transport no longer has data for this 65 * package in its backing store. 66 * 67 * <p>This is only valid when backup manager called {@link 68 * #performBackup(PackageInfo, ParcelFileDescriptor, int)} with {@link #FLAG_INCREMENTAL}. 69 */ 70 public static final int TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED = -1006; 71 72 // Indicates that operation was initiated by user, not a scheduled one. 73 // Transport should ignore its own moratoriums for call with this flag set. 74 public static final int FLAG_USER_INITIATED = 1; 75 76 /** 77 * For key value backup, indicates that the backup data is a diff from a previous backup. The 78 * transport must apply this diff to an existing backup to build the new backup set. 79 * 80 * @see #performBackup(PackageInfo, ParcelFileDescriptor, int) 81 */ 82 public static final int FLAG_INCREMENTAL = 1 << 1; 83 84 /** 85 * For key value backup, indicates that the backup data is a complete set, not a diff from a 86 * previous backup. The transport should clear any previous backup when storing this backup. 87 * 88 * @see #performBackup(PackageInfo, ParcelFileDescriptor, int) 89 */ 90 public static final int FLAG_NON_INCREMENTAL = 1 << 2; 91 92 /** 93 * For key value backup, indicates that the backup contains no new data since the last backup 94 * attempt completed without any errors. The transport should use this to record that 95 * a successful backup attempt has been completed but no backup data has been changed. 96 * 97 * @see #performBackup(PackageInfo, ParcelFileDescriptor, int) 98 */ 99 public static final int FLAG_DATA_NOT_CHANGED = 1 << 3; 100 101 /** 102 * Used as a boolean extra in the binding intent of transports. We pass {@code true} to 103 * notify transports that the current connection is used for registering the transport. 104 */ 105 public static final String EXTRA_TRANSPORT_REGISTRATION = 106 "android.app.backup.extra.TRANSPORT_REGISTRATION"; 107 108 IBackupTransport mBinderImpl = new TransportImpl(); 109 getBinder()110 public IBinder getBinder() { 111 return mBinderImpl.asBinder(); 112 } 113 114 // ------------------------------------------------------------------------------------ 115 // Transport self-description and general configuration interfaces 116 // 117 118 /** 119 * Ask the transport for the name under which it should be registered. This will 120 * typically be its host service's component name, but need not be. 121 */ name()122 public String name() { 123 throw new UnsupportedOperationException("Transport name() not implemented"); 124 } 125 126 /** 127 * Ask the transport for an Intent that can be used to launch any internal 128 * configuration Activity that it wishes to present. For example, the transport 129 * may offer a UI for allowing the user to supply login credentials for the 130 * transport's off-device backend. 131 * 132 * <p>If the transport does not supply any user-facing configuration UI, it should 133 * return {@code null} from this method. 134 * 135 * @return An Intent that can be passed to Context.startActivity() in order to 136 * launch the transport's configuration UI. This method will return {@code null} 137 * if the transport does not offer any user-facing configuration UI. 138 */ configurationIntent()139 public Intent configurationIntent() { 140 return null; 141 } 142 143 /** 144 * On demand, supply a one-line string that can be shown to the user that 145 * describes the current backend destination. For example, a transport that 146 * can potentially associate backup data with arbitrary user accounts should 147 * include the name of the currently-active account here. 148 * 149 * @return A string describing the destination to which the transport is currently 150 * sending data. This method should not return null. 151 */ currentDestinationString()152 public String currentDestinationString() { 153 throw new UnsupportedOperationException( 154 "Transport currentDestinationString() not implemented"); 155 } 156 157 /** 158 * Ask the transport for an Intent that can be used to launch a more detailed 159 * secondary data management activity. For example, the configuration intent might 160 * be one for allowing the user to select which account they wish to associate 161 * their backups with, and the management intent might be one which presents a 162 * UI for managing the data on the backend. 163 * 164 * <p>In the Settings UI, the configuration intent will typically be invoked 165 * when the user taps on the preferences item labeled with the current 166 * destination string, and the management intent will be placed in an overflow 167 * menu labelled with the management label string. 168 * 169 * <p>If the transport does not supply any user-facing data management 170 * UI, then it should return {@code null} from this method. 171 * 172 * @return An intent that can be passed to Context.startActivity() in order to 173 * launch the transport's data-management UI. This method will return 174 * {@code null} if the transport does not offer any user-facing data 175 * management UI. 176 */ dataManagementIntent()177 public Intent dataManagementIntent() { 178 return null; 179 } 180 181 /** 182 * On demand, supply a short string that can be shown to the user as the label on an overflow 183 * menu item used to invoke the data management UI. 184 * 185 * @return A string to be used as the label for the transport's data management affordance. If 186 * the transport supplies a data management intent, this method must not return {@code 187 * null}. 188 * @deprecated Since Android Q, please use the variant {@link #dataManagementIntentLabel()} 189 * instead. 190 */ 191 @Deprecated 192 @Nullable dataManagementLabel()193 public String dataManagementLabel() { 194 throw new UnsupportedOperationException( 195 "Transport dataManagementLabel() not implemented"); 196 } 197 198 /** 199 * On demand, supply a short CharSequence that can be shown to the user as the label on an 200 * overflow menu item used to invoke the data management UI. 201 * 202 * @return A CharSequence to be used as the label for the transport's data management 203 * affordance. If the transport supplies a data management intent, this method must not 204 * return {@code null}. 205 */ 206 @Nullable dataManagementIntentLabel()207 public CharSequence dataManagementIntentLabel() { 208 return dataManagementLabel(); 209 } 210 211 /** 212 * Ask the transport where, on local device storage, to keep backup state blobs. 213 * This is per-transport so that mock transports used for testing can coexist with 214 * "live" backup services without interfering with the live bookkeeping. The 215 * returned string should be a name that is expected to be unambiguous among all 216 * available backup transports; the name of the class implementing the transport 217 * is a good choice. 218 * 219 * @return A unique name, suitable for use as a file or directory name, that the 220 * Backup Manager could use to disambiguate state files associated with 221 * different backup transports. 222 */ transportDirName()223 public String transportDirName() { 224 throw new UnsupportedOperationException( 225 "Transport transportDirName() not implemented"); 226 } 227 228 // ------------------------------------------------------------------------------------ 229 // Device-level operations common to both key/value and full-data storage 230 231 /** 232 * Initialize the server side storage for this device, erasing all stored data. 233 * The transport may send the request immediately, or may buffer it. After 234 * this is called, {@link #finishBackup} will be called to ensure the request 235 * is sent and received successfully. 236 * 237 * <p>If the transport returns anything other than TRANSPORT_OK from this method, 238 * the OS will halt the current initialize operation and schedule a retry in the 239 * near future. Even if the transport is in a state such that attempting to 240 * "initialize" the backend storage is meaningless -- for example, if there is 241 * no current live dataset at all, or there is no authenticated account under which 242 * to store the data remotely -- the transport should return TRANSPORT_OK here 243 * and treat the initializeDevice() / finishBackup() pair as a graceful no-op. 244 * 245 * @return One of {@link BackupTransport#TRANSPORT_OK} (OK so far) or 246 * {@link BackupTransport#TRANSPORT_ERROR} (to retry following network error 247 * or other failure). 248 */ initializeDevice()249 public int initializeDevice() { 250 return BackupTransport.TRANSPORT_ERROR; 251 } 252 253 /** 254 * Erase the given application's data from the backup destination. This clears 255 * out the given package's data from the current backup set, making it as though 256 * the app had never yet been backed up. After this is called, {@link finishBackup} 257 * must be called to ensure that the operation is recorded successfully. 258 * 259 * @return the same error codes as {@link #performBackup}. 260 */ clearBackupData(PackageInfo packageInfo)261 public int clearBackupData(PackageInfo packageInfo) { 262 return BackupTransport.TRANSPORT_ERROR; 263 } 264 265 /** 266 * Finish sending application data to the backup destination. This must be 267 * called after {@link #performBackup}, {@link #performFullBackup}, or {@link clearBackupData} 268 * to ensure that all data is sent and the operation properly finalized. Only when this 269 * method returns true can a backup be assumed to have succeeded. 270 * 271 * @return the same error codes as {@link #performBackup} or {@link #performFullBackup}. 272 */ finishBackup()273 public int finishBackup() { 274 return BackupTransport.TRANSPORT_ERROR; 275 } 276 277 // ------------------------------------------------------------------------------------ 278 // Key/value incremental backup support interfaces 279 280 /** 281 * Verify that this is a suitable time for a key/value backup pass. This should return zero 282 * if a backup is reasonable right now, some positive value otherwise. This method 283 * will be called outside of the {@link #performBackup}/{@link #finishBackup} pair. 284 * 285 * <p>If this is not a suitable time for a backup, the transport should return a 286 * backoff delay, in milliseconds, after which the Backup Manager should try again. 287 * 288 * @return Zero if this is a suitable time for a backup pass, or a positive time delay 289 * in milliseconds to suggest deferring the backup pass for a while. 290 */ requestBackupTime()291 public long requestBackupTime() { 292 return 0; 293 } 294 295 /** 296 * Send one application's key/value data update to the backup destination. The 297 * transport may send the data immediately, or may buffer it. If this method returns 298 * {@link #TRANSPORT_OK}, {@link #finishBackup} will then be called to ensure the data 299 * is sent and recorded successfully. 300 * 301 * If the backup data is a diff against the previous backup then the flag {@link 302 * BackupTransport#FLAG_INCREMENTAL} will be set. Otherwise, if the data is a complete backup 303 * set then {@link BackupTransport#FLAG_NON_INCREMENTAL} will be set. Before P neither flag will 304 * be set regardless of whether the backup is incremental or not. 305 * 306 * <p>If {@link BackupTransport#FLAG_INCREMENTAL} is set and the transport does not have data 307 * for this package in its storage backend then it cannot apply the incremental diff. Thus it 308 * should return {@link BackupTransport#TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED} to indicate 309 * that backup manager should delete its state and retry the package as a non-incremental 310 * backup. Before P, or if this is a non-incremental backup, then this return code is equivalent 311 * to {@link BackupTransport#TRANSPORT_ERROR}. 312 * 313 * @param packageInfo The identity of the application whose data is being backed up. 314 * This specifically includes the signature list for the package. 315 * @param inFd Descriptor of file with data that resulted from invoking the application's 316 * BackupService.doBackup() method. This may be a pipe rather than a file on 317 * persistent media, so it may not be seekable. 318 * @param flags a combination of {@link BackupTransport#FLAG_USER_INITIATED}, {@link 319 * BackupTransport#FLAG_NON_INCREMENTAL}, {@link BackupTransport#FLAG_INCREMENTAL}, 320 * {@link BackupTransport#FLAG_DATA_NOT_CHANGED},or 0. 321 * @return one of {@link BackupTransport#TRANSPORT_OK} (OK so far), 322 * {@link BackupTransport#TRANSPORT_PACKAGE_REJECTED} (to suppress backup of this 323 * specific package, but allow others to proceed), 324 * {@link BackupTransport#TRANSPORT_ERROR} (on network error or other failure), {@link 325 * BackupTransport#TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED} (if the transport cannot accept 326 * an incremental backup for this package), or {@link 327 * BackupTransport#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has become lost due to 328 * inactivity purge or some other reason and needs re-initializing) 329 */ performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags)330 public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags) { 331 return performBackup(packageInfo, inFd); 332 } 333 334 /** 335 * Legacy version of {@link #performBackup(PackageInfo, ParcelFileDescriptor, int)} that 336 * doesn't use flags parameter. 337 */ performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd)338 public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd) { 339 return BackupTransport.TRANSPORT_ERROR; 340 } 341 342 // ------------------------------------------------------------------------------------ 343 // Key/value dataset restore interfaces 344 345 /** 346 * Get the set of all backups currently available over this transport. 347 * 348 * @return Descriptions of the set of restore images available for this device, 349 * or null if an error occurred (the attempt should be rescheduled). 350 **/ getAvailableRestoreSets()351 public RestoreSet[] getAvailableRestoreSets() { 352 return null; 353 } 354 355 /** 356 * Get the identifying token of the backup set currently being stored from 357 * this device. This is used in the case of applications wishing to restore 358 * their last-known-good data. 359 * 360 * @return A token that can be passed to {@link #startRestore}, or 0 if there 361 * is no backup set available corresponding to the current device state. 362 */ getCurrentRestoreSet()363 public long getCurrentRestoreSet() { 364 return 0; 365 } 366 367 /** 368 * Start restoring application data from backup. After calling this function, 369 * alternate calls to {@link #nextRestorePackage} and {@link #nextRestoreData} 370 * to walk through the actual application data. 371 * 372 * @param token A backup token as returned by {@link #getAvailableRestoreSets} 373 * or {@link #getCurrentRestoreSet}. 374 * @param packages List of applications to restore (if data is available). 375 * Application data will be restored in the order given. 376 * @return One of {@link BackupTransport#TRANSPORT_OK} (OK so far, call 377 * {@link #nextRestorePackage}) or {@link BackupTransport#TRANSPORT_ERROR} 378 * (an error occurred, the restore should be aborted and rescheduled). 379 */ startRestore(long token, PackageInfo[] packages)380 public int startRestore(long token, PackageInfo[] packages) { 381 return BackupTransport.TRANSPORT_ERROR; 382 } 383 384 /** 385 * Get the package name of the next application with data in the backup store, plus 386 * a description of the structure of the restored archive: either TYPE_KEY_VALUE for 387 * an original-API key/value dataset, or TYPE_FULL_STREAM for a tarball-type archive stream. 388 * 389 * <p>If the package name in the returned RestoreDescription object is the singleton 390 * {@link RestoreDescription#NO_MORE_PACKAGES}, it indicates that no further data is available 391 * in the current restore session: all packages described in startRestore() have been 392 * processed. 393 * 394 * <p>If this method returns {@code null}, it means that a transport-level error has 395 * occurred and the entire restore operation should be abandoned. 396 * 397 * <p class="note">The OS may call {@link #nextRestorePackage()} multiple times 398 * before calling either {@link #getRestoreData(ParcelFileDescriptor) getRestoreData()} 399 * or {@link #getNextFullRestoreDataChunk(ParcelFileDescriptor) getNextFullRestoreDataChunk()}. 400 * It does this when it has determined that it needs to skip restore of one or more 401 * packages. The transport should not actually transfer any restore data for 402 * the given package in response to {@link #nextRestorePackage()}, but rather wait 403 * for an explicit request before doing so. 404 * 405 * @return A RestoreDescription object containing the name of one of the packages 406 * supplied to {@link #startRestore} plus an indicator of the data type of that 407 * restore data; or {@link RestoreDescription#NO_MORE_PACKAGES} to indicate that 408 * no more packages can be restored in this session; or {@code null} to indicate 409 * a transport-level error. 410 */ nextRestorePackage()411 public RestoreDescription nextRestorePackage() { 412 return null; 413 } 414 415 /** 416 * Get the data for the application returned by {@link #nextRestorePackage}, if that 417 * method reported {@link RestoreDescription#TYPE_KEY_VALUE} as its delivery type. 418 * If the package has only TYPE_FULL_STREAM data, then this method will return an 419 * error. 420 * 421 * @param data An open, writable file into which the key/value backup data should be stored. 422 * @return the same error codes as {@link #startRestore}. 423 */ getRestoreData(ParcelFileDescriptor outFd)424 public int getRestoreData(ParcelFileDescriptor outFd) { 425 return BackupTransport.TRANSPORT_ERROR; 426 } 427 428 /** 429 * End a restore session (aborting any in-process data transfer as necessary), 430 * freeing any resources and connections used during the restore process. 431 */ finishRestore()432 public void finishRestore() { 433 throw new UnsupportedOperationException( 434 "Transport finishRestore() not implemented"); 435 } 436 437 // ------------------------------------------------------------------------------------ 438 // Full backup interfaces 439 440 /** 441 * Verify that this is a suitable time for a full-data backup pass. This should return zero 442 * if a backup is reasonable right now, some positive value otherwise. This method 443 * will be called outside of the {@link #performFullBackup}/{@link #finishBackup} pair. 444 * 445 * <p>If this is not a suitable time for a backup, the transport should return a 446 * backoff delay, in milliseconds, after which the Backup Manager should try again. 447 * 448 * @return Zero if this is a suitable time for a backup pass, or a positive time delay 449 * in milliseconds to suggest deferring the backup pass for a while. 450 * 451 * @see #requestBackupTime() 452 */ requestFullBackupTime()453 public long requestFullBackupTime() { 454 return 0; 455 } 456 457 /** 458 * Begin the process of sending an application's full-data archive to the backend. 459 * The description of the package whose data will be delivered is provided, as well as 460 * the socket file descriptor on which the transport will receive the data itself. 461 * 462 * <p>If the package is not eligible for backup, the transport should return 463 * {@link BackupTransport#TRANSPORT_PACKAGE_REJECTED}. In this case the system will 464 * simply proceed with the next candidate if any, or finish the full backup operation 465 * if all apps have been processed. 466 * 467 * <p>After the transport returns {@link BackupTransport#TRANSPORT_OK} from this 468 * method, the OS will proceed to call {@link #sendBackupData()} one or more times 469 * to deliver the application's data as a streamed tarball. The transport should not 470 * read() from the socket except as instructed to via the {@link #sendBackupData(int)} 471 * method. 472 * 473 * <p>After all data has been delivered to the transport, the system will call 474 * {@link #finishBackup()}. At this point the transport should commit the data to 475 * its datastore, if appropriate, and close the socket that had been provided in 476 * {@link #performFullBackup(PackageInfo, ParcelFileDescriptor)}. 477 * 478 * <p class="note">If the transport returns TRANSPORT_OK from this method, then the 479 * OS will always provide a matching call to {@link #finishBackup()} even if sending 480 * data via {@link #sendBackupData(int)} failed at some point. 481 * 482 * @param targetPackage The package whose data is to follow. 483 * @param socket The socket file descriptor through which the data will be provided. 484 * If the transport returns {@link #TRANSPORT_PACKAGE_REJECTED} here, it must still 485 * close this file descriptor now; otherwise it should be cached for use during 486 * succeeding calls to {@link #sendBackupData(int)}, and closed in response to 487 * {@link #finishBackup()}. 488 * @param flags {@link BackupTransport#FLAG_USER_INITIATED} or 0. 489 * @return TRANSPORT_PACKAGE_REJECTED to indicate that the stated application is not 490 * to be backed up; TRANSPORT_OK to indicate that the OS may proceed with delivering 491 * backup data; TRANSPORT_ERROR to indicate a fatal error condition that precludes 492 * performing a backup at this time. 493 */ performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket, int flags)494 public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket, 495 int flags) { 496 return performFullBackup(targetPackage, socket); 497 } 498 499 /** 500 * Legacy version of {@link #performFullBackup(PackageInfo, ParcelFileDescriptor, int)} that 501 * doesn't use flags parameter. 502 */ performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket)503 public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) { 504 return BackupTransport.TRANSPORT_PACKAGE_REJECTED; 505 } 506 507 /** 508 * Called after {@link #performFullBackup} to make sure that the transport is willing to 509 * handle a full-data backup operation of the specified size on the current package. 510 * If the transport returns anything other than TRANSPORT_OK, the package's backup 511 * operation will be skipped (and {@link #finishBackup() invoked} with no data for that 512 * package being passed to {@link #sendBackupData}. 513 * 514 * <p class="note">The platform does no size-based rejection of full backup attempts on 515 * its own: it is always the responsibility of the transport to implement its own policy. 516 * In particular, even if the preflighted payload size is zero, the platform will still call 517 * this method and will proceed to back up an archive metadata header with no file content 518 * if this method returns TRANSPORT_OK. To avoid storing such payloads the transport 519 * must recognize this case and return TRANSPORT_PACKAGE_REJECTED. 520 * 521 * Added in {@link android.os.Build.VERSION_CODES#M}. 522 * 523 * @param size The estimated size of the full-data payload for this app. This includes 524 * manifest and archive format overhead, but is not guaranteed to be precise. 525 * @return TRANSPORT_OK if the platform is to proceed with the full-data backup, 526 * TRANSPORT_PACKAGE_REJECTED if the proposed payload size is too large for 527 * the transport to handle, or TRANSPORT_ERROR to indicate a fatal error 528 * condition that means the platform cannot perform a backup at this time. 529 */ checkFullBackupSize(long size)530 public int checkFullBackupSize(long size) { 531 return BackupTransport.TRANSPORT_OK; 532 } 533 534 /** 535 * Tells the transport to read {@code numBytes} bytes of data from the socket file 536 * descriptor provided in the {@link #performFullBackup(PackageInfo, ParcelFileDescriptor)} 537 * call, and deliver those bytes to the datastore. 538 * 539 * @param numBytes The number of bytes of tarball data available to be read from the 540 * socket. 541 * @return TRANSPORT_OK on successful processing of the data; TRANSPORT_ERROR to 542 * indicate a fatal error situation. If an error is returned, the system will 543 * call finishBackup() and stop attempting backups until after a backoff and retry 544 * interval. 545 */ sendBackupData(int numBytes)546 public int sendBackupData(int numBytes) { 547 return BackupTransport.TRANSPORT_ERROR; 548 } 549 550 /** 551 * Tells the transport to cancel the currently-ongoing full backup operation. This 552 * will happen between {@link #performFullBackup()} and {@link #finishBackup()} 553 * if the OS needs to abort the backup operation for any reason, such as a crash in 554 * the application undergoing backup. 555 * 556 * <p>When it receives this call, the transport should discard any partial archive 557 * that it has stored so far. If possible it should also roll back to the previous 558 * known-good archive in its datastore. 559 * 560 * <p>If the transport receives this callback, it will <em>not</em> receive a 561 * call to {@link #finishBackup()}. It needs to tear down any ongoing backup state 562 * here. 563 */ cancelFullBackup()564 public void cancelFullBackup() { 565 throw new UnsupportedOperationException( 566 "Transport cancelFullBackup() not implemented"); 567 } 568 569 /** 570 * Ask the transport whether this app is eligible for backup. 571 * 572 * @param targetPackage The identity of the application. 573 * @param isFullBackup If set, transport should check if app is eligible for full data backup, 574 * otherwise to check if eligible for key-value backup. 575 * @return Whether this app is eligible for backup. 576 */ isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup)577 public boolean isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup) { 578 return true; 579 } 580 581 /** 582 * Ask the transport about current quota for backup size of the package. 583 * 584 * @param packageName ID of package to provide the quota. 585 * @param isFullBackup If set, transport should return limit for full data backup, otherwise 586 * for key-value backup. 587 * @return Current limit on backup size in bytes. 588 */ getBackupQuota(String packageName, boolean isFullBackup)589 public long getBackupQuota(String packageName, boolean isFullBackup) { 590 return Long.MAX_VALUE; 591 } 592 593 // ------------------------------------------------------------------------------------ 594 // Full restore interfaces 595 596 /** 597 * Ask the transport to provide data for the "current" package being restored. This 598 * is the package that was just reported by {@link #nextRestorePackage()} as having 599 * {@link RestoreDescription#TYPE_FULL_STREAM} data. 600 * 601 * The transport writes some data to the socket supplied to this call, and returns 602 * the number of bytes written. The system will then read that many bytes and 603 * stream them to the application's agent for restore, then will call this method again 604 * to receive the next chunk of the archive. This sequence will be repeated until the 605 * transport returns zero indicating that all of the package's data has been delivered 606 * (or returns a negative value indicating some sort of hard error condition at the 607 * transport level). 608 * 609 * <p>After this method returns zero, the system will then call 610 * {@link #nextRestorePackage()} to begin the restore process for the next 611 * application, and the sequence begins again. 612 * 613 * <p>The transport should always close this socket when returning from this method. 614 * Do not cache this socket across multiple calls or you may leak file descriptors. 615 * 616 * @param socket The file descriptor that the transport will use for delivering the 617 * streamed archive. The transport must close this socket in all cases when returning 618 * from this method. 619 * @return {@link #NO_MORE_DATA} when no more data for the current package is available. 620 * A positive value indicates the presence of that many bytes to be delivered to the app. 621 * A value of zero indicates that no data was deliverable at this time, but the restore 622 * is still running and the caller should retry. {@link #TRANSPORT_PACKAGE_REJECTED} 623 * means that the current package's restore operation should be aborted, but that 624 * the transport itself is still in a good state and so a multiple-package restore 625 * sequence can still be continued. Any other negative return value is treated as a 626 * fatal error condition that aborts all further restore operations on the current dataset. 627 */ getNextFullRestoreDataChunk(ParcelFileDescriptor socket)628 public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) { 629 return 0; 630 } 631 632 /** 633 * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM} 634 * data for restore, it will invoke this method to tell the transport that it should 635 * abandon the data download for the current package. The OS will then either call 636 * {@link #nextRestorePackage()} again to move on to restoring the next package in the 637 * set being iterated over, or will call {@link #finishRestore()} to shut down the restore 638 * operation. 639 * 640 * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the 641 * current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious 642 * transport-level failure. If the transport reports an error here, the entire restore 643 * operation will immediately be finished with no further attempts to restore app data. 644 */ abortFullRestore()645 public int abortFullRestore() { 646 return BackupTransport.TRANSPORT_OK; 647 } 648 649 /** 650 * Returns flags with additional information about the transport, which is accessible to the 651 * {@link android.app.backup.BackupAgent}. This allows the agent to decide what to do based on 652 * properties of the transport. 653 */ getTransportFlags()654 public int getTransportFlags() { 655 return 0; 656 } 657 658 /** 659 * Ask the transport for a {@link BackupManagerMonitor} instance which will be used by the 660 * framework to report logging events back to the transport. 661 * 662 * <p>Backups requested from outside the framework may pass in a monitor with the request, 663 * however backups initiated by the framework will call this method to retrieve one. 664 * 665 * @return {@link BackupManagerMonitor} or {@code null} if the transport implementation does not 666 * wish to receive the logging events. 667 */ 668 @Nullable getBackupManagerMonitor()669 public BackupManagerMonitor getBackupManagerMonitor() { 670 return null; 671 } 672 673 /** 674 * Bridge between the actual IBackupTransport implementation and the stable API. If the 675 * binder interface needs to change, we use this layer to translate so that we can 676 * (if appropriate) decouple those framework-side changes from the BackupTransport 677 * implementations. 678 */ 679 class TransportImpl extends IBackupTransport.Stub { 680 681 @Override name(AndroidFuture<String> resultFuture)682 public void name(AndroidFuture<String> resultFuture) throws RemoteException { 683 try { 684 String result = BackupTransport.this.name(); 685 resultFuture.complete(result); 686 } catch (RuntimeException e) { 687 resultFuture.cancel(/* mayInterruptIfRunning */ true); 688 } 689 } 690 691 @Override configurationIntent(AndroidFuture<Intent> resultFuture)692 public void configurationIntent(AndroidFuture<Intent> resultFuture) 693 throws RemoteException { 694 try { 695 Intent result = BackupTransport.this.configurationIntent(); 696 resultFuture.complete(result); 697 } catch (RuntimeException e) { 698 resultFuture.cancel(/* mayInterruptIfRunning */ true); 699 } 700 } 701 702 @Override currentDestinationString(AndroidFuture<String> resultFuture)703 public void currentDestinationString(AndroidFuture<String> resultFuture) 704 throws RemoteException { 705 try { 706 String result = BackupTransport.this.currentDestinationString(); 707 resultFuture.complete(result); 708 } catch (RuntimeException e) { 709 resultFuture.cancel(/* mayInterruptIfRunning */ true); 710 } 711 } 712 713 @Override dataManagementIntent(AndroidFuture<Intent> resultFuture)714 public void dataManagementIntent(AndroidFuture<Intent> resultFuture) 715 throws RemoteException { 716 try { 717 Intent result = BackupTransport.this.dataManagementIntent(); 718 resultFuture.complete(result); 719 } catch (RuntimeException e) { 720 resultFuture.cancel(/* mayInterruptIfRunning */ true); 721 } 722 } 723 724 @Override dataManagementIntentLabel(AndroidFuture<CharSequence> resultFuture)725 public void dataManagementIntentLabel(AndroidFuture<CharSequence> resultFuture) 726 throws RemoteException { 727 try { 728 CharSequence result = BackupTransport.this.dataManagementIntentLabel(); 729 resultFuture.complete(result); 730 } catch (RuntimeException e) { 731 resultFuture.cancel(/* mayInterruptIfRunning */ true); 732 } 733 } 734 735 @Override transportDirName(AndroidFuture<String> resultFuture)736 public void transportDirName(AndroidFuture<String> resultFuture) throws RemoteException { 737 try { 738 String result = BackupTransport.this.transportDirName(); 739 resultFuture.complete(result); 740 } catch (RuntimeException e) { 741 resultFuture.cancel(/* mayInterruptIfRunning */ true); 742 } 743 } 744 745 @Override requestBackupTime(AndroidFuture<Long> resultFuture)746 public void requestBackupTime(AndroidFuture<Long> resultFuture) throws RemoteException { 747 try { 748 long result = BackupTransport.this.requestBackupTime(); 749 resultFuture.complete(result); 750 } catch (RuntimeException e) { 751 resultFuture.cancel(/* mayInterruptIfRunning */ true); 752 } 753 } 754 755 @Override initializeDevice(ITransportStatusCallback callback)756 public void initializeDevice(ITransportStatusCallback callback) throws RemoteException { 757 try { 758 int result = BackupTransport.this.initializeDevice(); 759 callback.onOperationCompleteWithStatus(result); 760 } catch (RuntimeException e) { 761 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 762 } 763 } 764 765 @Override performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags, ITransportStatusCallback callback)766 public void performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags, 767 ITransportStatusCallback callback) throws RemoteException { 768 try { 769 int result = BackupTransport.this.performBackup(packageInfo, inFd, flags); 770 callback.onOperationCompleteWithStatus(result); 771 } catch (RuntimeException e) { 772 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 773 } 774 } 775 776 @Override clearBackupData(PackageInfo packageInfo, ITransportStatusCallback callback)777 public void clearBackupData(PackageInfo packageInfo, ITransportStatusCallback callback) 778 throws RemoteException { 779 try { 780 int result = BackupTransport.this.clearBackupData(packageInfo); 781 callback.onOperationCompleteWithStatus(result); 782 } catch (RuntimeException e) { 783 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 784 } 785 } 786 787 @Override finishBackup(ITransportStatusCallback callback)788 public void finishBackup(ITransportStatusCallback callback) throws RemoteException { 789 try { 790 int result = BackupTransport.this.finishBackup(); 791 callback.onOperationCompleteWithStatus(result); 792 } catch (RuntimeException e) { 793 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 794 } 795 } 796 797 @Override getAvailableRestoreSets(AndroidFuture<List<RestoreSet>> resultFuture)798 public void getAvailableRestoreSets(AndroidFuture<List<RestoreSet>> resultFuture) 799 throws RemoteException { 800 try { 801 RestoreSet[] result = BackupTransport.this.getAvailableRestoreSets(); 802 resultFuture.complete(Arrays.asList(result)); 803 } catch (RuntimeException e) { 804 resultFuture.cancel(/* mayInterruptIfRunning */ true); 805 } 806 } 807 808 @Override getCurrentRestoreSet(AndroidFuture<Long> resultFuture)809 public void getCurrentRestoreSet(AndroidFuture<Long> resultFuture) 810 throws RemoteException { 811 try { 812 long result = BackupTransport.this.getCurrentRestoreSet(); 813 resultFuture.complete(result); 814 } catch (RuntimeException e) { 815 resultFuture.cancel(/* mayInterruptIfRunning */ true); 816 } 817 } 818 819 @Override startRestore(long token, PackageInfo[] packages, ITransportStatusCallback callback)820 public void startRestore(long token, PackageInfo[] packages, 821 ITransportStatusCallback callback) throws RemoteException { 822 try { 823 int result = BackupTransport.this.startRestore(token, packages); 824 callback.onOperationCompleteWithStatus(result); 825 } catch (RuntimeException e) { 826 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 827 } 828 } 829 830 @Override nextRestorePackage(AndroidFuture<RestoreDescription> resultFuture)831 public void nextRestorePackage(AndroidFuture<RestoreDescription> resultFuture) 832 throws RemoteException { 833 try { 834 RestoreDescription result = BackupTransport.this.nextRestorePackage(); 835 resultFuture.complete(result); 836 } catch (RuntimeException e) { 837 resultFuture.cancel(/* mayInterruptIfRunning */ true); 838 } 839 } 840 841 @Override getRestoreData(ParcelFileDescriptor outFd, ITransportStatusCallback callback)842 public void getRestoreData(ParcelFileDescriptor outFd, 843 ITransportStatusCallback callback) throws RemoteException { 844 try { 845 int result = BackupTransport.this.getRestoreData(outFd); 846 callback.onOperationCompleteWithStatus(result); 847 } catch (RuntimeException e) { 848 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 849 } 850 } 851 852 @Override finishRestore(ITransportStatusCallback callback)853 public void finishRestore(ITransportStatusCallback callback) 854 throws RemoteException { 855 try { 856 BackupTransport.this.finishRestore(); 857 callback.onOperationComplete(); 858 } catch (RuntimeException e) { 859 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 860 } 861 } 862 863 @Override requestFullBackupTime(AndroidFuture<Long> resultFuture)864 public void requestFullBackupTime(AndroidFuture<Long> resultFuture) 865 throws RemoteException { 866 try { 867 long result = BackupTransport.this.requestFullBackupTime(); 868 resultFuture.complete(result); 869 } catch (RuntimeException e) { 870 resultFuture.cancel(/* mayInterruptIfRunning */ true); 871 } 872 } 873 874 @Override performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket, int flags, ITransportStatusCallback callback)875 public void performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket, 876 int flags, ITransportStatusCallback callback) throws RemoteException { 877 try { 878 int result = BackupTransport.this.performFullBackup(targetPackage, socket, flags); 879 callback.onOperationCompleteWithStatus(result); 880 } catch (RuntimeException e) { 881 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 882 } 883 } 884 885 @Override checkFullBackupSize(long size, ITransportStatusCallback callback)886 public void checkFullBackupSize(long size, ITransportStatusCallback callback) 887 throws RemoteException { 888 try { 889 int result = BackupTransport.this.checkFullBackupSize(size); 890 callback.onOperationCompleteWithStatus(result); 891 } catch (RuntimeException e) { 892 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 893 } 894 } 895 896 @Override sendBackupData(int numBytes, ITransportStatusCallback callback)897 public void sendBackupData(int numBytes, ITransportStatusCallback callback) 898 throws RemoteException { 899 try { 900 int result = BackupTransport.this.sendBackupData(numBytes); 901 callback.onOperationCompleteWithStatus(result); 902 } catch (RuntimeException e) { 903 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 904 } 905 } 906 907 @Override cancelFullBackup(ITransportStatusCallback callback)908 public void cancelFullBackup(ITransportStatusCallback callback) throws RemoteException { 909 try { 910 BackupTransport.this.cancelFullBackup(); 911 callback.onOperationComplete(); 912 } catch (RuntimeException e) { 913 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 914 } 915 } 916 917 @Override isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup, AndroidFuture<Boolean> resultFuture)918 public void isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup, 919 AndroidFuture<Boolean> resultFuture) throws RemoteException { 920 try { 921 boolean result = BackupTransport.this.isAppEligibleForBackup(targetPackage, 922 isFullBackup); 923 resultFuture.complete(result); 924 } catch (RuntimeException e) { 925 resultFuture.cancel(/* mayInterruptIfRunning */ true); 926 } 927 } 928 929 @Override getBackupQuota(String packageName, boolean isFullBackup, AndroidFuture<Long> resultFuture)930 public void getBackupQuota(String packageName, boolean isFullBackup, 931 AndroidFuture<Long> resultFuture) throws RemoteException { 932 try { 933 long result = BackupTransport.this.getBackupQuota(packageName, isFullBackup); 934 resultFuture.complete(result); 935 } catch (RuntimeException e) { 936 resultFuture.cancel(/* mayInterruptIfRunning */ true); 937 } 938 } 939 940 @Override getTransportFlags(AndroidFuture<Integer> resultFuture)941 public void getTransportFlags(AndroidFuture<Integer> resultFuture) throws RemoteException { 942 try { 943 int result = BackupTransport.this.getTransportFlags(); 944 resultFuture.complete(result); 945 } catch (RuntimeException e) { 946 resultFuture.cancel(/* mayInterruptIfRunning */ true); 947 } 948 } 949 950 @Override getNextFullRestoreDataChunk(ParcelFileDescriptor socket, ITransportStatusCallback callback)951 public void getNextFullRestoreDataChunk(ParcelFileDescriptor socket, 952 ITransportStatusCallback callback) throws RemoteException { 953 try { 954 int result = BackupTransport.this.getNextFullRestoreDataChunk(socket); 955 callback.onOperationCompleteWithStatus(result); 956 } catch (RuntimeException e) { 957 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 958 } 959 } 960 961 @Override abortFullRestore(ITransportStatusCallback callback)962 public void abortFullRestore(ITransportStatusCallback callback) throws RemoteException { 963 try { 964 int result = BackupTransport.this.abortFullRestore(); 965 callback.onOperationCompleteWithStatus(result); 966 } catch (RuntimeException e) { 967 callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR); 968 } 969 } 970 971 @Override getBackupManagerMonitor(AndroidFuture<IBackupManagerMonitor> resultFuture)972 public void getBackupManagerMonitor(AndroidFuture<IBackupManagerMonitor> resultFuture) { 973 try { 974 BackupManagerMonitor result = BackupTransport.this.getBackupManagerMonitor(); 975 resultFuture.complete(new BackupManagerMonitorWrapper(result)); 976 } catch (RuntimeException e) { 977 resultFuture.cancel(/* mayInterruptIfRunning */ true); 978 } 979 } 980 } 981 } 982