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