• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.backup;
18 
19 import android.annotation.SystemApi;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.os.Build;
22 import android.os.ParcelFileDescriptor;
23 
24 import java.io.FileDescriptor;
25 import java.io.IOException;
26 
27 /**
28  * Provides the structured interface through which a {@link BackupAgent} commits
29  * information to the backup data set, via its {@link
30  * BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
31  * onBackup()} method.  Data written for backup is presented
32  * as a set of "entities," key/value pairs in which each binary data record "value" is
33  * named with a string "key."
34  * <p>
35  * To commit a data record to the backup transport, the agent's
36  * {@link BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
37  * onBackup()} method first writes an "entity header" that supplies the key string for the record
38  * and the total size of the binary value for the record.  After the header has been
39  * written, the agent then writes the binary entity value itself.  The entity value can
40  * be written in multiple chunks if desired, as long as the total count of bytes written
41  * matches what was supplied to {@link #writeEntityHeader(String, int) writeEntityHeader()}.
42  * <p>
43  * Entity key strings are considered to be unique within a given application's backup
44  * data set. If a backup agent writes a new entity under an existing key string, its value will
45  * replace any previous value in the transport's remote data store.  You can remove a record
46  * entirely from the remote data set by writing a new entity header using the
47  * existing record's key, but supplying a negative <code>dataSize</code> parameter.
48  * When you do so, the agent does not need to call {@link #writeEntityData(byte[], int)}.
49  * <h3>Example</h3>
50  * <p>
51  * Here is an example illustrating a way to back up the value of a String variable
52  * called <code>mStringToBackUp</code>:
53  * <pre>
54  * static final String MY_STRING_KEY = "storedstring";
55  *
56  * public void {@link BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)}
57  *         throws IOException {
58  *     ...
59  *     byte[] stringBytes = mStringToBackUp.getBytes();
60  *     data.writeEntityHeader(MY_STRING_KEY, stringBytes.length);
61  *     data.writeEntityData(stringBytes, stringBytes.length);
62  *     ...
63  * }</pre>
64  *
65  * @see BackupAgent
66  */
67 public class BackupDataOutput {
68 
69     private final long mQuota;
70     private final int mTransportFlags;
71 
72     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
73     long mBackupWriter;
74 
75     /**
76      * Construct a BackupDataOutput purely for data-stream manipulation.  This instance will
77      * not report usable quota information.
78      * @hide */
79     @SystemApi
BackupDataOutput(FileDescriptor fd)80     public BackupDataOutput(FileDescriptor fd) {
81         this(fd, /*quota=*/ -1, /*transportFlags=*/ 0);
82     }
83 
84     /** @hide */
85     @SystemApi
BackupDataOutput(FileDescriptor fd, long quota)86     public BackupDataOutput(FileDescriptor fd, long quota) {
87         this(fd, quota, /*transportFlags=*/ 0);
88     }
89 
90     /** @hide */
BackupDataOutput(FileDescriptor fd, long quota, int transportFlags)91     public BackupDataOutput(FileDescriptor fd, long quota, int transportFlags) {
92         if (fd == null) throw new NullPointerException();
93         mQuota = quota;
94         mTransportFlags = transportFlags;
95         mBackupWriter = ctor(fd);
96         if (mBackupWriter == 0) {
97             throw new RuntimeException("Native initialization failed with fd=" + fd);
98         }
99     }
100 
101     /**
102      * Returns the quota in bytes for the application's current backup operation.  The
103      * value can vary for each operation.
104      *
105      * @see FullBackupDataOutput#getQuota()
106      */
getQuota()107     public long getQuota() {
108         return mQuota;
109     }
110 
111     /**
112      * Returns flags with additional information about the backup transport. For supported flags see
113      * {@link android.app.backup.BackupAgent}
114      *
115      * @see FullBackupDataOutput#getTransportFlags()
116      */
getTransportFlags()117     public int getTransportFlags() {
118         return mTransportFlags;
119     }
120 
121     /**
122      * Mark the beginning of one record in the backup data stream. This must be called before
123      * {@link #writeEntityData}.
124      * @param key A string key that uniquely identifies the data record within the application.
125      *    Keys whose first character is \uFF00 or higher are not valid.
126      * @param dataSize The size in bytes of this record's data.  Passing a dataSize
127      *    of -1 indicates that the record under this key should be deleted.
128      * @return The number of bytes written to the backup stream
129      * @throws IOException if the write failed
130      */
writeEntityHeader(String key, int dataSize)131     public int writeEntityHeader(String key, int dataSize) throws IOException {
132         int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
133         if (result >= 0) {
134             return result;
135         } else {
136             throw new IOException("result=0x" + Integer.toHexString(result));
137         }
138     }
139 
140     /**
141      * Write a chunk of data under the current entity to the backup transport.
142      * @param data A raw data buffer to send
143      * @param size The number of bytes to be sent in this chunk
144      * @return the number of bytes written
145      * @throws IOException if the write failed
146      */
writeEntityData(byte[] data, int size)147     public int writeEntityData(byte[] data, int size) throws IOException {
148         int result = writeEntityData_native(mBackupWriter, data, size);
149         if (result >= 0) {
150             return result;
151         } else {
152             throw new IOException("result=0x" + Integer.toHexString(result));
153         }
154     }
155 
156     /** @hide */
setKeyPrefix(String keyPrefix)157     public void setKeyPrefix(String keyPrefix) {
158         setKeyPrefix_native(mBackupWriter, keyPrefix);
159     }
160 
161     /** @hide */
162     @Override
finalize()163     protected void finalize() throws Throwable {
164         try {
165             dtor(mBackupWriter);
166         } finally {
167             super.finalize();
168         }
169     }
170 
ctor(FileDescriptor fd)171     private native static long ctor(FileDescriptor fd);
dtor(long mBackupWriter)172     private native static void dtor(long mBackupWriter);
173 
writeEntityHeader_native(long mBackupWriter, String key, int dataSize)174     private native static int writeEntityHeader_native(long mBackupWriter, String key, int dataSize);
writeEntityData_native(long mBackupWriter, byte[] data, int size)175     private native static int writeEntityData_native(long mBackupWriter, byte[] data, int size);
setKeyPrefix_native(long mBackupWriter, String keyPrefix)176     private native static void setKeyPrefix_native(long mBackupWriter, String keyPrefix);
177 }
178 
179