API CHANGE: expose backup/restore to the SDK

The core backup/restore classes [BackupManager, BackupAgent, RestoreSession, and
RestoreObserver] are now published for 3rd party developers, as well as the suite
of helper classes that exist so far to aid authorship of backup/restore agents.

In conjunction with the API change, the restore-time automatic data wipe has now
been removed:  applications are responsible for managing the logic of wipe vs
merge themselves.  If the app's agent onRestore() callback throws, the data
is presumed to be incoherent and a wipe is issued via the Activity Manager;
otherwise, no automatic action is ever taken.

Change-Id: I0b3418b829d4689b58b88be3d9c4ace37a8583a9
This commit is contained in:
Christopher Tate
2010-02-16 15:22:26 -08:00
parent bb9a51768d
commit e28290e21f
16 changed files with 864 additions and 49 deletions

View File

@@ -19850,6 +19850,83 @@
>
</method>
</class>
<class name="BackupAgent"
extends="android.content.ContextWrapper"
abstract="true"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<constructor name="BackupAgent"
type="android.app.BackupAgent"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</constructor>
<method name="onBackup"
return="void"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="oldState" type="android.os.ParcelFileDescriptor">
</parameter>
<parameter name="data" type="android.backup.BackupDataOutput">
</parameter>
<parameter name="newState" type="android.os.ParcelFileDescriptor">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="onCreate"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="onDestroy"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="onRestore"
return="void"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="data" type="android.backup.BackupDataInput">
</parameter>
<parameter name="appVersionCode" type="int">
</parameter>
<parameter name="newState" type="android.os.ParcelFileDescriptor">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
</class>
<class name="DatePickerDialog"
extends="android.app.AlertDialog"
abstract="false"
@@ -27399,6 +27476,615 @@
</field>
</class>
</package>
<package name="android.backup"
>
<class name="AbsoluteFileBackupHelper"
extends="android.backup.FileBackupHelperBase"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<implements name="android.backup.BackupHelper">
</implements>
<constructor name="AbsoluteFileBackupHelper"
type="android.backup.AbsoluteFileBackupHelper"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="files" type="java.lang.String...">
</parameter>
</constructor>
<method name="performBackup"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="oldState" type="android.os.ParcelFileDescriptor">
</parameter>
<parameter name="data" type="android.backup.BackupDataOutput">
</parameter>
<parameter name="newState" type="android.os.ParcelFileDescriptor">
</parameter>
</method>
<method name="restoreEntity"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="data" type="android.backup.BackupDataInputStream">
</parameter>
</method>
</class>
<class name="BackupDataInput"
extends="java.lang.Object"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<method name="getDataSize"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="getKey"
return="java.lang.String"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="readEntityData"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="data" type="byte[]">
</parameter>
<parameter name="offset" type="int">
</parameter>
<parameter name="size" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="readNextHeader"
return="boolean"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="skipEntityData"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
</class>
<class name="BackupDataInputStream"
extends="java.io.InputStream"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<method name="getKey"
return="java.lang.String"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="read"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="size"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
</class>
<class name="BackupDataOutput"
extends="java.lang.Object"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<method name="setKeyPrefix"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="keyPrefix" type="java.lang.String">
</parameter>
</method>
<method name="writeEntityData"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="data" type="byte[]">
</parameter>
<parameter name="size" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="writeEntityHeader"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="key" type="java.lang.String">
</parameter>
<parameter name="dataSize" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<field name="OP_DELETE"
type="int"
transient="false"
volatile="false"
value="2"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="OP_UPDATE"
type="int"
transient="false"
volatile="false"
value="1"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
</class>
<interface name="BackupHelper"
abstract="true"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<method name="performBackup"
return="void"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="oldState" type="android.os.ParcelFileDescriptor">
</parameter>
<parameter name="data" type="android.backup.BackupDataOutput">
</parameter>
<parameter name="newState" type="android.os.ParcelFileDescriptor">
</parameter>
</method>
<method name="restoreEntity"
return="void"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="data" type="android.backup.BackupDataInputStream">
</parameter>
</method>
<method name="writeRestoreSnapshot"
return="void"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="fd" type="android.os.ParcelFileDescriptor">
</parameter>
</method>
</interface>
<class name="BackupHelperAgent"
extends="android.app.BackupAgent"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<constructor name="BackupHelperAgent"
type="android.backup.BackupHelperAgent"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</constructor>
<method name="addHelper"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="keyPrefix" type="java.lang.String">
</parameter>
<parameter name="helper" type="android.backup.BackupHelper">
</parameter>
</method>
<method name="onBackup"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="oldState" type="android.os.ParcelFileDescriptor">
</parameter>
<parameter name="data" type="android.backup.BackupDataOutput">
</parameter>
<parameter name="newState" type="android.os.ParcelFileDescriptor">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="onRestore"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="data" type="android.backup.BackupDataInput">
</parameter>
<parameter name="appVersionCode" type="int">
</parameter>
<parameter name="newState" type="android.os.ParcelFileDescriptor">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
</class>
<class name="BackupManager"
extends="java.lang.Object"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<constructor name="BackupManager"
type="android.backup.BackupManager"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
</constructor>
<method name="beginRestoreSession"
return="android.backup.RestoreSession"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="dataChanged"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="dataChanged"
return="void"
abstract="false"
native="false"
synchronized="false"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="packageName" type="java.lang.String">
</parameter>
</method>
</class>
<class name="FileBackupHelper"
extends="android.backup.FileBackupHelperBase"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<implements name="android.backup.BackupHelper">
</implements>
<constructor name="FileBackupHelper"
type="android.backup.FileBackupHelper"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="files" type="java.lang.String...">
</parameter>
</constructor>
<method name="performBackup"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="oldState" type="android.os.ParcelFileDescriptor">
</parameter>
<parameter name="data" type="android.backup.BackupDataOutput">
</parameter>
<parameter name="newState" type="android.os.ParcelFileDescriptor">
</parameter>
</method>
<method name="restoreEntity"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="data" type="android.backup.BackupDataInputStream">
</parameter>
</method>
</class>
<class name="FileBackupHelperBase"
extends="java.lang.Object"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility=""
>
<method name="writeRestoreSnapshot"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="fd" type="android.os.ParcelFileDescriptor">
</parameter>
</method>
</class>
<class name="RestoreObserver"
extends="java.lang.Object"
abstract="true"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<constructor name="RestoreObserver"
type="android.backup.RestoreObserver"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</constructor>
</class>
<class name="RestoreSession"
extends="java.lang.Object"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<method name="endRestoreSession"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="restorePackage"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="packageName" type="java.lang.String">
</parameter>
<parameter name="observer" type="android.backup.RestoreObserver">
</parameter>
</method>
</class>
<class name="SharedPreferencesBackupHelper"
extends="android.backup.FileBackupHelperBase"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<implements name="android.backup.BackupHelper">
</implements>
<constructor name="SharedPreferencesBackupHelper"
type="android.backup.SharedPreferencesBackupHelper"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="prefGroups" type="java.lang.String...">
</parameter>
</constructor>
<method name="performBackup"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="oldState" type="android.os.ParcelFileDescriptor">
</parameter>
<parameter name="data" type="android.backup.BackupDataOutput">
</parameter>
<parameter name="newState" type="android.os.ParcelFileDescriptor">
</parameter>
</method>
<method name="restoreEntity"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="data" type="android.backup.BackupDataInputStream">
</parameter>
</method>
</class>
</package>
<package name="android.bluetooth"
>
<class name="BluetoothAdapter"

View File

@@ -33,8 +33,8 @@ import java.io.IOException;
/**
* This is the central interface between an application and Android's
* settings backup mechanism.
*
* @hide pending API solidification
*
* <p>STOPSHIP write more documentation about the backup process here.
*/
public abstract class BackupAgent extends ContextWrapper {
private static final String TAG = "BackupAgent";
@@ -62,9 +62,9 @@ public abstract class BackupAgent extends ContextWrapper {
* state provided by the application. May be null, in which
* case no prior state is being provided and the application should
* perform a full backup.
* @param data An open, read/write ParcelFileDescriptor pointing to the backup data
* destination. Typically the application will use backup helper
* classes to write to this file.
* @param data A structured wrapper around an open, read/write ParcelFileDescriptor
* pointing to the backup data destination. Typically the application will use
* backup helper classes to write to this file.
* @param newState An open, read/write ParcelFileDescriptor pointing to an empty
* file. The application should record the final backup state
* here after writing the requested data to dataFd.
@@ -77,10 +77,18 @@ public abstract class BackupAgent extends ContextWrapper {
* existing data with the contents of the backup. The backup data is
* provided in the file pointed to by the dataFd file descriptor. Once
* the restore is finished, the application should write a representation
* of the final state to the newStateFd file descriptor,
* of the final state to the newStateFd file descriptor,
*
* @param data An open, read-only ParcelFileDescriptor pointing to a full snapshot
* of the application's data.
* <p>The application is responsible for properly erasing its old data and
* replacing it with the data supplied to this method. No "clear user data"
* operation will be performed automatically by the operating system. The
* exception to this is in the case of a failed restore attempt: if onRestore()
* throws an exception, the OS will assume that the application's data may now
* be in an incoherent state, and will clear it before proceeding.
*
* @param data A structured wrapper around an open, read-only ParcelFileDescriptor
* pointing to a full snapshot of the application's data. Typically the
* application will use helper classes to read this data.
* @param appVersionCode The android:versionCode value of the application that backed
* up this particular data set. This makes it easier for an application's
* agent to distinguish among several possible older data versions when

View File

@@ -27,7 +27,7 @@ import java.io.FileDescriptor;
* Like FileBackupHelper, but takes absolute paths for the files instead of
* subpaths of getFilesDir()
*
* @hide
* STOPSHIP: document!
*/
public class AbsoluteFileBackupHelper extends FileBackupHelperBase implements BackupHelper {
private static final String TAG = "AbsoluteFileBackupHelper";
@@ -36,6 +36,13 @@ public class AbsoluteFileBackupHelper extends FileBackupHelperBase implements Ba
Context mContext;
String[] mFiles;
/**
* Construct a helper for backing up / restoring the files at the given absolute locations
* within the file system.
*
* @param context
* @param files
*/
public AbsoluteFileBackupHelper(Context context, String... files) {
super(context);
@@ -54,6 +61,9 @@ public class AbsoluteFileBackupHelper extends FileBackupHelperBase implements Ba
performBackup_checked(oldState, data, newState, mFiles, mFiles);
}
/**
* Restore one absolute file entity from the restore stream
*/
public void restoreEntity(BackupDataInputStream data) {
if (DEBUG) Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size());
String key = data.getKey();

View File

@@ -21,7 +21,9 @@ import android.content.Context;
import java.io.FileDescriptor;
import java.io.IOException;
/** @hide */
/**
* STOPSHIP: document!
*/
public class BackupDataInput {
int mBackupReader;
@@ -33,6 +35,7 @@ public class BackupDataInput {
int dataSize;
}
/** @hide */
public BackupDataInput(FileDescriptor fd) {
if (fd == null) throw new NullPointerException();
mBackupReader = ctor(fd);
@@ -41,6 +44,7 @@ public class BackupDataInput {
}
}
/** @hide */
protected void finalize() throws Throwable {
try {
dtor(mBackupReader);
@@ -49,6 +53,13 @@ public class BackupDataInput {
}
}
/**
* Consumes the next header from the restore stream.
*
* @return true when there is an entity ready for consumption from the restore stream,
* false if the restore stream has been fully consumed.
* @throws IOException if an error occurred while reading the restore stream
*/
public boolean readNextHeader() throws IOException {
int result = readNextHeader_native(mBackupReader, mHeader);
if (result == 0) {
@@ -66,6 +77,11 @@ public class BackupDataInput {
}
}
/**
* Report the key associated with the current record in the restore stream
* @return the current record's key string
* @throws IllegalStateException if the next record header has not yet been read
*/
public String getKey() {
if (mHeaderReady) {
return mHeader.key;
@@ -74,6 +90,13 @@ public class BackupDataInput {
}
}
/**
* Report the size in bytes of the data associated with the current record in the
* restore stream.
*
* @return The size of the record's raw data, in bytes
* @throws IllegalStateException if the next record header has not yet been read
*/
public int getDataSize() {
if (mHeaderReady) {
return mHeader.dataSize;
@@ -82,6 +105,19 @@ public class BackupDataInput {
}
}
/**
* Read a record's raw data from the restore stream. The record's header must first
* have been processed by the {@link #readNextHeader()} method. Multiple calls to
* this method may be made in order to process the data in chunks; not all of it
* must be read in a single call.
*
* @param data An allocated byte array of at least 'size' bytes
* @param offset Offset within the 'data' array at which the data will be placed
* when read from the stream.
* @param size The number of bytes to read in this pass.
* @return The number of bytes of data read
* @throws IOException if an error occurred when trying to read the restore data stream
*/
public int readEntityData(byte[] data, int offset, int size) throws IOException {
if (mHeaderReady) {
int result = readEntityData_native(mBackupReader, data, offset, size);
@@ -95,6 +131,14 @@ public class BackupDataInput {
}
}
/**
* Consume the current record's data without actually reading it into a buffer
* for further processing. This allows a {@link android.backup.BackupAgent} to
* efficiently discard obsolete or otherwise uninteresting records during the
* restore operation.
*
* @throws IOException if an error occurred when trying to read the restore data stream
*/
public void skipEntityData() throws IOException {
if (mHeaderReady) {
skipEntityData_native(mBackupReader);

View File

@@ -16,12 +16,11 @@
package android.backup;
import android.util.Log;
import java.io.InputStream;
import java.io.IOException;
/** @hide */
/**
* STOPSHIP: document */
public class BackupDataInputStream extends InputStream {
String key;
@@ -30,6 +29,7 @@ public class BackupDataInputStream extends InputStream {
BackupDataInput mData;
byte[] mOneByte;
/** @hide */
BackupDataInputStream(BackupDataInput data) {
mData = data;
}

View File

@@ -21,13 +21,16 @@ import android.content.Context;
import java.io.FileDescriptor;
import java.io.IOException;
/** @hide */
/**
* STOPSHIP: document
*/
public class BackupDataOutput {
int mBackupWriter;
public static final int OP_UPDATE = 1;
public static final int OP_DELETE = 2;
/** @hide */
public BackupDataOutput(FileDescriptor fd) {
if (fd == null) throw new NullPointerException();
mBackupWriter = ctor(fd);
@@ -36,7 +39,15 @@ public class BackupDataOutput {
}
}
// A dataSize of -1 indicates that the record under this key should be deleted
/**
* Mark the beginning of one record in the backup data stream.
*
* @param key
* @param dataSize The size in bytes of this record's data. Passing a dataSize
* of -1 indicates that the record under this key should be deleted.
* @return The number of bytes written to the backup stream
* @throws IOException if the write failed
*/
public int writeEntityHeader(String key, int dataSize) throws IOException {
int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
if (result >= 0) {
@@ -46,6 +57,13 @@ public class BackupDataOutput {
}
}
/**
* Write a chunk of data under the current entity to the backup transport.
* @param data A raw data buffer to send
* @param size The number of bytes to be sent in this chunk
* @return the number of bytes written
* @throws IOException if the write failed
*/
public int writeEntityData(byte[] data, int size) throws IOException {
int result = writeEntityData_native(mBackupWriter, data, size);
if (result >= 0) {
@@ -59,6 +77,7 @@ public class BackupDataOutput {
setKeyPrefix_native(mBackupWriter, keyPrefix);
}
/** @hide */
protected void finalize() throws Throwable {
try {
dtor(mBackupWriter);

View File

@@ -20,7 +20,9 @@ import android.os.ParcelFileDescriptor;
import java.io.InputStream;
/** @hide */
/**
* STOPSHIP: document!
*/
public interface BackupHelper {
/**
* Based on oldState, determine which of the files from the application's data directory
@@ -31,16 +33,18 @@ public interface BackupHelper {
ParcelFileDescriptor newState);
/**
* Called by BackupHelperDispatcher to dispatch one entity of data.
* Called by BackupHelperAgent to restore one entity from the restore dataset.
* <p class=note>
* Do not close the <code>data</code> stream. Do not read more than
* <code>dataSize</code> bytes from <code>data</code>.
* <code>data.size()</code> bytes from <code>data</code>.
*/
public void restoreEntity(BackupDataInputStream data);
/**
*
* Called by BackupHelperAgent to write the new backup state file corresponding to
* the current state of the app's data at the time the backup operation was
* performed.
*/
public void writeRestoreSnapshot(ParcelFileDescriptor fd);
public void writeNewStateDescription(ParcelFileDescriptor fd);
}

View File

@@ -26,28 +26,54 @@ import android.util.Log;
import java.io.IOException;
/** @hide */
/**
* A convenient BackupAgent wrapper class that automatically manages heterogeneous
* data sets within the backup data, each identified by a unique key prefix. An
* application will typically extend this class in their own backup agent. Then,
* within the agent's onBackup() and onRestore() methods, it will call
* {@link #addHelper(String, BackupHelper)} one or more times to specify the data
* sets, then invoke super.onBackup() or super.onRestore() to have the BackupHelperAgent
* implementation process the data.
*
* STOPSHIP: document!
*/
public class BackupHelperAgent extends BackupAgent {
static final String TAG = "BackupHelperAgent";
BackupHelperDispatcher mDispatcher = new BackupHelperDispatcher();
/**
* Run the backup process on each of the configured handlers.
*/
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
mDispatcher.performBackup(oldState, data, newState);
}
/**
* Run the restore process on each of the configured handlers.
*/
@Override
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
throws IOException {
mDispatcher.performRestore(data, appVersionCode, newState);
}
/** @hide */
public BackupHelperDispatcher getDispatcher() {
return mDispatcher;
}
/**
* Add a helper for a given data subset to the agent's configuration. Each helper
* must have a prefix string that is unique within this backup agent's set of
* helpers.
*
* @param keyPrefix A string used to disambiguate the various helpers within this agent
* @param helper A backup/restore helper object to be invoked during backup and restore
* operations.
*/
public void addHelper(String keyPrefix, BackupHelper helper) {
mDispatcher.addHelper(keyPrefix, helper);
}

View File

@@ -138,7 +138,7 @@ public class BackupHelperDispatcher {
// Write out the state files -- mHelpers is a TreeMap, so the order is well defined.
for (BackupHelper helper: mHelpers.values()) {
helper.writeRestoreSnapshot(newState);
helper.writeNewStateDescription(newState);
}
}

View File

@@ -38,7 +38,11 @@ import android.util.Log;
* documentation for {@link android.app.BackupAgent} for a detailed description
* of how the backup then proceeds.
*
* @hide pending API solidification
* <p>STOPSHIP more documentation here! Include the attributes:
* android:backupAgent
* android:allowBackup
* android:restoreNeedsApplication
* android:killAfterRestore
*/
public class BackupManager {
private static final String TAG = "BackupManager";
@@ -110,11 +114,8 @@ public class BackupManager {
}
/**
* Begin the process of restoring system data from backup. This method requires
* that the application hold the "android.permission.BACKUP" permission, and is
* not public.
*
* {@hide}
* Begin the process of restoring data from backup. See the
* {@link android.backup.RestoreSession} class for documentation on that process.
*/
public RestoreSession beginRestoreSession() {
if (!EVEN_THINK_ABOUT_DOING_RESTORE) {
@@ -128,7 +129,7 @@ public class BackupManager {
IRestoreSession binder = sService.beginRestoreSession(transport);
session = new RestoreSession(mContext, binder);
} catch (RemoteException e) {
Log.d(TAG, "beginRestoreSession() couldn't connect");
Log.w(TAG, "beginRestoreSession() couldn't connect");
}
}
return session;

View File

@@ -23,7 +23,9 @@ import android.util.Log;
import java.io.File;
import java.io.FileDescriptor;
/** @hide */
/**
* STOPSHIP: document! [manages backup of a set of files; restore is totally opaque]
*/
public class FileBackupHelper extends FileBackupHelperBase implements BackupHelper {
private static final String TAG = "FileBackupHelper";
private static final boolean DEBUG = false;
@@ -32,6 +34,13 @@ public class FileBackupHelper extends FileBackupHelperBase implements BackupHelp
File mFilesDir;
String[] mFiles;
/**
* Construct a helper to manage backup/restore of entire files within the
* application's data directory hierarchy.
*
* @param context The backup agent's Context object
* @param files A list of the files to be backed up or restored.
*/
public FileBackupHelper(Context context, String... files) {
super(context);
@@ -60,6 +69,9 @@ public class FileBackupHelper extends FileBackupHelperBase implements BackupHelp
performBackup_checked(oldState, data, newState, fullPaths, files);
}
/**
* Restore one record [representing a single file] from the restore dataset.
*/
public void restoreEntity(BackupDataInputStream data) {
if (DEBUG) Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size());
String key = data.getKey();

View File

@@ -20,7 +20,6 @@ import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.InputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
@@ -80,18 +79,14 @@ class FileBackupHelperBase {
}
}
void writeFile(File f, InputStream in) {
if (!(in instanceof BackupDataInputStream)) {
throw new IllegalStateException("input stream must be a BackupDataInputStream");
}
void writeFile(File f, BackupDataInputStream in) {
int result = -1;
// Create the enclosing directory.
File parent = f.getParentFile();
parent.mkdirs();
result = writeFile_native(mPtr, f.getAbsolutePath(),
((BackupDataInputStream)in).mData.mBackupReader);
result = writeFile_native(mPtr, f.getAbsolutePath(), in.mData.mBackupReader);
if (result != 0) {
// Bail on this entity. Only log one failure per helper object.
if (!mExceptionLogged) {
@@ -103,7 +98,7 @@ class FileBackupHelperBase {
}
}
public void writeRestoreSnapshot(ParcelFileDescriptor fd) {
public void writeNewStateDescription(ParcelFileDescriptor fd) {
int result = writeSnapshot_native(mPtr, fd.getFileDescriptor());
// TODO: Do something with the error.
}

View File

@@ -19,7 +19,6 @@ package android.backup;
/**
* Callback class for receiving progress reports during a restore operation. These
* methods will all be called on your application's main thread.
* @hide
*/
public abstract class RestoreObserver {
/**

View File

@@ -27,7 +27,6 @@ import android.util.Log;
/**
* Interface for applications to use when managing a restore session.
* @hide
*/
public class RestoreSession {
static final String TAG = "RestoreSession";
@@ -44,6 +43,8 @@ public class RestoreSession {
* and a String array under the key "names" whose entries are the user-meaningful
* text corresponding to the backup sets at each index in the tokens array.
* On error, returns null.
*
* {@hide}
*/
public RestoreSet[] getAvailableRestoreSets() {
try {
@@ -66,6 +67,8 @@ public class RestoreSession {
* the restore set that should be used.
* @param observer If non-null, this binder points to an object that will receive
* progress callbacks during the restore operation.
*
* {@hide}
*/
public int restoreAll(long token, RestoreObserver observer) {
int err = -1;

View File

@@ -23,7 +23,9 @@ import android.util.Log;
import java.io.File;
import java.io.FileDescriptor;
/** @hide */
/**
* STOPSHIP: document!
*/
public class SharedPreferencesBackupHelper extends FileBackupHelperBase implements BackupHelper {
private static final String TAG = "SharedPreferencesBackupHelper";
private static final boolean DEBUG = false;
@@ -31,6 +33,13 @@ public class SharedPreferencesBackupHelper extends FileBackupHelperBase implemen
private Context mContext;
private String[] mPrefGroups;
/**
* Construct a helper for backing up and restoring the
* {@link android.content.SharedPreferences} under the given names.
*
* @param context
* @param prefGroups
*/
public SharedPreferencesBackupHelper(Context context, String... prefGroups) {
super(context);
@@ -38,6 +47,9 @@ public class SharedPreferencesBackupHelper extends FileBackupHelperBase implemen
mPrefGroups = prefGroups;
}
/**
* Backs up the configured SharedPreferences groups
*/
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
Context context = mContext;
@@ -54,6 +66,10 @@ public class SharedPreferencesBackupHelper extends FileBackupHelperBase implemen
performBackup_checked(oldState, data, newState, files, prefGroups);
}
/**
* Restores one entity from the restore data stream to its proper shared
* preferences file store.
*/
public void restoreEntity(BackupDataInputStream data) {
Context context = mContext;

View File

@@ -1083,15 +1083,11 @@ class BackupManagerService extends IBackupManager.Stub {
synchronized(mClearDataLock) {
mClearingData = true;
/* This is causing some critical processes to be killed during setup.
Temporarily revert this change until we find a better solution.
try {
mActivityManager.clearApplicationUserData(packageName, observer);
} catch (RemoteException e) {
// can't happen because the activity manager is in this process
}
*/
mPackageManager.clearApplicationUserData(packageName, observer);
// only wait 10 seconds for the clear data to happen
long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
@@ -1660,10 +1656,6 @@ class BackupManagerService extends IBackupManager.Stub {
+ "] is compatible with installed version ["
+ packageInfo.versionCode + "]");
// Now perform the actual restore: first clear the app's data
// if appropriate
clearApplicationDataSynchronous(packageName);
// Then set up and bind the agent (with a restricted Application object
// unless the application says otherwise)
boolean useRealApp = (packageInfo.applicationInfo.flags