Merge change 4455 into donut

* changes:
  add feedback test with gsm7bit special case characters
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index a3ab641..128fd5a 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -215,7 +215,7 @@
 {
     Mutex::Autolock _l(mLock);
     // allow anyone to use camera
-    LOGV("unlock (%p)", getCameraClient()->asBinder().get());
+    LOGD("unlock (%p)", getCameraClient()->asBinder().get());
     status_t result = checkPid();
     if (result == NO_ERROR) {
         mClientPid = 0;
@@ -230,7 +230,7 @@
 status_t CameraService::Client::connect(const sp<ICameraClient>& client)
 {
     // connect a new process to the camera
-    LOGV("connect (%p)", client->asBinder().get());
+    LOGD("connect (%p)", client->asBinder().get());
 
     // I hate this hack, but things get really ugly when the media recorder
     // service is handing back the camera to the app. The ICameraClient
@@ -257,7 +257,7 @@
             mCameraClient = client;
             mClientPid = -1;
             mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
-            LOGV("connect new process (%d) to existing camera client", mClientPid);
+            LOGD("connect new process (%d) to existing camera client", mClientPid);
         }
 
     }
@@ -319,17 +319,17 @@
             IPCThreadState::self()->getCallingPid());
     Mutex::Autolock lock(mLock);
     if (mClientPid <= 0) {
-        LOGV("camera is unlocked, don't tear down hardware");
+        LOGD("camera is unlocked, don't tear down hardware");
         return;
     }
     if (checkPid() != NO_ERROR) {
-        LOGV("Different client - don't disconnect");
+        LOGD("Different client - don't disconnect");
         return;
     }
 
     mCameraService->removeClient(mCameraClient);
     if (mHardware != 0) {
-        LOGV("hardware teardown");
+        LOGD("hardware teardown");
         // Before destroying mHardware, we must make sure it's in the
         // idle state.
         mHardware->stopPreview();
diff --git a/cmds/keystore/commands.c b/cmds/keystore/commands.c
index e53cece..17dd060 100644
--- a/cmds/keystore/commands.c
+++ b/cmds/keystore/commands.c
@@ -1,5 +1,5 @@
 /*
-** Copyright 2008, The Android Open Source Project
+** Copyright 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.
@@ -30,7 +30,8 @@
     return d;
 }
 
-static int list_files(const char *dir, char reply[REPLY_MAX]) {
+static int list_files(const char *dir, char reply[REPLY_MAX])
+{
     struct dirent *de;
     DIR *d;
 
@@ -39,7 +40,9 @@
     }
     reply[0]=0;
     while ((de = readdir(d))) {
-        if (de->d_type != DT_REG) continue;
+        if (de->d_type != DT_DIR) continue;
+        if ((strcmp(DOT, de->d_name) == 0) ||
+                (strcmp(DOTDOT, de->d_name) == 0)) continue;
         if (reply[0] != 0) strlcat(reply, " ", REPLY_MAX);
         if (strlcat(reply, de->d_name, REPLY_MAX) >= REPLY_MAX) {
             LOGE("reply is too long(too many files under '%s'\n", dir);
@@ -50,31 +53,25 @@
     return 0;
 }
 
-static int copy_keyfile(const char *keystore, const char *srcfile) {
-    int srcfd, dstfd;
-    int length;
-    char buf[2048];
-    char dstfile[KEYNAME_LENGTH];
-    const char *filename = strrchr(srcfile, '/');
+static int copy_keyfile(const char *src, int src_type, const char *dstfile) {
+    int srcfd = -1, dstfd;
+    char buf[REPLY_MAX];
 
-    strlcpy(dstfile, keystore, KEYNAME_LENGTH);
-    strlcat(dstfile, "/", KEYNAME_LENGTH);
-    if (strlcat(dstfile, filename ? filename + 1 : srcfile,
-                KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
-        LOGE("keyname is too long '%s'\n", srcfile);
-        return -1;
-    }
-
-    if ((srcfd = open(srcfile, O_RDONLY)) == -1) {
-        LOGE("Cannot open the original file '%s'\n", srcfile);
+    if ((src_type == IS_FILE) && (srcfd = open(src, O_RDONLY)) == -1) {
+        LOGE("Cannot open the original file '%s'\n", src);
         return -1;
     }
     if ((dstfd = open(dstfile, O_CREAT|O_RDWR)) == -1) {
         LOGE("Cannot open the destination file '%s'\n", dstfile);
         return -1;
     }
-    while((length = read(srcfd, buf, 2048)) > 0) {
-        write(dstfd, buf, length);
+    if (src_type == IS_FILE) {
+        int length;
+        while((length = read(srcfd, buf, REPLY_MAX)) > 0) {
+            write(dstfd, buf, length);
+        }
+    } else {
+        write(dstfd, src, strlen(src));
     }
     close(srcfd);
     close(dstfd);
@@ -82,60 +79,149 @@
     return 0;
 }
 
-static int install_key(const char *dir, const char *keyfile)
+static int install_key(const char *path, const char *certname, const char *src,
+        int src_is_file, char *dstfile)
 {
     struct dirent *de;
+    char fullpath[KEYNAME_LENGTH];
     DIR *d;
 
-    if ((d = open_keystore(dir)) == NULL) {
+    if (snprintf(fullpath, sizeof(fullpath), "%s/%s/", path, certname)
+            >= KEYNAME_LENGTH) {
+        LOGE("cert name '%s' is too long.\n", certname);
         return -1;
     }
-    return copy_keyfile(dir, keyfile);
+
+    if ((d = open_keystore(fullpath)) == NULL) {
+        LOGE("Can not open the keystore '%s'\n", fullpath);
+        return -1;
+    }
+    closedir(d);
+    if (strlcat(fullpath, dstfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
+        LOGE("cert name '%s' is too long.\n", certname);
+        return -1;
+    }
+    return copy_keyfile(src, src_is_file, fullpath);
 }
 
-static int remove_key(const char *dir, const char *keyfile)
+static int get_key(const char *path, const char *keyname, const char *file,
+        char reply[REPLY_MAX])
 {
-    char dstfile[KEYNAME_LENGTH];
+    struct dirent *de;
+    char filename[KEYNAME_LENGTH];
+    int fd;
 
-    strlcpy(dstfile, dir, KEYNAME_LENGTH);
-    strlcat(dstfile, "/", KEYNAME_LENGTH);
-    if (strlcat(dstfile, keyfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
-        LOGE("keyname is too long '%s'\n", keyfile);
+    if (snprintf(filename, sizeof(filename), "%s/%s/%s", path, keyname, file)
+            >= KEYNAME_LENGTH) {
+        LOGE("cert name '%s' is too long.\n", keyname);
         return -1;
     }
-    if (unlink(dstfile)) {
-        LOGE("cannot delete '%s': %s\n", dstfile, strerror(errno));
+
+    if ((fd = open(filename, O_RDONLY)) == -1) {
+        return -1;
+    }
+    close(fd);
+    strlcpy(reply, filename, REPLY_MAX);
+    return 0;
+}
+
+static int remove_key(const char *dir, const char *key)
+{
+    char dstfile[KEYNAME_LENGTH];
+    char *keyfile[4] = { USER_KEY, USER_P12_CERT, USER_CERTIFICATE,
+            CA_CERTIFICATE };
+    int i, count = 0;
+
+    for ( i = 0 ; i < 4 ; i++) {
+        if (snprintf(dstfile, KEYNAME_LENGTH, "%s/%s/%s", dir, key, keyfile[i])
+                >= KEYNAME_LENGTH) {
+            LOGE("keyname is too long '%s'\n", key);
+            return -1;
+        }
+        if (unlink(dstfile) == 0) count++;
+    }
+
+    if (count == 0) {
+        LOGE("can not clean up '%s' keys or not exist\n", key);
+        return -1;
+    }
+
+    snprintf(dstfile, KEYNAME_LENGTH, "%s/%s", dir, key);
+    if (rmdir(dstfile)) {
+        LOGE("can not clean up '%s' directory\n", key);
         return -1;
     }
     return 0;
 }
 
-int list_certs(char reply[REPLY_MAX])
+int list_user_certs(char reply[REPLY_MAX])
 {
     return list_files(CERTS_DIR, reply);
 }
 
-int list_userkeys(char reply[REPLY_MAX])
+int list_ca_certs(char reply[REPLY_MAX])
 {
-    return list_files(USERKEYS_DIR, reply);
+    return list_files(CACERTS_DIR, reply);
 }
 
-int install_cert(const char *certfile)
+int install_user_cert(const char *keyname, const char *cert, const char *key)
 {
-    return install_key(CERTS_DIR, certfile);
+    if (install_key(CERTS_DIR, keyname, cert, IS_FILE, USER_CERTIFICATE) == 0) {
+        return install_key(CERTS_DIR, keyname, key, IS_FILE, USER_KEY);
+    }
+    return -1;
 }
 
-int install_userkey(const char *keyfile)
+int install_ca_cert(const char *keyname, const char *certfile)
 {
-    return install_key(USERKEYS_DIR, keyfile);
+    return install_key(CACERTS_DIR, keyname, certfile, IS_FILE, CA_CERTIFICATE);
 }
 
-int remove_cert(const char *certfile)
+int install_p12_cert(const char *keyname, const char *certfile)
 {
-    return remove_key(CERTS_DIR, certfile);
+    return install_key(CERTS_DIR, keyname, certfile, IS_FILE, USER_P12_CERT);
 }
 
-int remove_userkey(const char *keyfile)
+int add_ca_cert(const char *keyname, const char *certificate)
 {
-    return remove_key(USERKEYS_DIR, keyfile);
+    return install_key(CACERTS_DIR, keyname, certificate, IS_CONTENT,
+            CA_CERTIFICATE);
+}
+
+int add_user_cert(const char *keyname, const char *certificate)
+{
+    return install_key(CERTS_DIR, keyname, certificate, IS_CONTENT,
+            USER_CERTIFICATE);
+}
+
+int add_user_key(const char *keyname, const char *key)
+{
+    return install_key(CERTS_DIR, keyname, key, IS_CONTENT, USER_KEY);
+}
+
+int get_ca_cert(const char *keyname, char reply[REPLY_MAX])
+{
+    return get_key(CACERTS_DIR, keyname, CA_CERTIFICATE, reply);
+}
+
+int get_user_cert(const char *keyname, char reply[REPLY_MAX])
+{
+    return get_key(CERTS_DIR, keyname, USER_CERTIFICATE, reply);
+}
+
+int get_user_key(const char *keyname, char reply[REPLY_MAX])
+{
+    if(get_key(CERTS_DIR, keyname, USER_KEY, reply))
+        return get_key(CERTS_DIR, keyname, USER_P12_CERT, reply);
+    return 0;
+}
+
+int remove_user_cert(const char *key)
+{
+    return remove_key(CERTS_DIR, key);
+}
+
+int remove_ca_cert(const char *key)
+{
+    return remove_key(CACERTS_DIR, key);
 }
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index 5193b3d..df8d832 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -16,37 +16,89 @@
 
 #include "keystore.h"
 
-
-static int do_list_certs(char **arg, char reply[REPLY_MAX])
+static inline int has_whitespace(char *name)
 {
-    return list_certs(reply);
+    if((strrchr(name, ' ') != NULL)) {
+        LOGE("'%s' contains whitespace character\n", name);
+        return 1;
+    }
+    return 0;
 }
 
-static int do_list_userkeys(char **arg, char reply[REPLY_MAX])
+static int do_list_user_certs(char **arg, char reply[REPLY_MAX])
 {
-    return list_userkeys(reply);
+    return list_user_certs(reply);
 }
 
-static int do_install_cert(char **arg, char reply[REPLY_MAX])
+static int do_list_ca_certs(char **arg, char reply[REPLY_MAX])
 {
-    return install_cert(arg[0]); /* move the certificate to keystore */
+    return list_ca_certs(reply);
 }
 
-static int do_remove_cert(char **arg, char reply[REPLY_MAX])
+static int do_install_user_cert(char **arg, char reply[REPLY_MAX])
 {
-    return remove_cert(arg[0]); /* certificate */
+    if (has_whitespace(arg[0])) return -1;
+    /* copy the certificate and key to keystore */
+    return install_user_cert(arg[0], arg[1], arg[2]);
 }
 
-static int do_install_userkey(char **arg, char reply[REPLY_MAX])
+static int do_install_p12_cert(char **arg, char reply[REPLY_MAX])
 {
-    return install_userkey(arg[0]); /* move the certificate to keystore */
+    if (has_whitespace(arg[0])) return -1;
+    return install_p12_cert(arg[0], arg[1]);
 }
 
-static int do_remove_userkey(char **arg, char reply[REPLY_MAX])
+static int do_install_ca_cert(char **arg, char reply[REPLY_MAX])
 {
-    return remove_userkey(arg[0]); /* userkey */
+    if (has_whitespace(arg[0])) return -1;
+    /* copy the certificate and key to keystore */
+    return install_ca_cert(arg[0], arg[1]);
 }
 
+static int do_add_ca_cert(char **arg, char reply[REPLY_MAX])
+{
+    if (has_whitespace(arg[0])) return -1;
+    return add_ca_cert(arg[0], arg[1]);
+}
+
+static int do_add_user_cert(char **arg, char reply[REPLY_MAX])
+{
+    if (has_whitespace(arg[0])) return -1;
+    return add_user_cert(arg[0], arg[1]);
+}
+
+static int do_add_user_key(char **arg, char reply[REPLY_MAX])
+{
+    if (has_whitespace(arg[0])) return -1;
+    return add_user_key(arg[0], arg[1]);
+}
+
+static int do_get_ca_cert(char **arg, char reply[REPLY_MAX])
+{
+    return get_ca_cert(arg[0], reply);
+}
+
+static int do_get_user_cert(char **arg, char reply[REPLY_MAX])
+{
+    return get_user_cert(arg[0], reply);
+}
+
+static int do_get_user_key(char **arg, char reply[REPLY_MAX])
+{
+    return get_user_key(arg[0], reply);
+}
+
+static int do_remove_user_cert(char **arg, char reply[REPLY_MAX])
+{
+    return remove_user_cert(arg[0]);
+}
+
+static int do_remove_ca_cert(char **arg, char reply[REPLY_MAX])
+{
+    return remove_ca_cert(arg[0]);
+}
+
+
 struct cmdinfo {
     const char *name;
     unsigned numargs;
@@ -55,12 +107,19 @@
 
 
 struct cmdinfo cmds[] = {
-    { "listcerts",            0, do_list_certs },
-    { "listuserkeys",         0, do_list_userkeys },
-    { "installcert",          1, do_install_cert },
-    { "removecert",           1, do_remove_cert },
-    { "installuserkey",       1, do_install_userkey },
-    { "removeuserkey",        1, do_remove_userkey },
+    { "listcacerts",        0, do_list_ca_certs },
+    { "listusercerts",      0, do_list_user_certs },
+    { "installusercert",    3, do_install_user_cert },
+    { "installcacert",      2, do_install_ca_cert },
+    { "installp12cert",     2, do_install_p12_cert },
+    { "addusercert",        2, do_add_user_cert },
+    { "adduserkey",         2, do_add_user_key },
+    { "addcacert",          2, do_add_ca_cert },
+    { "getusercert",        1, do_get_user_cert },
+    { "getuserkey",         1, do_get_user_key },
+    { "getcacert",          1, do_get_ca_cert },
+    { "removecacert",       1, do_remove_ca_cert },
+    { "removeusercert",     1, do_remove_user_cert },
 };
 
 static int readx(int s, void *_buf, int count)
@@ -121,7 +180,7 @@
     /* n is number of args (not counting arg[0]) */
     arg[0] = cmd;
     while (*cmd) {
-        if (isspace(*cmd)) {
+        if (*cmd == CMD_DELIMITER) {
             *cmd++ = 0;
             n++;
             arg[n] = cmd;
@@ -167,6 +226,7 @@
     int fd, i;
     short ret;
     unsigned short count;
+    char delimiter[2] = { CMD_DELIMITER, 0 };
     char buf[BUFFER_MAX]="";
 
     fd = socket_local_client(SOCKET_PATH,
@@ -177,7 +237,7 @@
         exit(1);
     }
     for(i = 0; i < argc; i++) {
-        if (i > 0) strlcat(buf, " ", BUFFER_MAX);
+        if (i > 0) strlcat(buf, delimiter, BUFFER_MAX);
         if(strlcat(buf, argv[i], BUFFER_MAX) >= BUFFER_MAX) {
             fprintf(stderr, "Arguments are too long\n");
             exit(1);
diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h
index 35acf0b..b9cb185 100644
--- a/cmds/keystore/keystore.h
+++ b/cmds/keystore/keystore.h
@@ -40,18 +40,35 @@
 /* path of the keystore */
 
 #define KEYSTORE_DIR_PREFIX "/data/misc/keystore"
-#define CERTS_DIR           KEYSTORE_DIR_PREFIX "/certs"
-#define USERKEYS_DIR         KEYSTORE_DIR_PREFIX "/userkeys"
+#define CERTS_DIR           KEYSTORE_DIR_PREFIX "/keys"
+#define CACERTS_DIR         KEYSTORE_DIR_PREFIX "/cacerts"
+#define CA_CERTIFICATE      "ca.crt"
+#define USER_CERTIFICATE    "user.crt"
+#define USER_P12_CERT       "user.p12"
+#define USER_KEY            "user.key"
+#define DOT                 "."
+#define DOTDOT              ".."
 
-#define BUFFER_MAX      1024  /* input buffer for commands */
+#define BUFFER_MAX      4096  /* input buffer for commands */
 #define TOKEN_MAX       8     /* max number of arguments in buffer */
-#define REPLY_MAX       1024  /* largest reply allowed */
+#define REPLY_MAX       4096  /* largest reply allowed */
+#define CMD_DELIMITER   '\t'
 #define KEYNAME_LENGTH  128
+#define IS_CONTENT      0
+#define IS_FILE         1
+
 
 /* commands.c */
-int list_certs(char reply[REPLY_MAX]);
-int list_userkeys(char reply[REPLY_MAX]);
-int install_cert(const char *certfile);
-int install_userkey(const char *keyfile);
-int remove_cert(const char *certfile);
-int remove_userkey(const char *keyfile);
+int list_ca_certs(char reply[REPLY_MAX]);
+int list_user_certs(char reply[REPLY_MAX]);
+int install_user_cert(const char *certname, const char *cert, const char *key);
+int install_ca_cert(const char *certname, const char *cert);
+int install_p12_cert(const char *certname, const char *cert);
+int add_ca_cert(const char *certname, const char *content);
+int add_user_cert(const char *certname, const char *content);
+int add_user_key(const char *keyname, const char *content);
+int get_ca_cert(const char *keyname, char reply[REPLY_MAX]);
+int get_user_cert(const char *keyname, char reply[REPLY_MAX]);
+int get_user_key(const char *keyname, char reply[REPLY_MAX]);
+int remove_user_cert(const char *certname);
+int remove_ca_cert(const char *certname);
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
index d2aa30e..8486532 100644
--- a/include/tts/TtsEngine.h
+++ b/include/tts/TtsEngine.h
@@ -99,14 +99,18 @@
     // @param size  length of the language value
     // @return TTS_SUCCESS, or TTS_FAILURE
     virtual tts_result loadLanguage(const char *value, const size_t size);
-
-    // Signal the engine to use the specified language. This will force the
-    // language to be loaded if it wasn't loaded previously with loadLanguage().
-    // See loadLanguage for the specification of the language.
-    // @param value pointer to the language value
-    // @param size  length of the language value
+    
+    // Load the resources associated with the specified language, country and Locale variant.
+    // The loaded language will only be used once a call to setLanguageFromLocale() with the same
+    // language value is issued. Language and country values are coded according to the ISO three
+    // letter codes for languages and countries, as can be retrieved from a java.util.Locale
+    // instance. The variant value is encoded as the variant string retrieved from a
+    // java.util.Locale instance built with that variant data.
+    // @param lang pointer to the ISO three letter code for the language
+    // @param country pointer to the ISO three letter code for the country
+    // @param variant pointer to the variant code
     // @return TTS_SUCCESS, or TTS_FAILURE
-    virtual tts_result setLanguage(const char *value, const size_t size);
+    virtual tts_result setLanguage(const char *lang, const char *country, const char *variant);
 
     // Retrieve the currently set language, or an empty "value" if no language
     // has been set.
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index f60f4ea..3ca8ad2 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -23,30 +23,15 @@
 namespace android {
 
 enum {
-    BACKUP_HEADER_APP_V1 = 0x31707041, // App1 (little endian)
     BACKUP_HEADER_ENTITY_V1 = 0x61746144, // Data (little endian)
-    BACKUP_FOOTER_APP_V1 = 0x746f6f46, // Foot (little endian)
 };
 
-// the sizes of all of these match.
-typedef struct {
-    int type; // == BACKUP_HEADER_APP_V1
-    int packageLen; // length of the name of the package that follows, not including the null.
-    int cookie;
-} app_header_v1;
-
 typedef struct {
     int type; // BACKUP_HEADER_ENTITY_V1
     int keyLen; // length of the key name, not including the null terminator
     int dataSize; // size of the data, not including the padding, -1 means delete
 } entity_header_v1;
 
-typedef struct {
-    int type; // BACKUP_FOOTER_APP_V1
-    int entityCount; // the number of entities that were written
-    int cookie;
-} app_footer_v1;
-
 
 /**
  * Writes the data.
@@ -61,13 +46,9 @@
     // does not close fd
     ~BackupDataWriter();
 
-    status_t WriteAppHeader(const String8& packageName, int cookie);
-
     status_t WriteEntityHeader(const String8& key, size_t dataSize);
     status_t WriteEntityData(const void* data, size_t size);
 
-    status_t WriteAppFooter(int cookie);
-
 private:
     explicit BackupDataWriter();
     status_t write_padding_for(int n);
@@ -92,28 +73,26 @@
     ~BackupDataReader();
 
     status_t Status();
-    status_t ReadNextHeader(int* type = NULL);
+    status_t ReadNextHeader(bool* done, int* type);
 
-    status_t ReadAppHeader(String8* packageName, int* cookie);
     bool HasEntities();
     status_t ReadEntityHeader(String8* key, size_t* dataSize);
     status_t SkipEntityData(); // must be called with the pointer at the begining of the data.
     status_t ReadEntityData(void* data, size_t size);
-    status_t ReadAppFooter(int* cookie);
 
 private:
     explicit BackupDataReader();
     status_t skip_padding();
     
     int m_fd;
+    bool m_done;
     status_t m_status;
     ssize_t m_pos;
+    ssize_t m_dataEndPos;
     int m_entityCount;
     union {
         int type;
-        app_header_v1 app;
         entity_header_v1 entity;
-        app_footer_v1 footer;
     } m_header;
 };
 
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index 8c9f875..16ff1e5 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -86,46 +86,6 @@
 }
 
 status_t
-BackupDataWriter::WriteAppHeader(const String8& packageName, int cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-
-    ssize_t amt;
-
-    amt = write_padding_for(m_pos);
-    if (amt != 0) {
-        return amt;
-    }
-
-    app_header_v1 header;
-    ssize_t nameLen;
-
-    nameLen = packageName.length();
-
-    header.type = tolel(BACKUP_HEADER_APP_V1);
-    header.packageLen = tolel(nameLen);
-    header.cookie = cookie;
-
-    amt = write(m_fd, &header, sizeof(app_header_v1));
-    if (amt != sizeof(app_header_v1)) {
-        m_status = errno;
-        return m_status;
-    }
-    m_pos += amt;
-
-    amt = write(m_fd, packageName.string(), nameLen+1);
-    if (amt != nameLen+1) {
-        m_status = errno;
-        return m_status;
-    }
-    m_pos += amt;
-
-    return NO_ERROR;
-}
-
-status_t
 BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
 {
     if (m_status != NO_ERROR) {
@@ -188,40 +148,11 @@
     return NO_ERROR;
 }
 
-status_t
-BackupDataWriter::WriteAppFooter(int cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-
-    ssize_t amt;
-
-    amt = write_padding_for(m_pos);
-    if (amt != 0) {
-        return amt;
-    }
-
-    app_footer_v1 footer;
-    ssize_t nameLen;
-
-    footer.type = tolel(BACKUP_FOOTER_APP_V1);
-    footer.entityCount = tolel(m_entityCount);
-    footer.cookie = cookie;
-
-    amt = write(m_fd, &footer, sizeof(app_footer_v1));
-    if (amt != sizeof(app_footer_v1)) {
-        m_status = errno;
-        return m_status;
-    }
-    m_pos += amt;
-
-    return NO_ERROR;
-}
 
 
 BackupDataReader::BackupDataReader(int fd)
     :m_fd(fd),
+     m_done(false),
      m_status(NO_ERROR),
      m_pos(0),
      m_entityCount(0)
@@ -260,31 +191,25 @@
     } while(0)
 
 status_t
-BackupDataReader::ReadNextHeader(int* type)
+BackupDataReader::ReadNextHeader(bool* done, int* type)
 {
+    *done = m_done;
     if (m_status != NO_ERROR) {
         return m_status;
     }
 
     int amt;
 
-    SKIP_PADDING();
+    // No error checking here, in case we're at the end of the stream.  Just let read() fail.
+    skip_padding();
     amt = read(m_fd, &m_header, sizeof(m_header));
+    *done = m_done = (amt == 0);
     CHECK_SIZE(amt, sizeof(m_header));
 
     // validate and fix up the fields.
     m_header.type = fromlel(m_header.type);
     switch (m_header.type)
     {
-        case BACKUP_HEADER_APP_V1:
-            m_header.app.packageLen = fromlel(m_header.app.packageLen);
-            if (m_header.app.packageLen < 0) {
-                LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos,
-                    (int)m_header.app.packageLen);
-                m_status = EINVAL;
-            }
-            m_header.app.cookie = m_header.app.cookie;
-            break;
         case BACKUP_HEADER_ENTITY_V1:
             m_header.entity.keyLen = fromlel(m_header.entity.keyLen);
             if (m_header.entity.keyLen <= 0) {
@@ -295,15 +220,6 @@
             m_header.entity.dataSize = fromlel(m_header.entity.dataSize);
             m_entityCount++;
             break;
-        case BACKUP_FOOTER_APP_V1:
-            m_header.footer.entityCount = fromlel(m_header.footer.entityCount);
-            if (m_header.footer.entityCount < 0) {
-                LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos,
-                        (int)m_header.footer.entityCount);
-                m_status = EINVAL;
-            }
-            m_header.footer.cookie = m_header.footer.cookie;
-            break;
         default:
             LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type);
             m_status = EINVAL;
@@ -316,30 +232,6 @@
     return m_status;
 }
 
-status_t
-BackupDataReader::ReadAppHeader(String8* packageName, int* cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-    if (m_header.type != BACKUP_HEADER_APP_V1) {
-        return EINVAL;
-    }
-    size_t size = m_header.app.packageLen;
-    char* buf = packageName->lockBuffer(size);
-    if (buf == NULL) {
-        packageName->unlockBuffer();
-        m_status = ENOMEM;
-        return m_status;
-    }
-    int amt = read(m_fd, buf, size+1);
-    CHECK_SIZE(amt, (int)size+1);
-    packageName->unlockBuffer(size);
-    m_pos += size+1;
-    *cookie = m_header.app.cookie;
-    return NO_ERROR;
-}
-
 bool
 BackupDataReader::HasEntities()
 {
@@ -368,6 +260,7 @@
     m_pos += size+1;
     *dataSize = m_header.entity.dataSize;
     SKIP_PADDING();
+    m_dataEndPos = m_pos + *dataSize;
     return NO_ERROR;
 }
 
@@ -381,7 +274,7 @@
         return EINVAL;
     }
     if (m_header.entity.dataSize > 0) {
-        int pos = lseek(m_fd, m_header.entity.dataSize, SEEK_CUR);
+        int pos = lseek(m_fd, m_dataEndPos, SEEK_SET);
         return pos == -1 ? (int)errno : (int)NO_ERROR;
     } else {
         return NO_ERROR;
@@ -394,6 +287,15 @@
     if (m_status != NO_ERROR) {
         return m_status;
     }
+    int remaining = m_dataEndPos - m_pos;
+    if (size > remaining) {
+        printf("size=%d m_pos=0x%x m_dataEndPos=0x%x remaining=%d\n",
+                size, m_pos, m_dataEndPos, remaining);
+        size = remaining;
+    }
+    if (remaining <= 0) {
+        return 0;
+    }
     int amt = read(m_fd, data, size);
     CHECK_SIZE(amt, (int)size);
     m_pos += size;
@@ -401,25 +303,6 @@
 }
 
 status_t
-BackupDataReader::ReadAppFooter(int* cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-    if (m_header.type != BACKUP_FOOTER_APP_V1) {
-        return EINVAL;
-    }
-    if (m_header.footer.entityCount != m_entityCount) {
-        LOGD("entity count mismatch actual=%d expected=%d", m_entityCount,
-                m_header.footer.entityCount);
-        m_status = EINVAL;
-        return m_status;
-    }
-    *cookie = m_header.footer.cookie;
-    return NO_ERROR;
-}
-
-status_t
 BackupDataReader::skip_padding()
 {
     ssize_t amt;
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index 4c3e37d..c1d5404 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -689,41 +689,27 @@
 
 // hexdump -v -e '"    " 8/1 " 0x%02x," "\n"' data_writer.data
 const unsigned char DATA_GOLDEN_FILE[] = {
-     0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
-     0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70,
-     0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
      0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
      0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
      0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
      0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
-     0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31,
-     0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
+     0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
+     0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
      0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
-     0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
-     0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
-     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
-     0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
-     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
-     0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
-     0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
-     0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
+     0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
      0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
      0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
      0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
      0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
      0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
-     0x5f, 0x00, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
-     0x0a, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
-     0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
-     0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
+     0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
      0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
      0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
-     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
-     0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
-     0x99, 0x99, 0x77, 0x77
+     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
+
 };
 const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
 
@@ -733,12 +719,6 @@
     int err;
     String8 text(str);
 
-    err = writer.WriteAppHeader(text, 0xaabbccdd);
-    if (err != 0) {
-        fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
-        return err;
-    }
-
     err = writer.WriteEntityHeader(text, text.length()+1);
     if (err != 0) {
         fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
@@ -779,8 +759,6 @@
     err |= test_write_header_and_entity(writer, "padded_to_2__");
     err |= test_write_header_and_entity(writer, "padded_to1");
 
-    writer.WriteAppFooter(0x77779999);
-
     close(fd);
 
     err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
@@ -800,70 +778,59 @@
     String8 string;
     int cookie = 0x11111111;
     size_t actualSize;
+    bool done;
+    int type;
 
     // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
 
-    err = reader.ReadNextHeader();
+    err = reader.ReadNextHeader(&done, &type);
+    if (done) {
+        fprintf(stderr, "should not be done yet\n");
+        goto finished;
+    }
     if (err != 0) {
         fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
-        goto done;
+        goto finished;
     }
-
-    err = reader.ReadAppHeader(&string, &cookie);
-    if (err != 0) {
-        fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err));
-        goto done;
-    }
-    if (string != str) {
-        fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string());
+    if (type != BACKUP_HEADER_ENTITY_V1) {
         err = EINVAL;
-        goto done;
-    }
-    if (cookie != (int)0xaabbccdd) {
-        fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie);
-        err = EINVAL;
-        goto done;
-    }
-
-    err = reader.ReadNextHeader();
-    if (err != 0) {
-        fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err));
-        goto done;
+        fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
     }
 
     err = reader.ReadEntityHeader(&string, &actualSize);
     if (err != 0) {
         fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
-        goto done;
+        goto finished;
     }
     if (string != str) {
         fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
         err = EINVAL;
-        goto done;
+        goto finished;
     }
     if ((int)actualSize != bufSize) {
         fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
                 actualSize);
         err = EINVAL;
-        goto done;
+        goto finished;
     }
 
     err = reader.ReadEntityData(buf, bufSize);
     if (err != NO_ERROR) {
         fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
-        goto done;
+        goto finished;
     }
 
     if (0 != memcmp(buf, str, bufSize)) {
         fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
-                "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]);
+                "%02x %02x %02x %02x  '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
+                buf[0], buf[1], buf[2], buf[3]);
         err = EINVAL;
-        goto done;
+        goto finished;
     }
 
     // The next read will confirm whether it got the right amount of data.
 
-done:
+finished:
     if (err != NO_ERROR) {
         fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
     }
@@ -923,23 +890,6 @@
         if (err == NO_ERROR) {
             err = test_read_header_and_entity(reader, "padded_to1");
         }
-
-        if (err == NO_ERROR) {
-            err = reader.ReadNextHeader();
-            if (err != 0) {
-                fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
-            }
-
-            if (err == NO_ERROR) {
-                int cookie;
-                err |= reader.ReadAppFooter(&cookie);
-                if (cookie != 0x77779999) {
-                    fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n",
-                        0x77779999, cookie);
-                    err = EINVAL;
-                }
-            }
-        }
     }
 
     close(fd);