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
17package android.app.backup;
18
19import android.annotation.SystemApi;
20import android.content.Intent;
21import android.content.pm.PackageInfo;
22import android.os.IBinder;
23import android.os.ParcelFileDescriptor;
24import android.os.RemoteException;
25
26import 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
35public 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.  If this method returns
217     * {@link #TRANSPORT_OK}, {@link #finishBackup} will then be called to ensure the data
218     * is sent and recorded successfully.
219     *
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)
235     */
236    public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd) {
237        return BackupTransport.TRANSPORT_ERROR;
238    }
239
240    // ------------------------------------------------------------------------------------
241    // Key/value dataset restore interfaces
242
243    /**
244     * Get the set of all backups currently available over this transport.
245     *
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).
248     **/
249    public RestoreSet[] getAvailableRestoreSets() {
250        return null;
251    }
252
253    /**
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.
257     *
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.
260     */
261    public long getCurrentRestoreSet() {
262        return 0;
263    }
264
265    /**
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.
269     *
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).
277     */
278    public int startRestore(long token, PackageInfo[] packages) {
279        return BackupTransport.TRANSPORT_ERROR;
280    }
281
282    /**
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.
286     *
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
290     * processed.
291     *
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.
294     *
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.
302     *
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.
308     */
309    public RestoreDescription nextRestorePackage() {
310        return null;
311    }
312
313    /**
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
317     * error.
318     *
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}.
321     */
322    public int getRestoreData(ParcelFileDescriptor outFd) {
323        return BackupTransport.TRANSPORT_ERROR;
324    }
325
326    /**
327     * End a restore session (aborting any in-process data transfer as necessary),
328     * freeing any resources and connections used during the restore process.
329     */
330    public void finishRestore() {
331        throw new UnsupportedOperationException(
332                "Transport finishRestore() not implemented");
333    }
334
335    // ------------------------------------------------------------------------------------
336    // Full backup interfaces
337
338    /**
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.
342     *
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.
345     *
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.
348     *
349     * @see #requestBackupTime()
350     */
351    public long requestFullBackupTime() {
352        return 0;
353    }
354
355    /**
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.
359     *
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.
364     *
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)}
369     * method.
370     *
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)}.
375     *
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.
379     *
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.
390     */
391    public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) {
392        return BackupTransport.TRANSPORT_PACKAGE_REJECTED;
393    }
394
395    /**
396     * Tells the transport to read {@code numBytes} bytes of data from the socket file
397     * descriptor provided in the {@link #performFullBackup(PackageInfo, ParcelFileDescriptor)}
398     * call, and deliver those bytes to the datastore.
399     *
400     * @param numBytes The number of bytes of tarball data available to be read from the
401     *    socket.
402     * @return TRANSPORT_OK on successful processing of the data; TRANSPORT_ERROR to
403     *    indicate a fatal error situation.  If an error is returned, the system will
404     *    call finishBackup() and stop attempting backups until after a backoff and retry
405     *    interval.
406     */
407    public int sendBackupData(int numBytes) {
408        return BackupTransport.TRANSPORT_ERROR;
409    }
410
411    /**
412     * Tells the transport to cancel the currently-ongoing full backup operation.  This
413     * will happen between {@link #performFullBackup()} and {@link #finishBackup()}
414     * if the OS needs to abort the backup operation for any reason, such as a crash in
415     * the application undergoing backup.
416     *
417     * <p>When it receives this call, the transport should discard any partial archive
418     * that it has stored so far.  If possible it should also roll back to the previous
419     * known-good archive in its datastore.
420     *
421     * <p>If the transport receives this callback, it will <em>not</em> receive a
422     * call to {@link #finishBackup()}.  It needs to tear down any ongoing backup state
423     * here.
424     */
425    public void cancelFullBackup() {
426        throw new UnsupportedOperationException(
427                "Transport cancelFullBackup() not implemented");
428    }
429
430    // ------------------------------------------------------------------------------------
431    // Full restore interfaces
432
433    /**
434     * Ask the transport to provide data for the "current" package being restored.  This
435     * is the package that was just reported by {@link #nextRestorePackage()} as having
436     * {@link RestoreDescription#TYPE_FULL_STREAM} data.
437     *
438     * The transport writes some data to the socket supplied to this call, and returns
439     * the number of bytes written.  The system will then read that many bytes and
440     * stream them to the application's agent for restore, then will call this method again
441     * to receive the next chunk of the archive.  This sequence will be repeated until the
442     * transport returns zero indicating that all of the package's data has been delivered
443     * (or returns a negative value indicating some sort of hard error condition at the
444     * transport level).
445     *
446     * <p>After this method returns zero, the system will then call
447     * {@link #getNextFullRestorePackage()} to begin the restore process for the next
448     * application, and the sequence begins again.
449     *
450     * <p>The transport should always close this socket when returning from this method.
451     * Do not cache this socket across multiple calls or you may leak file descriptors.
452     *
453     * @param socket The file descriptor that the transport will use for delivering the
454     *    streamed archive.  The transport must close this socket in all cases when returning
455     *    from this method.
456     * @return {@link #NO_MORE_DATA} when no more data for the current package is available.
457     *    A positive value indicates the presence of that many bytes to be delivered to the app.
458     *    A value of zero indicates that no data was deliverable at this time, but the restore
459     *    is still running and the caller should retry.  {@link #TRANSPORT_PACKAGE_REJECTED}
460     *    means that the current package's restore operation should be aborted, but that
461     *    the transport itself is still in a good state and so a multiple-package restore
462     *    sequence can still be continued.  Any other negative return value is treated as a
463     *    fatal error condition that aborts all further restore operations on the current dataset.
464     */
465    public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
466        return 0;
467    }
468
469    /**
470     * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM}
471     * data for restore, it will invoke this method to tell the transport that it should
472     * abandon the data download for the current package.  The OS will then either call
473     * {@link #nextRestorePackage()} again to move on to restoring the next package in the
474     * set being iterated over, or will call {@link #finishRestore()} to shut down the restore
475     * operation.
476     *
477     * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the
478     *    current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious
479     *    transport-level failure.  If the transport reports an error here, the entire restore
480     *    operation will immediately be finished with no further attempts to restore app data.
481     */
482    public int abortFullRestore() {
483        return BackupTransport.TRANSPORT_OK;
484    }
485
486    /**
487     * Bridge between the actual IBackupTransport implementation and the stable API.  If the
488     * binder interface needs to change, we use this layer to translate so that we can
489     * (if appropriate) decouple those framework-side changes from the BackupTransport
490     * implementations.
491     */
492    class TransportImpl extends IBackupTransport.Stub {
493
494        @Override
495        public String name() throws RemoteException {
496            return BackupTransport.this.name();
497        }
498
499        @Override
500        public Intent configurationIntent() throws RemoteException {
501            return BackupTransport.this.configurationIntent();
502        }
503
504        @Override
505        public String currentDestinationString() throws RemoteException {
506            return BackupTransport.this.currentDestinationString();
507        }
508
509        @Override
510        public Intent dataManagementIntent() {
511            return BackupTransport.this.dataManagementIntent();
512        }
513
514        @Override
515        public String dataManagementLabel() {
516            return BackupTransport.this.dataManagementLabel();
517        }
518
519        @Override
520        public String transportDirName() throws RemoteException {
521            return BackupTransport.this.transportDirName();
522        }
523
524        @Override
525        public long requestBackupTime() throws RemoteException {
526            return BackupTransport.this.requestBackupTime();
527        }
528
529        @Override
530        public int initializeDevice() throws RemoteException {
531            return BackupTransport.this.initializeDevice();
532        }
533
534        @Override
535        public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd)
536                throws RemoteException {
537            return BackupTransport.this.performBackup(packageInfo, inFd);
538        }
539
540        @Override
541        public int clearBackupData(PackageInfo packageInfo) throws RemoteException {
542            return BackupTransport.this.clearBackupData(packageInfo);
543        }
544
545        @Override
546        public int finishBackup() throws RemoteException {
547            return BackupTransport.this.finishBackup();
548        }
549
550        @Override
551        public RestoreSet[] getAvailableRestoreSets() throws RemoteException {
552            return BackupTransport.this.getAvailableRestoreSets();
553        }
554
555        @Override
556        public long getCurrentRestoreSet() throws RemoteException {
557            return BackupTransport.this.getCurrentRestoreSet();
558        }
559
560        @Override
561        public int startRestore(long token, PackageInfo[] packages) throws RemoteException {
562            return BackupTransport.this.startRestore(token, packages);
563        }
564
565        @Override
566        public RestoreDescription nextRestorePackage() throws RemoteException {
567            return BackupTransport.this.nextRestorePackage();
568        }
569
570        @Override
571        public int getRestoreData(ParcelFileDescriptor outFd) throws RemoteException {
572            return BackupTransport.this.getRestoreData(outFd);
573        }
574
575        @Override
576        public void finishRestore() throws RemoteException {
577            BackupTransport.this.finishRestore();
578        }
579
580        @Override
581        public long requestFullBackupTime() throws RemoteException {
582            return BackupTransport.this.requestFullBackupTime();
583        }
584
585        @Override
586        public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) throws RemoteException {
587            return BackupTransport.this.performFullBackup(targetPackage, socket);
588        }
589
590        @Override
591        public int sendBackupData(int numBytes) throws RemoteException {
592            return BackupTransport.this.sendBackupData(numBytes);
593        }
594
595        @Override
596        public void cancelFullBackup() throws RemoteException {
597            BackupTransport.this.cancelFullBackup();
598        }
599
600        @Override
601        public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
602            return BackupTransport.this.getNextFullRestoreDataChunk(socket);
603        }
604
605        @Override
606        public int abortFullRestore() {
607            return BackupTransport.this.abortFullRestore();
608        }
609    }
610}
611