diff options
author | Christopher Tate <ctate@google.com> | 2009-06-14 21:13:03 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-06-14 21:13:03 -0700 |
commit | daf701fa6250ae89ad93e2e41127e0f676a322a5 (patch) | |
tree | 5b816f0e72d4bd2b0b2040242799c4008abf3a59 /core | |
parent | aa73f17201481f943345253328071118abc02933 (diff) | |
parent | 2fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2 (diff) | |
download | frameworks_base-daf701fa6250ae89ad93e2e41127e0f676a322a5.zip frameworks_base-daf701fa6250ae89ad93e2e41127e0f676a322a5.tar.gz frameworks_base-daf701fa6250ae89ad93e2e41127e0f676a322a5.tar.bz2 |
am 2fdd428e: Fix some backup reader/writer issues; make local transport do backup
Merge commit '2fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2'
* commit '2fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2':
Fix some backup reader/writer issues; make local transport do backup
Fix the jni initializer.
Add RestoreFileHelper, BackupDataInput, and add java wrappers for the methods on BackupDataOutput.
Fix bug #1812041: activity manager crash with bad args.
Journal backup requests so that they won't be lost in a crash
Fix data connection issues.
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/app/FullBackupAgent.java | 5 | ||||
-rw-r--r-- | core/java/android/backup/BackupDataInput.java | 103 | ||||
-rw-r--r-- | core/java/android/backup/BackupDataOutput.java | 22 | ||||
-rw-r--r-- | core/java/android/backup/FileBackupHelper.java | 43 | ||||
-rw-r--r-- | core/java/android/backup/RestoreHelper.java | 23 | ||||
-rw-r--r-- | core/java/android/backup/RestoreHelperDistributor.java | 28 | ||||
-rw-r--r-- | core/java/android/backup/SharedPreferencesBackupHelper.java | 23 | ||||
-rw-r--r-- | core/java/com/android/internal/backup/LocalTransport.java | 86 | ||||
-rw-r--r-- | core/jni/Android.mk | 1 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 2 | ||||
-rw-r--r-- | core/jni/android_backup_BackupDataInput.cpp | 173 | ||||
-rw-r--r-- | core/jni/android_backup_BackupDataOutput.cpp | 51 | ||||
-rw-r--r-- | core/jni/android_backup_FileBackupHelper.cpp | 4 |
13 files changed, 528 insertions, 36 deletions
diff --git a/core/java/android/app/FullBackupAgent.java b/core/java/android/app/FullBackupAgent.java index 18d62e3..bf5cb5d 100644 --- a/core/java/android/app/FullBackupAgent.java +++ b/core/java/android/app/FullBackupAgent.java @@ -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) { } - } diff --git a/core/java/android/backup/BackupDataInput.java b/core/java/android/backup/BackupDataInput.java new file mode 100644 index 0000000..609dd90 --- /dev/null +++ b/core/java/android/backup/BackupDataInput.java @@ -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); +} diff --git a/core/java/android/backup/BackupDataOutput.java b/core/java/android/backup/BackupDataOutput.java index 25ae15b..1348d81 100644 --- a/core/java/android/backup/BackupDataOutput.java +++ b/core/java/android/backup/BackupDataOutput.java @@ -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); } diff --git a/core/java/android/backup/FileBackupHelper.java b/core/java/android/backup/FileBackupHelper.java index 99051bf..ed840bb 100644 --- a/core/java/android/backup/FileBackupHelper.java +++ b/core/java/android/backup/FileBackupHelper.java @@ -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; + } } /** diff --git a/core/java/android/backup/RestoreHelper.java b/core/java/android/backup/RestoreHelper.java new file mode 100644 index 0000000..ebd9906 --- /dev/null +++ b/core/java/android/backup/RestoreHelper.java @@ -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(); +} + diff --git a/core/java/android/backup/RestoreHelperDistributor.java b/core/java/android/backup/RestoreHelperDistributor.java new file mode 100644 index 0000000..555ca79 --- /dev/null +++ b/core/java/android/backup/RestoreHelperDistributor.java @@ -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); + } +} diff --git a/core/java/android/backup/SharedPreferencesBackupHelper.java b/core/java/android/backup/SharedPreferencesBackupHelper.java index 923dc1b..cad79df 100644 --- a/core/java/android/backup/SharedPreferencesBackupHelper.java +++ b/core/java/android/backup/SharedPreferencesBackupHelper.java @@ -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); } } diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java index 62fba4a..83182f2 100644 --- a/core/java/com/android/internal/backup/LocalTransport.java +++ b/core/java/com/android/internal/backup/LocalTransport.java @@ -1,5 +1,6 @@ package com.android.internal.backup; +import android.backup.BackupDataInput; import android.backup.RestoreSet; import android.content.Context; import android.content.pm.PackageInfo; @@ -24,7 +25,7 @@ import java.util.ArrayList; public class LocalTransport extends IBackupTransport.Stub { private static final String TAG = "LocalTransport"; - private static final String DATA_FILE_NAME = "data"; + private static final boolean DEBUG = true; private Context mContext; private PackageManager mPackageManager; @@ -37,6 +38,7 @@ public class LocalTransport extends IBackupTransport.Stub { public LocalTransport(Context context) { + if (DEBUG) Log.v(TAG, "Transport constructed"); mContext = context; mPackageManager = context.getPackageManager(); } @@ -47,29 +49,63 @@ public class LocalTransport extends IBackupTransport.Stub { } public int startSession() throws RemoteException { + if (DEBUG) Log.v(TAG, "session started"); + mDataDir.mkdirs(); return 0; } public int endSession() throws RemoteException { + if (DEBUG) Log.v(TAG, "session ended"); return 0; } public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) throws RemoteException { - File packageDir = new File(mDataDir, packageInfo.packageName); - File imageFileName = new File(packageDir, DATA_FILE_NAME); - - //!!! TODO: process the (partial) update into the persistent restore set: - - // Parse out the existing image file into the key/value map + if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName); + int err = 0; - // Parse out the backup data into the key/value updates - - // Apply the backup key/value updates to the image + File packageDir = new File(mDataDir, packageInfo.packageName); + packageDir.mkdirs(); - // Write out the image in the canonical format + // Each 'record' in the restore set is kept in its own file, named by + // the record key. Wind through the data file, extracting individual + // record operations and building a set of all the updates to apply + // in this update. + BackupDataInput changeSet = new BackupDataInput(data.getFileDescriptor()); + try { + int bufSize = 512; + byte[] buf = new byte[bufSize]; + while (changeSet.readNextHeader()) { + String key = changeSet.getKey(); + int dataSize = changeSet.getDataSize(); + if (DEBUG) Log.v(TAG, "Got change set key=" + key + " size=" + dataSize); + if (dataSize > bufSize) { + bufSize = dataSize; + buf = new byte[bufSize]; + } + changeSet.readEntityData(buf, dataSize); + if (DEBUG) Log.v(TAG, " + data size " + dataSize); + + File entityFile = new File(packageDir, key); + FileOutputStream entity = new FileOutputStream(entityFile); + try { + entity.write(buf, 0, dataSize); + } catch (IOException e) { + Log.e(TAG, "Unable to update key file " + + entityFile.getAbsolutePath()); + err = -1; + } finally { + entity.close(); + } + } + } catch (IOException e) { + // oops, something went wrong. abort the operation and return error. + Log.v(TAG, "Exception reading backup input:"); + e.printStackTrace(); + err = -1; + } - return -1; + return err; } // Restore handling @@ -83,6 +119,7 @@ public class LocalTransport extends IBackupTransport.Stub { } public PackageInfo[] getAppSet(int token) throws android.os.RemoteException { + if (DEBUG) Log.v(TAG, "getting app set " + token); // the available packages are the extant subdirs of mDatadir File[] packageDirs = mDataDir.listFiles(mDirFileFilter); ArrayList<PackageInfo> packages = new ArrayList<PackageInfo>(); @@ -99,9 +136,11 @@ public class LocalTransport extends IBackupTransport.Stub { } } - Log.v(TAG, "Built app set of " + packages.size() + " entries:"); - for (PackageInfo p : packages) { - Log.v(TAG, " + " + p.packageName); + if (DEBUG) { + Log.v(TAG, "Built app set of " + packages.size() + " entries:"); + for (PackageInfo p : packages) { + Log.v(TAG, " + " + p.packageName); + } } PackageInfo[] result = new PackageInfo[packages.size()]; @@ -110,16 +149,25 @@ public class LocalTransport extends IBackupTransport.Stub { public int getRestoreData(int token, PackageInfo packageInfo, ParcelFileDescriptor output) throws android.os.RemoteException { + if (DEBUG) Log.v(TAG, "getting restore data " + token + " : " + packageInfo.packageName); // we only support one hardcoded restore set if (token != 0) return -1; // the data for a given package is at a known location File packageDir = new File(mDataDir, packageInfo.packageName); - File imageFile = new File(packageDir, DATA_FILE_NAME); - // restore is relatively easy: we already maintain the full data set in - // the canonical form understandable to the BackupAgent - return copyFileToFD(imageFile, output); + // The restore set is the concatenation of the individual record blobs, + // each of which is a file in the package's directory + File[] blobs = packageDir.listFiles(); + int err = 0; + if (blobs != null && blobs.length > 0) { + for (File f : blobs) { + err = copyFileToFD(f, output); + if (err != 0) break; + } + } + + return err; } private int copyFileToFD(File source, ParcelFileDescriptor dest) { diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 31cc4f7..aca6670 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -115,6 +115,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 diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 6de37f0..4512fef 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -153,6 +153,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); @@ -1168,6 +1169,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), }; diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp new file mode 100644 index 0000000..5b2fb73 --- /dev/null +++ b/core/jni/android_backup_BackupDataInput.cpp @@ -0,0 +1,173 @@ +/* + * 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; + } + + int type = 0; + + err = reader->ReadNextHeader(&type); + if (err == EIO) { + // Clean EOF with no footer block; just claim we're done + return 1; + } + + 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) { + LOGD("ReadAppHeader() returned %d; aborting", err); + return err < 0 ? err : -1; + } + break; + } + case BACKUP_HEADER_ENTITY_V1: + { + String8 key; + size_t dataSize; + err = reader->ReadEntityHeader(&key, &dataSize); + if (err != 0) { + LOGD("ReadEntityHeader(); aborting", err); + return err < 0 ? err : -1; + } + // TODO: Set the fields in the entity object + jstring keyStr = env->NewStringUTF(key.string()); + env->SetObjectField(entity, s_keyField, keyStr); + env->SetIntField(entity, s_dataSizeField, dataSize); + 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 -2; + } + + 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", "I"); + 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)); +} + +} diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp index aab1233..6362439 100644 --- a/core/jni/android_backup_BackupDataOutput.cpp +++ b/core/jni/android_backup_BackupDataOutput.cpp @@ -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,19 +41,62 @@ 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) { - LOGD("register_android_backup_BackupDataOutput"); + //LOGD("register_android_backup_BackupDataOutput"); jclass clazz; diff --git a/core/jni/android_backup_FileBackupHelper.cpp b/core/jni/android_backup_FileBackupHelper.cpp index 2ee064b..418db8a 100644 --- a/core/jni/android_backup_FileBackupHelper.cpp +++ b/core/jni/android_backup_FileBackupHelper.cpp @@ -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"); |