11cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato/* 21cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * Copyright (C) 2009 The Android Open Source Project 31cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * 41cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * Licensed under the Apache License, Version 2.0 (the "License"); 51cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * you may not use this file except in compliance with the License. 61cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * You may obtain a copy of the License at 71cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * 81cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * http://www.apache.org/licenses/LICENSE-2.0 91cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * 101cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * Unless required by applicable law or agreed to in writing, software 111cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * distributed under the License is distributed on an "AS IS" BASIS, 121cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * See the License for the specific language governing permissions and 141cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato * limitations under the License. 151cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato */ 161cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 174528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tatepackage android.app.backup; 181cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 191cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onoratoimport java.io.FileDescriptor; 201cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onoratoimport java.io.IOException; 211cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 22e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate/** 23d17da43c82c4edb97514d6138bc208eeba321636Scott Main * Provides the structured interface through which a {@link BackupAgent} reads 24d17da43c82c4edb97514d6138bc208eeba321636Scott Main * information from the backup data set, via its 25d17da43c82c4edb97514d6138bc208eeba321636Scott Main * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()} 264e14a829129feee14ebe453f61a124784c870610Christopher Tate * method. The data is presented as a set of "entities," each 274e14a829129feee14ebe453f61a124784c870610Christopher Tate * representing one named record as previously stored by the agent's 28d17da43c82c4edb97514d6138bc208eeba321636Scott Main * {@link BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 29d17da43c82c4edb97514d6138bc208eeba321636Scott Main * onBackup()} implementation. An entity is composed of a descriptive header plus a 30d17da43c82c4edb97514d6138bc208eeba321636Scott Main * byte array that holds the raw data saved in the remote backup. 314e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p> 324e14a829129feee14ebe453f61a124784c870610Christopher Tate * The agent must consume every entity in the data stream, otherwise the 334e14a829129feee14ebe453f61a124784c870610Christopher Tate * restored state of the application will be incomplete. 34d17da43c82c4edb97514d6138bc208eeba321636Scott Main * <h3>Example</h3> 354e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p> 364e14a829129feee14ebe453f61a124784c870610Christopher Tate * A typical 37d17da43c82c4edb97514d6138bc208eeba321636Scott Main * {@link BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 38d17da43c82c4edb97514d6138bc208eeba321636Scott Main * onRestore()} implementation might be structured something like this: 394e14a829129feee14ebe453f61a124784c870610Christopher Tate * <pre> 40d17da43c82c4edb97514d6138bc208eeba321636Scott Main * public void onRestore(BackupDataInput data, int appVersionCode, 41d17da43c82c4edb97514d6138bc208eeba321636Scott Main * ParcelFileDescriptor newState) { 42d17da43c82c4edb97514d6138bc208eeba321636Scott Main * while (data.readNextHeader()) { 43d17da43c82c4edb97514d6138bc208eeba321636Scott Main * String key = data.getKey(); 44d17da43c82c4edb97514d6138bc208eeba321636Scott Main * int dataSize = data.getDataSize(); 454e14a829129feee14ebe453f61a124784c870610Christopher Tate * 46d17da43c82c4edb97514d6138bc208eeba321636Scott Main * if (key.equals(MY_BACKUP_KEY_ONE)) { 47d17da43c82c4edb97514d6138bc208eeba321636Scott Main * // process this kind of record here 48d17da43c82c4edb97514d6138bc208eeba321636Scott Main * byte[] buffer = new byte[dataSize]; 49d17da43c82c4edb97514d6138bc208eeba321636Scott Main * data.readEntityData(buffer, 0, dataSize); // reads the entire entity at once 504e14a829129feee14ebe453f61a124784c870610Christopher Tate * 51d17da43c82c4edb97514d6138bc208eeba321636Scott Main * // now 'buffer' holds the raw data and can be processed however 52d17da43c82c4edb97514d6138bc208eeba321636Scott Main * // the agent wishes 53d17da43c82c4edb97514d6138bc208eeba321636Scott Main * processBackupKeyOne(buffer); 54d17da43c82c4edb97514d6138bc208eeba321636Scott Main * } else if (key.equals(MY_BACKUP_KEY_TO_IGNORE) { 55d17da43c82c4edb97514d6138bc208eeba321636Scott Main * // a key we recognize but wish to discard 56d17da43c82c4edb97514d6138bc208eeba321636Scott Main * data.skipEntityData(); 57d17da43c82c4edb97514d6138bc208eeba321636Scott Main * } // ... etc. 58d17da43c82c4edb97514d6138bc208eeba321636Scott Main * } 594e14a829129feee14ebe453f61a124784c870610Christopher Tate * }</pre> 60e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 611cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onoratopublic class BackupDataInput { 621cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato int mBackupReader; 631cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 641cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato private EntityHeader mHeader = new EntityHeader(); 651cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato private boolean mHeaderReady; 661cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 671cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato private static class EntityHeader { 681cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato String key; 691cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato int dataSize; 701cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 711cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 72e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** @hide */ 731cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato public BackupDataInput(FileDescriptor fd) { 741cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (fd == null) throw new NullPointerException(); 751cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato mBackupReader = ctor(fd); 761cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (mBackupReader == 0) { 771cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato throw new RuntimeException("Native initialization failed with fd=" + fd); 781cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 791cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 801cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 81e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** @hide */ 821cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato protected void finalize() throws Throwable { 831cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato try { 841cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato dtor(mBackupReader); 851cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } finally { 861cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato super.finalize(); 871cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 881cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 891cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 90e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 914e14a829129feee14ebe453f61a124784c870610Christopher Tate * Extract the next entity header from the restore stream. After this method 924e14a829129feee14ebe453f61a124784c870610Christopher Tate * return success, the {@link #getKey()} and {@link #getDataSize()} methods can 934e14a829129feee14ebe453f61a124784c870610Christopher Tate * be used to inspect the entity that is now available for processing. 94e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * 954e14a829129feee14ebe453f61a124784c870610Christopher Tate * @return <code>true</code> when there is an entity ready for consumption from the 964e14a829129feee14ebe453f61a124784c870610Christopher Tate * restore stream, <code>false</code> if the restore stream has been fully consumed. 97e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @throws IOException if an error occurred while reading the restore stream 98e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 991cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato public boolean readNextHeader() throws IOException { 1001cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato int result = readNextHeader_native(mBackupReader, mHeader); 1011cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (result == 0) { 1021cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato // read successfully 1031cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato mHeaderReady = true; 1041cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato return true; 1051cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else if (result > 0) { 1061cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato // done 1071cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato mHeaderReady = false; 1081cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato return false; 1091cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else { 1101cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato // error 1111cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato mHeaderReady = false; 1124e14a829129feee14ebe453f61a124784c870610Christopher Tate throw new IOException("failed: 0x" + Integer.toHexString(result)); 1131cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1141cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1151cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 116e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 1174e14a829129feee14ebe453f61a124784c870610Christopher Tate * Report the key associated with the current entity in the restore stream 1184e14a829129feee14ebe453f61a124784c870610Christopher Tate * @return the current entity's key string 119e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @throws IllegalStateException if the next record header has not yet been read 120e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 1211cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato public String getKey() { 1221cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (mHeaderReady) { 1231cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato return mHeader.key; 1241cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else { 1254e14a829129feee14ebe453f61a124784c870610Christopher Tate throw new IllegalStateException("Entity header not read"); 1261cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1271cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1281cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 129e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 1304e14a829129feee14ebe453f61a124784c870610Christopher Tate * Report the size in bytes of the data associated with the current entity in the 131e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * restore stream. 132e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * 133e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @return The size of the record's raw data, in bytes 134e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @throws IllegalStateException if the next record header has not yet been read 135e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 1361cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato public int getDataSize() { 1371cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (mHeaderReady) { 1381cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato return mHeader.dataSize; 1391cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else { 1404e14a829129feee14ebe453f61a124784c870610Christopher Tate throw new IllegalStateException("Entity header not read"); 1411cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1421cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1431cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 144e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 145e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * Read a record's raw data from the restore stream. The record's header must first 146e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * have been processed by the {@link #readNextHeader()} method. Multiple calls to 147e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * this method may be made in order to process the data in chunks; not all of it 1484e14a829129feee14ebe453f61a124784c870610Christopher Tate * must be read in a single call. Once all of the raw data for the current entity 1494e14a829129feee14ebe453f61a124784c870610Christopher Tate * has been read, further calls to this method will simply return zero. 150e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * 151e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @param data An allocated byte array of at least 'size' bytes 152e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @param offset Offset within the 'data' array at which the data will be placed 1534e14a829129feee14ebe453f61a124784c870610Christopher Tate * when read from the stream 1544e14a829129feee14ebe453f61a124784c870610Christopher Tate * @param size The number of bytes to read in this pass 1554e14a829129feee14ebe453f61a124784c870610Christopher Tate * @return The number of bytes of data read. Once all of the data for this entity 1564e14a829129feee14ebe453f61a124784c870610Christopher Tate * has been read, further calls to this method will return zero. 157e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @throws IOException if an error occurred when trying to read the restore data stream 158e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 1595f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato public int readEntityData(byte[] data, int offset, int size) throws IOException { 1601cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (mHeaderReady) { 1615f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato int result = readEntityData_native(mBackupReader, data, offset, size); 1621cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (result >= 0) { 1631cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato return result; 1641cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else { 1651cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato throw new IOException("result=0x" + Integer.toHexString(result)); 1661cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1671cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else { 1684e14a829129feee14ebe453f61a124784c870610Christopher Tate throw new IllegalStateException("Entity header not read"); 1691cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1701cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1711cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 172e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 1734e14a829129feee14ebe453f61a124784c870610Christopher Tate * Consume the current entity's data without extracting it into a buffer 1744528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tate * for further processing. This allows a {@link android.app.backup.BackupAgent} to 175e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * efficiently discard obsolete or otherwise uninteresting records during the 176e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * restore operation. 177e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * 178e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @throws IOException if an error occurred when trying to read the restore data stream 179e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 1805f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato public void skipEntityData() throws IOException { 1815f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato if (mHeaderReady) { 1829bb8fd77c8dc177aab9ac96bed4f55972dcda70aJoe Onorato skipEntityData_native(mBackupReader); 1835f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato } else { 1844e14a829129feee14ebe453f61a124784c870610Christopher Tate throw new IllegalStateException("Entity header not read"); 1855f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato } 1865f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato } 1875f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato 1881cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato private native static int ctor(FileDescriptor fd); 1891cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato private native static void dtor(int mBackupReader); 1901cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 1911cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato private native int readNextHeader_native(int mBackupReader, EntityHeader entity); 1925f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato private native int readEntityData_native(int mBackupReader, byte[] data, int offset, int size); 1935f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato private native int skipEntityData_native(int mBackupReader); 1941cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato} 195