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.SystemApi; 20 import android.content.Intent; 21 import android.content.pm.PackageInfo; 22 import android.os.IBinder; 23 import android.os.ParcelFileDescriptor; 24 import android.os.RemoteException; 25 26 import com.android.internal.backup.IBackupTransport; 27 28 /** 29 * Concrete class that provides a stable-API bridge between IBackupTransport 30 * and its implementations. 31 * 32 * @hide 33 */ 34 @SystemApi 35 public class BackupTransport { 36 // Zero return always means things are okay. If returned from 37 // getNextFullRestoreDataChunk(), it means that no data could be delivered at 38 // this time, but the restore is still running and the caller should simply 39 // retry. 40 public static final int TRANSPORT_OK = 0; 41 42 // -1 is special; it is used in getNextFullRestoreDataChunk() to indicate that 43 // we've delivered the entire data stream for the current restore target. 44 public static final int NO_MORE_DATA = -1; 45 46 // Result codes that indicate real errors are negative and not -1 47 public static final int TRANSPORT_ERROR = -1000; 48 public static final int TRANSPORT_NOT_INITIALIZED = -1001; 49 public static final int TRANSPORT_PACKAGE_REJECTED = -1002; 50 public static final int AGENT_ERROR = -1003; 51 public static final int AGENT_UNKNOWN = -1004; 52 53 IBackupTransport mBinderImpl = new TransportImpl(); 54 55 public IBinder getBinder() { 56 return mBinderImpl.asBinder(); 57 } 58 59 // ------------------------------------------------------------------------------------ 60 // Transport self-description and general configuration interfaces 61 // 62 63 /** 64 * Ask the transport for the name under which it should be registered. This will 65 * typically be its host service's component name, but need not be. 66 */ 67 public String name() { 68 throw new UnsupportedOperationException("Transport name() not implemented"); 69 } 70 71 /** 72 * Ask the transport for an Intent that can be used to launch any internal 73 * configuration Activity that it wishes to present. For example, the transport 74 * may offer a UI for allowing the user to supply login credentials for the 75 * transport's off-device backend. 76 * 77 * <p>If the transport does not supply any user-facing configuration UI, it should 78 * return {@code null} from this method. 79 * 80 * @return An Intent that can be passed to Context.startActivity() in order to 81 * launch the transport's configuration UI. This method will return {@code null} 82 * if the transport does not offer any user-facing configuration UI. 83 */ 84 public Intent configurationIntent() { 85 return null; 86 } 87 88 /** 89 * On demand, supply a one-line string that can be shown to the user that 90 * describes the current backend destination. For example, a transport that 91 * can potentially associate backup data with arbitrary user accounts should 92 * include the name of the currently-active account here. 93 * 94 * @return A string describing the destination to which the transport is currently 95 * sending data. This method should not return null. 96 */ 97 public String currentDestinationString() { 98 throw new UnsupportedOperationException( 99 "Transport currentDestinationString() not implemented"); 100 } 101 102 /** 103 * Ask the transport for an Intent that can be used to launch a more detailed 104 * secondary data management activity. For example, the configuration intent might 105 * be one for allowing the user to select which account they wish to associate 106 * their backups with, and the management intent might be one which presents a 107 * UI for managing the data on the backend. 108 * 109 * <p>In the Settings UI, the configuration intent will typically be invoked 110 * when the user taps on the preferences item labeled with the current 111 * destination string, and the management intent will be placed in an overflow 112 * menu labelled with the management label string. 113 * 114 * <p>If the transport does not supply any user-facing data management 115 * UI, then it should return {@code null} from this method. 116 * 117 * @return An intent that can be passed to Context.startActivity() in order to 118 * launch the transport's data-management UI. This method will return 119 * {@code null} if the transport does not offer any user-facing data 120 * management UI. 121 */ 122 public Intent dataManagementIntent() { 123 return null; 124 } 125 126 /** 127 * On demand, supply a short string that can be shown to the user as the label 128 * on an overflow menu item used to invoked the data management UI. 129 * 130 * @return A string to be used as the label for the transport's data management 131 * affordance. If the transport supplies a data management intent, this 132 * method must not return {@code null}. 133 */ 134 public String dataManagementLabel() { 135 throw new UnsupportedOperationException( 136 "Transport dataManagementLabel() not implemented"); 137 } 138 139 /** 140 * Ask the transport where, on local device storage, to keep backup state blobs. 141 * This is per-transport so that mock transports used for testing can coexist with 142 * "live" backup services without interfering with the live bookkeeping. The 143 * returned string should be a name that is expected to be unambiguous among all 144 * available backup transports; the name of the class implementing the transport 145 * is a good choice. 146 * 147 * @return A unique name, suitable for use as a file or directory name, that the 148 * Backup Manager could use to disambiguate state files associated with 149 * different backup transports. 150 */ 151 public String transportDirName() { 152 throw new UnsupportedOperationException( 153 "Transport transportDirName() not implemented"); 154 } 155 156 // ------------------------------------------------------------------------------------ 157 // Device-level operations common to both key/value and full-data storage 158 159 /** 160 * Initialize the server side storage for this device, erasing all stored data. 161 * The transport may send the request immediately, or may buffer it. After 162 * this is called, {@link #finishBackup} will be called to ensure the request 163 * is sent and received successfully. 164 * 165 * @return One of {@link BackupTransport#TRANSPORT_OK} (OK so far) or 166 * {@link BackupTransport#TRANSPORT_ERROR} (on network error or other failure). 167 */ 168 public int initializeDevice() { 169 return BackupTransport.TRANSPORT_ERROR; 170 } 171 172 /** 173 * Erase the given application's data from the backup destination. This clears 174 * out the given package's data from the current backup set, making it as though 175 * the app had never yet been backed up. After this is called, {@link finishBackup} 176 * must be called to ensure that the operation is recorded successfully. 177 * 178 * @return the same error codes as {@link #performBackup}. 179 */ 180 public int clearBackupData(PackageInfo packageInfo) { 181 return BackupTransport.TRANSPORT_ERROR; 182 } 183 184 /** 185 * Finish sending application data to the backup destination. This must be 186 * called after {@link #performBackup}, {@link #performFullBackup}, or {@link clearBackupData} 187 * to ensure that all data is sent and the operation properly finalized. Only when this 188 * method returns true can a backup be assumed to have succeeded. 189 * 190 * @return the same error codes as {@link #performBackup} or {@link #performFullBackup}. 191 */ 192 public int finishBackup() { 193 return BackupTransport.TRANSPORT_ERROR; 194 } 195 196 // ------------------------------------------------------------------------------------ 197 // Key/value incremental backup support interfaces 198 199 /** 200 * Verify that this is a suitable time for a key/value backup pass. This should return zero 201 * if a backup is reasonable right now, some positive value otherwise. This method 202 * will be called outside of the {@link #performBackup}/{@link #finishBackup} pair. 203 * 204 * <p>If this is not a suitable time for a backup, the transport should return a 205 * backoff delay, in milliseconds, after which the Backup Manager should try again. 206 * 207 * @return Zero if this is a suitable time for a backup pass, or a positive time delay 208 * in milliseconds to suggest deferring the backup pass for a while. 209 */ 210 public long requestBackupTime() { 211 return 0; 212 } 213 214 /** 215 * Send one application's key/value data update to the backup destination. The 216 * transport may send the data immediately, or may buffer it. After this is called, 217 * {@link #finishBackup} will be called to ensure the data is sent and recorded successfully. 218 * 219 * @param packageInfo The identity of the application whose data is being backed up. 220 * This specifically includes the signature list for the package. 221 * @param data The data stream that resulted from invoking the application's 222 * BackupService.doBackup() method. This may be a pipe rather than a file on 223 * persistent media, so it may not be seekable. 224 * @param wipeAllFirst When true, <i>all</i> backed-up data for the current device/account 225 * must be erased prior to the storage of the data provided here. The purpose of this 226 * is to provide a guarantee that no stale data exists in the restore set when the 227 * device begins providing incremental backups. 228 * @return one of {@link BackupTransport#TRANSPORT_OK} (OK so far), 229 * {@link BackupTransport#TRANSPORT_ERROR} (on network error or other failure), or 230 * {@link BackupTransport#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has 231 * become lost due to inactivity purge or some other reason and needs re-initializing) 232 */ 233 public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd) { 234 return BackupTransport.TRANSPORT_ERROR; 235 } 236 237 // ------------------------------------------------------------------------------------ 238 // Key/value dataset restore interfaces 239 240 /** 241 * Get the set of all backups currently available over this transport. 242 * 243 * @return Descriptions of the set of restore images available for this device, 244 * or null if an error occurred (the attempt should be rescheduled). 245 **/ 246 public RestoreSet[] getAvailableRestoreSets() { 247 return null; 248 } 249 250 /** 251 * Get the identifying token of the backup set currently being stored from 252 * this device. This is used in the case of applications wishing to restore 253 * their last-known-good data. 254 * 255 * @return A token that can be passed to {@link #startRestore}, or 0 if there 256 * is no backup set available corresponding to the current device state. 257 */ 258 public long getCurrentRestoreSet() { 259 return 0; 260 } 261 262 /** 263 * Start restoring application data from backup. After calling this function, 264 * alternate calls to {@link #nextRestorePackage} and {@link #nextRestoreData} 265 * to walk through the actual application data. 266 * 267 * @param token A backup token as returned by {@link #getAvailableRestoreSets} 268 * or {@link #getCurrentRestoreSet}. 269 * @param packages List of applications to restore (if data is available). 270 * Application data will be restored in the order given. 271 * @return One of {@link BackupTransport#TRANSPORT_OK} (OK so far, call 272 * {@link #nextRestorePackage}) or {@link BackupTransport#TRANSPORT_ERROR} 273 * (an error occurred, the restore should be aborted and rescheduled). 274 */ 275 public int startRestore(long token, PackageInfo[] packages) { 276 return BackupTransport.TRANSPORT_ERROR; 277 } 278 279 /** 280 * Get the package name of the next application with data in the backup store, plus 281 * a description of the structure of the restored archive: either TYPE_KEY_VALUE for 282 * an original-API key/value dataset, or TYPE_FULL_STREAM for a tarball-type archive stream. 283 * 284 * <p>If the package name in the returned RestoreDescription object is the singleton 285 * {@link RestoreDescription#NO_MORE_PACKAGES}, it indicates that no further data is available 286 * in the current restore session: all packages described in startRestore() have been 287 * processed. 288 * 289 * <p>If this method returns {@code null}, it means that a transport-level error has 290 * occurred and the entire restore operation should be abandoned. 291 * 292 * <p class="note">The OS may call {@link #nextRestorePackage()} multiple times 293 * before calling either {@link #getRestoreData(ParcelFileDescriptor) getRestoreData()} 294 * or {@link #getNextFullRestoreDataChunk(ParcelFileDescriptor) getNextFullRestoreDataChunk()}. 295 * It does this when it has determined that it needs to skip restore of one or more 296 * packages. The transport should not actually transfer any restore data for 297 * the given package in response to {@link #nextRestorePackage()}, but rather wait 298 * for an explicit request before doing so. 299 * 300 * @return A RestoreDescription object containing the name of one of the packages 301 * supplied to {@link #startRestore} plus an indicator of the data type of that 302 * restore data; or {@link RestoreDescription#NO_MORE_PACKAGES} to indicate that 303 * no more packages can be restored in this session; or {@code null} to indicate 304 * a transport-level error. 305 */ 306 public RestoreDescription nextRestorePackage() { 307 return null; 308 } 309 310 /** 311 * Get the data for the application returned by {@link #nextRestorePackage}, if that 312 * method reported {@link RestoreDescription#TYPE_KEY_VALUE} as its delivery type. 313 * If the package has only TYPE_FULL_STREAM data, then this method will return an 314 * error. 315 * 316 * @param data An open, writable file into which the key/value backup data should be stored. 317 * @return the same error codes as {@link #startRestore}. 318 */ 319 public int getRestoreData(ParcelFileDescriptor outFd) { 320 return BackupTransport.TRANSPORT_ERROR; 321 } 322 323 /** 324 * End a restore session (aborting any in-process data transfer as necessary), 325 * freeing any resources and connections used during the restore process. 326 */ 327 public void finishRestore() { 328 throw new UnsupportedOperationException( 329 "Transport finishRestore() not implemented"); 330 } 331 332 // ------------------------------------------------------------------------------------ 333 // Full backup interfaces 334 335 /** 336 * Verify that this is a suitable time for a full-data backup pass. This should return zero 337 * if a backup is reasonable right now, some positive value otherwise. This method 338 * will be called outside of the {@link #performFullBackup}/{@link #finishBackup} pair. 339 * 340 * <p>If this is not a suitable time for a backup, the transport should return a 341 * backoff delay, in milliseconds, after which the Backup Manager should try again. 342 * 343 * @return Zero if this is a suitable time for a backup pass, or a positive time delay 344 * in milliseconds to suggest deferring the backup pass for a while. 345 * 346 * @see #requestBackupTime() 347 */ 348 public long requestFullBackupTime() { 349 return 0; 350 } 351 352 /** 353 * Begin the process of sending an application's full-data archive to the backend. 354 * The description of the package whose data will be delivered is provided, as well as 355 * the socket file descriptor on which the transport will receive the data itself. 356 * 357 * <p>If the package is not eligible for backup, the transport should return 358 * {@link BackupTransport#TRANSPORT_PACKAGE_REJECTED}. In this case the system will 359 * simply proceed with the next candidate if any, or finish the full backup operation 360 * if all apps have been processed. 361 * 362 * <p>After the transport returns {@link BackupTransport#TRANSPORT_OK} from this 363 * method, the OS will proceed to call {@link #sendBackupData()} one or more times 364 * to deliver the application's data as a streamed tarball. The transport should not 365 * read() from the socket except as instructed to via the {@link #sendBackupData(int)} 366 * method. 367 * 368 * <p>After all data has been delivered to the transport, the system will call 369 * {@link #finishBackup()}. At this point the transport should commit the data to 370 * its datastore, if appropriate, and close the socket that had been provided in 371 * {@link #performFullBackup(PackageInfo, ParcelFileDescriptor)}. 372 * 373 * <p class="note">If the transport returns TRANSPORT_OK from this method, then the 374 * OS will always provide a matching call to {@link #finishBackup()} even if sending 375 * data via {@link #sendBackupData(int)} failed at some point. 376 * 377 * @param targetPackage The package whose data is to follow. 378 * @param socket The socket file descriptor through which the data will be provided. 379 * If the transport returns {@link #TRANSPORT_PACKAGE_REJECTED} here, it must still 380 * close this file descriptor now; otherwise it should be cached for use during 381 * succeeding calls to {@link #sendBackupData(int)}, and closed in response to 382 * {@link #finishBackup()}. 383 * @return TRANSPORT_PACKAGE_REJECTED to indicate that the stated application is not 384 * to be backed up; TRANSPORT_OK to indicate that the OS may proceed with delivering 385 * backup data; TRANSPORT_ERROR to indicate a fatal error condition that precludes 386 * performing a backup at this time. 387 */ 388 public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) { 389 return BackupTransport.TRANSPORT_PACKAGE_REJECTED; 390 } 391 392 /** 393 * Tells the transport to read {@code numBytes} bytes of data from the socket file 394 * descriptor provided in the {@link #performFullBackup(PackageInfo, ParcelFileDescriptor)} 395 * call, and deliver those bytes to the datastore. 396 * 397 * @param numBytes The number of bytes of tarball data available to be read from the 398 * socket. 399 * @return TRANSPORT_OK on successful processing of the data; TRANSPORT_ERROR to 400 * indicate a fatal error situation. If an error is returned, the system will 401 * call finishBackup() and stop attempting backups until after a backoff and retry 402 * interval. 403 */ 404 public int sendBackupData(int numBytes) { 405 return BackupTransport.TRANSPORT_ERROR; 406 } 407 408 /** 409 * Tells the transport to cancel the currently-ongoing full backup operation. This 410 * will happen between {@link #performFullBackup()} and {@link #finishBackup()} 411 * if the OS needs to abort the backup operation for any reason, such as a crash in 412 * the application undergoing backup. 413 * 414 * <p>When it receives this call, the transport should discard any partial archive 415 * that it has stored so far. If possible it should also roll back to the previous 416 * known-good archive in its datastore. 417 * 418 * <p>If the transport receives this callback, it will <em>not</em> receive a 419 * call to {@link #finishBackup()}. It needs to tear down any ongoing backup state 420 * here. 421 */ 422 public void cancelFullBackup() { 423 throw new UnsupportedOperationException( 424 "Transport cancelFullBackup() not implemented"); 425 } 426 427 // ------------------------------------------------------------------------------------ 428 // Full restore interfaces 429 430 /** 431 * Ask the transport to provide data for the "current" package being restored. This 432 * is the package that was just reported by {@link #nextRestorePackage()} as having 433 * {@link RestoreDescription#TYPE_FULL_STREAM} data. 434 * 435 * The transport writes some data to the socket supplied to this call, and returns 436 * the number of bytes written. The system will then read that many bytes and 437 * stream them to the application's agent for restore, then will call this method again 438 * to receive the next chunk of the archive. This sequence will be repeated until the 439 * transport returns zero indicating that all of the package's data has been delivered 440 * (or returns a negative value indicating some sort of hard error condition at the 441 * transport level). 442 * 443 * <p>After this method returns zero, the system will then call 444 * {@link #getNextFullRestorePackage()} to begin the restore process for the next 445 * application, and the sequence begins again. 446 * 447 * <p>The transport should always close this socket when returning from this method. 448 * Do not cache this socket across multiple calls or you may leak file descriptors. 449 * 450 * @param socket The file descriptor that the transport will use for delivering the 451 * streamed archive. The transport must close this socket in all cases when returning 452 * from this method. 453 * @return {@link #NO_MORE_DATA} when no more data for the current package is available. 454 * A positive value indicates the presence of that many bytes to be delivered to the app. 455 * A value of zero indicates that no data was deliverable at this time, but the restore 456 * is still running and the caller should retry. {@link #TRANSPORT_PACKAGE_REJECTED} 457 * means that the current package's restore operation should be aborted, but that 458 * the transport itself is still in a good state and so a multiple-package restore 459 * sequence can still be continued. Any other negative return value is treated as a 460 * fatal error condition that aborts all further restore operations on the current dataset. 461 */ 462 public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) { 463 return 0; 464 } 465 466 /** 467 * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM} 468 * data for restore, it will invoke this method to tell the transport that it should 469 * abandon the data download for the current package. The OS will then either call 470 * {@link #nextRestorePackage()} again to move on to restoring the next package in the 471 * set being iterated over, or will call {@link #finishRestore()} to shut down the restore 472 * operation. 473 * 474 * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the 475 * current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious 476 * transport-level failure. If the transport reports an error here, the entire restore 477 * operation will immediately be finished with no further attempts to restore app data. 478 */ 479 public int abortFullRestore() { 480 return BackupTransport.TRANSPORT_OK; 481 } 482 483 /** 484 * Bridge between the actual IBackupTransport implementation and the stable API. If the 485 * binder interface needs to change, we use this layer to translate so that we can 486 * (if appropriate) decouple those framework-side changes from the BackupTransport 487 * implementations. 488 */ 489 class TransportImpl extends IBackupTransport.Stub { 490 491 @Override 492 public String name() throws RemoteException { 493 return BackupTransport.this.name(); 494 } 495 496 @Override 497 public Intent configurationIntent() throws RemoteException { 498 return BackupTransport.this.configurationIntent(); 499 } 500 501 @Override 502 public String currentDestinationString() throws RemoteException { 503 return BackupTransport.this.currentDestinationString(); 504 } 505 506 @Override 507 public Intent dataManagementIntent() { 508 return BackupTransport.this.dataManagementIntent(); 509 } 510 511 @Override 512 public String dataManagementLabel() { 513 return BackupTransport.this.dataManagementLabel(); 514 } 515 516 @Override 517 public String transportDirName() throws RemoteException { 518 return BackupTransport.this.transportDirName(); 519 } 520 521 @Override 522 public long requestBackupTime() throws RemoteException { 523 return BackupTransport.this.requestBackupTime(); 524 } 525 526 @Override 527 public int initializeDevice() throws RemoteException { 528 return BackupTransport.this.initializeDevice(); 529 } 530 531 @Override 532 public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd) 533 throws RemoteException { 534 return BackupTransport.this.performBackup(packageInfo, inFd); 535 } 536 537 @Override 538 public int clearBackupData(PackageInfo packageInfo) throws RemoteException { 539 return BackupTransport.this.clearBackupData(packageInfo); 540 } 541 542 @Override 543 public int finishBackup() throws RemoteException { 544 return BackupTransport.this.finishBackup(); 545 } 546 547 @Override 548 public RestoreSet[] getAvailableRestoreSets() throws RemoteException { 549 return BackupTransport.this.getAvailableRestoreSets(); 550 } 551 552 @Override 553 public long getCurrentRestoreSet() throws RemoteException { 554 return BackupTransport.this.getCurrentRestoreSet(); 555 } 556 557 @Override 558 public int startRestore(long token, PackageInfo[] packages) throws RemoteException { 559 return BackupTransport.this.startRestore(token, packages); 560 } 561 562 @Override 563 public RestoreDescription nextRestorePackage() throws RemoteException { 564 return BackupTransport.this.nextRestorePackage(); 565 } 566 567 @Override 568 public int getRestoreData(ParcelFileDescriptor outFd) throws RemoteException { 569 return BackupTransport.this.getRestoreData(outFd); 570 } 571 572 @Override 573 public void finishRestore() throws RemoteException { 574 BackupTransport.this.finishRestore(); 575 } 576 577 @Override 578 public long requestFullBackupTime() throws RemoteException { 579 return BackupTransport.this.requestFullBackupTime(); 580 } 581 582 @Override 583 public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) throws RemoteException { 584 return BackupTransport.this.performFullBackup(targetPackage, socket); 585 } 586 587 @Override 588 public int sendBackupData(int numBytes) throws RemoteException { 589 return BackupTransport.this.sendBackupData(numBytes); 590 } 591 592 @Override 593 public void cancelFullBackup() throws RemoteException { 594 BackupTransport.this.cancelFullBackup(); 595 } 596 597 @Override 598 public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) { 599 return BackupTransport.this.getNextFullRestoreDataChunk(socket); 600 } 601 602 @Override 603 public int abortFullRestore() { 604 return BackupTransport.this.abortFullRestore(); 605 } 606 } 607 } 608