BackupDataOutput.java revision adfe8b86e9178a553b6db9722340fa4ff5201cf1
1b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato/*
2b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * Copyright (C) 2009 The Android Open Source Project
3b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato *
4b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * Licensed under the Apache License, Version 2.0 (the "License");
5b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * you may not use this file except in compliance with the License.
6b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * You may obtain a copy of the License at
7b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato *
8b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato *      http://www.apache.org/licenses/LICENSE-2.0
9b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato *
10b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * Unless required by applicable law or agreed to in writing, software
11b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * distributed under the License is distributed on an "AS IS" BASIS,
12b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * See the License for the specific language governing permissions and
14b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * limitations under the License.
15b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato */
16b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato
174528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tatepackage android.app.backup;
18b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato
194e14a829129feee14ebe453f61a124784c870610Christopher Tateimport android.os.ParcelFileDescriptor;
20adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tateimport android.os.Process;
214e14a829129feee14ebe453f61a124784c870610Christopher Tate
22b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onoratoimport java.io.FileDescriptor;
231cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onoratoimport java.io.IOException;
24b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato
25e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate/**
26d17da43c82c4edb97514d6138bc208eeba321636Scott Main * Provides the structured interface through which a {@link BackupAgent} commits
27d17da43c82c4edb97514d6138bc208eeba321636Scott Main * information to the backup data set, via its {@link
28d17da43c82c4edb97514d6138bc208eeba321636Scott Main * BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
29d17da43c82c4edb97514d6138bc208eeba321636Scott Main * onBackup()} method.  Data written for backup is presented
304e14a829129feee14ebe453f61a124784c870610Christopher Tate * as a set of "entities," key/value pairs in which each binary data record "value" is
314e14a829129feee14ebe453f61a124784c870610Christopher Tate * named with a string "key."
324e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
334e14a829129feee14ebe453f61a124784c870610Christopher Tate * To commit a data record to the backup transport, the agent's
34d17da43c82c4edb97514d6138bc208eeba321636Scott Main * {@link BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
35d17da43c82c4edb97514d6138bc208eeba321636Scott Main * onBackup()} method first writes an "entity header" that supplies the key string for the record
364e14a829129feee14ebe453f61a124784c870610Christopher Tate * and the total size of the binary value for the record.  After the header has been
37d17da43c82c4edb97514d6138bc208eeba321636Scott Main * written, the agent then writes the binary entity value itself.  The entity value can
384e14a829129feee14ebe453f61a124784c870610Christopher Tate * be written in multiple chunks if desired, as long as the total count of bytes written
39d17da43c82c4edb97514d6138bc208eeba321636Scott Main * matches what was supplied to {@link #writeEntityHeader(String, int) writeEntityHeader()}.
404e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
414e14a829129feee14ebe453f61a124784c870610Christopher Tate * Entity key strings are considered to be unique within a given application's backup
42d17da43c82c4edb97514d6138bc208eeba321636Scott Main * data set. If a backup agent writes a new entity under an existing key string, its value will
43d17da43c82c4edb97514d6138bc208eeba321636Scott Main * replace any previous value in the transport's remote data store.  You can remove a record
44d17da43c82c4edb97514d6138bc208eeba321636Scott Main * entirely from the remote data set by writing a new entity header using the
454e14a829129feee14ebe453f61a124784c870610Christopher Tate * existing record's key, but supplying a negative <code>dataSize</code> parameter.
46d17da43c82c4edb97514d6138bc208eeba321636Scott Main * When you do so, the agent does not need to call {@link #writeEntityData(byte[], int)}.
47d17da43c82c4edb97514d6138bc208eeba321636Scott Main * <h3>Example</h3>
484e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
494e14a829129feee14ebe453f61a124784c870610Christopher Tate * Here is an example illustrating a way to back up the value of a String variable
504e14a829129feee14ebe453f61a124784c870610Christopher Tate * called <code>mStringToBackUp</code>:
514e14a829129feee14ebe453f61a124784c870610Christopher Tate * <pre>
524e14a829129feee14ebe453f61a124784c870610Christopher Tate * static final String MY_STRING_KEY = "storedstring";
534e14a829129feee14ebe453f61a124784c870610Christopher Tate *
544e14a829129feee14ebe453f61a124784c870610Christopher Tate * public void {@link BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)}
554e14a829129feee14ebe453f61a124784c870610Christopher Tate *         throws IOException {
564e14a829129feee14ebe453f61a124784c870610Christopher Tate *     ...
574e14a829129feee14ebe453f61a124784c870610Christopher Tate *     byte[] stringBytes = mStringToBackUp.getBytes();
584e14a829129feee14ebe453f61a124784c870610Christopher Tate *     data.writeEntityHeader(MY_STRING_KEY, stringBytes.length);
594e14a829129feee14ebe453f61a124784c870610Christopher Tate *     data.writeEntityData(stringBytes, stringBytes.length);
604e14a829129feee14ebe453f61a124784c870610Christopher Tate *     ...
614e14a829129feee14ebe453f61a124784c870610Christopher Tate * }</pre>
624e14a829129feee14ebe453f61a124784c870610Christopher Tate *
634e14a829129feee14ebe453f61a124784c870610Christopher Tate * @see BackupAgent
64e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */
65b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onoratopublic class BackupDataOutput {
6658b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat    long mBackupWriter;
67b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato
68e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate    /** @hide */
6983248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato    public BackupDataOutput(FileDescriptor fd) {
70d2110dbce071a236b6176de344ca797b737542ebJoe Onorato        if (fd == null) throw new NullPointerException();
71d2110dbce071a236b6176de344ca797b737542ebJoe Onorato        mBackupWriter = ctor(fd);
72d2110dbce071a236b6176de344ca797b737542ebJoe Onorato        if (mBackupWriter == 0) {
73d2110dbce071a236b6176de344ca797b737542ebJoe Onorato            throw new RuntimeException("Native initialization failed with fd=" + fd);
74d2110dbce071a236b6176de344ca797b737542ebJoe Onorato        }
75b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato    }
76b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato
77e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate    /**
78d17da43c82c4edb97514d6138bc208eeba321636Scott Main     * Mark the beginning of one record in the backup data stream. This must be called before
79d17da43c82c4edb97514d6138bc208eeba321636Scott Main     * {@link #writeEntityData}.
80adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate     * @param key A string key that uniquely identifies the data record within the application.
81adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate     *    Keys whose first character is \uFF00 or higher are not valid.
82e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * @param dataSize The size in bytes of this record's data.  Passing a dataSize
83e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     *    of -1 indicates that the record under this key should be deleted.
84e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * @return The number of bytes written to the backup stream
85e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * @throws IOException if the write failed
86e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     */
871cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato    public int writeEntityHeader(String key, int dataSize) throws IOException {
88adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        if (key != null && key.charAt(0) >= 0xff00) {
89adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            if (Process.myUid() != Process.SYSTEM_UID) {
90adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                throw new IllegalArgumentException("Invalid key " + key);
91adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
92adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
931cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
941cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        if (result >= 0) {
951cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato            return result;
961cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        } else {
971cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato            throw new IOException("result=0x" + Integer.toHexString(result));
981cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        }
991cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato    }
1001cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato
101e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate    /**
102e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * Write a chunk of data under the current entity to the backup transport.
103e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * @param data A raw data buffer to send
104e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * @param size The number of bytes to be sent in this chunk
105e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * @return the number of bytes written
106e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * @throws IOException if the write failed
107e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     */
1081cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato    public int writeEntityData(byte[] data, int size) throws IOException {
1091cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        int result = writeEntityData_native(mBackupWriter, data, size);
1101cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        if (result >= 0) {
1111cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato            return result;
1121cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        } else {
1131cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato            throw new IOException("result=0x" + Integer.toHexString(result));
1141cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        }
1151cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato    }
1161cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato
117fc922f115325371aaadd4e423472476303039a72Christopher Tate    /** @hide */
11806290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato    public void setKeyPrefix(String keyPrefix) {
11906290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato        setKeyPrefix_native(mBackupWriter, keyPrefix);
12006290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato    }
12106290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato
122e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate    /** @hide */
123d2110dbce071a236b6176de344ca797b737542ebJoe Onorato    protected void finalize() throws Throwable {
124d2110dbce071a236b6176de344ca797b737542ebJoe Onorato        try {
125d2110dbce071a236b6176de344ca797b737542ebJoe Onorato            dtor(mBackupWriter);
126d2110dbce071a236b6176de344ca797b737542ebJoe Onorato        } finally {
127d2110dbce071a236b6176de344ca797b737542ebJoe Onorato            super.finalize();
128d2110dbce071a236b6176de344ca797b737542ebJoe Onorato        }
129b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato    }
13006290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato
13158b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat    private native static long ctor(FileDescriptor fd);
13258b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat    private native static void dtor(long mBackupWriter);
1331cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato
13458b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat    private native static int writeEntityHeader_native(long mBackupWriter, String key, int dataSize);
13558b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat    private native static int writeEntityData_native(long mBackupWriter, byte[] data, int size);
13658b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat    private native static void setKeyPrefix_native(long mBackupWriter, String keyPrefix);
137b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato}
138b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato
139