diff --git a/core/java/android/app/FullBackupAgent.java b/core/java/android/app/FullBackupAgent.java index 89becf40a6595..bc6bb151baf42 100644 --- a/core/java/android/app/FullBackupAgent.java +++ b/core/java/android/app/FullBackupAgent.java @@ -48,8 +48,8 @@ public class FullBackupAgent extends BackupAgent { } // That's the file set; now back it all up - FileBackupHelper helper = new FileBackupHelper(this); - helper.performBackup(oldState, data, newState, (String[])allFiles.toArray()); + FileBackupHelper helper = new FileBackupHelper(this, (String[])allFiles.toArray()); + helper.performBackup(oldState, data, newState); } @Override diff --git a/core/java/android/backup/BackupDataOutput.java b/core/java/android/backup/BackupDataOutput.java index 05e667ed4764f..d29c5ba02f140 100644 --- a/core/java/android/backup/BackupDataOutput.java +++ b/core/java/android/backup/BackupDataOutput.java @@ -55,6 +55,10 @@ public class BackupDataOutput { } } + public void setKeyPrefix(String keyPrefix) { + setKeyPrefix_native(mBackupWriter, keyPrefix); + } + protected void finalize() throws Throwable { try { dtor(mBackupWriter); @@ -62,11 +66,12 @@ public class BackupDataOutput { super.finalize(); } } - + 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); + private native static void setKeyPrefix_native(int mBackupWriter, String keyPrefix); } diff --git a/core/java/android/backup/RestoreHelper.java b/core/java/android/backup/BackupHelper.java similarity index 63% rename from core/java/android/backup/RestoreHelper.java rename to core/java/android/backup/BackupHelper.java index e47869ce4ca3d..3983e28cce399 100644 --- a/core/java/android/backup/RestoreHelper.java +++ b/core/java/android/backup/BackupHelper.java @@ -21,14 +21,26 @@ import android.os.ParcelFileDescriptor; import java.io.InputStream; /** @hide */ -public interface RestoreHelper { +public interface BackupHelper { /** - * Called by RestoreHelperDispatcher to dispatch one entity of data. + * Based on oldState, determine which of the files from the application's data directory + * need to be backed up, write them to the data stream, and fill in newState with the + * state as it exists now. + */ + public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, + ParcelFileDescriptor newState); + + /** + * Called by BackupHelperDispatcher to dispatch one entity of data. *

* Do not close the data stream. Do not read more than * dataSize bytes from data. */ public void restoreEntity(BackupDataInputStream data); - public void writeSnapshot(ParcelFileDescriptor fd); + + /** + * + */ + public void writeRestoreSnapshot(ParcelFileDescriptor fd); } diff --git a/core/java/android/backup/BackupHelperAgent.java b/core/java/android/backup/BackupHelperAgent.java new file mode 100644 index 0000000000000..f7eb1b88df47f --- /dev/null +++ b/core/java/android/backup/BackupHelperAgent.java @@ -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); + } +} + + diff --git a/core/java/android/backup/RestoreHelperDispatcher.java b/core/java/android/backup/BackupHelperDispatcher.java similarity index 62% rename from core/java/android/backup/RestoreHelperDispatcher.java rename to core/java/android/backup/BackupHelperDispatcher.java index 48617757cb472..e9a8f71b4e1c5 100644 --- a/core/java/android/backup/RestoreHelperDispatcher.java +++ b/core/java/android/backup/BackupHelperDispatcher.java @@ -20,20 +20,34 @@ import android.os.ParcelFileDescriptor; import android.util.Log; import java.io.IOException; -import java.util.HashMap; +import java.util.TreeMap; import java.util.Map; /** @hide */ -public class RestoreHelperDispatcher { - private static final String TAG = "RestoreHelperDispatcher"; +public class BackupHelperDispatcher { + private static final String TAG = "BackupHelperDispatcher"; - HashMap mHelpers = new HashMap(); + TreeMap mHelpers = new TreeMap(); + + public BackupHelperDispatcher() { + } - public void addHelper(String keyPrefix, RestoreHelper helper) { + public void addHelper(String keyPrefix, BackupHelper helper) { mHelpers.put(keyPrefix, helper); } - public void dispatch(BackupDataInput input, ParcelFileDescriptor newState) throws IOException { + /** TODO: Make this save and restore the key prefix. */ + public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, + ParcelFileDescriptor newState) { + // Write out the state files -- mHelpers is a TreeMap, so the order is well defined. + for (Map.Entry entry: mHelpers.entrySet()) { + data.setKeyPrefix(entry.getKey()); + entry.getValue().performBackup(oldState, data, newState); + } + } + + public void performRestore(BackupDataInput input, ParcelFileDescriptor newState) + throws IOException { boolean alreadyComplained = false; BackupDataInputStream stream = new BackupDataInputStream(input); @@ -43,7 +57,7 @@ public class RestoreHelperDispatcher { int pos = rawKey.indexOf(':'); if (pos > 0) { String prefix = rawKey.substring(0, pos); - RestoreHelper helper = mHelpers.get(prefix); + BackupHelper helper = mHelpers.get(prefix); if (helper != null) { stream.dataSize = input.getDataSize(); stream.key = rawKey.substring(pos+1); @@ -63,15 +77,9 @@ public class RestoreHelperDispatcher { input.skipEntityData(); // In case they didn't consume the data. } - if (mHelpers.size() > 1) { - throw new RuntimeException("RestoreHelperDispatcher won't get your your" - + " data in the right order yet."); - } - - // Write out the state files - for (RestoreHelper helper: mHelpers.values()) { - // TODO: Write a header for the state - helper.writeSnapshot(newState); + // Write out the state files -- mHelpers is a TreeMap, so the order is well defined. + for (BackupHelper helper: mHelpers.values()) { + helper.writeRestoreSnapshot(newState); } } } diff --git a/core/java/android/backup/FileBackupHelper.java b/core/java/android/backup/FileBackupHelper.java index ed840bb3ffba5..405849705ff76 100644 --- a/core/java/android/backup/FileBackupHelper.java +++ b/core/java/android/backup/FileBackupHelper.java @@ -24,19 +24,19 @@ import java.io.File; import java.io.FileDescriptor; /** @hide */ -public class FileBackupHelper { +public class FileBackupHelper extends FileBackupHelperBase implements BackupHelper { private static final String TAG = "FileBackupHelper"; Context mContext; - String mKeyPrefix; + File mFilesDir; + String[] mFiles; - public FileBackupHelper(Context context) { - mContext = context; - } + public FileBackupHelper(Context context, String... files) { + super(context); - public FileBackupHelper(Context context, String keyPrefix) { mContext = context; - mKeyPrefix = keyPrefix; + mFilesDir = context.getFilesDir(); + mFiles = files; } /** @@ -45,8 +45,9 @@ public class FileBackupHelper { * state as it exists now. */ public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, - ParcelFileDescriptor newState, String[] files) { + ParcelFileDescriptor newState) { // file names + String[] files = mFiles; File base = mContext.getFilesDir(); final int N = files.length; String[] fullPaths = new String[N]; @@ -54,66 +55,18 @@ public class FileBackupHelper { fullPaths[i] = (new File(base, files[i])).getAbsolutePath(); } - // keys - String[] keys = makeKeys(mKeyPrefix, files); - // go - performBackup_checked(oldState, data, newState, fullPaths, keys); + performBackup_checked(oldState, data, newState, fullPaths, files); } - /** - * If keyPrefix is not null, prepend it to each of the strings in original; - * 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; iSetKeyPrefix(keyPrefix); + + env->ReleaseStringUTFChars(keyPrefixObj, keyPrefixUTF); +} + static const JNINativeMethod g_methods[] = { { "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native }, { "dtor", "(I)V", (void*)dtor_native }, { "writeEntityHeader_native", "(ILjava/lang/String;I)I", (void*)writeEntityHeader_native }, { "writeEntityData_native", "(I[BI)I", (void*)writeEntityData_native }, + { "setKeyPrefix_native", "(ILjava/lang/String;)V", (void*)setKeyPrefix_native }, }; int register_android_backup_BackupDataOutput(JNIEnv* env) diff --git a/core/jni/android_backup_FileBackupHelper.cpp b/core/jni/android_backup_FileBackupHelperBase.cpp similarity index 69% rename from core/jni/android_backup_FileBackupHelper.cpp rename to core/jni/android_backup_FileBackupHelperBase.cpp index 418db8a3bd75b..8225a36b41648 100644 --- a/core/jni/android_backup_FileBackupHelper.cpp +++ b/core/jni/android_backup_FileBackupHelperBase.cpp @@ -28,6 +28,18 @@ namespace android // java.io.FileDescriptor static jfieldID s_descriptorField = 0; +static int +ctor(JNIEnv* env, jobject clazz) +{ + return (int)new RestoreHelperBase(); +} + +static void +dtor(JNIEnv* env, jobject clazz, jint ptr) +{ + delete (RestoreHelperBase*)ptr; +} + static int performBackup_native(JNIEnv* env, jobject clazz, jobject oldState, int data, jobject newState, jobjectArray files, jobjectArray keys) @@ -66,13 +78,48 @@ performBackup_native(JNIEnv* env, jobject clazz, jobject oldState, int data, return err; } + +static int +writeFile_native(JNIEnv* env, jobject clazz, jint ptr, jstring filenameObj, int backupReaderPtr) +{ + int err; + RestoreHelperBase* restore = (RestoreHelperBase*)ptr; + BackupDataReader* reader = (BackupDataReader*)backupReaderPtr; + char const* filename; + + filename = env->GetStringUTFChars(filenameObj, NULL); + + err = restore->WriteFile(String8(filename), reader); + + env->ReleaseStringUTFChars(filenameObj, filename); + + return err; +} + +static int +writeSnapshot_native(JNIEnv* env, jobject clazz, jint ptr, jobject fileDescriptor) +{ + int err; + + RestoreHelperBase* restore = (RestoreHelperBase*)ptr; + int fd = env->GetIntField(fileDescriptor, s_descriptorField); + + err = restore->WriteSnapshot(fd); + + return err; +} + static const JNINativeMethod g_methods[] = { + { "ctor", "()I", (void*)ctor }, + { "dtor", "(I)V", (void*)dtor }, { "performBackup_native", "(Ljava/io/FileDescriptor;ILjava/io/FileDescriptor;[Ljava/lang/String;[Ljava/lang/String;)I", (void*)performBackup_native }, + { "writeFile_native", "(ILjava/lang/String;I)I", (void*)writeFile_native }, + { "writeSnapshot_native", "(ILjava/io/FileDescriptor;)I", (void*)writeSnapshot_native }, }; -int register_android_backup_FileBackupHelper(JNIEnv* env) +int register_android_backup_FileBackupHelperBase(JNIEnv* env) { jclass clazz; @@ -82,7 +129,7 @@ int register_android_backup_FileBackupHelper(JNIEnv* env) LOG_FATAL_IF(s_descriptorField == NULL, "Unable to find descriptor field in java.io.FileDescriptor"); - return AndroidRuntime::registerNativeMethods(env, "android/backup/FileBackupHelper", + return AndroidRuntime::registerNativeMethods(env, "android/backup/FileBackupHelperBase", g_methods, NELEM(g_methods)); } diff --git a/core/jni/android_backup_RestoreHelperBase.cpp b/core/jni/android_backup_RestoreHelperBase.cpp deleted file mode 100644 index 3173420a317e2..0000000000000 --- a/core/jni/android_backup_RestoreHelperBase.cpp +++ /dev/null @@ -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 - -#include "JNIHelp.h" -#include - -#include - -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 c78b99a8dca00..a21359f55eaf6 100644 --- a/include/utils/BackupHelpers.h +++ b/include/utils/BackupHelpers.h @@ -71,6 +71,8 @@ public: status_t WriteEntityHeader(const String8& key, size_t dataSize); status_t WriteEntityData(const void* data, size_t size); + void SetKeyPrefix(const String8& keyPrefix); + private: explicit BackupDataWriter(); status_t write_padding_for(int n); @@ -79,6 +81,7 @@ private: status_t m_status; ssize_t m_pos; int m_entityCount; + String8 m_keyPrefix; }; /** diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp index 6a7f056464725..0868cff6c177c 100644 --- a/libs/utils/BackupData.cpp +++ b/libs/utils/BackupData.cpp @@ -99,10 +99,20 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) return amt; } + String8 k; + if (m_keyPrefix.length() > 0) { + k = m_keyPrefix; + k += ":"; + k += key; + } else { + k = key; + } + LOGD("m_keyPrefix=%s key=%s k=%s", m_keyPrefix.string(), key.string(), k.string()); + entity_header_v1 header; ssize_t keyLen; - keyLen = key.length(); + keyLen = k.length(); header.type = tolel(BACKUP_HEADER_ENTITY_V1); header.keyLen = tolel(keyLen); @@ -115,7 +125,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) } m_pos += amt; - amt = write(m_fd, key.string(), keyLen+1); + amt = write(m_fd, k.string(), keyLen+1); if (amt != keyLen+1) { m_status = errno; return m_status; @@ -148,6 +158,11 @@ BackupDataWriter::WriteEntityData(const void* data, size_t size) return NO_ERROR; } +void +BackupDataWriter::SetKeyPrefix(const String8& keyPrefix) +{ + m_keyPrefix = keyPrefix; +} BackupDataReader::BackupDataReader(int fd) @@ -298,7 +313,7 @@ BackupDataReader::ReadEntityData(void* data, size_t size) if (remaining <= 0) { return 0; } - if (size > remaining) { + if (((int)size) > remaining) { size = remaining; } //LOGD(" reading %d bytes", size); diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 75e0e64b1d927..9a8d7401e8d29 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -164,8 +164,8 @@ class BackupManagerService extends IBackupManager.Stub { // Set up our transport options and initialize the default transport // TODO: Have transports register themselves somehow? // TODO: Don't create transports that we don't need to? - //mTransportId = BackupManager.TRANSPORT_LOCAL; - mTransportId = BackupManager.TRANSPORT_GOOGLE; + mTransportId = BackupManager.TRANSPORT_LOCAL; + //mTransportId = BackupManager.TRANSPORT_GOOGLE; mLocalTransport = new LocalTransport(context); // This is actually pretty cheap mGoogleTransport = null; diff --git a/tests/backup/src/com/android/backuptest/BackupTestActivity.java b/tests/backup/src/com/android/backuptest/BackupTestActivity.java index f0c3f93a8f434..69da7610bedd6 100644 --- a/tests/backup/src/com/android/backuptest/BackupTestActivity.java +++ b/tests/backup/src/com/android/backuptest/BackupTestActivity.java @@ -17,12 +17,11 @@ package com.android.backuptest; import android.app.ListActivity; +import android.backup.BackupHelperDispatcher; import android.backup.BackupDataInput; import android.backup.BackupDataOutput; import android.backup.BackupManager; import android.backup.FileBackupHelper; -import android.backup.FileRestoreHelper; -import android.backup.RestoreHelperDispatcher; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; @@ -142,10 +141,10 @@ public class BackupTestActivity extends ListActivity ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE| ParcelFileDescriptor.MODE_TRUNCATE); FileBackupHelper h = new FileBackupHelper(BackupTestActivity.this, - "FileBackupHelper"); + new String[] { "a", "empty" }); FileOutputStream dataFile = openFileOutput("backup_test", MODE_WORLD_READABLE); BackupDataOutput data = new BackupDataOutput(dataFile.getFD()); - h.performBackup(null, data, state, new String[] { "a", "empty" }); + h.performBackup(null, data, state); dataFile.close(); state.close(); } catch (IOException ex) { @@ -156,16 +155,16 @@ public class BackupTestActivity extends ListActivity new Test("Restore Helpers") { void run() { try { - RestoreHelperDispatcher dispatch = new RestoreHelperDispatcher(); - dispatch.addHelper("FileBackupHelper", - new FileRestoreHelper(BackupTestActivity.this)); + BackupHelperDispatcher dispatch = new BackupHelperDispatcher(); + dispatch.addHelper("", new FileBackupHelper(BackupTestActivity.this, + new String[] { "a", "empty" })); FileInputStream dataFile = openFileInput("backup_test"); BackupDataInput data = new BackupDataInput(dataFile.getFD()); ParcelFileDescriptor state = ParcelFileDescriptor.open( new File(getFilesDir(), "restore_state"), ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE| ParcelFileDescriptor.MODE_TRUNCATE); - dispatch.dispatch(data, state); + dispatch.performRestore(data, state); dataFile.close(); state.close(); } catch (IOException ex) { diff --git a/tests/backup/src/com/android/backuptest/BackupTestAgent.java b/tests/backup/src/com/android/backuptest/BackupTestAgent.java index 0da41519a007d..c6acc66d66f61 100644 --- a/tests/backup/src/com/android/backuptest/BackupTestAgent.java +++ b/tests/backup/src/com/android/backuptest/BackupTestAgent.java @@ -16,46 +16,13 @@ package com.android.backuptest; -import android.app.BackupAgent; -import android.backup.BackupDataInput; -import android.backup.BackupDataOutput; +import android.backup.BackupHelperAgent; import android.backup.FileBackupHelper; -import android.backup.FileRestoreHelper; -import android.backup.RestoreHelperDispatcher; -import android.os.ParcelFileDescriptor; -import android.util.Log; -import java.io.IOException; - -public class BackupTestAgent extends BackupAgent +public class BackupTestAgent extends BackupHelperAgent { - static final String TAG = "BackupTestAgent"; - - static final String SHARED_PREFS = "shared_prefs"; - static final String DATA_FILES = "data_files"; - static final String[] FILES = new String[] { - BackupTestActivity.FILE_NAME - }; - - @Override - public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, - ParcelFileDescriptor newState) { - Log.d(TAG, "onBackup"); - - (new FileBackupHelper(this, DATA_FILES)).performBackup(oldState, data, newState, FILES); - } - - @Override - public void onRestore(BackupDataInput data, ParcelFileDescriptor newState) - throws IOException { - Log.d(TAG, "onRestore"); - - RestoreHelperDispatcher dispatch = new RestoreHelperDispatcher(); - - // dispatch.addHelper(SHARED_PREFS, new SharedPrefsRestoreHelper(this)); - dispatch.addHelper(DATA_FILES, new FileRestoreHelper(this)); - - dispatch.dispatch(data, newState); + public void onCreate() { + addHelper("data_files", new FileBackupHelper(this, BackupTestActivity.FILE_NAME)); } }