summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/backup/RestoreHelper.java3
-rw-r--r--core/java/android/backup/RestoreHelperBase.java71
-rw-r--r--core/java/android/backup/RestoreHelperDispatcher.java16
-rw-r--r--core/jni/Android.mk3
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android_backup_RestoreHelperBase.cpp94
-rw-r--r--include/utils/BackupHelpers.h35
-rw-r--r--libs/utils/BackupHelpers.cpp115
-rw-r--r--tests/backup/src/com/android/backuptest/BackupTestActivity.java7
-rw-r--r--tests/backup/src/com/android/backuptest/BackupTestAgent.java2
10 files changed, 278 insertions, 70 deletions
diff --git a/core/java/android/backup/RestoreHelper.java b/core/java/android/backup/RestoreHelper.java
index ac7d8ee..e47869c 100644
--- a/core/java/android/backup/RestoreHelper.java
+++ b/core/java/android/backup/RestoreHelper.java
@@ -16,6 +16,8 @@
package android.backup;
+import android.os.ParcelFileDescriptor;
+
import java.io.InputStream;
/** @hide */
@@ -27,5 +29,6 @@ public interface RestoreHelper {
* <code>dataSize</code> bytes from <code>data</code>.
*/
public void restoreEntity(BackupDataInputStream data);
+ public void writeSnapshot(ParcelFileDescriptor fd);
}
diff --git a/core/java/android/backup/RestoreHelperBase.java b/core/java/android/backup/RestoreHelperBase.java
index 894c9af..93a8fef 100644
--- a/core/java/android/backup/RestoreHelperBase.java
+++ b/core/java/android/backup/RestoreHelperBase.java
@@ -17,69 +17,66 @@
package android.backup;
import android.content.Context;
+import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.InputStream;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileOutputStream;
-import java.io.IOException;
class RestoreHelperBase {
private static final String TAG = "RestoreHelperBase";
- private static final int BUF_SIZE = 8 * 1024;
+ int mPtr;
Context mContext;
- byte[] mBuf = new byte[BUF_SIZE];
boolean mExceptionLogged;
RestoreHelperBase(Context context) {
+ mPtr = ctor();
mContext = context;
}
- void writeFile(File f, InputStream in) {
- boolean success = false;
- FileOutputStream out = null;
+ protected void finalize() throws Throwable {
try {
- // Create the enclosing directory.
- File parent = f.getParentFile();
- parent.mkdirs();
+ dtor(mPtr);
+ } finally {
+ super.finalize();
+ }
+ }
- // Copy the file.
- int sum = 0;
- out = new FileOutputStream(f);
- byte[] buf = mBuf;
- int amt;
- while ((amt = in.read(buf)) > 0) {
- out.write(buf, 0, amt);
- sum += amt;
- }
+ void writeFile(File f, InputStream in) {
+ if (!(in instanceof BackupDataInputStream)) {
+ throw new IllegalStateException("input stream must be a BackupDataInputStream");
+ }
+ int result = -1;
- // TODO: Set the permissions of the file.
+ // Create the enclosing directory.
+ File parent = f.getParentFile();
+ parent.mkdirs();
- // We're done
- success = true;
- out = null;
- } catch (IOException ex) {
- // Bail on this entity. Only log one exception per helper object.
+ result = writeFile_native(mPtr, f.getAbsolutePath(),
+ ((BackupDataInputStream)in).mData.mBackupReader);
+ if (result != 0) {
+ // Bail on this entity. Only log one failure per helper object.
if (!mExceptionLogged) {
Log.e(TAG, "Failed restoring file '" + f + "' for app '"
- + mContext.getPackageName() + '\'', ex);
+ + mContext.getPackageName() + "\' result=0x"
+ + Integer.toHexString(result));
mExceptionLogged = true;
}
}
- finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException ex) {
- }
- }
- if (!success) {
- // Something didn't work out, delete the file
- f.delete();
- }
- }
}
+
+ public void writeSnapshot(ParcelFileDescriptor fd) {
+ int result = writeSnapshot_native(mPtr, fd.getFileDescriptor());
+ // TODO: Do something with the error.
+ }
+
+ private static native int ctor();
+ private static native void dtor(int ptr);
+ private static native int writeFile_native(int ptr, String filename, int backupReader);
+ private static native int writeSnapshot_native(int ptr, FileDescriptor fd);
}
diff --git a/core/java/android/backup/RestoreHelperDispatcher.java b/core/java/android/backup/RestoreHelperDispatcher.java
index 5928914..4861775 100644
--- a/core/java/android/backup/RestoreHelperDispatcher.java
+++ b/core/java/android/backup/RestoreHelperDispatcher.java
@@ -16,10 +16,12 @@
package android.backup;
+import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.IOException;
import java.util.HashMap;
+import java.util.Map;
/** @hide */
public class RestoreHelperDispatcher {
@@ -31,7 +33,7 @@ public class RestoreHelperDispatcher {
mHelpers.put(keyPrefix, helper);
}
- public void dispatch(BackupDataInput input) throws IOException {
+ public void dispatch(BackupDataInput input, ParcelFileDescriptor newState) throws IOException {
boolean alreadyComplained = false;
BackupDataInputStream stream = new BackupDataInputStream(input);
@@ -60,5 +62,17 @@ 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);
+ }
}
}
+
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index fee8396..faa04f7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -119,7 +119,8 @@ LOCAL_SRC_FILES:= \
com_android_internal_graphics_NativeUtils.cpp \
android_backup_BackupDataInput.cpp \
android_backup_BackupDataOutput.cpp \
- android_backup_FileBackupHelper.cpp
+ android_backup_FileBackupHelper.cpp \
+ android_backup_RestoreHelperBase.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6d829fc..18f6d5f9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -158,6 +158,7 @@ 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);
static AndroidRuntime* gCurRuntime = NULL;
@@ -1131,6 +1132,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_backup_BackupDataInput),
REG_JNI(register_android_backup_BackupDataOutput),
REG_JNI(register_android_backup_FileBackupHelper),
+ REG_JNI(register_android_backup_RestoreHelperBase),
};
/*
diff --git a/core/jni/android_backup_RestoreHelperBase.cpp b/core/jni/android_backup_RestoreHelperBase.cpp
new file mode 100644
index 0000000..3173420
--- /dev/null
+++ b/core/jni/android_backup_RestoreHelperBase.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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));
+}
+
+}
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index fa7f8d5..fc701fd 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -19,6 +19,7 @@
#include <utils/Errors.h>
#include <utils/String8.h>
+#include <utils/KeyedVector.h>
namespace android {
@@ -32,6 +33,27 @@ typedef struct {
int dataSize; // size of the data, not including the padding, -1 means delete
} entity_header_v1;
+struct SnapshotHeader {
+ int magic0;
+ int fileCount;
+ int magic1;
+ int totalSize;
+};
+
+struct FileState {
+ int modTime_sec;
+ int modTime_nsec;
+ int size;
+ int crc32;
+ int nameLen;
+};
+
+struct FileRec {
+ String8 file;
+ bool deleted;
+ FileState s;
+};
+
/**
* Writes the data.
@@ -99,6 +121,19 @@ private:
int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
char const* const* files, char const* const *keys, int fileCount);
+class RestoreHelperBase
+{
+public:
+ RestoreHelperBase();
+ ~RestoreHelperBase();
+
+ status_t WriteFile(const String8& filename, BackupDataReader* in);
+ status_t WriteSnapshot(int fd);
+
+private:
+ void* m_buf;
+ KeyedVector<String8,FileRec> m_files;
+};
#define TEST_BACKUP_HELPERS 1
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index c1d5404..99687bc 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -47,27 +47,6 @@ namespace android {
#define LOGP(x...) LOGD(x)
#endif
-struct SnapshotHeader {
- int magic0;
- int fileCount;
- int magic1;
- int totalSize;
-};
-
-struct FileState {
- int modTime_sec;
- int modTime_nsec;
- int size;
- int crc32;
- int nameLen;
-};
-
-struct FileRec {
- char const* file; // this object does not own this string
- bool deleted;
- FileState s;
-};
-
const static int ROUND_UP[4] = { 0, 3, 2, 1 };
static inline int
@@ -310,7 +289,8 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
for (int i=0; i<fileCount; i++) {
String8 key(keys[i]);
FileRec r;
- char const* file = r.file = files[i];
+ char const* file = files[i];
+ r.file = file;
struct stat st;
err = stat(file, &st);
@@ -351,20 +331,20 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
}
else if (cmp > 0) {
// file added
- LOGP("file added: %s", g.file);
- write_update_file(dataStream, q, g.file);
+ LOGP("file added: %s", g.file.string());
+ write_update_file(dataStream, q, g.file.string());
m++;
}
else {
// both files exist, check them
const FileState& f = oldSnapshot.valueAt(n);
- int fd = open(g.file, O_RDONLY);
+ int fd = open(g.file.string(), O_RDONLY);
if (fd < 0) {
// We can't open the file. Don't report it as a delete either. Let the
// server keep the old version. Maybe they'll be able to deal with it
// on restore.
- LOGP("Unable to open file %s - skipping", g.file);
+ LOGP("Unable to open file %s - skipping", g.file.string());
} else {
g.s.crc32 = compute_crc32(fd);
@@ -375,7 +355,7 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
g.s.modTime_sec, g.s.modTime_nsec, g.s.size, g.s.crc32);
if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
|| f.size != g.s.size || f.crc32 != g.s.crc32) {
- write_update_file(dataStream, fd, p, g.file);
+ write_update_file(dataStream, fd, p, g.file.string());
}
close(fd);
@@ -395,7 +375,7 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
while (m<fileCount) {
const String8& q = newSnapshot.keyAt(m);
FileRec& g = newSnapshot.editValueAt(m);
- write_update_file(dataStream, q, g.file);
+ write_update_file(dataStream, q, g.file.string());
m++;
}
@@ -404,6 +384,84 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
return 0;
}
+#define RESTORE_BUF_SIZE (8*1024)
+
+RestoreHelperBase::RestoreHelperBase()
+{
+ m_buf = malloc(RESTORE_BUF_SIZE);
+}
+
+RestoreHelperBase::~RestoreHelperBase()
+{
+ free(m_buf);
+}
+
+status_t
+RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
+{
+ ssize_t err;
+ size_t dataSize;
+ String8 key;
+ int fd;
+ void* buf = m_buf;
+ ssize_t amt;
+ int mode;
+ int crc;
+ struct stat st;
+ FileRec r;
+
+ err = in->ReadEntityHeader(&key, &dataSize);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ // TODO: World readable/writable for now.
+ mode = 0666;
+
+ // Write the file and compute the crc
+ crc = crc32(0L, Z_NULL, 0);
+ fd = open(filename.string(), O_CREAT|O_RDWR, mode);
+ if (fd != -1) {
+ return errno;
+ }
+
+ while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
+ err = write(fd, buf, amt);
+ if (err != amt) {
+ close(fd);
+ return errno;
+ }
+ crc = crc32(crc, (Bytef*)buf, amt);
+ }
+
+ close(fd);
+
+ // Record for the snapshot
+ err = stat(filename.string(), &st);
+ if (err != 0) {
+ LOGW("Error stating file that we just created %s", filename.string());
+ return errno;
+ }
+
+ r.file = filename;
+ r.deleted = false;
+ r.s.modTime_sec = st.st_mtime;
+ r.s.modTime_nsec = 0; // workaround sim breakage
+ //r.s.modTime_nsec = st.st_mtime_nsec;
+ r.s.size = st.st_size;
+ r.s.crc32 = crc;
+
+ m_files.add(key, r);
+
+ return NO_ERROR;
+}
+
+status_t
+RestoreHelperBase::WriteSnapshot(int fd)
+{
+ return write_snapshot_file(fd, m_files);;
+}
+
#if TEST_BACKUP_HELPERS
#define SCRATCH_DIR "/data/backup_helper_test/"
@@ -560,7 +618,6 @@ backup_helper_test_four()
FileState states[4];
FileRec r;
r.deleted = false;
- r.file = NULL;
states[0].modTime_sec = 0xfedcba98;
states[0].modTime_nsec = 0xdeadbeef;
diff --git a/tests/backup/src/com/android/backuptest/BackupTestActivity.java b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
index d87e85c..f0c3f93 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestActivity.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
@@ -161,8 +161,13 @@ public class BackupTestActivity extends ListActivity
new FileRestoreHelper(BackupTestActivity.this));
FileInputStream dataFile = openFileInput("backup_test");
BackupDataInput data = new BackupDataInput(dataFile.getFD());
- dispatch.dispatch(data);
+ ParcelFileDescriptor state = ParcelFileDescriptor.open(
+ new File(getFilesDir(), "restore_state"),
+ ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE|
+ ParcelFileDescriptor.MODE_TRUNCATE);
+ dispatch.dispatch(data, state);
dataFile.close();
+ state.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
diff --git a/tests/backup/src/com/android/backuptest/BackupTestAgent.java b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
index e3566ec..0da4151 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestAgent.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
@@ -55,7 +55,7 @@ public class BackupTestAgent extends BackupAgent
// dispatch.addHelper(SHARED_PREFS, new SharedPrefsRestoreHelper(this));
dispatch.addHelper(DATA_FILES, new FileRestoreHelper(this));
- dispatch.dispatch(data);
+ dispatch.dispatch(data, newState);
}
}