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