Merge change 4085 into donut

* changes:
  Add RestoreFileHelper, BackupDataInput, and add java wrappers for the methods on BackupDataOutput.
This commit is contained in:
Android (Google) Code Review
2009-06-12 16:22:55 -07:00
14 changed files with 452 additions and 18 deletions

View File

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

View File

@@ -0,0 +1,103 @@
/*
* 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 java.io.FileDescriptor;
import java.io.IOException;
/** @hide */
public class BackupDataInput {
int mBackupReader;
private EntityHeader mHeader = new EntityHeader();
private boolean mHeaderReady;
private static class EntityHeader {
String key;
int dataSize;
}
public BackupDataInput(FileDescriptor fd) {
if (fd == null) throw new NullPointerException();
mBackupReader = ctor(fd);
if (mBackupReader == 0) {
throw new RuntimeException("Native initialization failed with fd=" + fd);
}
}
protected void finalize() throws Throwable {
try {
dtor(mBackupReader);
} finally {
super.finalize();
}
}
public boolean readNextHeader() throws IOException {
int result = readNextHeader_native(mBackupReader, mHeader);
if (result == 0) {
// read successfully
mHeaderReady = true;
return true;
} else if (result > 0) {
// done
mHeaderReady = false;
return false;
} else {
// error
mHeaderReady = false;
throw new IOException("result=0x" + Integer.toHexString(result));
}
}
public String getKey() {
if (mHeaderReady) {
return mHeader.key;
} else {
throw new IllegalStateException("mHeaderReady=false");
}
}
public int getDataSize() {
if (mHeaderReady) {
return mHeader.dataSize;
} else {
throw new IllegalStateException("mHeaderReady=false");
}
}
public int readEntityData(byte[] data, int size) throws IOException {
if (mHeaderReady) {
int result = readEntityData_native(mBackupReader, data, size);
if (result >= 0) {
return result;
} else {
throw new IOException("result=0x" + Integer.toHexString(result));
}
} else {
throw new IllegalStateException("mHeaderReady=false");
}
}
private native static int ctor(FileDescriptor fd);
private native static void dtor(int mBackupReader);
private native int readNextHeader_native(int mBackupReader, EntityHeader entity);
private native int readEntityData_native(int mBackupReader, byte[] data, int size);
}

View File

@@ -19,6 +19,7 @@ package android.backup;
import android.content.Context;
import java.io.FileDescriptor;
import java.io.IOException;
/** @hide */
public class BackupDataOutput {
@@ -37,6 +38,24 @@ public class BackupDataOutput {
}
}
public int writeEntityHeader(String key, int dataSize) throws IOException {
int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
if (result >= 0) {
return result;
} else {
throw new IOException("result=0x" + Integer.toHexString(result));
}
}
public int writeEntityData(byte[] data, int size) throws IOException {
int result = writeEntityData_native(mBackupWriter, data, size);
if (result >= 0) {
return result;
} else {
throw new IOException("result=0x" + Integer.toHexString(result));
}
}
protected void finalize() throws Throwable {
try {
dtor(mBackupWriter);
@@ -47,5 +66,8 @@ public class BackupDataOutput {
private native static int ctor(FileDescriptor fd);
private native static void dtor(int mBackupWriter);
private native static int writeEntityHeader_native(int mBackupWriter, String key, int dataSize);
private native static int writeEntityData_native(int mBackupWriter, byte[] data, int size);
}

View File

@@ -27,21 +27,56 @@ import java.io.FileDescriptor;
public class FileBackupHelper {
private static final String TAG = "FileBackupHelper";
Context mContext;
String mKeyPrefix;
public FileBackupHelper(Context context) {
mContext = context;
}
public FileBackupHelper(Context context, String keyPrefix) {
mContext = context;
mKeyPrefix = keyPrefix;
}
/**
* 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 static void performBackup(Context context,
ParcelFileDescriptor oldState, BackupDataOutput data,
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState, String[] files) {
File base = context.getFilesDir();
// file names
File base = mContext.getFilesDir();
final int N = files.length;
String[] fullPaths = new String[N];
for (int i=0; i<N; i++) {
fullPaths[i] = (new File(base, files[i])).getAbsolutePath();
}
performBackup_checked(oldState, data, newState, fullPaths, files);
// keys
String[] keys = makeKeys(mKeyPrefix, files);
// go
performBackup_checked(oldState, data, newState, fullPaths, keys);
}
/**
* 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;
}
}
/**

View File

@@ -0,0 +1,23 @@
/*
* 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;
/** @hide */
public interface RestoreHelper {
public void performRestore();
}

View File

@@ -0,0 +1,28 @@
/*
* 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 java.util.HashMap;
/** @hide */
public class RestoreHelperDistributor {
HashMap<String,RestoreHelper> mHelpers;
public void addHelper(String keyPrefix, RestoreHelper helper) {
mHelpers.put(keyPrefix, helper);
}
}

View File

@@ -23,16 +23,33 @@ import java.io.FileDescriptor;
/** @hide */
public class SharedPreferencesBackupHelper {
public static void performBackup(Context context,
ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot,
private Context mContext;
private String mKeyPrefix;
public SharedPreferencesBackupHelper(Context context) {
mContext = context;
}
public SharedPreferencesBackupHelper(Context context, String keyPrefix) {
mContext = context;
mKeyPrefix = keyPrefix;
}
public void performBackup(ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot,
BackupDataOutput data, String[] prefGroups) {
Context context = mContext;
// make filenames for the prefGroups
final int N = prefGroups.length;
String[] files = new String[N];
for (int i=0; i<N; i++) {
files[i] = context.getSharedPrefsFile(prefGroups[i]).toString();
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);
}
}

View File

@@ -117,6 +117,7 @@ LOCAL_SRC_FILES:= \
android_location_GpsLocationProvider.cpp \
com_android_internal_os_ZygoteInit.cpp \
com_android_internal_graphics_NativeUtils.cpp \
android_backup_BackupDataInput.cpp \
android_backup_BackupDataOutput.cpp \
android_backup_FileBackupHelper.cpp

View File

@@ -155,6 +155,7 @@ extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
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);
@@ -1127,6 +1128,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
REG_JNI(register_android_util_Base64),
REG_JNI(register_android_location_GpsLocationProvider),
REG_JNI(register_android_backup_BackupDataInput),
REG_JNI(register_android_backup_BackupDataOutput),
REG_JNI(register_android_backup_FileBackupHelper),
};

View File

@@ -0,0 +1,162 @@
/*
* 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;
// android.backup.BackupDataInput$EntityHeader
static jfieldID s_keyField = 0;
static jfieldID s_dataSizeField = 0;
static int
ctor_native(JNIEnv* env, jobject clazz, jobject fileDescriptor)
{
int err;
int fd = env->GetIntField(fileDescriptor, s_descriptorField);
if (fd == -1) {
return NULL;
}
return (int)new BackupDataReader(fd);
}
static void
dtor_native(JNIEnv* env, jobject clazz, int r)
{
delete (BackupDataReader*)r;
}
static jint
readNextHeader_native(JNIEnv* env, jobject clazz, int r, jobject entity)
{
int err;
BackupDataReader* reader = (BackupDataReader*)r;
err = reader->Status();
if (err != 0) {
return err < 0 ? err : -1;
}
while (reader->HasEntities()) {
int type;
err = reader->ReadNextHeader(&type);
if (err != 0) {
return err < 0 ? err : -1;
}
switch (type) {
case BACKUP_HEADER_APP_V1:
{
String8 packageName;
int cookie;
err = reader->ReadAppHeader(&packageName, &cookie);
if (err != 0) {
return err < 0 ? err : -1;
}
break;
}
case BACKUP_HEADER_ENTITY_V1:
{
String8 key;
size_t dataSize;
err = reader->ReadEntityHeader(&key, &dataSize);
if (err != 0) {
return err < 0 ? err : -1;
}
// TODO: Set the fields in the entity object
return 0;
}
case BACKUP_FOOTER_APP_V1:
break;
default:
LOGD("Unknown header type: 0x%08x\n", type);
return -1;
}
}
// done
return 1;
}
static jint
readEntityData_native(JNIEnv* env, jobject clazz, int r, jbyteArray data, int size)
{
int err;
BackupDataReader* reader = (BackupDataReader*)r;
if (env->GetArrayLength(data) > size) {
// size mismatch
return -1;
}
jbyte* dataBytes = env->GetByteArrayElements(data, NULL);
if (dataBytes == NULL) {
return -1;
}
err = reader->ReadEntityData(dataBytes, size);
env->ReleaseByteArrayElements(data, dataBytes, 0);
return err;
}
static const JNINativeMethod g_methods[] = {
{ "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native },
{ "dtor", "(I)V", (void*)dtor_native },
{ "readNextHeader_native", "(ILandroid/backup/BackupDataInput$EntityHeader;)I",
(void*)readNextHeader_native },
{ "readEntityData_native", "(I[BI)I", (void*)readEntityData_native },
};
int register_android_backup_BackupDataInput(JNIEnv* env)
{
LOGD("register_android_backup_BackupDataInput");
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");
clazz = env->FindClass("android/backup/BackupDataInput$EntityHeader");
LOG_FATAL_IF(clazz == NULL, "Unable to find class android.backup.BackupDataInput.EntityHeader");
s_keyField = env->GetFieldID(clazz, "key", "Ljava/lang/String;");
LOG_FATAL_IF(s_keyField == NULL,
"Unable to find key field in android.backup.BackupDataInput.EntityHeader");
s_dataSizeField = env->GetFieldID(clazz, "dataSize", "Ljava/lang/String;");
LOG_FATAL_IF(s_dataSizeField == NULL,
"Unable to find dataSize field in android.backup.BackupDataInput.EntityHeader");
return AndroidRuntime::registerNativeMethods(env, "android/backup/BackupDataInput",
g_methods, NELEM(g_methods));
}
}

View File

@@ -28,7 +28,7 @@ namespace android
static jfieldID s_descriptorField = 0;
static int
ctor_native(JNIEnv* env, jobject This, jobject fileDescriptor)
ctor_native(JNIEnv* env, jobject clazz, jobject fileDescriptor)
{
int err;
@@ -41,14 +41,57 @@ ctor_native(JNIEnv* env, jobject This, jobject fileDescriptor)
}
static void
dtor_native(JNIEnv* env, jobject This, int fd)
dtor_native(JNIEnv* env, jobject clazz, int w)
{
delete (BackupDataWriter*)fd;
delete (BackupDataWriter*)w;
}
static jint
writeEntityHeader_native(JNIEnv* env, jobject clazz, int w, jstring key, int dataSize)
{
int err;
BackupDataWriter* writer = (BackupDataWriter*)w;
const char* keyUTF = env->GetStringUTFChars(key, NULL);
if (keyUTF == NULL) {
return -1;
}
err = writer->WriteEntityHeader(String8(keyUTF), dataSize);
env->ReleaseStringUTFChars(key, keyUTF);
return err;
}
static jint
writeEntityData_native(JNIEnv* env, jobject clazz, int w, jbyteArray data, int size)
{
int err;
BackupDataWriter* writer = (BackupDataWriter*)w;
if (env->GetArrayLength(data) > size) {
// size mismatch
return -1;
}
jbyte* dataBytes = env->GetByteArrayElements(data, NULL);
if (dataBytes == NULL) {
return -1;
}
err = writer->WriteEntityData(dataBytes, size);
env->ReleaseByteArrayElements(data, dataBytes, JNI_ABORT);
return err;
}
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 },
};
int register_android_backup_BackupDataOutput(JNIEnv* env)

View File

@@ -25,6 +25,7 @@
namespace android
{
// java.io.FileDescriptor
static jfieldID s_descriptorField = 0;
static int
@@ -34,7 +35,6 @@ performBackup_native(JNIEnv* env, jobject clazz, jobject oldState, int data,
int err;
// all parameters have already been checked against null
LOGD("oldState=%p newState=%p data=%p\n", oldState, newState, data);
int oldStateFD = oldState != NULL ? env->GetIntField(oldState, s_descriptorField) : -1;
int newStateFD = env->GetIntField(newState, s_descriptorField);
BackupDataWriter* dataStream = (BackupDataWriter*)data;
@@ -74,8 +74,6 @@ static const JNINativeMethod g_methods[] = {
int register_android_backup_FileBackupHelper(JNIEnv* env)
{
LOGD("register_android_backup_FileBackupHelper");
jclass clazz;
clazz = env->FindClass("java/io/FileDescriptor");

View File

@@ -327,7 +327,7 @@ BackupDataReader::ReadAppHeader(String8* packageName, int* cookie)
}
size_t size = m_header.app.packageLen;
char* buf = packageName->lockBuffer(size);
if (packageName == NULL) {
if (buf == NULL) {
packageName->unlockBuffer();
m_status = ENOMEM;
return m_status;

View File

@@ -30,7 +30,8 @@ public class BackupTestAgent extends BackupAgent
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
Log.d(TAG, "onBackup");
FileBackupHelper.performBackup(this, oldState, data, newState, new String[] {
FileBackupHelper helper = new FileBackupHelper(this);
helper.performBackup(oldState, data, newState, new String[] {
BackupTestActivity.FILE_NAME
});
}