Merge change 4952 into donut
* changes: Helper API cleanup. Allows multiple helpers to function, because they'll always go in the same order, and this lets us not have to write headers to keep them paired.
This commit is contained in:
@ -48,8 +48,8 @@ public class FullBackupAgent extends BackupAgent {
|
||||
}
|
||||
|
||||
// That's the file set; now back it all up
|
||||
FileBackupHelper helper = new FileBackupHelper(this);
|
||||
helper.performBackup(oldState, data, newState, (String[])allFiles.toArray());
|
||||
FileBackupHelper helper = new FileBackupHelper(this, (String[])allFiles.toArray());
|
||||
helper.performBackup(oldState, data, newState);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,6 +55,10 @@ public class BackupDataOutput {
|
||||
}
|
||||
}
|
||||
|
||||
public void setKeyPrefix(String keyPrefix) {
|
||||
setKeyPrefix_native(mBackupWriter, keyPrefix);
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
dtor(mBackupWriter);
|
||||
@ -68,5 +72,6 @@ public class BackupDataOutput {
|
||||
|
||||
private native static int writeEntityHeader_native(int mBackupWriter, String key, int dataSize);
|
||||
private native static int writeEntityData_native(int mBackupWriter, byte[] data, int size);
|
||||
private native static void setKeyPrefix_native(int mBackupWriter, String keyPrefix);
|
||||
}
|
||||
|
||||
|
@ -21,14 +21,26 @@ import android.os.ParcelFileDescriptor;
|
||||
import java.io.InputStream;
|
||||
|
||||
/** @hide */
|
||||
public interface RestoreHelper {
|
||||
public interface BackupHelper {
|
||||
/**
|
||||
* Called by RestoreHelperDispatcher to dispatch one entity of data.
|
||||
* Based on oldState, determine which of the files from the application's data directory
|
||||
* need to be backed up, write them to the data stream, and fill in newState with the
|
||||
* state as it exists now.
|
||||
*/
|
||||
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
|
||||
ParcelFileDescriptor newState);
|
||||
|
||||
/**
|
||||
* Called by BackupHelperDispatcher to dispatch one entity of data.
|
||||
* <p class=note>
|
||||
* Do not close the <code>data</code> stream. Do not read more than
|
||||
* <code>dataSize</code> bytes from <code>data</code>.
|
||||
*/
|
||||
public void restoreEntity(BackupDataInputStream data);
|
||||
public void writeSnapshot(ParcelFileDescriptor fd);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void writeRestoreSnapshot(ParcelFileDescriptor fd);
|
||||
}
|
||||
|
56
core/java/android/backup/BackupHelperAgent.java
Normal file
56
core/java/android/backup/BackupHelperAgent.java
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.backup;
|
||||
|
||||
import android.app.BackupAgent;
|
||||
import android.backup.BackupHelper;
|
||||
import android.backup.BackupHelperDispatcher;
|
||||
import android.backup.BackupDataInput;
|
||||
import android.backup.BackupDataOutput;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/** @hide */
|
||||
public class BackupHelperAgent extends BackupAgent {
|
||||
static final String TAG = "BackupHelperAgent";
|
||||
|
||||
BackupHelperDispatcher mDispatcher = new BackupHelperDispatcher();
|
||||
|
||||
@Override
|
||||
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
|
||||
ParcelFileDescriptor newState) {
|
||||
mDispatcher.performBackup(oldState, data, newState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestore(BackupDataInput data, ParcelFileDescriptor newState)
|
||||
throws IOException {
|
||||
mDispatcher.performRestore(data, newState);
|
||||
}
|
||||
|
||||
public BackupHelperDispatcher getDispatcher() {
|
||||
return mDispatcher;
|
||||
}
|
||||
|
||||
public void addHelper(String keyPrefix, BackupHelper helper) {
|
||||
mDispatcher.addHelper(keyPrefix, helper);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,20 +20,34 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** @hide */
|
||||
public class RestoreHelperDispatcher {
|
||||
private static final String TAG = "RestoreHelperDispatcher";
|
||||
public class BackupHelperDispatcher {
|
||||
private static final String TAG = "BackupHelperDispatcher";
|
||||
|
||||
HashMap<String,RestoreHelper> mHelpers = new HashMap<String,RestoreHelper>();
|
||||
TreeMap<String,BackupHelper> mHelpers = new TreeMap<String,BackupHelper>();
|
||||
|
||||
public void addHelper(String keyPrefix, RestoreHelper helper) {
|
||||
public BackupHelperDispatcher() {
|
||||
}
|
||||
|
||||
public void addHelper(String keyPrefix, BackupHelper helper) {
|
||||
mHelpers.put(keyPrefix, helper);
|
||||
}
|
||||
|
||||
public void dispatch(BackupDataInput input, ParcelFileDescriptor newState) throws IOException {
|
||||
/** TODO: Make this save and restore the key prefix. */
|
||||
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
|
||||
ParcelFileDescriptor newState) {
|
||||
// Write out the state files -- mHelpers is a TreeMap, so the order is well defined.
|
||||
for (Map.Entry<String,BackupHelper> entry: mHelpers.entrySet()) {
|
||||
data.setKeyPrefix(entry.getKey());
|
||||
entry.getValue().performBackup(oldState, data, newState);
|
||||
}
|
||||
}
|
||||
|
||||
public void performRestore(BackupDataInput input, ParcelFileDescriptor newState)
|
||||
throws IOException {
|
||||
boolean alreadyComplained = false;
|
||||
|
||||
BackupDataInputStream stream = new BackupDataInputStream(input);
|
||||
@ -43,7 +57,7 @@ public class RestoreHelperDispatcher {
|
||||
int pos = rawKey.indexOf(':');
|
||||
if (pos > 0) {
|
||||
String prefix = rawKey.substring(0, pos);
|
||||
RestoreHelper helper = mHelpers.get(prefix);
|
||||
BackupHelper helper = mHelpers.get(prefix);
|
||||
if (helper != null) {
|
||||
stream.dataSize = input.getDataSize();
|
||||
stream.key = rawKey.substring(pos+1);
|
||||
@ -63,15 +77,9 @@ public class RestoreHelperDispatcher {
|
||||
input.skipEntityData(); // In case they didn't consume the data.
|
||||
}
|
||||
|
||||
if (mHelpers.size() > 1) {
|
||||
throw new RuntimeException("RestoreHelperDispatcher won't get your your"
|
||||
+ " data in the right order yet.");
|
||||
}
|
||||
|
||||
// Write out the state files
|
||||
for (RestoreHelper helper: mHelpers.values()) {
|
||||
// TODO: Write a header for the state
|
||||
helper.writeSnapshot(newState);
|
||||
// Write out the state files -- mHelpers is a TreeMap, so the order is well defined.
|
||||
for (BackupHelper helper: mHelpers.values()) {
|
||||
helper.writeRestoreSnapshot(newState);
|
||||
}
|
||||
}
|
||||
}
|
@ -24,19 +24,19 @@ import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
|
||||
/** @hide */
|
||||
public class FileBackupHelper {
|
||||
public class FileBackupHelper extends FileBackupHelperBase implements BackupHelper {
|
||||
private static final String TAG = "FileBackupHelper";
|
||||
|
||||
Context mContext;
|
||||
String mKeyPrefix;
|
||||
File mFilesDir;
|
||||
String[] mFiles;
|
||||
|
||||
public FileBackupHelper(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
public FileBackupHelper(Context context, String... files) {
|
||||
super(context);
|
||||
|
||||
public FileBackupHelper(Context context, String keyPrefix) {
|
||||
mContext = context;
|
||||
mKeyPrefix = keyPrefix;
|
||||
mFilesDir = context.getFilesDir();
|
||||
mFiles = files;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,8 +45,9 @@ public class FileBackupHelper {
|
||||
* state as it exists now.
|
||||
*/
|
||||
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
|
||||
ParcelFileDescriptor newState, String[] files) {
|
||||
ParcelFileDescriptor newState) {
|
||||
// file names
|
||||
String[] files = mFiles;
|
||||
File base = mContext.getFilesDir();
|
||||
final int N = files.length;
|
||||
String[] fullPaths = new String[N];
|
||||
@ -54,66 +55,18 @@ public class FileBackupHelper {
|
||||
fullPaths[i] = (new File(base, files[i])).getAbsolutePath();
|
||||
}
|
||||
|
||||
// keys
|
||||
String[] keys = makeKeys(mKeyPrefix, files);
|
||||
|
||||
// go
|
||||
performBackup_checked(oldState, data, newState, fullPaths, keys);
|
||||
performBackup_checked(oldState, data, newState, fullPaths, files);
|
||||
}
|
||||
|
||||
/**
|
||||
* If keyPrefix is not null, prepend it to each of the strings in <code>original</code>;
|
||||
* otherwise, return original.
|
||||
*/
|
||||
static String[] makeKeys(String keyPrefix, String[] original) {
|
||||
if (keyPrefix != null) {
|
||||
String[] keys;
|
||||
final int N = original.length;
|
||||
keys = new String[N];
|
||||
for (int i=0; i<N; i++) {
|
||||
keys[i] = keyPrefix + ':' + original[i];
|
||||
}
|
||||
return keys;
|
||||
} else {
|
||||
return original;
|
||||
public void restoreEntity(BackupDataInputStream data) {
|
||||
// TODO: turn this off before ship
|
||||
Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size());
|
||||
String key = data.getKey();
|
||||
if (isKeyInList(key, mFiles)) {
|
||||
File f = new File(mFilesDir, key);
|
||||
writeFile(f, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the parameters so the native code doens't have to throw all the exceptions
|
||||
* since it's easier to do that from java.
|
||||
*/
|
||||
static void performBackup_checked(ParcelFileDescriptor oldState, BackupDataOutput data,
|
||||
ParcelFileDescriptor newState, String[] files, String[] keys) {
|
||||
if (files.length == 0) {
|
||||
return;
|
||||
}
|
||||
// files must be all absolute paths
|
||||
for (String f: files) {
|
||||
if (f.charAt(0) != '/') {
|
||||
throw new RuntimeException("files must have all absolute paths: " + f);
|
||||
}
|
||||
}
|
||||
// the length of files and keys must be the same
|
||||
if (files.length != keys.length) {
|
||||
throw new RuntimeException("files.length=" + files.length
|
||||
+ " keys.length=" + keys.length);
|
||||
}
|
||||
// oldStateFd can be null
|
||||
FileDescriptor oldStateFd = oldState != null ? oldState.getFileDescriptor() : null;
|
||||
FileDescriptor newStateFd = newState.getFileDescriptor();
|
||||
if (newStateFd == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
int err = performBackup_native(oldStateFd, data.mBackupWriter, newStateFd, files, keys);
|
||||
|
||||
if (err != 0) {
|
||||
// TODO: more here
|
||||
throw new RuntimeException("Backup failed 0x" + Integer.toHexString(err));
|
||||
}
|
||||
}
|
||||
|
||||
native private static int performBackup_native(FileDescriptor oldState,
|
||||
int data, FileDescriptor newState, String[] files, String[] keys);
|
||||
}
|
||||
|
||||
|
@ -25,14 +25,14 @@ import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
class RestoreHelperBase {
|
||||
class FileBackupHelperBase {
|
||||
private static final String TAG = "RestoreHelperBase";
|
||||
|
||||
int mPtr;
|
||||
Context mContext;
|
||||
boolean mExceptionLogged;
|
||||
|
||||
RestoreHelperBase(Context context) {
|
||||
FileBackupHelperBase(Context context) {
|
||||
mPtr = ctor();
|
||||
mContext = context;
|
||||
}
|
||||
@ -45,6 +45,41 @@ class RestoreHelperBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the parameters so the native code doens't have to throw all the exceptions
|
||||
* since it's easier to do that from java.
|
||||
*/
|
||||
static void performBackup_checked(ParcelFileDescriptor oldState, BackupDataOutput data,
|
||||
ParcelFileDescriptor newState, String[] files, String[] keys) {
|
||||
if (files.length == 0) {
|
||||
return;
|
||||
}
|
||||
// files must be all absolute paths
|
||||
for (String f: files) {
|
||||
if (f.charAt(0) != '/') {
|
||||
throw new RuntimeException("files must have all absolute paths: " + f);
|
||||
}
|
||||
}
|
||||
// the length of files and keys must be the same
|
||||
if (files.length != keys.length) {
|
||||
throw new RuntimeException("files.length=" + files.length
|
||||
+ " keys.length=" + keys.length);
|
||||
}
|
||||
// oldStateFd can be null
|
||||
FileDescriptor oldStateFd = oldState != null ? oldState.getFileDescriptor() : null;
|
||||
FileDescriptor newStateFd = newState.getFileDescriptor();
|
||||
if (newStateFd == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
int err = performBackup_native(oldStateFd, data.mBackupWriter, newStateFd, files, keys);
|
||||
|
||||
if (err != 0) {
|
||||
// TODO: more here
|
||||
throw new RuntimeException("Backup failed 0x" + Integer.toHexString(err));
|
||||
}
|
||||
}
|
||||
|
||||
void writeFile(File f, InputStream in) {
|
||||
if (!(in instanceof BackupDataInputStream)) {
|
||||
throw new IllegalStateException("input stream must be a BackupDataInputStream");
|
||||
@ -68,13 +103,26 @@ class RestoreHelperBase {
|
||||
}
|
||||
}
|
||||
|
||||
public void writeSnapshot(ParcelFileDescriptor fd) {
|
||||
public void writeRestoreSnapshot(ParcelFileDescriptor fd) {
|
||||
int result = writeSnapshot_native(mPtr, fd.getFileDescriptor());
|
||||
// TODO: Do something with the error.
|
||||
}
|
||||
|
||||
boolean isKeyInList(String key, String[] list) {
|
||||
for (String s: list) {
|
||||
if (s.equals(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static native int ctor();
|
||||
private static native void dtor(int ptr);
|
||||
|
||||
native private static int performBackup_native(FileDescriptor oldState,
|
||||
int data, FileDescriptor newState, String[] files, String[] keys);
|
||||
|
||||
private static native int writeFile_native(int ptr, String filename, int backupReader);
|
||||
private static native int writeSnapshot_native(int ptr, FileDescriptor fd);
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.backup;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/** @hide */
|
||||
public class FileRestoreHelper extends RestoreHelperBase implements RestoreHelper {
|
||||
private static final String TAG = "FileRestoreHelper";
|
||||
|
||||
File mFilesDir;
|
||||
|
||||
public FileRestoreHelper(Context context) {
|
||||
super(context);
|
||||
mFilesDir = context.getFilesDir();
|
||||
}
|
||||
|
||||
public void restoreEntity(BackupDataInputStream data) {
|
||||
Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size()); // TODO: turn this off before ship
|
||||
File f = new File(mFilesDir, data.getKey());
|
||||
writeFile(f, data);
|
||||
}
|
||||
}
|
||||
|
@ -18,39 +18,51 @@ package android.backup;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
|
||||
/** @hide */
|
||||
public class SharedPreferencesBackupHelper {
|
||||
public class SharedPreferencesBackupHelper extends FileBackupHelperBase implements BackupHelper {
|
||||
private static final String TAG = "SharedPreferencesBackupHelper";
|
||||
|
||||
private Context mContext;
|
||||
private String mKeyPrefix;
|
||||
private String[] mPrefGroups;
|
||||
|
||||
public SharedPreferencesBackupHelper(Context context, String[] prefGroups) {
|
||||
super(context);
|
||||
|
||||
public SharedPreferencesBackupHelper(Context context) {
|
||||
mContext = context;
|
||||
mPrefGroups = prefGroups;
|
||||
}
|
||||
|
||||
public SharedPreferencesBackupHelper(Context context, String keyPrefix) {
|
||||
mContext = context;
|
||||
mKeyPrefix = keyPrefix;
|
||||
}
|
||||
|
||||
public void performBackup(ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot,
|
||||
BackupDataOutput data, String[] prefGroups) {
|
||||
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
|
||||
ParcelFileDescriptor newState) {
|
||||
Context context = mContext;
|
||||
|
||||
// make filenames for the prefGroups
|
||||
String[] prefGroups = mPrefGroups;
|
||||
final int N = prefGroups.length;
|
||||
String[] files = new String[N];
|
||||
for (int i=0; i<N; i++) {
|
||||
files[i] = context.getSharedPrefsFile(prefGroups[i]).getAbsolutePath();
|
||||
}
|
||||
|
||||
// make keys if necessary
|
||||
String[] keys = FileBackupHelper.makeKeys(mKeyPrefix, prefGroups);
|
||||
|
||||
// go
|
||||
FileBackupHelper.performBackup_checked(oldSnapshot, data, newSnapshot, files, prefGroups);
|
||||
performBackup_checked(oldState, data, newState, files, prefGroups);
|
||||
}
|
||||
|
||||
public void restoreEntity(BackupDataInputStream data) {
|
||||
Context context = mContext;
|
||||
|
||||
// TODO: turn this off before ship
|
||||
Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size());
|
||||
String key = data.getKey();
|
||||
if (isKeyInList(key, mPrefGroups)) {
|
||||
File f = context.getSharedPrefsFile(key).getAbsoluteFile();
|
||||
writeFile(f, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,8 +119,7 @@ LOCAL_SRC_FILES:= \
|
||||
com_android_internal_graphics_NativeUtils.cpp \
|
||||
android_backup_BackupDataInput.cpp \
|
||||
android_backup_BackupDataOutput.cpp \
|
||||
android_backup_FileBackupHelper.cpp \
|
||||
android_backup_RestoreHelperBase.cpp
|
||||
android_backup_FileBackupHelperBase.cpp
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(JNI_H_INCLUDE) \
|
||||
|
@ -157,8 +157,7 @@ extern int register_android_util_Base64(JNIEnv* env);
|
||||
extern int register_android_location_GpsLocationProvider(JNIEnv* env);
|
||||
extern int register_android_backup_BackupDataInput(JNIEnv *env);
|
||||
extern int register_android_backup_BackupDataOutput(JNIEnv *env);
|
||||
extern int register_android_backup_FileBackupHelper(JNIEnv *env);
|
||||
extern int register_android_backup_RestoreHelperBase(JNIEnv *env);
|
||||
extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
|
||||
|
||||
static AndroidRuntime* gCurRuntime = NULL;
|
||||
|
||||
@ -1131,8 +1130,7 @@ static const RegJNIRec gRegJNI[] = {
|
||||
REG_JNI(register_android_location_GpsLocationProvider),
|
||||
REG_JNI(register_android_backup_BackupDataInput),
|
||||
REG_JNI(register_android_backup_BackupDataOutput),
|
||||
REG_JNI(register_android_backup_FileBackupHelper),
|
||||
REG_JNI(register_android_backup_RestoreHelperBase),
|
||||
REG_JNI(register_android_backup_FileBackupHelperBase),
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -87,11 +87,26 @@ writeEntityData_native(JNIEnv* env, jobject clazz, int w, jbyteArray data, int s
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
setKeyPrefix_native(JNIEnv* env, jobject clazz, int w, jstring keyPrefixObj)
|
||||
{
|
||||
int err;
|
||||
BackupDataWriter* writer = (BackupDataWriter*)w;
|
||||
|
||||
const char* keyPrefixUTF = env->GetStringUTFChars(keyPrefixObj, NULL);
|
||||
String8 keyPrefix(keyPrefixUTF ? keyPrefixUTF : "");
|
||||
|
||||
writer->SetKeyPrefix(keyPrefix);
|
||||
|
||||
env->ReleaseStringUTFChars(keyPrefixObj, keyPrefixUTF);
|
||||
}
|
||||
|
||||
static const JNINativeMethod g_methods[] = {
|
||||
{ "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native },
|
||||
{ "dtor", "(I)V", (void*)dtor_native },
|
||||
{ "writeEntityHeader_native", "(ILjava/lang/String;I)I", (void*)writeEntityHeader_native },
|
||||
{ "writeEntityData_native", "(I[BI)I", (void*)writeEntityData_native },
|
||||
{ "setKeyPrefix_native", "(ILjava/lang/String;)V", (void*)setKeyPrefix_native },
|
||||
};
|
||||
|
||||
int register_android_backup_BackupDataOutput(JNIEnv* env)
|
||||
|
@ -28,6 +28,18 @@ namespace android
|
||||
// java.io.FileDescriptor
|
||||
static jfieldID s_descriptorField = 0;
|
||||
|
||||
static int
|
||||
ctor(JNIEnv* env, jobject clazz)
|
||||
{
|
||||
return (int)new RestoreHelperBase();
|
||||
}
|
||||
|
||||
static void
|
||||
dtor(JNIEnv* env, jobject clazz, jint ptr)
|
||||
{
|
||||
delete (RestoreHelperBase*)ptr;
|
||||
}
|
||||
|
||||
static int
|
||||
performBackup_native(JNIEnv* env, jobject clazz, jobject oldState, int data,
|
||||
jobject newState, jobjectArray files, jobjectArray keys)
|
||||
@ -66,13 +78,48 @@ performBackup_native(JNIEnv* env, jobject clazz, jobject oldState, int data,
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
writeFile_native(JNIEnv* env, jobject clazz, jint ptr, jstring filenameObj, int backupReaderPtr)
|
||||
{
|
||||
int err;
|
||||
RestoreHelperBase* restore = (RestoreHelperBase*)ptr;
|
||||
BackupDataReader* reader = (BackupDataReader*)backupReaderPtr;
|
||||
char const* filename;
|
||||
|
||||
filename = env->GetStringUTFChars(filenameObj, NULL);
|
||||
|
||||
err = restore->WriteFile(String8(filename), reader);
|
||||
|
||||
env->ReleaseStringUTFChars(filenameObj, filename);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
writeSnapshot_native(JNIEnv* env, jobject clazz, jint ptr, jobject fileDescriptor)
|
||||
{
|
||||
int err;
|
||||
|
||||
RestoreHelperBase* restore = (RestoreHelperBase*)ptr;
|
||||
int fd = env->GetIntField(fileDescriptor, s_descriptorField);
|
||||
|
||||
err = restore->WriteSnapshot(fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const JNINativeMethod g_methods[] = {
|
||||
{ "ctor", "()I", (void*)ctor },
|
||||
{ "dtor", "(I)V", (void*)dtor },
|
||||
{ "performBackup_native",
|
||||
"(Ljava/io/FileDescriptor;ILjava/io/FileDescriptor;[Ljava/lang/String;[Ljava/lang/String;)I",
|
||||
(void*)performBackup_native },
|
||||
{ "writeFile_native", "(ILjava/lang/String;I)I", (void*)writeFile_native },
|
||||
{ "writeSnapshot_native", "(ILjava/io/FileDescriptor;)I", (void*)writeSnapshot_native },
|
||||
};
|
||||
|
||||
int register_android_backup_FileBackupHelper(JNIEnv* env)
|
||||
int register_android_backup_FileBackupHelperBase(JNIEnv* env)
|
||||
{
|
||||
jclass clazz;
|
||||
|
||||
@ -82,7 +129,7 @@ int register_android_backup_FileBackupHelper(JNIEnv* env)
|
||||
LOG_FATAL_IF(s_descriptorField == NULL,
|
||||
"Unable to find descriptor field in java.io.FileDescriptor");
|
||||
|
||||
return AndroidRuntime::registerNativeMethods(env, "android/backup/FileBackupHelper",
|
||||
return AndroidRuntime::registerNativeMethods(env, "android/backup/FileBackupHelperBase",
|
||||
g_methods, NELEM(g_methods));
|
||||
}
|
||||
|
@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "FileBackupHelper_native"
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "JNIHelp.h"
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
|
||||
#include <utils/BackupHelpers.h>
|
||||
|
||||
namespace android
|
||||
{
|
||||
|
||||
// java.io.FileDescriptor
|
||||
static jfieldID s_descriptorField = 0;
|
||||
|
||||
static int
|
||||
ctor(JNIEnv* env, jobject clazz)
|
||||
{
|
||||
return (int)new RestoreHelperBase();
|
||||
}
|
||||
|
||||
static void
|
||||
dtor(JNIEnv* env, jobject clazz, jint ptr)
|
||||
{
|
||||
delete (RestoreHelperBase*)ptr;
|
||||
}
|
||||
|
||||
static int
|
||||
writeFile_native(JNIEnv* env, jobject clazz, jint ptr, jstring filenameObj, int backupReaderPtr)
|
||||
{
|
||||
int err;
|
||||
RestoreHelperBase* restore = (RestoreHelperBase*)ptr;
|
||||
BackupDataReader* reader = (BackupDataReader*)backupReaderPtr;
|
||||
char const* filename;
|
||||
|
||||
filename = env->GetStringUTFChars(filenameObj, NULL);
|
||||
|
||||
err = restore->WriteFile(String8(filename), reader);
|
||||
|
||||
env->ReleaseStringUTFChars(filenameObj, filename);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
writeSnapshot_native(JNIEnv* env, jobject clazz, jint ptr, jobject fileDescriptor)
|
||||
{
|
||||
int err;
|
||||
|
||||
RestoreHelperBase* restore = (RestoreHelperBase*)ptr;
|
||||
int fd = env->GetIntField(fileDescriptor, s_descriptorField);
|
||||
|
||||
err = restore->WriteSnapshot(fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const JNINativeMethod g_methods[] = {
|
||||
{ "ctor", "()I", (void*)ctor },
|
||||
{ "dtor", "(I)V", (void*)dtor },
|
||||
{ "writeFile_native", "(ILjava/lang/String;I)I", (void*)writeFile_native },
|
||||
{ "writeSnapshot_native", "(ILjava/io/FileDescriptor;)I", (void*)writeSnapshot_native },
|
||||
};
|
||||
|
||||
int register_android_backup_RestoreHelperBase(JNIEnv* env)
|
||||
{
|
||||
jclass clazz;
|
||||
|
||||
clazz = env->FindClass("java/io/FileDescriptor");
|
||||
LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
|
||||
s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
|
||||
LOG_FATAL_IF(s_descriptorField == NULL,
|
||||
"Unable to find descriptor field in java.io.FileDescriptor");
|
||||
|
||||
return AndroidRuntime::registerNativeMethods(env, "android/backup/RestoreHelperBase",
|
||||
g_methods, NELEM(g_methods));
|
||||
}
|
||||
|
||||
}
|
@ -71,6 +71,8 @@ public:
|
||||
status_t WriteEntityHeader(const String8& key, size_t dataSize);
|
||||
status_t WriteEntityData(const void* data, size_t size);
|
||||
|
||||
void SetKeyPrefix(const String8& keyPrefix);
|
||||
|
||||
private:
|
||||
explicit BackupDataWriter();
|
||||
status_t write_padding_for(int n);
|
||||
@ -79,6 +81,7 @@ private:
|
||||
status_t m_status;
|
||||
ssize_t m_pos;
|
||||
int m_entityCount;
|
||||
String8 m_keyPrefix;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -99,10 +99,20 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
|
||||
return amt;
|
||||
}
|
||||
|
||||
String8 k;
|
||||
if (m_keyPrefix.length() > 0) {
|
||||
k = m_keyPrefix;
|
||||
k += ":";
|
||||
k += key;
|
||||
} else {
|
||||
k = key;
|
||||
}
|
||||
LOGD("m_keyPrefix=%s key=%s k=%s", m_keyPrefix.string(), key.string(), k.string());
|
||||
|
||||
entity_header_v1 header;
|
||||
ssize_t keyLen;
|
||||
|
||||
keyLen = key.length();
|
||||
keyLen = k.length();
|
||||
|
||||
header.type = tolel(BACKUP_HEADER_ENTITY_V1);
|
||||
header.keyLen = tolel(keyLen);
|
||||
@ -115,7 +125,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
|
||||
}
|
||||
m_pos += amt;
|
||||
|
||||
amt = write(m_fd, key.string(), keyLen+1);
|
||||
amt = write(m_fd, k.string(), keyLen+1);
|
||||
if (amt != keyLen+1) {
|
||||
m_status = errno;
|
||||
return m_status;
|
||||
@ -148,6 +158,11 @@ BackupDataWriter::WriteEntityData(const void* data, size_t size)
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void
|
||||
BackupDataWriter::SetKeyPrefix(const String8& keyPrefix)
|
||||
{
|
||||
m_keyPrefix = keyPrefix;
|
||||
}
|
||||
|
||||
|
||||
BackupDataReader::BackupDataReader(int fd)
|
||||
@ -298,7 +313,7 @@ BackupDataReader::ReadEntityData(void* data, size_t size)
|
||||
if (remaining <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (size > remaining) {
|
||||
if (((int)size) > remaining) {
|
||||
size = remaining;
|
||||
}
|
||||
//LOGD(" reading %d bytes", size);
|
||||
|
@ -164,8 +164,8 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
// Set up our transport options and initialize the default transport
|
||||
// TODO: Have transports register themselves somehow?
|
||||
// TODO: Don't create transports that we don't need to?
|
||||
//mTransportId = BackupManager.TRANSPORT_LOCAL;
|
||||
mTransportId = BackupManager.TRANSPORT_GOOGLE;
|
||||
mTransportId = BackupManager.TRANSPORT_LOCAL;
|
||||
//mTransportId = BackupManager.TRANSPORT_GOOGLE;
|
||||
mLocalTransport = new LocalTransport(context); // This is actually pretty cheap
|
||||
mGoogleTransport = null;
|
||||
|
||||
|
@ -17,12 +17,11 @@
|
||||
package com.android.backuptest;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.backup.BackupHelperDispatcher;
|
||||
import android.backup.BackupDataInput;
|
||||
import android.backup.BackupDataOutput;
|
||||
import android.backup.BackupManager;
|
||||
import android.backup.FileBackupHelper;
|
||||
import android.backup.FileRestoreHelper;
|
||||
import android.backup.RestoreHelperDispatcher;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
@ -142,10 +141,10 @@ public class BackupTestActivity extends ListActivity
|
||||
ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE|
|
||||
ParcelFileDescriptor.MODE_TRUNCATE);
|
||||
FileBackupHelper h = new FileBackupHelper(BackupTestActivity.this,
|
||||
"FileBackupHelper");
|
||||
new String[] { "a", "empty" });
|
||||
FileOutputStream dataFile = openFileOutput("backup_test", MODE_WORLD_READABLE);
|
||||
BackupDataOutput data = new BackupDataOutput(dataFile.getFD());
|
||||
h.performBackup(null, data, state, new String[] { "a", "empty" });
|
||||
h.performBackup(null, data, state);
|
||||
dataFile.close();
|
||||
state.close();
|
||||
} catch (IOException ex) {
|
||||
@ -156,16 +155,16 @@ public class BackupTestActivity extends ListActivity
|
||||
new Test("Restore Helpers") {
|
||||
void run() {
|
||||
try {
|
||||
RestoreHelperDispatcher dispatch = new RestoreHelperDispatcher();
|
||||
dispatch.addHelper("FileBackupHelper",
|
||||
new FileRestoreHelper(BackupTestActivity.this));
|
||||
BackupHelperDispatcher dispatch = new BackupHelperDispatcher();
|
||||
dispatch.addHelper("", new FileBackupHelper(BackupTestActivity.this,
|
||||
new String[] { "a", "empty" }));
|
||||
FileInputStream dataFile = openFileInput("backup_test");
|
||||
BackupDataInput data = new BackupDataInput(dataFile.getFD());
|
||||
ParcelFileDescriptor state = ParcelFileDescriptor.open(
|
||||
new File(getFilesDir(), "restore_state"),
|
||||
ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE|
|
||||
ParcelFileDescriptor.MODE_TRUNCATE);
|
||||
dispatch.dispatch(data, state);
|
||||
dispatch.performRestore(data, state);
|
||||
dataFile.close();
|
||||
state.close();
|
||||
} catch (IOException ex) {
|
||||
|
@ -16,46 +16,13 @@
|
||||
|
||||
package com.android.backuptest;
|
||||
|
||||
import android.app.BackupAgent;
|
||||
import android.backup.BackupDataInput;
|
||||
import android.backup.BackupDataOutput;
|
||||
import android.backup.BackupHelperAgent;
|
||||
import android.backup.FileBackupHelper;
|
||||
import android.backup.FileRestoreHelper;
|
||||
import android.backup.RestoreHelperDispatcher;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class BackupTestAgent extends BackupAgent
|
||||
public class BackupTestAgent extends BackupHelperAgent
|
||||
{
|
||||
static final String TAG = "BackupTestAgent";
|
||||
|
||||
static final String SHARED_PREFS = "shared_prefs";
|
||||
static final String DATA_FILES = "data_files";
|
||||
static final String[] FILES = new String[] {
|
||||
BackupTestActivity.FILE_NAME
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
|
||||
ParcelFileDescriptor newState) {
|
||||
Log.d(TAG, "onBackup");
|
||||
|
||||
(new FileBackupHelper(this, DATA_FILES)).performBackup(oldState, data, newState, FILES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestore(BackupDataInput data, ParcelFileDescriptor newState)
|
||||
throws IOException {
|
||||
Log.d(TAG, "onRestore");
|
||||
|
||||
RestoreHelperDispatcher dispatch = new RestoreHelperDispatcher();
|
||||
|
||||
// dispatch.addHelper(SHARED_PREFS, new SharedPrefsRestoreHelper(this));
|
||||
dispatch.addHelper(DATA_FILES, new FileRestoreHelper(this));
|
||||
|
||||
dispatch.dispatch(data, newState);
|
||||
public void onCreate() {
|
||||
addHelper("data_files", new FileBackupHelper(this, BackupTestActivity.FILE_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user