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.
diff --git a/core/java/android/app/FullBackupAgent.java b/core/java/android/app/FullBackupAgent.java
index 89becf4..bc6bb15 100644
--- a/core/java/android/app/FullBackupAgent.java
+++ b/core/java/android/app/FullBackupAgent.java
@@ -48,8 +48,8 @@
         }
 
         // 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 05e667e..d29c5ba 100644
--- a/core/java/android/backup/BackupDataOutput.java
+++ b/core/java/android/backup/BackupDataOutput.java
@@ -55,6 +55,10 @@
         }
     }
 
+    public void setKeyPrefix(String keyPrefix) {
+        setKeyPrefix_native(mBackupWriter, keyPrefix);
+    }
+
     protected void finalize() throws Throwable {
         try {
             dtor(mBackupWriter);
@@ -62,11 +66,12 @@
             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 e47869c..3983e28 100644
--- a/core/java/android/backup/RestoreHelper.java
+++ b/core/java/android/backup/BackupHelper.java
@@ -21,14 +21,26 @@
 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.
      * <p class=note>
      * Do not close the <code>data</code> stream.  Do not read more than
      * <code>dataSize</code> bytes from <code>data</code>.
      */
     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 0000000..f7eb1b8
--- /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 4861775..e9a8f71 100644
--- a/core/java/android/backup/RestoreHelperDispatcher.java
+++ b/core/java/android/backup/BackupHelperDispatcher.java
@@ -20,20 +20,34 @@
 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<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);
     }
 
-    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;
 
         BackupDataInputStream stream = new BackupDataInputStream(input);
@@ -43,7 +57,7 @@
             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 @@
             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 ed840bb..4058497 100644
--- a/core/java/android/backup/FileBackupHelper.java
+++ b/core/java/android/backup/FileBackupHelper.java
@@ -24,19 +24,19 @@
 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 @@
      * 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 @@
             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 <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;
+    public void restoreEntity(BackupDataInputStream data) {
+        // TODO: turn this off before ship
+        Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size());
+        String key = data.getKey();
+        if (isKeyInList(key, mFiles)) {
+            File f = new File(mFilesDir, key);
+            writeFile(f, data);
         }
     }
-
-    /**
-     * 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);
 }
+
diff --git a/core/java/android/backup/FileBackupHelperBase.java b/core/java/android/backup/FileBackupHelperBase.java
new file mode 100644
index 0000000..03ae476
--- /dev/null
+++ b/core/java/android/backup/FileBackupHelperBase.java
@@ -0,0 +1,130 @@
+/*
+ * 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.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.InputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+
+class FileBackupHelperBase {
+    private static final String TAG = "RestoreHelperBase";
+
+    int mPtr;
+    Context mContext;
+    boolean mExceptionLogged;
+    
+    FileBackupHelperBase(Context context) {
+        mPtr = ctor();
+        mContext = context;
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            dtor(mPtr);
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * 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) {
+        if (!(in instanceof BackupDataInputStream)) {
+            throw new IllegalStateException("input stream must be a BackupDataInputStream");
+        }
+        int result = -1;
+
+        // Create the enclosing directory.
+        File parent = f.getParentFile();
+        parent.mkdirs();
+
+        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() + "\' result=0x"
+                        + Integer.toHexString(result));
+                mExceptionLogged = true;
+            }
+        }
+    }
+
+    public void writeRestoreSnapshot(ParcelFileDescriptor fd) {
+        int result = writeSnapshot_native(mPtr, fd.getFileDescriptor());
+        // 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 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 writeSnapshot_native(int ptr, FileDescriptor fd);
+}
+
+
diff --git a/core/java/android/backup/FileRestoreHelper.java b/core/java/android/backup/FileRestoreHelper.java
deleted file mode 100644
index b7e3625..0000000
--- a/core/java/android/backup/FileRestoreHelper.java
+++ /dev/null
@@ -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);
-    }
-}
-
diff --git a/core/java/android/backup/RestoreHelperBase.java b/core/java/android/backup/RestoreHelperBase.java
deleted file mode 100644
index 93a8fef..0000000
--- a/core/java/android/backup/RestoreHelperBase.java
+++ /dev/null
@@ -1,82 +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.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import java.io.InputStream;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-
-class RestoreHelperBase {
-    private static final String TAG = "RestoreHelperBase";
-
-    int mPtr;
-    Context mContext;
-    boolean mExceptionLogged;
-    
-    RestoreHelperBase(Context context) {
-        mPtr = ctor();
-        mContext = context;
-    }
-
-    protected void finalize() throws Throwable {
-        try {
-            dtor(mPtr);
-        } finally {
-            super.finalize();
-        }
-    }
-
-    void writeFile(File f, InputStream in) {
-        if (!(in instanceof BackupDataInputStream)) {
-            throw new IllegalStateException("input stream must be a BackupDataInputStream");
-        }
-        int result = -1;
-
-        // Create the enclosing directory.
-        File parent = f.getParentFile();
-        parent.mkdirs();
-
-        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() + "\' result=0x"
-                        + Integer.toHexString(result));
-                mExceptionLogged = true;
-            }
-        }
-    }
-
-    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/SharedPreferencesBackupHelper.java b/core/java/android/backup/SharedPreferencesBackupHelper.java
index cad79df..f492629 100644
--- a/core/java/android/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/backup/SharedPreferencesBackupHelper.java
@@ -18,39 +18,51 @@
 
 import android.content.Context;
 import android.os.ParcelFileDescriptor;
+import android.util.Log;
 
+import java.io.File;
 import java.io.FileDescriptor;
 
 /** @hide */
-public class SharedPreferencesBackupHelper {
+public class SharedPreferencesBackupHelper extends FileBackupHelperBase implements BackupHelper {
+    private static final String TAG = "SharedPreferencesBackupHelper";
+
     private Context mContext;
-    private String mKeyPrefix;
+    private String[] mPrefGroups;
 
-    public SharedPreferencesBackupHelper(Context context) {
+    public SharedPreferencesBackupHelper(Context context, String[] prefGroups) {
+        super(context);
+
         mContext = context;
+        mPrefGroups = prefGroups;
     }
 
-    public SharedPreferencesBackupHelper(Context context, String keyPrefix) {
-        mContext = context;
-        mKeyPrefix = keyPrefix;
-    }
-    
-    public void performBackup(ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot,
-            BackupDataOutput data, String[] prefGroups) {
+    public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) {
         Context context = mContext;
         
         // make filenames for the prefGroups
+        String[] prefGroups = mPrefGroups;
         final int N = prefGroups.length;
         String[] files = new String[N];
         for (int i=0; i<N; i++) {
             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);
+        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);
+        }
     }
 }
 
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index faa04f7..80c2489 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -119,8 +119,7 @@
 	com_android_internal_graphics_NativeUtils.cpp \
 	android_backup_BackupDataInput.cpp \
 	android_backup_BackupDataOutput.cpp \
-	android_backup_FileBackupHelper.cpp \
-	android_backup_RestoreHelperBase.cpp
+	android_backup_FileBackupHelperBase.cpp
 
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 18f6d5f9..7350348 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -157,8 +157,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);
+extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
 
 static AndroidRuntime* gCurRuntime = NULL;
 
@@ -1131,8 +1130,7 @@
     REG_JNI(register_android_location_GpsLocationProvider),
     REG_JNI(register_android_backup_BackupDataInput),
     REG_JNI(register_android_backup_BackupDataOutput),
-    REG_JNI(register_android_backup_FileBackupHelper),
-    REG_JNI(register_android_backup_RestoreHelperBase),
+    REG_JNI(register_android_backup_FileBackupHelperBase),
 };
 
 /*
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index 6362439..d02590e 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -87,11 +87,26 @@
     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[] = {
     { "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 418db8a..8225a36 100644
--- a/core/jni/android_backup_FileBackupHelper.cpp
+++ b/core/jni/android_backup_FileBackupHelperBase.cpp
@@ -29,6 +29,18 @@
 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 @@
     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 @@
     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 3173420..0000000
--- 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 <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 c78b99a..a21359f 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -71,6 +71,8 @@
     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 @@
     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 6a7f056..0868cff 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -99,10 +99,20 @@
         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 @@
     }
     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 @@
     return NO_ERROR;
 }
 
+void
+BackupDataWriter::SetKeyPrefix(const String8& keyPrefix)
+{
+    m_keyPrefix = keyPrefix;
+}
 
 
 BackupDataReader::BackupDataReader(int fd)
@@ -298,7 +313,7 @@
     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 75e0e64..9a8d740 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -164,8 +164,8 @@
         // 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 f0c3f93..69da761 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 @@
                             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 @@
         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 0da4151..c6acc66 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));
     }
 }