2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.app.backup;
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;
26 import com.android.internal.backup.IBackupTransport;
29 * Concrete class that provides a stable-API bridge between IBackupTransport
30 * and its implementations.
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
40 public static final int TRANSPORT_OK = 0;
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;
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;
53 IBackupTransport mBinderImpl = new TransportImpl();
55 public IBinder getBinder() {
56 return mBinderImpl.asBinder();
59 // ------------------------------------------------------------------------------------
60 // Transport self-description and general configuration interfaces
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.
67 public String name() {
68 throw new UnsupportedOperationException("Transport name() not implemented");
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.
77 * <p>If the transport does not supply any user-facing configuration UI, it should
78 * return {@code null} from this method.
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.
84 public Intent configurationIntent() {
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.
94 * @return A string describing the destination to which the transport is currently
95 * sending data. This method should not return null.
97 public String currentDestinationString() {
98 throw new UnsupportedOperationException(
99 "Transport currentDestinationString() not implemented");
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.
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.
114 * <p>If the transport does not supply any user-facing data management
115 * UI, then it should return {@code null} from this method.
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
122 public Intent dataManagementIntent() {
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.
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}.
134 public String dataManagementLabel() {
135 throw new UnsupportedOperationException(
136 "Transport dataManagementLabel() not implemented");
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
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.
151 public String transportDirName() {
152 throw new UnsupportedOperationException(
153 "Transport transportDirName() not implemented");
156 // ------------------------------------------------------------------------------------
157 // Device-level operations common to both key/value and full-data storage
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.
165 * @return One of {@link BackupTransport#TRANSPORT_OK} (OK so far) or
166 * {@link BackupTransport#TRANSPORT_ERROR} (on network error or other failure).
168 public int initializeDevice() {
169 return BackupTransport.TRANSPORT_ERROR;
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.
178 * @return the same error codes as {@link #performBackup}.
180 public int clearBackupData(PackageInfo packageInfo) {
181 return BackupTransport.TRANSPORT_ERROR;
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.
190 * @return the same error codes as {@link #performBackup} or {@link #performFullBackup}.
192 public int finishBackup() {
193 return BackupTransport.TRANSPORT_ERROR;
196 // ------------------------------------------------------------------------------------
197 // Key/value incremental backup support interfaces
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.
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.
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.
210 public long requestBackupTime() {
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. If this method returns
217 * {@link #TRANSPORT_OK}, {@link #finishBackup} will then be called to ensure the data
218 * is sent and recorded successfully.
220 * @param packageInfo The identity of the application whose data is being backed up.
221 * This specifically includes the signature list for the package.
222 * @param data The data stream that resulted from invoking the application's
223 * BackupService.doBackup() method. This may be a pipe rather than a file on
224 * persistent media, so it may not be seekable.
225 * @param wipeAllFirst When true, <i>all</i> backed-up data for the current device/account
226 * must be erased prior to the storage of the data provided here. The purpose of this
227 * is to provide a guarantee that no stale data exists in the restore set when the
228 * device begins providing incremental backups.
229 * @return one of {@link BackupTransport#TRANSPORT_OK} (OK so far),
230 * {@link BackupTransport#TRANSPORT_PACKAGE_REJECTED} (to suppress backup of this
231 * specific package, but allow others to proceed),
232 * {@link BackupTransport#TRANSPORT_ERROR} (on network error or other failure), or
233 * {@link BackupTransport#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has
234 * become lost due to inactivity purge or some other reason and needs re-initializing)
236 public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd) {
237 return BackupTransport.TRANSPORT_ERROR;
240 // ------------------------------------------------------------------------------------
241 // Key/value dataset restore interfaces
244 * Get the set of all backups currently available over this transport.
246 * @return Descriptions of the set of restore images available for this device,
247 * or null if an error occurred (the attempt should be rescheduled).
249 public RestoreSet[] getAvailableRestoreSets() {
254 * Get the identifying token of the backup set currently being stored from
255 * this device. This is used in the case of applications wishing to restore
256 * their last-known-good data.
258 * @return A token that can be passed to {@link #startRestore}, or 0 if there
259 * is no backup set available corresponding to the current device state.
261 public long getCurrentRestoreSet() {
266 * Start restoring application data from backup. After calling this function,
267 * alternate calls to {@link #nextRestorePackage} and {@link #nextRestoreData}
268 * to walk through the actual application data.
270 * @param token A backup token as returned by {@link #getAvailableRestoreSets}
271 * or {@link #getCurrentRestoreSet}.
272 * @param packages List of applications to restore (if data is available).
273 * Application data will be restored in the order given.
274 * @return One of {@link BackupTransport#TRANSPORT_OK} (OK so far, call
275 * {@link #nextRestorePackage}) or {@link BackupTransport#TRANSPORT_ERROR}
276 * (an error occurred, the restore should be aborted and rescheduled).
278 public int startRestore(long token, PackageInfo[] packages) {
279 return BackupTransport.TRANSPORT_ERROR;
283 * Get the package name of the next application with data in the backup store, plus
284 * a description of the structure of the restored archive: either TYPE_KEY_VALUE for
285 * an original-API key/value dataset, or TYPE_FULL_STREAM for a tarball-type archive stream.
287 * <p>If the package name in the returned RestoreDescription object is the singleton
288 * {@link RestoreDescription#NO_MORE_PACKAGES}, it indicates that no further data is available
289 * in the current restore session: all packages described in startRestore() have been
292 * <p>If this method returns {@code null}, it means that a transport-level error has
293 * occurred and the entire restore operation should be abandoned.
295 * <p class="note">The OS may call {@link #nextRestorePackage()} multiple times
296 * before calling either {@link #getRestoreData(ParcelFileDescriptor) getRestoreData()}
297 * or {@link #getNextFullRestoreDataChunk(ParcelFileDescriptor) getNextFullRestoreDataChunk()}.
298 * It does this when it has determined that it needs to skip restore of one or more
299 * packages. The transport should not actually transfer any restore data for
300 * the given package in response to {@link #nextRestorePackage()}, but rather wait
301 * for an explicit request before doing so.
303 * @return A RestoreDescription object containing the name of one of the packages
304 * supplied to {@link #startRestore} plus an indicator of the data type of that
305 * restore data; or {@link RestoreDescription#NO_MORE_PACKAGES} to indicate that
306 * no more packages can be restored in this session; or {@code null} to indicate
307 * a transport-level error.
309 public RestoreDescription nextRestorePackage() {
314 * Get the data for the application returned by {@link #nextRestorePackage}, if that
315 * method reported {@link RestoreDescription#TYPE_KEY_VALUE} as its delivery type.
316 * If the package has only TYPE_FULL_STREAM data, then this method will return an
319 * @param data An open, writable file into which the key/value backup data should be stored.
320 * @return the same error codes as {@link #startRestore}.
322 public int getRestoreData(ParcelFileDescriptor outFd) {
323 return BackupTransport.TRANSPORT_ERROR;
327 * End a restore session (aborting any in-process data transfer as necessary),
328 * freeing any resources and connections used during the restore process.
330 public void finishRestore() {
331 throw new UnsupportedOperationException(
332 "Transport finishRestore() not implemented");
335 // ------------------------------------------------------------------------------------
336 // Full backup interfaces
339 * Verify that this is a suitable time for a full-data backup pass. This should return zero
340 * if a backup is reasonable right now, some positive value otherwise. This method
341 * will be called outside of the {@link #performFullBackup}/{@link #finishBackup} pair.
343 * <p>If this is not a suitable time for a backup, the transport should return a
344 * backoff delay, in milliseconds, after which the Backup Manager should try again.
346 * @return Zero if this is a suitable time for a backup pass, or a positive time delay
347 * in milliseconds to suggest deferring the backup pass for a while.
349 * @see #requestBackupTime()
351 public long requestFullBackupTime() {
356 * Begin the process of sending an application's full-data archive to the backend.
357 * The description of the package whose data will be delivered is provided, as well as
358 * the socket file descriptor on which the transport will receive the data itself.
360 * <p>If the package is not eligible for backup, the transport should return
361 * {@link BackupTransport#TRANSPORT_PACKAGE_REJECTED}. In this case the system will
362 * simply proceed with the next candidate if any, or finish the full backup operation
363 * if all apps have been processed.
365 * <p>After the transport returns {@link BackupTransport#TRANSPORT_OK} from this
366 * method, the OS will proceed to call {@link #sendBackupData()} one or more times
367 * to deliver the application's data as a streamed tarball. The transport should not
368 * read() from the socket except as instructed to via the {@link #sendBackupData(int)}
371 * <p>After all data has been delivered to the transport, the system will call
372 * {@link #finishBackup()}. At this point the transport should commit the data to
373 * its datastore, if appropriate, and close the socket that had been provided in
374 * {@link #performFullBackup(PackageInfo, ParcelFileDescriptor)}.
376 * <p class="note">If the transport returns TRANSPORT_OK from this method, then the
377 * OS will always provide a matching call to {@link #finishBackup()} even if sending
378 * data via {@link #sendBackupData(int)} failed at some point.
380 * @param targetPackage The package whose data is to follow.
381 * @param socket The socket file descriptor through which the data will be provided.
382 * If the transport returns {@link #TRANSPORT_PACKAGE_REJECTED} here, it must still
383 * close this file descriptor now; otherwise it should be cached for use during
384 * succeeding calls to {@link #sendBackupData(int)}, and closed in response to
385 * {@link #finishBackup()}.
386 * @return TRANSPORT_PACKAGE_REJECTED to indicate that the stated application is not
387 * to be backed up; TRANSPORT_OK to indicate that the OS may proceed with delivering
388 * backup data; TRANSPORT_ERROR to indicate a fatal error condition that precludes
389 * performing a backup at this time.
391 public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) {
392 return BackupTransport.TRANSPORT_PACKAGE_REJECTED;
396 * Called after {@link #performFullBackup} to make sure that the transport is willing to
397 * handle a full-data backup operation of the specified size on the current package.
398 * If the transport returns anything other than TRANSPORT_OK, the package's backup
399 * operation will be skipped (and {@link #finishBackup() invoked} with no data for that
400 * package being passed to {@link #sendBackupData}.
402 * Added in MNC (API 23).
404 * @param size The estimated size of the full-data payload for this app. This includes
405 * manifest and archive format overhead, but is not guaranteed to be precise.
406 * @return TRANSPORT_OK if the platform is to proceed with the full-data backup,
407 * TRANSPORT_PACKAGE_REJECTED if the proposed payload size is too large for
408 * the transport to handle, or TRANSPORT_ERROR to indicate a fatal error
409 * condition that means the platform cannot perform a backup at this time.
411 public int checkFullBackupSize(long size) {
412 return BackupTransport.TRANSPORT_OK;
416 * Tells the transport to read {@code numBytes} bytes of data from the socket file
417 * descriptor provided in the {@link #performFullBackup(PackageInfo, ParcelFileDescriptor)}
418 * call, and deliver those bytes to the datastore.
420 * @param numBytes The number of bytes of tarball data available to be read from the
422 * @return TRANSPORT_OK on successful processing of the data; TRANSPORT_ERROR to
423 * indicate a fatal error situation. If an error is returned, the system will
424 * call finishBackup() and stop attempting backups until after a backoff and retry
427 public int sendBackupData(int numBytes) {
428 return BackupTransport.TRANSPORT_ERROR;
432 * Tells the transport to cancel the currently-ongoing full backup operation. This
433 * will happen between {@link #performFullBackup()} and {@link #finishBackup()}
434 * if the OS needs to abort the backup operation for any reason, such as a crash in
435 * the application undergoing backup.
437 * <p>When it receives this call, the transport should discard any partial archive
438 * that it has stored so far. If possible it should also roll back to the previous
439 * known-good archive in its datastore.
441 * <p>If the transport receives this callback, it will <em>not</em> receive a
442 * call to {@link #finishBackup()}. It needs to tear down any ongoing backup state
445 public void cancelFullBackup() {
446 throw new UnsupportedOperationException(
447 "Transport cancelFullBackup() not implemented");
450 // ------------------------------------------------------------------------------------
451 // Full restore interfaces
454 * Ask the transport to provide data for the "current" package being restored. This
455 * is the package that was just reported by {@link #nextRestorePackage()} as having
456 * {@link RestoreDescription#TYPE_FULL_STREAM} data.
458 * The transport writes some data to the socket supplied to this call, and returns
459 * the number of bytes written. The system will then read that many bytes and
460 * stream them to the application's agent for restore, then will call this method again
461 * to receive the next chunk of the archive. This sequence will be repeated until the
462 * transport returns zero indicating that all of the package's data has been delivered
463 * (or returns a negative value indicating some sort of hard error condition at the
466 * <p>After this method returns zero, the system will then call
467 * {@link #getNextFullRestorePackage()} to begin the restore process for the next
468 * application, and the sequence begins again.
470 * <p>The transport should always close this socket when returning from this method.
471 * Do not cache this socket across multiple calls or you may leak file descriptors.
473 * @param socket The file descriptor that the transport will use for delivering the
474 * streamed archive. The transport must close this socket in all cases when returning
476 * @return {@link #NO_MORE_DATA} when no more data for the current package is available.
477 * A positive value indicates the presence of that many bytes to be delivered to the app.
478 * A value of zero indicates that no data was deliverable at this time, but the restore
479 * is still running and the caller should retry. {@link #TRANSPORT_PACKAGE_REJECTED}
480 * means that the current package's restore operation should be aborted, but that
481 * the transport itself is still in a good state and so a multiple-package restore
482 * sequence can still be continued. Any other negative return value is treated as a
483 * fatal error condition that aborts all further restore operations on the current dataset.
485 public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
490 * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM}
491 * data for restore, it will invoke this method to tell the transport that it should
492 * abandon the data download for the current package. The OS will then either call
493 * {@link #nextRestorePackage()} again to move on to restoring the next package in the
494 * set being iterated over, or will call {@link #finishRestore()} to shut down the restore
497 * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the
498 * current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious
499 * transport-level failure. If the transport reports an error here, the entire restore
500 * operation will immediately be finished with no further attempts to restore app data.
502 public int abortFullRestore() {
503 return BackupTransport.TRANSPORT_OK;
507 * Bridge between the actual IBackupTransport implementation and the stable API. If the
508 * binder interface needs to change, we use this layer to translate so that we can
509 * (if appropriate) decouple those framework-side changes from the BackupTransport
512 class TransportImpl extends IBackupTransport.Stub {
515 public String name() throws RemoteException {
516 return BackupTransport.this.name();
520 public Intent configurationIntent() throws RemoteException {
521 return BackupTransport.this.configurationIntent();
525 public String currentDestinationString() throws RemoteException {
526 return BackupTransport.this.currentDestinationString();
530 public Intent dataManagementIntent() {
531 return BackupTransport.this.dataManagementIntent();
535 public String dataManagementLabel() {
536 return BackupTransport.this.dataManagementLabel();
540 public String transportDirName() throws RemoteException {
541 return BackupTransport.this.transportDirName();
545 public long requestBackupTime() throws RemoteException {
546 return BackupTransport.this.requestBackupTime();
550 public int initializeDevice() throws RemoteException {
551 return BackupTransport.this.initializeDevice();
555 public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd)
556 throws RemoteException {
557 return BackupTransport.this.performBackup(packageInfo, inFd);
561 public int clearBackupData(PackageInfo packageInfo) throws RemoteException {
562 return BackupTransport.this.clearBackupData(packageInfo);
566 public int finishBackup() throws RemoteException {
567 return BackupTransport.this.finishBackup();
571 public RestoreSet[] getAvailableRestoreSets() throws RemoteException {
572 return BackupTransport.this.getAvailableRestoreSets();
576 public long getCurrentRestoreSet() throws RemoteException {
577 return BackupTransport.this.getCurrentRestoreSet();
581 public int startRestore(long token, PackageInfo[] packages) throws RemoteException {
582 return BackupTransport.this.startRestore(token, packages);
586 public RestoreDescription nextRestorePackage() throws RemoteException {
587 return BackupTransport.this.nextRestorePackage();
591 public int getRestoreData(ParcelFileDescriptor outFd) throws RemoteException {
592 return BackupTransport.this.getRestoreData(outFd);
596 public void finishRestore() throws RemoteException {
597 BackupTransport.this.finishRestore();
601 public long requestFullBackupTime() throws RemoteException {
602 return BackupTransport.this.requestFullBackupTime();
606 public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) throws RemoteException {
607 return BackupTransport.this.performFullBackup(targetPackage, socket);
611 public int checkFullBackupSize(long size) {
612 return BackupTransport.this.checkFullBackupSize(size);
616 public int sendBackupData(int numBytes) throws RemoteException {
617 return BackupTransport.this.sendBackupData(numBytes);
621 public void cancelFullBackup() throws RemoteException {
622 BackupTransport.this.cancelFullBackup();
626 public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
627 return BackupTransport.this.getNextFullRestoreDataChunk(socket);
631 public int abortFullRestore() {
632 return BackupTransport.this.abortFullRestore();