Home | History | Annotate | Download | only in backup
      1 /*
      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 
     17 package android.app.backup;
     18 
     19 import android.annotation.SystemApi;
     20 import android.os.ParcelFileDescriptor;
     21 import java.io.FileDescriptor;
     22 import java.io.IOException;
     23 
     24 /**
     25  * Provides the structured interface through which a {@link BackupAgent} commits
     26  * information to the backup data set, via its {@link
     27  * BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
     28  * onBackup()} method.  Data written for backup is presented
     29  * as a set of "entities," key/value pairs in which each binary data record "value" is
     30  * named with a string "key."
     31  * <p>
     32  * To commit a data record to the backup transport, the agent's
     33  * {@link BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
     34  * onBackup()} method first writes an "entity header" that supplies the key string for the record
     35  * and the total size of the binary value for the record.  After the header has been
     36  * written, the agent then writes the binary entity value itself.  The entity value can
     37  * be written in multiple chunks if desired, as long as the total count of bytes written
     38  * matches what was supplied to {@link #writeEntityHeader(String, int) writeEntityHeader()}.
     39  * <p>
     40  * Entity key strings are considered to be unique within a given application's backup
     41  * data set. If a backup agent writes a new entity under an existing key string, its value will
     42  * replace any previous value in the transport's remote data store.  You can remove a record
     43  * entirely from the remote data set by writing a new entity header using the
     44  * existing record's key, but supplying a negative <code>dataSize</code> parameter.
     45  * When you do so, the agent does not need to call {@link #writeEntityData(byte[], int)}.
     46  * <h3>Example</h3>
     47  * <p>
     48  * Here is an example illustrating a way to back up the value of a String variable
     49  * called <code>mStringToBackUp</code>:
     50  * <pre>
     51  * static final String MY_STRING_KEY = "storedstring";
     52  *
     53  * public void {@link BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)}
     54  *         throws IOException {
     55  *     ...
     56  *     byte[] stringBytes = mStringToBackUp.getBytes();
     57  *     data.writeEntityHeader(MY_STRING_KEY, stringBytes.length);
     58  *     data.writeEntityData(stringBytes, stringBytes.length);
     59  *     ...
     60  * }</pre>
     61  *
     62  * @see BackupAgent
     63  */
     64 public class BackupDataOutput {
     65     final long mQuota;
     66     long mBackupWriter;
     67 
     68     /**
     69      * Construct a BackupDataOutput purely for data-stream manipulation.  This instance will
     70      * not report usable quota information.
     71      * @hide */
     72     @SystemApi
     73     public BackupDataOutput(FileDescriptor fd) {
     74         this(fd, -1);
     75     }
     76 
     77     /** @hide */
     78     @SystemApi
     79     public BackupDataOutput(FileDescriptor fd, long quota) {
     80         if (fd == null) throw new NullPointerException();
     81         mQuota = quota;
     82         mBackupWriter = ctor(fd);
     83         if (mBackupWriter == 0) {
     84             throw new RuntimeException("Native initialization failed with fd=" + fd);
     85         }
     86     }
     87 
     88     /**
     89      * Returns the quota in bytes for the application's current backup operation.  The
     90      * value can vary for each operation.
     91      *
     92      * @see FullBackupDataOutput#getQuota()
     93      */
     94     public long getQuota() {
     95         return mQuota;
     96     }
     97 
     98     /**
     99      * Mark the beginning of one record in the backup data stream. This must be called before
    100      * {@link #writeEntityData}.
    101      * @param key A string key that uniquely identifies the data record within the application.
    102      *    Keys whose first character is \uFF00 or higher are not valid.
    103      * @param dataSize The size in bytes of this record's data.  Passing a dataSize
    104      *    of -1 indicates that the record under this key should be deleted.
    105      * @return The number of bytes written to the backup stream
    106      * @throws IOException if the write failed
    107      */
    108     public int writeEntityHeader(String key, int dataSize) throws IOException {
    109         int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
    110         if (result >= 0) {
    111             return result;
    112         } else {
    113             throw new IOException("result=0x" + Integer.toHexString(result));
    114         }
    115     }
    116 
    117     /**
    118      * Write a chunk of data under the current entity to the backup transport.
    119      * @param data A raw data buffer to send
    120      * @param size The number of bytes to be sent in this chunk
    121      * @return the number of bytes written
    122      * @throws IOException if the write failed
    123      */
    124     public int writeEntityData(byte[] data, int size) throws IOException {
    125         int result = writeEntityData_native(mBackupWriter, data, size);
    126         if (result >= 0) {
    127             return result;
    128         } else {
    129             throw new IOException("result=0x" + Integer.toHexString(result));
    130         }
    131     }
    132 
    133     /** @hide */
    134     public void setKeyPrefix(String keyPrefix) {
    135         setKeyPrefix_native(mBackupWriter, keyPrefix);
    136     }
    137 
    138     /** @hide */
    139     @Override
    140     protected void finalize() throws Throwable {
    141         try {
    142             dtor(mBackupWriter);
    143         } finally {
    144             super.finalize();
    145         }
    146     }
    147 
    148     private native static long ctor(FileDescriptor fd);
    149     private native static void dtor(long mBackupWriter);
    150 
    151     private native static int writeEntityHeader_native(long mBackupWriter, String key, int dataSize);
    152     private native static int writeEntityData_native(long mBackupWriter, byte[] data, int size);
    153     private native static void setKeyPrefix_native(long mBackupWriter, String keyPrefix);
    154 }
    155 
    156