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 19ff31addb9b767496ba5c907513be172779eadfc5areteimport android.annotation.SystemApi; 20ff31addb9b767496ba5c907513be172779eadfc5arete 211cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onoratoimport java.io.FileDescriptor; 221cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onoratoimport java.io.IOException; 231cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 24e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate/** 25d17da43c82c4edb97514d6138bc208eeba321636Scott Main * Provides the structured interface through which a {@link BackupAgent} reads 26d17da43c82c4edb97514d6138bc208eeba321636Scott Main * information from the backup data set, via its 27d17da43c82c4edb97514d6138bc208eeba321636Scott Main * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()} 284e14a829129feee14ebe453f61a124784c870610Christopher Tate * method. The data is presented as a set of "entities," each 294e14a829129feee14ebe453f61a124784c870610Christopher Tate * representing one named record as previously stored by the agent's 30d17da43c82c4edb97514d6138bc208eeba321636Scott Main * {@link BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 31d17da43c82c4edb97514d6138bc208eeba321636Scott Main * onBackup()} implementation. An entity is composed of a descriptive header plus a 32d17da43c82c4edb97514d6138bc208eeba321636Scott Main * byte array that holds the raw data saved in the remote backup. 334e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p> 344e14a829129feee14ebe453f61a124784c870610Christopher Tate * The agent must consume every entity in the data stream, otherwise the 354e14a829129feee14ebe453f61a124784c870610Christopher Tate * restored state of the application will be incomplete. 36d17da43c82c4edb97514d6138bc208eeba321636Scott Main * <h3>Example</h3> 374e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p> 384e14a829129feee14ebe453f61a124784c870610Christopher Tate * A typical 39d17da43c82c4edb97514d6138bc208eeba321636Scott Main * {@link BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 40d17da43c82c4edb97514d6138bc208eeba321636Scott Main * onRestore()} implementation might be structured something like this: 414e14a829129feee14ebe453f61a124784c870610Christopher Tate * <pre> 42d17da43c82c4edb97514d6138bc208eeba321636Scott Main * public void onRestore(BackupDataInput data, int appVersionCode, 43d17da43c82c4edb97514d6138bc208eeba321636Scott Main * ParcelFileDescriptor newState) { 44d17da43c82c4edb97514d6138bc208eeba321636Scott Main * while (data.readNextHeader()) { 45d17da43c82c4edb97514d6138bc208eeba321636Scott Main * String key = data.getKey(); 46d17da43c82c4edb97514d6138bc208eeba321636Scott Main * int dataSize = data.getDataSize(); 474e14a829129feee14ebe453f61a124784c870610Christopher Tate * 48d17da43c82c4edb97514d6138bc208eeba321636Scott Main * if (key.equals(MY_BACKUP_KEY_ONE)) { 49d17da43c82c4edb97514d6138bc208eeba321636Scott Main * // process this kind of record here 50d17da43c82c4edb97514d6138bc208eeba321636Scott Main * byte[] buffer = new byte[dataSize]; 51d17da43c82c4edb97514d6138bc208eeba321636Scott Main * data.readEntityData(buffer, 0, dataSize); // reads the entire entity at once 524e14a829129feee14ebe453f61a124784c870610Christopher Tate * 53d17da43c82c4edb97514d6138bc208eeba321636Scott Main * // now 'buffer' holds the raw data and can be processed however 54d17da43c82c4edb97514d6138bc208eeba321636Scott Main * // the agent wishes 55d17da43c82c4edb97514d6138bc208eeba321636Scott Main * processBackupKeyOne(buffer); 56d17da43c82c4edb97514d6138bc208eeba321636Scott Main * } else if (key.equals(MY_BACKUP_KEY_TO_IGNORE) { 57d17da43c82c4edb97514d6138bc208eeba321636Scott Main * // a key we recognize but wish to discard 58d17da43c82c4edb97514d6138bc208eeba321636Scott Main * data.skipEntityData(); 59d17da43c82c4edb97514d6138bc208eeba321636Scott Main * } // ... etc. 60d17da43c82c4edb97514d6138bc208eeba321636Scott Main * } 614e14a829129feee14ebe453f61a124784c870610Christopher Tate * }</pre> 62e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 631cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onoratopublic class BackupDataInput { 6458b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat long mBackupReader; 651cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 661cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato private EntityHeader mHeader = new EntityHeader(); 671cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato private boolean mHeaderReady; 681cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 691cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato private static class EntityHeader { 701cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato String key; 711cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato int dataSize; 721cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 731cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 74e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** @hide */ 75ff31addb9b767496ba5c907513be172779eadfc5arete @SystemApi 761cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato public BackupDataInput(FileDescriptor fd) { 771cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (fd == null) throw new NullPointerException(); 781cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato mBackupReader = ctor(fd); 791cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (mBackupReader == 0) { 801cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato throw new RuntimeException("Native initialization failed with fd=" + fd); 811cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 821cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 831cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 84e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** @hide */ 85ff31addb9b767496ba5c907513be172779eadfc5arete @Override 861cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato protected void finalize() throws Throwable { 871cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato try { 881cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato dtor(mBackupReader); 891cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } finally { 901cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato super.finalize(); 911cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 921cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 931cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 94e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 954e14a829129feee14ebe453f61a124784c870610Christopher Tate * Extract the next entity header from the restore stream. After this method 964e14a829129feee14ebe453f61a124784c870610Christopher Tate * return success, the {@link #getKey()} and {@link #getDataSize()} methods can 974e14a829129feee14ebe453f61a124784c870610Christopher Tate * be used to inspect the entity that is now available for processing. 98e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * 994e14a829129feee14ebe453f61a124784c870610Christopher Tate * @return <code>true</code> when there is an entity ready for consumption from the 1004e14a829129feee14ebe453f61a124784c870610Christopher Tate * restore stream, <code>false</code> if the restore stream has been fully consumed. 101e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @throws IOException if an error occurred while reading the restore stream 102e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 1031cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato public boolean readNextHeader() throws IOException { 1041cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato int result = readNextHeader_native(mBackupReader, mHeader); 1051cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (result == 0) { 1061cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato // read successfully 1071cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato mHeaderReady = true; 1081cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato return true; 1091cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else if (result > 0) { 1101cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato // done 1111cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato mHeaderReady = false; 1121cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato return false; 1131cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else { 1141cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato // error 1151cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato mHeaderReady = false; 1164e14a829129feee14ebe453f61a124784c870610Christopher Tate throw new IOException("failed: 0x" + Integer.toHexString(result)); 1171cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1181cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1191cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 120e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 1214e14a829129feee14ebe453f61a124784c870610Christopher Tate * Report the key associated with the current entity in the restore stream 1224e14a829129feee14ebe453f61a124784c870610Christopher Tate * @return the current entity's key string 123e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @throws IllegalStateException if the next record header has not yet been read 124e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 1251cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato public String getKey() { 1261cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (mHeaderReady) { 1271cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato return mHeader.key; 1281cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else { 1294e14a829129feee14ebe453f61a124784c870610Christopher Tate throw new IllegalStateException("Entity header not read"); 1301cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1311cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1321cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 133e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 1344e14a829129feee14ebe453f61a124784c870610Christopher Tate * Report the size in bytes of the data associated with the current entity in the 135e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * restore stream. 136e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * 137e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @return The size of the record's raw data, in bytes 138e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @throws IllegalStateException if the next record header has not yet been read 139e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 1401cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato public int getDataSize() { 1411cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (mHeaderReady) { 1421cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato return mHeader.dataSize; 1431cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else { 1444e14a829129feee14ebe453f61a124784c870610Christopher Tate throw new IllegalStateException("Entity header not read"); 1451cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1461cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1471cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 148e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 149e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * Read a record's raw data from the restore stream. The record's header must first 150e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * have been processed by the {@link #readNextHeader()} method. Multiple calls to 151e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * this method may be made in order to process the data in chunks; not all of it 1524e14a829129feee14ebe453f61a124784c870610Christopher Tate * must be read in a single call. Once all of the raw data for the current entity 1534e14a829129feee14ebe453f61a124784c870610Christopher Tate * has been read, further calls to this method will simply return zero. 154e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * 155e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @param data An allocated byte array of at least 'size' bytes 156e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @param offset Offset within the 'data' array at which the data will be placed 1574e14a829129feee14ebe453f61a124784c870610Christopher Tate * when read from the stream 1584e14a829129feee14ebe453f61a124784c870610Christopher Tate * @param size The number of bytes to read in this pass 1594e14a829129feee14ebe453f61a124784c870610Christopher Tate * @return The number of bytes of data read. Once all of the data for this entity 1604e14a829129feee14ebe453f61a124784c870610Christopher Tate * has been read, further calls to this method will return zero. 161e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @throws IOException if an error occurred when trying to read the restore data stream 162e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 1635f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato public int readEntityData(byte[] data, int offset, int size) throws IOException { 1641cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (mHeaderReady) { 1655f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato int result = readEntityData_native(mBackupReader, data, offset, size); 1661cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato if (result >= 0) { 1671cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato return result; 1681cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else { 1691cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato throw new IOException("result=0x" + Integer.toHexString(result)); 1701cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1711cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } else { 1724e14a829129feee14ebe453f61a124784c870610Christopher Tate throw new IllegalStateException("Entity header not read"); 1731cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1741cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 1751cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 176e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 1774e14a829129feee14ebe453f61a124784c870610Christopher Tate * Consume the current entity's data without extracting it into a buffer 1784528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tate * for further processing. This allows a {@link android.app.backup.BackupAgent} to 179e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * efficiently discard obsolete or otherwise uninteresting records during the 180e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * restore operation. 181ff31addb9b767496ba5c907513be172779eadfc5arete * 182e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * @throws IOException if an error occurred when trying to read the restore data stream 183e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 1845f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato public void skipEntityData() throws IOException { 1855f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato if (mHeaderReady) { 1869bb8fd77c8dc177aab9ac96bed4f55972dcda70aJoe Onorato skipEntityData_native(mBackupReader); 1875f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato } else { 1884e14a829129feee14ebe453f61a124784c870610Christopher Tate throw new IllegalStateException("Entity header not read"); 1895f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato } 1905f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato } 1915f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato 19258b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat private native static long ctor(FileDescriptor fd); 19358b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat private native static void dtor(long mBackupReader); 1941cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 19558b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat private native int readNextHeader_native(long mBackupReader, EntityHeader entity); 19658b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat private native int readEntityData_native(long mBackupReader, byte[] data, int offset, int size); 19758b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat private native int skipEntityData_native(long mBackupReader); 1981cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato} 199