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:
Android (Google) Code Review
2009-06-22 13:18:09 -07:00
19 changed files with 299 additions and 297 deletions

View File

@ -48,8 +48,8 @@ public class FullBackupAgent extends BackupAgent {
} }
// That's the file set; now back it all up // That's the file set; now back it all up
FileBackupHelper helper = new FileBackupHelper(this); FileBackupHelper helper = new FileBackupHelper(this, (String[])allFiles.toArray());
helper.performBackup(oldState, data, newState, (String[])allFiles.toArray()); helper.performBackup(oldState, data, newState);
} }
@Override @Override

View File

@ -55,6 +55,10 @@ public class BackupDataOutput {
} }
} }
public void setKeyPrefix(String keyPrefix) {
setKeyPrefix_native(mBackupWriter, keyPrefix);
}
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
try { try {
dtor(mBackupWriter); dtor(mBackupWriter);
@ -62,11 +66,12 @@ public class BackupDataOutput {
super.finalize(); super.finalize();
} }
} }
private native static int ctor(FileDescriptor fd); private native static int ctor(FileDescriptor fd);
private native static void dtor(int mBackupWriter); private native static void dtor(int mBackupWriter);
private native static int writeEntityHeader_native(int mBackupWriter, String key, int dataSize); 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 int writeEntityData_native(int mBackupWriter, byte[] data, int size);
private native static void setKeyPrefix_native(int mBackupWriter, String keyPrefix);
} }

View File

@ -21,14 +21,26 @@ import android.os.ParcelFileDescriptor;
import java.io.InputStream; import java.io.InputStream;
/** @hide */ /** @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> * <p class=note>
* Do not close the <code>data</code> stream. Do not read more than * Do not close the <code>data</code> stream. Do not read more than
* <code>dataSize</code> bytes from <code>data</code>. * <code>dataSize</code> bytes from <code>data</code>.
*/ */
public void restoreEntity(BackupDataInputStream data); public void restoreEntity(BackupDataInputStream data);
public void writeSnapshot(ParcelFileDescriptor fd);
/**
*
*/
public void writeRestoreSnapshot(ParcelFileDescriptor fd);
} }

View 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);
}
}

View File

@ -20,20 +20,34 @@ import android.os.ParcelFileDescriptor;
import android.util.Log; import android.util.Log;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.TreeMap;
import java.util.Map; import java.util.Map;
/** @hide */ /** @hide */
public class RestoreHelperDispatcher { public class BackupHelperDispatcher {
private static final String TAG = "RestoreHelperDispatcher"; private static final String TAG = "BackupHelperDispatcher";
HashMap<String,RestoreHelper> mHelpers = new HashMap<String,RestoreHelper>(); TreeMap<String,BackupHelper> mHelpers = new TreeMap<String,BackupHelper>();
public BackupHelperDispatcher() {
}
public void addHelper(String keyPrefix, RestoreHelper helper) { public void addHelper(String keyPrefix, BackupHelper helper) {
mHelpers.put(keyPrefix, 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; boolean alreadyComplained = false;
BackupDataInputStream stream = new BackupDataInputStream(input); BackupDataInputStream stream = new BackupDataInputStream(input);
@ -43,7 +57,7 @@ public class RestoreHelperDispatcher {
int pos = rawKey.indexOf(':'); int pos = rawKey.indexOf(':');
if (pos > 0) { if (pos > 0) {
String prefix = rawKey.substring(0, pos); String prefix = rawKey.substring(0, pos);
RestoreHelper helper = mHelpers.get(prefix); BackupHelper helper = mHelpers.get(prefix);
if (helper != null) { if (helper != null) {
stream.dataSize = input.getDataSize(); stream.dataSize = input.getDataSize();
stream.key = rawKey.substring(pos+1); stream.key = rawKey.substring(pos+1);
@ -63,15 +77,9 @@ public class RestoreHelperDispatcher {
input.skipEntityData(); // In case they didn't consume the data. input.skipEntityData(); // In case they didn't consume the data.
} }
if (mHelpers.size() > 1) { // Write out the state files -- mHelpers is a TreeMap, so the order is well defined.
throw new RuntimeException("RestoreHelperDispatcher won't get your your" for (BackupHelper helper: mHelpers.values()) {
+ " data in the right order yet."); helper.writeRestoreSnapshot(newState);
}
// Write out the state files
for (RestoreHelper helper: mHelpers.values()) {
// TODO: Write a header for the state
helper.writeSnapshot(newState);
} }
} }
} }

View File

@ -24,19 +24,19 @@ import java.io.File;
import java.io.FileDescriptor; import java.io.FileDescriptor;
/** @hide */ /** @hide */
public class FileBackupHelper { public class FileBackupHelper extends FileBackupHelperBase implements BackupHelper {
private static final String TAG = "FileBackupHelper"; private static final String TAG = "FileBackupHelper";
Context mContext; Context mContext;
String mKeyPrefix; File mFilesDir;
String[] mFiles;
public FileBackupHelper(Context context) { public FileBackupHelper(Context context, String... files) {
mContext = context; super(context);
}
public FileBackupHelper(Context context, String keyPrefix) {
mContext = context; mContext = context;
mKeyPrefix = keyPrefix; mFilesDir = context.getFilesDir();
mFiles = files;
} }
/** /**
@ -45,8 +45,9 @@ public class FileBackupHelper {
* state as it exists now. * state as it exists now.
*/ */
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState, String[] files) { ParcelFileDescriptor newState) {
// file names // file names
String[] files = mFiles;
File base = mContext.getFilesDir(); File base = mContext.getFilesDir();
final int N = files.length; final int N = files.length;
String[] fullPaths = new String[N]; String[] fullPaths = new String[N];
@ -54,66 +55,18 @@ public class FileBackupHelper {
fullPaths[i] = (new File(base, files[i])).getAbsolutePath(); fullPaths[i] = (new File(base, files[i])).getAbsolutePath();
} }
// keys
String[] keys = makeKeys(mKeyPrefix, files);
// go // go
performBackup_checked(oldState, data, newState, fullPaths, keys); performBackup_checked(oldState, data, newState, fullPaths, files);
} }
/** public void restoreEntity(BackupDataInputStream data) {
* If keyPrefix is not null, prepend it to each of the strings in <code>original</code>; // TODO: turn this off before ship
* otherwise, return original. Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size());
*/ String key = data.getKey();
static String[] makeKeys(String keyPrefix, String[] original) { if (isKeyInList(key, mFiles)) {
if (keyPrefix != null) { File f = new File(mFilesDir, key);
String[] keys; writeFile(f, data);
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;
} }
} }
/**
* 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);
} }

View File

@ -25,14 +25,14 @@ import java.io.File;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.FileOutputStream; import java.io.FileOutputStream;
class RestoreHelperBase { class FileBackupHelperBase {
private static final String TAG = "RestoreHelperBase"; private static final String TAG = "RestoreHelperBase";
int mPtr; int mPtr;
Context mContext; Context mContext;
boolean mExceptionLogged; boolean mExceptionLogged;
RestoreHelperBase(Context context) { FileBackupHelperBase(Context context) {
mPtr = ctor(); mPtr = ctor();
mContext = context; 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) { void writeFile(File f, InputStream in) {
if (!(in instanceof BackupDataInputStream)) { if (!(in instanceof BackupDataInputStream)) {
throw new IllegalStateException("input stream must be a 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()); int result = writeSnapshot_native(mPtr, fd.getFileDescriptor());
// TODO: Do something with the error. // 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 int ctor();
private static native void dtor(int ptr); 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 writeFile_native(int ptr, String filename, int backupReader);
private static native int writeSnapshot_native(int ptr, FileDescriptor fd); private static native int writeSnapshot_native(int ptr, FileDescriptor fd);
} }

View File

@ -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);
}
}

View File

@ -18,39 +18,51 @@ package android.backup;
import android.content.Context; import android.content.Context;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.File;
import java.io.FileDescriptor; import java.io.FileDescriptor;
/** @hide */ /** @hide */
public class SharedPreferencesBackupHelper { public class SharedPreferencesBackupHelper extends FileBackupHelperBase implements BackupHelper {
private static final String TAG = "SharedPreferencesBackupHelper";
private Context mContext; private Context mContext;
private String mKeyPrefix; private String[] mPrefGroups;
public SharedPreferencesBackupHelper(Context context, String[] prefGroups) {
super(context);
public SharedPreferencesBackupHelper(Context context) {
mContext = context; mContext = context;
mPrefGroups = prefGroups;
} }
public SharedPreferencesBackupHelper(Context context, String keyPrefix) { public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
mContext = context; ParcelFileDescriptor newState) {
mKeyPrefix = keyPrefix;
}
public void performBackup(ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot,
BackupDataOutput data, String[] prefGroups) {
Context context = mContext; Context context = mContext;
// make filenames for the prefGroups // make filenames for the prefGroups
String[] prefGroups = mPrefGroups;
final int N = prefGroups.length; final int N = prefGroups.length;
String[] files = new String[N]; String[] files = new String[N];
for (int i=0; i<N; i++) { for (int i=0; i<N; i++) {
files[i] = context.getSharedPrefsFile(prefGroups[i]).getAbsolutePath(); files[i] = context.getSharedPrefsFile(prefGroups[i]).getAbsolutePath();
} }
// make keys if necessary
String[] keys = FileBackupHelper.makeKeys(mKeyPrefix, prefGroups);
// go // 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);
}
} }
} }

View File

@ -119,8 +119,7 @@ LOCAL_SRC_FILES:= \
com_android_internal_graphics_NativeUtils.cpp \ com_android_internal_graphics_NativeUtils.cpp \
android_backup_BackupDataInput.cpp \ android_backup_BackupDataInput.cpp \
android_backup_BackupDataOutput.cpp \ android_backup_BackupDataOutput.cpp \
android_backup_FileBackupHelper.cpp \ android_backup_FileBackupHelperBase.cpp
android_backup_RestoreHelperBase.cpp
LOCAL_C_INCLUDES += \ LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \ $(JNI_H_INCLUDE) \

View File

@ -157,8 +157,7 @@ extern int register_android_util_Base64(JNIEnv* env);
extern int register_android_location_GpsLocationProvider(JNIEnv* env); extern int register_android_location_GpsLocationProvider(JNIEnv* env);
extern int register_android_backup_BackupDataInput(JNIEnv *env); extern int register_android_backup_BackupDataInput(JNIEnv *env);
extern int register_android_backup_BackupDataOutput(JNIEnv *env); extern int register_android_backup_BackupDataOutput(JNIEnv *env);
extern int register_android_backup_FileBackupHelper(JNIEnv *env); extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
extern int register_android_backup_RestoreHelperBase(JNIEnv *env);
static AndroidRuntime* gCurRuntime = NULL; static AndroidRuntime* gCurRuntime = NULL;
@ -1131,8 +1130,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_location_GpsLocationProvider), REG_JNI(register_android_location_GpsLocationProvider),
REG_JNI(register_android_backup_BackupDataInput), REG_JNI(register_android_backup_BackupDataInput),
REG_JNI(register_android_backup_BackupDataOutput), REG_JNI(register_android_backup_BackupDataOutput),
REG_JNI(register_android_backup_FileBackupHelper), REG_JNI(register_android_backup_FileBackupHelperBase),
REG_JNI(register_android_backup_RestoreHelperBase),
}; };
/* /*

View File

@ -87,11 +87,26 @@ writeEntityData_native(JNIEnv* env, jobject clazz, int w, jbyteArray data, int s
return err; 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[] = { static const JNINativeMethod g_methods[] = {
{ "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native }, { "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native },
{ "dtor", "(I)V", (void*)dtor_native }, { "dtor", "(I)V", (void*)dtor_native },
{ "writeEntityHeader_native", "(ILjava/lang/String;I)I", (void*)writeEntityHeader_native }, { "writeEntityHeader_native", "(ILjava/lang/String;I)I", (void*)writeEntityHeader_native },
{ "writeEntityData_native", "(I[BI)I", (void*)writeEntityData_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) int register_android_backup_BackupDataOutput(JNIEnv* env)

View File

@ -28,6 +28,18 @@ namespace android
// java.io.FileDescriptor // java.io.FileDescriptor
static jfieldID s_descriptorField = 0; 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 static int
performBackup_native(JNIEnv* env, jobject clazz, jobject oldState, int data, performBackup_native(JNIEnv* env, jobject clazz, jobject oldState, int data,
jobject newState, jobjectArray files, jobjectArray keys) jobject newState, jobjectArray files, jobjectArray keys)
@ -66,13 +78,48 @@ performBackup_native(JNIEnv* env, jobject clazz, jobject oldState, int data,
return err; 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[] = { static const JNINativeMethod g_methods[] = {
{ "ctor", "()I", (void*)ctor },
{ "dtor", "(I)V", (void*)dtor },
{ "performBackup_native", { "performBackup_native",
"(Ljava/io/FileDescriptor;ILjava/io/FileDescriptor;[Ljava/lang/String;[Ljava/lang/String;)I", "(Ljava/io/FileDescriptor;ILjava/io/FileDescriptor;[Ljava/lang/String;[Ljava/lang/String;)I",
(void*)performBackup_native }, (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; jclass clazz;
@ -82,7 +129,7 @@ int register_android_backup_FileBackupHelper(JNIEnv* env)
LOG_FATAL_IF(s_descriptorField == NULL, LOG_FATAL_IF(s_descriptorField == NULL,
"Unable to find descriptor field in java.io.FileDescriptor"); "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)); g_methods, NELEM(g_methods));
} }

View File

@ -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));
}
}

View File

@ -71,6 +71,8 @@ public:
status_t WriteEntityHeader(const String8& key, size_t dataSize); status_t WriteEntityHeader(const String8& key, size_t dataSize);
status_t WriteEntityData(const void* data, size_t size); status_t WriteEntityData(const void* data, size_t size);
void SetKeyPrefix(const String8& keyPrefix);
private: private:
explicit BackupDataWriter(); explicit BackupDataWriter();
status_t write_padding_for(int n); status_t write_padding_for(int n);
@ -79,6 +81,7 @@ private:
status_t m_status; status_t m_status;
ssize_t m_pos; ssize_t m_pos;
int m_entityCount; int m_entityCount;
String8 m_keyPrefix;
}; };
/** /**

View File

@ -99,10 +99,20 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
return amt; 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; entity_header_v1 header;
ssize_t keyLen; ssize_t keyLen;
keyLen = key.length(); keyLen = k.length();
header.type = tolel(BACKUP_HEADER_ENTITY_V1); header.type = tolel(BACKUP_HEADER_ENTITY_V1);
header.keyLen = tolel(keyLen); header.keyLen = tolel(keyLen);
@ -115,7 +125,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
} }
m_pos += amt; m_pos += amt;
amt = write(m_fd, key.string(), keyLen+1); amt = write(m_fd, k.string(), keyLen+1);
if (amt != keyLen+1) { if (amt != keyLen+1) {
m_status = errno; m_status = errno;
return m_status; return m_status;
@ -148,6 +158,11 @@ BackupDataWriter::WriteEntityData(const void* data, size_t size)
return NO_ERROR; return NO_ERROR;
} }
void
BackupDataWriter::SetKeyPrefix(const String8& keyPrefix)
{
m_keyPrefix = keyPrefix;
}
BackupDataReader::BackupDataReader(int fd) BackupDataReader::BackupDataReader(int fd)
@ -298,7 +313,7 @@ BackupDataReader::ReadEntityData(void* data, size_t size)
if (remaining <= 0) { if (remaining <= 0) {
return 0; return 0;
} }
if (size > remaining) { if (((int)size) > remaining) {
size = remaining; size = remaining;
} }
//LOGD(" reading %d bytes", size); //LOGD(" reading %d bytes", size);

View File

@ -164,8 +164,8 @@ class BackupManagerService extends IBackupManager.Stub {
// Set up our transport options and initialize the default transport // Set up our transport options and initialize the default transport
// TODO: Have transports register themselves somehow? // TODO: Have transports register themselves somehow?
// TODO: Don't create transports that we don't need to? // TODO: Don't create transports that we don't need to?
//mTransportId = BackupManager.TRANSPORT_LOCAL; mTransportId = BackupManager.TRANSPORT_LOCAL;
mTransportId = BackupManager.TRANSPORT_GOOGLE; //mTransportId = BackupManager.TRANSPORT_GOOGLE;
mLocalTransport = new LocalTransport(context); // This is actually pretty cheap mLocalTransport = new LocalTransport(context); // This is actually pretty cheap
mGoogleTransport = null; mGoogleTransport = null;

View File

@ -17,12 +17,11 @@
package com.android.backuptest; package com.android.backuptest;
import android.app.ListActivity; import android.app.ListActivity;
import android.backup.BackupHelperDispatcher;
import android.backup.BackupDataInput; import android.backup.BackupDataInput;
import android.backup.BackupDataOutput; import android.backup.BackupDataOutput;
import android.backup.BackupManager; import android.backup.BackupManager;
import android.backup.FileBackupHelper; import android.backup.FileBackupHelper;
import android.backup.FileRestoreHelper;
import android.backup.RestoreHelperDispatcher;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
@ -142,10 +141,10 @@ public class BackupTestActivity extends ListActivity
ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE| ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE|
ParcelFileDescriptor.MODE_TRUNCATE); ParcelFileDescriptor.MODE_TRUNCATE);
FileBackupHelper h = new FileBackupHelper(BackupTestActivity.this, FileBackupHelper h = new FileBackupHelper(BackupTestActivity.this,
"FileBackupHelper"); new String[] { "a", "empty" });
FileOutputStream dataFile = openFileOutput("backup_test", MODE_WORLD_READABLE); FileOutputStream dataFile = openFileOutput("backup_test", MODE_WORLD_READABLE);
BackupDataOutput data = new BackupDataOutput(dataFile.getFD()); BackupDataOutput data = new BackupDataOutput(dataFile.getFD());
h.performBackup(null, data, state, new String[] { "a", "empty" }); h.performBackup(null, data, state);
dataFile.close(); dataFile.close();
state.close(); state.close();
} catch (IOException ex) { } catch (IOException ex) {
@ -156,16 +155,16 @@ public class BackupTestActivity extends ListActivity
new Test("Restore Helpers") { new Test("Restore Helpers") {
void run() { void run() {
try { try {
RestoreHelperDispatcher dispatch = new RestoreHelperDispatcher(); BackupHelperDispatcher dispatch = new BackupHelperDispatcher();
dispatch.addHelper("FileBackupHelper", dispatch.addHelper("", new FileBackupHelper(BackupTestActivity.this,
new FileRestoreHelper(BackupTestActivity.this)); new String[] { "a", "empty" }));
FileInputStream dataFile = openFileInput("backup_test"); FileInputStream dataFile = openFileInput("backup_test");
BackupDataInput data = new BackupDataInput(dataFile.getFD()); BackupDataInput data = new BackupDataInput(dataFile.getFD());
ParcelFileDescriptor state = ParcelFileDescriptor.open( ParcelFileDescriptor state = ParcelFileDescriptor.open(
new File(getFilesDir(), "restore_state"), new File(getFilesDir(), "restore_state"),
ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE| ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE|
ParcelFileDescriptor.MODE_TRUNCATE); ParcelFileDescriptor.MODE_TRUNCATE);
dispatch.dispatch(data, state); dispatch.performRestore(data, state);
dataFile.close(); dataFile.close();
state.close(); state.close();
} catch (IOException ex) { } catch (IOException ex) {

View File

@ -16,46 +16,13 @@
package com.android.backuptest; package com.android.backuptest;
import android.app.BackupAgent; import android.backup.BackupHelperAgent;
import android.backup.BackupDataInput;
import android.backup.BackupDataOutput;
import android.backup.FileBackupHelper; 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 BackupHelperAgent
public class BackupTestAgent extends BackupAgent
{ {
static final String TAG = "BackupTestAgent"; public void onCreate() {
addHelper("data_files", new FileBackupHelper(this, BackupTestActivity.FILE_NAME));
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);
} }
} }