BackupDataOutput.java revision 4e14a829129feee14ebe453f61a124784c870610
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.os.ParcelFileDescriptor;
20
21import java.io.FileDescriptor;
22import java.io.IOException;
23
24/**
25 * This class is the structured conduit through which a {@link BackupAgent} commits
26 * information to the current backup data set.  Data written for backup is presented
27 * as a set of "entities," key/value pairs in which each binary data record "value" is
28 * named with a string "key."
29 * <p>
30 * To commit a data record to the backup transport, the agent's
31 * {@link BackupAgent#onBackup(android.os.ParcelFileDescriptor, BackupDataOutput, android.os.ParcelFileDescriptor)}
32 * method first writes an "entity header" that supplies the key string for the record
33 * and the total size of the binary value for the record.  After the header has been
34 * written the agent then writes the binary entity value itself.  The entity value can
35 * be written in multiple chunks if desired, as long as the total count of bytes written
36 * matches what was supplied to {@link #writeEntityHeader(String, int)}.
37 * <p>
38 * Entity key strings are considered to be unique within a given application's backup
39 * data set.  If a new entity is written under an existing key string, its value will
40 * replace any previous value in the transport's remote data store.  A record can be
41 * removed entirely from the remote data set by writing a new entity header using the
42 * existing record's key, but supplying a negative <code>dataSize</code> parameter.
43 * When doing this the agent does not need to call {@link #writeEntityData(byte[], int)}.
44 * <p>
45 * <b>Example</b>
46 * <p>
47 * Here is an example illustrating a way to back up the value of a String variable
48 * called <code>mStringToBackUp</code>:
49 * <pre>
50 * static final String MY_STRING_KEY = "storedstring";
51 *
52 * public void {@link BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)}
53 *         throws IOException {
54 *     ...
55 *     byte[] stringBytes = mStringToBackUp.getBytes();
56 *     data.writeEntityHeader(MY_STRING_KEY, stringBytes.length);
57 *     data.writeEntityData(stringBytes, stringBytes.length);
58 *     ...
59 * }</pre>
60 *
61 * @see BackupAgent
62 */
63public class BackupDataOutput {
64    int mBackupWriter;
65
66    /** @hide */
67    public BackupDataOutput(FileDescriptor fd) {
68        if (fd == null) throw new NullPointerException();
69        mBackupWriter = ctor(fd);
70        if (mBackupWriter == 0) {
71            throw new RuntimeException("Native initialization failed with fd=" + fd);
72        }
73    }
74
75    /**
76     * Mark the beginning of one record in the backup data stream.
77     *
78     * @param key
79     * @param dataSize The size in bytes of this record's data.  Passing a dataSize
80     *    of -1 indicates that the record under this key should be deleted.
81     * @return The number of bytes written to the backup stream
82     * @throws IOException if the write failed
83     */
84    public int writeEntityHeader(String key, int dataSize) throws IOException {
85        int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
86        if (result >= 0) {
87            return result;
88        } else {
89            throw new IOException("result=0x" + Integer.toHexString(result));
90        }
91    }
92
93    /**
94     * Write a chunk of data under the current entity to the backup transport.
95     * @param data A raw data buffer to send
96     * @param size The number of bytes to be sent in this chunk
97     * @return the number of bytes written
98     * @throws IOException if the write failed
99     */
100    public int writeEntityData(byte[] data, int size) throws IOException {
101        int result = writeEntityData_native(mBackupWriter, data, size);
102        if (result >= 0) {
103            return result;
104        } else {
105            throw new IOException("result=0x" + Integer.toHexString(result));
106        }
107    }
108
109    /** @hide */
110    public void setKeyPrefix(String keyPrefix) {
111        setKeyPrefix_native(mBackupWriter, keyPrefix);
112    }
113
114    /** @hide */
115    protected void finalize() throws Throwable {
116        try {
117            dtor(mBackupWriter);
118        } finally {
119            super.finalize();
120        }
121    }
122
123    private native static int ctor(FileDescriptor fd);
124    private native static void dtor(int mBackupWriter);
125
126    private native static int writeEntityHeader_native(int mBackupWriter, String key, int dataSize);
127    private native static int writeEntityData_native(int mBackupWriter, byte[] data, int size);
128    private native static void setKeyPrefix_native(int mBackupWriter, String keyPrefix);
129}
130
131