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