blob: 43b920a9b1804cca52c8744aebfe584dcbc1c133 [file] [log] [blame]
Joe Onorato1cf58742009-06-12 11:06:24 -07001/*
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
Christopher Tate45281862010-03-05 15:46:30 -080017package android.app.backup;
Joe Onorato1cf58742009-06-12 11:06:24 -070018
Joe Onorato1cf58742009-06-12 11:06:24 -070019import java.io.FileDescriptor;
20import java.io.IOException;
21
Christopher Tatee28290e2010-02-16 15:22:26 -080022/**
Scott Maind17da432010-04-29 21:42:58 -070023 * Provides the structured interface through which a {@link BackupAgent} reads
24 * information from the backup data set, via its
25 * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
Christopher Tate4e14a822010-04-08 12:54:23 -070026 * method. The data is presented as a set of "entities," each
27 * representing one named record as previously stored by the agent's
Scott Maind17da432010-04-29 21:42:58 -070028 * {@link BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
29 * onBackup()} implementation. An entity is composed of a descriptive header plus a
30 * byte array that holds the raw data saved in the remote backup.
Christopher Tate4e14a822010-04-08 12:54:23 -070031 * <p>
32 * The agent must consume every entity in the data stream, otherwise the
33 * restored state of the application will be incomplete.
Scott Maind17da432010-04-29 21:42:58 -070034 * <h3>Example</h3>
Christopher Tate4e14a822010-04-08 12:54:23 -070035 * <p>
36 * A typical
Scott Maind17da432010-04-29 21:42:58 -070037 * {@link BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
38 * onRestore()} implementation might be structured something like this:
Christopher Tate4e14a822010-04-08 12:54:23 -070039 * <pre>
Scott Maind17da432010-04-29 21:42:58 -070040 * public void onRestore(BackupDataInput data, int appVersionCode,
41 * ParcelFileDescriptor newState) {
42 * while (data.readNextHeader()) {
43 * String key = data.getKey();
44 * int dataSize = data.getDataSize();
Christopher Tate4e14a822010-04-08 12:54:23 -070045 *
Scott Maind17da432010-04-29 21:42:58 -070046 * if (key.equals(MY_BACKUP_KEY_ONE)) {
47 * // process this kind of record here
48 * byte[] buffer = new byte[dataSize];
49 * data.readEntityData(buffer, 0, dataSize); // reads the entire entity at once
Christopher Tate4e14a822010-04-08 12:54:23 -070050 *
Scott Maind17da432010-04-29 21:42:58 -070051 * // now 'buffer' holds the raw data and can be processed however
52 * // the agent wishes
53 * processBackupKeyOne(buffer);
54 * } else if (key.equals(MY_BACKUP_KEY_TO_IGNORE) {
55 * // a key we recognize but wish to discard
56 * data.skipEntityData();
57 * } // ... etc.
58 * }
Christopher Tate4e14a822010-04-08 12:54:23 -070059 * }</pre>
Christopher Tatee28290e2010-02-16 15:22:26 -080060 */
Joe Onorato1cf58742009-06-12 11:06:24 -070061public class BackupDataInput {
62 int mBackupReader;
63
64 private EntityHeader mHeader = new EntityHeader();
65 private boolean mHeaderReady;
66
67 private static class EntityHeader {
68 String key;
69 int dataSize;
70 }
71
Christopher Tatee28290e2010-02-16 15:22:26 -080072 /** @hide */
Joe Onorato1cf58742009-06-12 11:06:24 -070073 public BackupDataInput(FileDescriptor fd) {
74 if (fd == null) throw new NullPointerException();
75 mBackupReader = ctor(fd);
76 if (mBackupReader == 0) {
77 throw new RuntimeException("Native initialization failed with fd=" + fd);
78 }
79 }
80
Christopher Tatee28290e2010-02-16 15:22:26 -080081 /** @hide */
Joe Onorato1cf58742009-06-12 11:06:24 -070082 protected void finalize() throws Throwable {
83 try {
84 dtor(mBackupReader);
85 } finally {
86 super.finalize();
87 }
88 }
89
Christopher Tatee28290e2010-02-16 15:22:26 -080090 /**
Christopher Tate4e14a822010-04-08 12:54:23 -070091 * Extract the next entity header from the restore stream. After this method
92 * return success, the {@link #getKey()} and {@link #getDataSize()} methods can
93 * be used to inspect the entity that is now available for processing.
Christopher Tatee28290e2010-02-16 15:22:26 -080094 *
Christopher Tate4e14a822010-04-08 12:54:23 -070095 * @return <code>true</code> when there is an entity ready for consumption from the
96 * restore stream, <code>false</code> if the restore stream has been fully consumed.
Christopher Tatee28290e2010-02-16 15:22:26 -080097 * @throws IOException if an error occurred while reading the restore stream
98 */
Joe Onorato1cf58742009-06-12 11:06:24 -070099 public boolean readNextHeader() throws IOException {
100 int result = readNextHeader_native(mBackupReader, mHeader);
101 if (result == 0) {
102 // read successfully
103 mHeaderReady = true;
104 return true;
105 } else if (result > 0) {
106 // done
107 mHeaderReady = false;
108 return false;
109 } else {
110 // error
111 mHeaderReady = false;
Christopher Tate4e14a822010-04-08 12:54:23 -0700112 throw new IOException("failed: 0x" + Integer.toHexString(result));
Joe Onorato1cf58742009-06-12 11:06:24 -0700113 }
114 }
115
Christopher Tatee28290e2010-02-16 15:22:26 -0800116 /**
Christopher Tate4e14a822010-04-08 12:54:23 -0700117 * Report the key associated with the current entity in the restore stream
118 * @return the current entity's key string
Christopher Tatee28290e2010-02-16 15:22:26 -0800119 * @throws IllegalStateException if the next record header has not yet been read
120 */
Joe Onorato1cf58742009-06-12 11:06:24 -0700121 public String getKey() {
122 if (mHeaderReady) {
123 return mHeader.key;
124 } else {
Christopher Tate4e14a822010-04-08 12:54:23 -0700125 throw new IllegalStateException("Entity header not read");
Joe Onorato1cf58742009-06-12 11:06:24 -0700126 }
127 }
128
Christopher Tatee28290e2010-02-16 15:22:26 -0800129 /**
Christopher Tate4e14a822010-04-08 12:54:23 -0700130 * Report the size in bytes of the data associated with the current entity in the
Christopher Tatee28290e2010-02-16 15:22:26 -0800131 * restore stream.
132 *
133 * @return The size of the record's raw data, in bytes
134 * @throws IllegalStateException if the next record header has not yet been read
135 */
Joe Onorato1cf58742009-06-12 11:06:24 -0700136 public int getDataSize() {
137 if (mHeaderReady) {
138 return mHeader.dataSize;
139 } else {
Christopher Tate4e14a822010-04-08 12:54:23 -0700140 throw new IllegalStateException("Entity header not read");
Joe Onorato1cf58742009-06-12 11:06:24 -0700141 }
142 }
143
Christopher Tatee28290e2010-02-16 15:22:26 -0800144 /**
145 * Read a record's raw data from the restore stream. The record's header must first
146 * have been processed by the {@link #readNextHeader()} method. Multiple calls to
147 * this method may be made in order to process the data in chunks; not all of it
Christopher Tate4e14a822010-04-08 12:54:23 -0700148 * must be read in a single call. Once all of the raw data for the current entity
149 * has been read, further calls to this method will simply return zero.
Christopher Tatee28290e2010-02-16 15:22:26 -0800150 *
151 * @param data An allocated byte array of at least 'size' bytes
152 * @param offset Offset within the 'data' array at which the data will be placed
Christopher Tate4e14a822010-04-08 12:54:23 -0700153 * when read from the stream
154 * @param size The number of bytes to read in this pass
155 * @return The number of bytes of data read. Once all of the data for this entity
156 * has been read, further calls to this method will return zero.
Christopher Tatee28290e2010-02-16 15:22:26 -0800157 * @throws IOException if an error occurred when trying to read the restore data stream
158 */
Joe Onorato5f15d152009-06-16 16:31:35 -0400159 public int readEntityData(byte[] data, int offset, int size) throws IOException {
Joe Onorato1cf58742009-06-12 11:06:24 -0700160 if (mHeaderReady) {
Joe Onorato5f15d152009-06-16 16:31:35 -0400161 int result = readEntityData_native(mBackupReader, data, offset, size);
Joe Onorato1cf58742009-06-12 11:06:24 -0700162 if (result >= 0) {
163 return result;
164 } else {
165 throw new IOException("result=0x" + Integer.toHexString(result));
166 }
167 } else {
Christopher Tate4e14a822010-04-08 12:54:23 -0700168 throw new IllegalStateException("Entity header not read");
Joe Onorato1cf58742009-06-12 11:06:24 -0700169 }
170 }
171
Christopher Tatee28290e2010-02-16 15:22:26 -0800172 /**
Christopher Tate4e14a822010-04-08 12:54:23 -0700173 * Consume the current entity's data without extracting it into a buffer
Christopher Tate45281862010-03-05 15:46:30 -0800174 * for further processing. This allows a {@link android.app.backup.BackupAgent} to
Christopher Tatee28290e2010-02-16 15:22:26 -0800175 * efficiently discard obsolete or otherwise uninteresting records during the
176 * restore operation.
177 *
178 * @throws IOException if an error occurred when trying to read the restore data stream
179 */
Joe Onorato5f15d152009-06-16 16:31:35 -0400180 public void skipEntityData() throws IOException {
181 if (mHeaderReady) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700182 skipEntityData_native(mBackupReader);
Joe Onorato5f15d152009-06-16 16:31:35 -0400183 } else {
Christopher Tate4e14a822010-04-08 12:54:23 -0700184 throw new IllegalStateException("Entity header not read");
Joe Onorato5f15d152009-06-16 16:31:35 -0400185 }
186 }
187
Joe Onorato1cf58742009-06-12 11:06:24 -0700188 private native static int ctor(FileDescriptor fd);
189 private native static void dtor(int mBackupReader);
190
191 private native int readNextHeader_native(int mBackupReader, EntityHeader entity);
Joe Onorato5f15d152009-06-16 16:31:35 -0400192 private native int readEntityData_native(int mBackupReader, byte[] data, int offset, int size);
193 private native int skipEntityData_native(int mBackupReader);
Joe Onorato1cf58742009-06-12 11:06:24 -0700194}