am bac5eb96: Merge "Delay disk inserted broadcast until disk is ready"

* commit 'bac5eb966c5c3aa9abe83cdb5187326f422741ab':
  Delay disk inserted broadcast until disk is ready
diff --git a/Android.mk b/Android.mk
index bba6122..b7a4905 100644
--- a/Android.mk
+++ b/Android.mk
@@ -10,6 +10,7 @@
 	DirectVolume.cpp \
 	logwrapper.c \
 	Process.cpp \
+	Ext4.cpp \
 	Fat.cpp \
 	Loop.cpp \
 	Devmapper.cpp \
@@ -39,6 +40,8 @@
 
 LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
 
+LOCAL_STATIC_LIBRARIES := libfs_mgr
+
 LOCAL_MODULE_TAGS := eng tests
 
 include $(BUILD_STATIC_LIBRARY)
@@ -53,10 +56,12 @@
 
 LOCAL_C_INCLUDES := $(common_c_includes)
 
-LOCAL_CFLAGS := 
+LOCAL_CFLAGS := -Werror=format
 
 LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
 
+LOCAL_STATIC_LIBRARIES := libfs_mgr
+
 include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
diff --git a/Asec.h b/Asec.h
index 136ad3b..dd64fd0 100644
--- a/Asec.h
+++ b/Asec.h
@@ -33,6 +33,7 @@
     unsigned char c_chain;
 
 #define ASEC_SB_C_OPTS_NONE 0
+#define ASEC_SB_C_OPTS_EXT4 1
     unsigned char c_opts;
 
 #define ASEC_SB_C_MODE_NONE 0
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 97ed2ce..dff4625 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -40,7 +40,7 @@
 #include "cryptfs.h"
 
 CommandListener::CommandListener() :
-                 FrameworkListener("vold") {
+                 FrameworkListener("vold", true) {
     registerCmd(new DumpCmd());
     registerCmd(new VolumeCmd());
     registerCmd(new AsecCmd());
@@ -261,6 +261,44 @@
                  VoldCommand("asec") {
 }
 
+void CommandListener::AsecCmd::listAsecsInDirectory(SocketClient *cli, const char *directory) {
+    DIR *d = opendir(directory);
+
+    if (!d) {
+        cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
+        return;
+    }
+
+    size_t dirent_len = offsetof(struct dirent, d_name) +
+            pathconf(directory, _PC_NAME_MAX) + 1;
+
+    struct dirent *dent = (struct dirent *) malloc(dirent_len);
+    if (dent == NULL) {
+        cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", true);
+        return;
+    }
+
+    struct dirent *result;
+
+    while (!readdir_r(d, dent, &result) && result != NULL) {
+        if (dent->d_name[0] == '.')
+            continue;
+        if (dent->d_type != DT_REG)
+            continue;
+        size_t name_len = strlen(dent->d_name);
+        if (name_len > 5 && name_len < 260 &&
+                !strcmp(&dent->d_name[name_len - 5], ".asec")) {
+            char id[255];
+            memset(id, 0, sizeof(id));
+            strlcpy(id, dent->d_name, name_len - 4);
+            cli->sendMsg(ResponseCode::AsecListResult, id, false);
+        }
+    }
+    closedir(d);
+
+    free(dent);
+}
+
 int CommandListener::AsecCmd::runCommand(SocketClient *cli,
                                                       int argc, char **argv) {
     if (argc < 2) {
@@ -273,35 +311,21 @@
 
     if (!strcmp(argv[1], "list")) {
         dumpArgs(argc, argv, -1);
-        DIR *d = opendir(Volume::SEC_ASECDIR);
 
-        if (!d) {
-            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
-            return 0;
-        }
-
-        struct dirent *dent;
-        while ((dent = readdir(d))) {
-            if (dent->d_name[0] == '.')
-                continue;
-            if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) {
-                char id[255];
-                memset(id, 0, sizeof(id));
-                strncpy(id, dent->d_name, strlen(dent->d_name) -5);
-                cli->sendMsg(ResponseCode::AsecListResult, id, false);
-            }
-        }
-        closedir(d);
+        listAsecsInDirectory(cli, Volume::SEC_ASECDIR_EXT);
+        listAsecsInDirectory(cli, Volume::SEC_ASECDIR_INT);
     } else if (!strcmp(argv[1], "create")) {
         dumpArgs(argc, argv, 5);
-        if (argc != 7) {
+        if (argc != 8) {
             cli->sendMsg(ResponseCode::CommandSyntaxError,
-                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid>", false);
+                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid> "
+                    "<isExternal>", false);
             return 0;
         }
 
         unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
-        rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]));
+        const bool isExternal = (atoi(argv[7]) == 1);
+        rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]), isExternal);
     } else if (!strcmp(argv[1], "finalize")) {
         dumpArgs(argc, argv, -1);
         if (argc != 3) {
@@ -309,6 +333,21 @@
             return 0;
         }
         rc = vm->finalizeAsec(argv[2]);
+    } else if (!strcmp(argv[1], "fixperms")) {
+        dumpArgs(argc, argv, -1);
+        if  (argc != 5) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
+            return 0;
+        }
+
+        char *endptr;
+        gid_t gid = (gid_t) strtoul(argv[3], &endptr, 10);
+        if (*endptr != '\0') {
+            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
+            return 0;
+        }
+
+        rc = vm->fixupAsecPermissions(argv[2], gid, argv[4]);
     } else if (!strcmp(argv[1], "destroy")) {
         dumpArgs(argc, argv, -1);
         if (argc < 3) {
@@ -566,4 +605,3 @@
 
     return 0;
 }
-
diff --git a/CommandListener.h b/CommandListener.h
index baf7760..4ef4a0c 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -47,6 +47,8 @@
         AsecCmd();
         virtual ~AsecCmd() {}
         int runCommand(SocketClient *c, int argc, char ** argv);
+    private:
+        void listAsecsInDirectory(SocketClient *c, const char *directory);
     };
 
     class ObbCmd : public VoldCommand {
diff --git a/Ext4.cpp b/Ext4.cpp
new file mode 100644
index 0000000..290489e
--- /dev/null
+++ b/Ext4.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+
+#include <linux/kdev_t.h>
+#include <linux/fs.h>
+
+#define LOG_TAG "Vold"
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "Ext4.h"
+
+#define MKEXT4FS_PATH "/system/bin/make_ext4fs";
+
+extern "C" int logwrap(int argc, const char **argv, int background);
+
+
+int Ext4::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount,
+        bool executable) {
+    int rc;
+    unsigned long flags;
+
+    flags = MS_NOATIME | MS_NODEV | MS_NOSUID | MS_DIRSYNC;
+
+    flags |= (executable ? 0 : MS_NOEXEC);
+    flags |= (ro ? MS_RDONLY : 0);
+    flags |= (remount ? MS_REMOUNT : 0);
+
+    rc = mount(fsPath, mountPoint, "ext4", flags, NULL);
+
+    if (rc && errno == EROFS) {
+        SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath);
+        flags |= MS_RDONLY;
+        rc = mount(fsPath, mountPoint, "ext4", flags, NULL);
+    }
+
+    return rc;
+}
+
+int Ext4::format(const char *fsPath) {
+    int fd;
+    const char *args[4];
+    int rc;
+
+    args[0] = MKEXT4FS_PATH;
+    args[1] = "-J";
+    args[2] = fsPath;
+    args[3] = NULL;
+    rc = logwrap(3, args, 1);
+
+    if (rc == 0) {
+        SLOGI("Filesystem (ext4) formatted OK");
+        return 0;
+    } else {
+        SLOGE("Format (ext4) failed (unknown exit code %d)", rc);
+        errno = EIO;
+        return -1;
+    }
+    return 0;
+}
diff --git a/Ext4.h b/Ext4.h
new file mode 100644
index 0000000..a09b576
--- /dev/null
+++ b/Ext4.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _EXT4_H
+#define _EXT4_H
+
+#include <unistd.h>
+
+class Ext4 {
+public:
+    static int doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount,
+            bool executable);
+    static int format(const char *fsPath);
+};
+
+#endif
diff --git a/Loop.cpp b/Loop.cpp
index dad2c3f..78df132 100644
--- a/Loop.cpp
+++ b/Loop.cpp
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <string.h>
 
+#include <sys/mount.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
@@ -33,6 +34,7 @@
 
 #include <sysutils/SocketClient.h>
 #include "Loop.h"
+#include "Asec.h"
 
 int Loop::dumpState(SocketClient *c) {
     int i;
@@ -246,3 +248,45 @@
     close(fd);
     return 0;
 }
+
+int Loop::lookupInfo(const char *loopDevice, struct asec_superblock *sb, unsigned int *nr_sec) {
+    int fd;
+    struct asec_superblock buffer;
+
+    if ((fd = open(loopDevice, O_RDONLY)) < 0) {
+        SLOGE("Failed to open loopdevice (%s)", strerror(errno));
+        destroyByDevice(loopDevice);
+        return -1;
+    }
+
+    if (ioctl(fd, BLKGETSIZE, nr_sec)) {
+        SLOGE("Failed to get loop size (%s)", strerror(errno));
+        destroyByDevice(loopDevice);
+        close(fd);
+        return -1;
+    }
+
+    /*
+     * Try to read superblock.
+     */
+    memset(&buffer, 0, sizeof(struct asec_superblock));
+    if (lseek(fd, ((*nr_sec - 1) * 512), SEEK_SET) < 0) {
+        SLOGE("lseek failed (%s)", strerror(errno));
+        close(fd);
+        destroyByDevice(loopDevice);
+        return -1;
+    }
+    if (read(fd, &buffer, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
+        SLOGE("superblock read failed (%s)", strerror(errno));
+        close(fd);
+        destroyByDevice(loopDevice);
+        return -1;
+    }
+    close(fd);
+
+    /*
+     * Superblock successfully read. Copy to caller's struct.
+     */
+    memcpy(sb, &buffer, sizeof(struct asec_superblock));
+    return 0;
+}
diff --git a/Loop.h b/Loop.h
index e48536b..d717cf0 100644
--- a/Loop.h
+++ b/Loop.h
@@ -27,6 +27,7 @@
     static const int LOOP_MAX = 4096;
 public:
     static int lookupActive(const char *id, char *buffer, size_t len);
+    static int lookupInfo(const char *loopDevice, struct asec_superblock *sb, unsigned int *nr_sec);
     static int create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len);
     static int destroyByDevice(const char *loopDevice);
     static int destroyByFile(const char *loopFile);
diff --git a/Volume.cpp b/Volume.cpp
index e70a590..a71000e 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -69,11 +69,15 @@
 const char *Volume::SEC_STG_SECIMGDIR = "/mnt/secure/staging/.android_secure";
 
 /*
- * Path to where *only* root can access asec imagefiles
+ * Path to external storage where *only* root can access ASEC image files
  */
-const char *Volume::SEC_ASECDIR       = "/mnt/secure/asec";
+const char *Volume::SEC_ASECDIR_EXT   = "/mnt/secure/asec";
 
 /*
+ * Path to internal storage where *only* root can access ASEC image files
+ */
+const char *Volume::SEC_ASECDIR_INT   = "/data/app-asec";
+/*
  * Path to where secure containers are mounted
  */
 const char *Volume::ASECDIR           = "/mnt/asec";
@@ -504,9 +508,9 @@
      * Bind mount /mnt/secure/staging/android_secure -> /mnt/secure/asec so we'll
      * have a root only accessable mountpoint for it.
      */
-    if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR, "", MS_BIND, NULL)) {
+    if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, "", MS_BIND, NULL)) {
         SLOGE("Failed to bind mount points %s -> %s (%s)",
-                SEC_STG_SECIMGDIR, SEC_ASECDIR, strerror(errno));
+                SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, strerror(errno));
         return -1;
     }
 
@@ -630,8 +634,8 @@
      * the previously obscured directory.
      */
 
-    if (doUnmount(Volume::SEC_ASECDIR, force)) {
-        SLOGE("Failed to remove bindmount on %s (%s)", SEC_ASECDIR, strerror(errno));
+    if (doUnmount(Volume::SEC_ASECDIR_EXT, force)) {
+        SLOGE("Failed to remove bindmount on %s (%s)", SEC_ASECDIR_EXT, strerror(errno));
         goto fail_remount_tmpfs;
     }
 
@@ -663,7 +667,7 @@
      * Failure handling - try to restore everything back the way it was
      */
 fail_recreate_bindmount:
-    if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR, "", MS_BIND, NULL)) {
+    if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, "", MS_BIND, NULL)) {
         SLOGE("Failed to restore bindmount after failure! - Storage will appear offline!");
         goto out_nomedia;
     }
diff --git a/Volume.h b/Volume.h
index 274fb54..c717d4d 100644
--- a/Volume.h
+++ b/Volume.h
@@ -41,7 +41,8 @@
     static const char *SECDIR;
     static const char *SEC_STGDIR;
     static const char *SEC_STG_SECIMGDIR;
-    static const char *SEC_ASECDIR;
+    static const char *SEC_ASECDIR_EXT;
+    static const char *SEC_ASECDIR_INT;
     static const char *ASECDIR;
 
     static const char *LOOPDIR;
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 0eb72a1..f5c254f 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -19,6 +19,8 @@
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <fts.h>
+#include <unistd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/mount.h>
@@ -33,10 +35,13 @@
 
 #include <sysutils/NetlinkEvent.h>
 
+#include <private/android_filesystem_config.h>
+
 #include "VolumeManager.h"
 #include "DirectVolume.h"
 #include "ResponseCode.h"
 #include "Loop.h"
+#include "Ext4.h"
 #include "Fat.h"
 #include "Devmapper.h"
 #include "Process.h"
@@ -197,7 +202,11 @@
 
 int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
     char asecFileName[255];
-    snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+
+    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+        SLOGE("Couldn't find ASEC %s", id);
+        return -1;
+    }
 
     memset(buffer, 0, maxlen);
     if (access(asecFileName, F_OK)) {
@@ -211,7 +220,11 @@
 
 int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
     char asecFileName[255];
-    snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+
+    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+        SLOGE("Couldn't find ASEC %s", id);
+        return -1;
+    }
 
     memset(buffer, 0, maxlen);
     if (access(asecFileName, F_OK)) {
@@ -223,11 +236,24 @@
     return 0;
 }
 
-int VolumeManager::createAsec(const char *id, unsigned int numSectors,
-                              const char *fstype, const char *key, int ownerUid) {
+int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
+        const char *key, const int ownerUid, bool isExternal) {
     struct asec_superblock sb;
     memset(&sb, 0, sizeof(sb));
 
+    const bool wantFilesystem = strcmp(fstype, "none");
+    bool usingExt4 = false;
+    if (wantFilesystem) {
+        usingExt4 = !strcmp(fstype, "ext4");
+        if (usingExt4) {
+            sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
+        } else if (strcmp(fstype, "fat")) {
+            SLOGE("Invalid filesystem type %s", fstype);
+            errno = EINVAL;
+            return -1;
+        }
+    }
+
     sb.magic = ASEC_SB_MAGIC;
     sb.ver = ASEC_SB_VER;
 
@@ -244,11 +270,21 @@
     }
 
     char asecFileName[255];
-    snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+
+    if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
+        SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
+                asecFileName, strerror(errno));
+        errno = EADDRINUSE;
+        return -1;
+    }
+
+    const char *asecDir = isExternal ? Volume::SEC_ASECDIR_EXT : Volume::SEC_ASECDIR_INT;
+
+    snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
 
     if (!access(asecFileName, F_OK)) {
         SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
-             asecFileName, strerror(errno));
+                asecFileName, strerror(errno));
         errno = EADDRINUSE;
         return -1;
     }
@@ -340,13 +376,16 @@
     }
     close(sbfd);
 
-    if (strcmp(fstype, "none")) {
-        if (strcmp(fstype, "fat")) {
-            SLOGW("Unknown fstype '%s' specified for container", fstype);
+    if (wantFilesystem) {
+        int formatStatus;
+        if (usingExt4) {
+            formatStatus = Ext4::format(dmDevice);
+        } else {
+            formatStatus = Fat::format(dmDevice, numImgSectors);
         }
 
-        if (Fat::format(dmDevice, numImgSectors)) {
-            SLOGE("ASEC FAT format failed (%s)", strerror(errno));
+        if (formatStatus < 0) {
+            SLOGE("ASEC fs format failed (%s)", strerror(errno));
             if (cleanupDm) {
                 Devmapper::destroy(idHash);
             }
@@ -354,10 +393,11 @@
             unlink(asecFileName);
             return -1;
         }
+
         char mountPoint[255];
 
         snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
-        if (mkdir(mountPoint, 0777)) {
+        if (mkdir(mountPoint, 0000)) {
             if (errno != EEXIST) {
                 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
                 if (cleanupDm) {
@@ -369,8 +409,15 @@
             }
         }
 
-        if (Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid,
-                         0, 0000, false)) {
+        int mountStatus;
+        if (usingExt4) {
+            mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
+        } else {
+            mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
+                    false);
+        }
+
+        if (mountStatus) {
             SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
             if (cleanupDm) {
                 Devmapper::destroy(idHash);
@@ -379,6 +426,17 @@
             unlink(asecFileName);
             return -1;
         }
+
+        if (usingExt4) {
+            int dirfd = open(mountPoint, O_DIRECTORY);
+            if (dirfd >= 0) {
+                if (fchown(dirfd, ownerUid, AID_SYSTEM)
+                        || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
+                    SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
+                }
+                close(dirfd);
+            }
+        }
     } else {
         SLOGI("Created raw secure container %s (no filesystem)", id);
     }
@@ -392,7 +450,10 @@
     char loopDevice[255];
     char mountPoint[255];
 
-    snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+        SLOGE("Couldn't find ASEC %s", id);
+        return -1;
+    }
 
     char idHash[33];
     if (!asecHash(id, idHash, sizeof(idHash))) {
@@ -405,9 +466,23 @@
         return -1;
     }
 
+    unsigned int nr_sec = 0;
+    struct asec_superblock sb;
+
+    if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
+        return -1;
+    }
+
     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
-    // XXX:
-    if (Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false)) {
+
+    int result = 0;
+    if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
+        result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
+    } else {
+        result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
+    }
+
+    if (result) {
         SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
         return -1;
     }
@@ -418,13 +493,131 @@
     return 0;
 }
 
+int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
+    char asecFileName[255];
+    char loopDevice[255];
+    char mountPoint[255];
+
+    if (gid < AID_APP) {
+        SLOGE("Group ID is not in application range");
+        return -1;
+    }
+
+    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+        SLOGE("Couldn't find ASEC %s", id);
+        return -1;
+    }
+
+    char idHash[33];
+    if (!asecHash(id, idHash, sizeof(idHash))) {
+        SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
+        return -1;
+    }
+
+    if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
+        SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
+        return -1;
+    }
+
+    unsigned int nr_sec = 0;
+    struct asec_superblock sb;
+
+    if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
+        return -1;
+    }
+
+    snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
+
+    int result = 0;
+    if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
+        return 0;
+    }
+
+    int ret = Ext4::doMount(loopDevice, mountPoint,
+            false /* read-only */,
+            true  /* remount */,
+            false /* executable */);
+    if (ret) {
+        SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
+        return -1;
+    }
+
+    char *paths[] = { mountPoint, NULL };
+
+    FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
+    if (fts) {
+        // Traverse the entire hierarchy and chown to system UID.
+        for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
+            // We don't care about the lost+found directory.
+            if (!strcmp(ftsent->fts_name, "lost+found")) {
+                continue;
+            }
+
+            /*
+             * There can only be one file marked as private right now.
+             * This should be more robust, but it satisfies the requirements
+             * we have for right now.
+             */
+            const bool privateFile = !strcmp(ftsent->fts_name, filename);
+
+            int fd = open(ftsent->fts_accpath, O_NOFOLLOW);
+            if (fd < 0) {
+                SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
+                result = -1;
+                continue;
+            }
+
+            result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
+
+            if (ftsent->fts_info & FTS_D) {
+                result |= fchmod(fd, 0755);
+            } else if (ftsent->fts_info & FTS_F) {
+                result |= fchmod(fd, privateFile ? 0640 : 0644);
+            }
+            close(fd);
+        }
+        fts_close(fts);
+
+        // Finally make the directory readable by everyone.
+        int dirfd = open(mountPoint, O_DIRECTORY);
+        if (dirfd < 0 || fchmod(dirfd, 0755)) {
+            SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
+            result |= -1;
+        }
+        close(dirfd);
+    } else {
+        result |= -1;
+    }
+
+    result |= Ext4::doMount(loopDevice, mountPoint,
+            true /* read-only */,
+            true /* remount */,
+            true /* execute */);
+
+    if (result) {
+        SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
+        return -1;
+    }
+
+    if (mDebug) {
+        SLOGD("ASEC %s permissions fixed", id);
+    }
+    return 0;
+}
+
 int VolumeManager::renameAsec(const char *id1, const char *id2) {
-    char *asecFilename1;
+    char asecFilename1[255];
     char *asecFilename2;
     char mountPoint[255];
 
-    asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
-    asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
+    const char *dir;
+
+    if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
+        SLOGE("Couldn't find ASEC %s", id1);
+        return -1;
+    }
+
+    asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
 
     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
     if (isMountpointMounted(mountPoint)) {
@@ -451,12 +644,10 @@
         goto out_err;
     }
 
-    free(asecFilename1);
     free(asecFilename2);
     return 0;
 
 out_err:
-    free(asecFilename1);
     free(asecFilename2);
     return -1;
 }
@@ -467,7 +658,11 @@
     char asecFileName[255];
     char mountPoint[255];
 
-    snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+        SLOGE("Couldn't find ASEC %s", id);
+        return -1;
+    }
+
     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
 
     char idHash[33];
@@ -579,7 +774,11 @@
     char asecFileName[255];
     char mountPoint[255];
 
-    snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+        SLOGE("Couldn't find ASEC %s", id);
+        return -1;
+    }
+
     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
 
     if (isMountpointMounted(mountPoint)) {
@@ -603,11 +802,70 @@
     return 0;
 }
 
+bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
+    int dirfd = open(dir, O_DIRECTORY);
+    if (dirfd < 0) {
+        SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
+        return -1;
+    }
+
+    bool ret = false;
+
+    if (!faccessat(dirfd, asecName, F_OK, AT_SYMLINK_NOFOLLOW)) {
+        ret = true;
+    }
+
+    close(dirfd);
+
+    return ret;
+}
+
+int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
+        const char **directory) const {
+    int dirfd, fd;
+    const int idLen = strlen(id);
+    char *asecName;
+
+    if (asprintf(&asecName, "%s.asec", id) < 0) {
+        SLOGE("Couldn't allocate string to write ASEC name");
+        return -1;
+    }
+
+    const char *dir;
+    if (isAsecInDirectory(Volume::SEC_ASECDIR_INT, asecName)) {
+        dir = Volume::SEC_ASECDIR_INT;
+    } else if (isAsecInDirectory(Volume::SEC_ASECDIR_EXT, asecName)) {
+        dir = Volume::SEC_ASECDIR_EXT;
+    } else {
+        free(asecName);
+        return -1;
+    }
+
+    if (directory != NULL) {
+        *directory = dir;
+    }
+
+    if (asecPath != NULL) {
+        int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
+        if (written < 0 || static_cast<size_t>(written) >= asecPathLen) {
+            free(asecName);
+            return -1;
+        }
+    }
+
+    free(asecName);
+    return 0;
+}
+
 int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
     char asecFileName[255];
     char mountPoint[255];
 
-    snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+        SLOGE("Couldn't find ASEC %s", id);
+        return -1;
+    }
+
     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
 
     if (isMountpointMounted(mountPoint)) {
@@ -641,39 +899,11 @@
     bool cleanupDm = false;
     int fd;
     unsigned int nr_sec = 0;
-
-    if ((fd = open(loopDevice, O_RDWR)) < 0) {
-        SLOGE("Failed to open loopdevice (%s)", strerror(errno));
-        Loop::destroyByDevice(loopDevice);
-        return -1;
-    }
-
-    if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
-        SLOGE("Failed to get loop size (%s)", strerror(errno));
-        Loop::destroyByDevice(loopDevice);
-        close(fd);
-        return -1;
-    }
-
-    /*
-     * Validate superblock
-     */
     struct asec_superblock sb;
-    memset(&sb, 0, sizeof(sb));
-    if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
-        SLOGE("lseek failed (%s)", strerror(errno));
-        close(fd);
-        Loop::destroyByDevice(loopDevice);
-        return -1;
-    }
-    if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
-        SLOGE("superblock read failed (%s)", strerror(errno));
-        close(fd);
-        Loop::destroyByDevice(loopDevice);
-        return -1;
-    }
 
-    close(fd);
+    if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
+        return -1;
+    }
 
     if (mDebug) {
         SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
@@ -707,7 +937,7 @@
         strcpy(dmDevice, loopDevice);
     }
 
-    if (mkdir(mountPoint, 0777)) {
+    if (mkdir(mountPoint, 0000)) {
         if (errno != EEXIST) {
             SLOGE("Mountpoint creation failed (%s)", strerror(errno));
             if (cleanupDm) {
@@ -718,9 +948,27 @@
         }
     }
 
-    if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
-                     0222, false)) {
-//                     0227, false)) {
+    /*
+     * The device mapper node needs to be created. Sometimes it takes a
+     * while. Wait for up to 1 second. We could also inspect incoming uevents,
+     * but that would take more effort.
+     */
+    int tries = 25;
+    while (tries--) {
+        if (!access(dmDevice, F_OK) || errno != ENOENT) {
+            break;
+        }
+        usleep(40 * 1000);
+    }
+
+    int result;
+    if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
+        result = Ext4::doMount(dmDevice, mountPoint, true, false, true);
+    } else {
+        result = Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false);
+    }
+
+    if (result) {
         SLOGE("ASEC mount failed (%s)", strerror(errno));
         if (cleanupDm) {
             Devmapper::destroy(idHash);
diff --git a/VolumeManager.h b/VolumeManager.h
index a000556..3802503 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -87,9 +87,23 @@
     void disableVolumeManager(void) { mVolManagerDisabled = 1; }
 
     /* ASEC */
+    int findAsec(const char *id, char *asecPath = NULL, size_t asecPathLen = 0,
+            const char **directory = NULL) const;
     int createAsec(const char *id, unsigned numSectors, const char *fstype,
-                   const char *key, int ownerUid);
+                   const char *key, const int ownerUid, bool isExternal);
     int finalizeAsec(const char *id);
+
+    /**
+     * Fixes ASEC permissions on a filesystem that has owners and permissions.
+     * This currently means EXT4-based ASEC containers.
+     *
+     * There is a single file that can be marked as "private" and will not have
+     * world-readable permission. The group for that file will be set to the gid
+     * supplied.
+     *
+     * Returns 0 on success.
+     */
+    int fixupAsecPermissions(const char *id, gid_t gid, const char* privateFilename);
     int destroyAsec(const char *id, bool force);
     int mountAsec(const char *id, const char *key, int ownerUid);
     int unmountAsec(const char *id, bool force);
@@ -127,6 +141,7 @@
     VolumeManager();
     void readInitialState();
     bool isMountpointMounted(const char *mp);
+    bool isAsecInDirectory(const char *dir, const char *asec) const;
 };
 
 extern "C" {
diff --git a/cryptfs.c b/cryptfs.c
index 052c033..cc7797a 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -38,8 +38,10 @@
 #include <cutils/android_reboot.h>
 #include <ext4.h>
 #include <linux/kdev_t.h>
+#include <fs_mgr.h>
 #include "cryptfs.h"
 #define LOG_TAG "Cryptfs"
+#include "cutils/android_reboot.h"
 #include "cutils/log.h"
 #include "cutils/properties.h"
 #include "hardware_legacy/power.h"
@@ -52,7 +54,6 @@
 #define KEY_LEN_BYTES 16
 #define IV_LEN_BYTES 16
 
-#define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
 #define KEY_IN_FOOTER  "footer"
 
 #define EXT4_FS 1
@@ -64,6 +65,8 @@
 static char *saved_data_blkdev;
 static char *saved_mount_point;
 static int  master_key_saved = 0;
+#define FSTAB_PREFIX "/fstab."
+static char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
 
 static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
 {
@@ -121,6 +124,19 @@
   return nr_sec;
 }
 
+/* Get and cache the name of the fstab file so we don't
+ * keep talking over the socket to the property service.
+ */
+static char *get_fstab_filename(void)
+{
+    if (fstab_filename[0] == 0) {
+        strcpy(fstab_filename, FSTAB_PREFIX);
+        property_get("ro.hardware", fstab_filename + sizeof(FSTAB_PREFIX) - 1, "");
+    }
+
+    return fstab_filename;
+}
+
 /* key or salt can be NULL, in which case just skip writing that value.  Useful to
  * update the failed mount count but not change the key.
  */
@@ -135,7 +151,7 @@
   char key_loc[PROPERTY_VALUE_MAX];
   struct stat statbuf;
 
-  property_get(KEY_LOC_PROP, key_loc, KEY_IN_FOOTER);
+  fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
 
   if (!strcmp(key_loc, KEY_IN_FOOTER)) {
     fname = real_blk_name;
@@ -166,7 +182,7 @@
       return -1;
     }
   } else {
-    SLOGE("Unexpected value for" KEY_LOC_PROP "\n");
+    SLOGE("Unexpected value for crypto key location\n");
     return -1;;
   }
 
@@ -234,7 +250,7 @@
   char *fname;
   struct stat statbuf;
 
-  property_get(KEY_LOC_PROP, key_loc, KEY_IN_FOOTER);
+  fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
 
   if (!strcmp(key_loc, KEY_IN_FOOTER)) {
     fname = real_blk_name;
@@ -272,7 +288,7 @@
       goto errout;
     }
   } else {
-    SLOGE("Unexpected value for" KEY_LOC_PROP "\n");
+    SLOGE("Unexpected value for crypto key location\n");
     return -1;;
   }
 
@@ -556,27 +572,6 @@
     return encrypt_master_key(passwd, salt, key_buf, master_key);
 }
 
-static int get_orig_mount_parms(char *mount_point, char *fs_type, char *real_blkdev,
-                                unsigned long *mnt_flags, char *fs_options)
-{
-  char mount_point2[PROPERTY_VALUE_MAX];
-  char fs_flags[PROPERTY_VALUE_MAX];
-
-  property_get("ro.crypto.fs_type", fs_type, "");
-  property_get("ro.crypto.fs_real_blkdev", real_blkdev, "");
-  property_get("ro.crypto.fs_mnt_point", mount_point2, "");
-  property_get("ro.crypto.fs_options", fs_options, "");
-  property_get("ro.crypto.fs_flags", fs_flags, "");
-  *mnt_flags = strtol(fs_flags, 0, 0);
-
-  if (strcmp(mount_point, mount_point2)) {
-    /* Consistency check.  These should match. If not, something odd happened. */
-    return -1;
-  }
-
-  return 0;
-}
-
 static int wait_and_unmount(char *mountpoint)
 {
     int i, rc;
@@ -691,26 +686,22 @@
         return -1;
     }
 
-    if (! get_orig_mount_parms(DATA_MNT_POINT, fs_type, real_blkdev, &mnt_flags, fs_options)) {
-        SLOGD("Just got orig mount parms\n");
+    if (! (rc = wait_and_unmount(DATA_MNT_POINT)) ) {
+        /* If that succeeded, then mount the decrypted filesystem */
+        fs_mgr_do_mount(get_fstab_filename(), DATA_MNT_POINT, crypto_blkdev, 0);
 
-        if (! (rc = wait_and_unmount(DATA_MNT_POINT)) ) {
-            /* If that succeeded, then mount the decrypted filesystem */
-            mount(crypto_blkdev, DATA_MNT_POINT, fs_type, mnt_flags, fs_options);
-
-            property_set("vold.decrypt", "trigger_load_persist_props");
-            /* Create necessary paths on /data */
-            if (prep_data_fs()) {
-                return -1;
-            }
-
-            /* startup service classes main and late_start */
-            property_set("vold.decrypt", "trigger_restart_framework");
-            SLOGD("Just triggered restart_framework\n");
-
-            /* Give it a few moments to get started */
-            sleep(1);
+        property_set("vold.decrypt", "trigger_load_persist_props");
+        /* Create necessary paths on /data */
+        if (prep_data_fs()) {
+            return -1;
         }
+
+        /* startup service classes main and late_start */
+        property_set("vold.decrypt", "trigger_restart_framework");
+        SLOGD("Just triggered restart_framework\n");
+
+        /* Give it a few moments to get started */
+        sleep(1);
     }
 
     if (rc == 0) {
@@ -726,10 +717,8 @@
   unsigned char encrypted_master_key[32];
   unsigned char salt[SALT_LEN];
   char real_blkdev[MAXPATHLEN];
-  char fs_type[PROPERTY_VALUE_MAX];
-  char fs_options[PROPERTY_VALUE_MAX];
-  unsigned long mnt_flags;
   char encrypted_state[PROPERTY_VALUE_MAX];
+  char key_loc[PROPERTY_VALUE_MAX];
 
   property_get("ro.crypto.state", encrypted_state, "");
   if (strcmp(encrypted_state, "encrypted") ) {
@@ -737,14 +726,25 @@
     return 1;
   }
 
-  if (get_orig_mount_parms(mount_point, fs_type, real_blkdev, &mnt_flags, fs_options)) {
-    SLOGE("Error reading original mount parms for mount point %s\n", mount_point);
-    return -1;
-  }
+  fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
 
   if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
-    SLOGE("Error getting crypt footer and key\n");
-    return -1;
+    fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+
+    /*
+     * Only report this error if key_loc is a file and it exists.
+     * If the device was never encrypted, and /data is not mountable for
+     * some reason, returning 1 should prevent the UI from presenting the
+     * a "enter password" screen, or worse, a "press button to wipe the
+     * device" screen.
+     */
+    if ((key_loc[0] == '/') && (access("key_loc", F_OK) == -1)) {
+      SLOGE("master key file does not exist, aborting");
+      return 1;
+    } else {
+      SLOGE("Error getting crypt footer and key\n");
+      return -1;
+    }
   }
 
   if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS) {
@@ -765,10 +765,7 @@
   unsigned char salt[SALT_LEN];
   char crypto_blkdev[MAXPATHLEN];
   char real_blkdev[MAXPATHLEN];
-  char fs_type[PROPERTY_VALUE_MAX];
-  char fs_options[PROPERTY_VALUE_MAX];
   char tmp_mount_point[64];
-  unsigned long mnt_flags;
   unsigned int orig_failed_decrypt_count;
   char encrypted_state[PROPERTY_VALUE_MAX];
   int rc;
@@ -779,10 +776,7 @@
     return -1;
   }
 
-  if (get_orig_mount_parms(mount_point, fs_type, real_blkdev, &mnt_flags, fs_options)) {
-    SLOGE("Error reading original mount parms for mount point %s\n", mount_point);
-    return -1;
-  }
+  fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
 
   if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
     SLOGE("Error getting crypt footer and key\n");
@@ -811,7 +805,7 @@
    */
   sprintf(tmp_mount_point, "%s/tmp_mnt", mount_point);
   mkdir(tmp_mount_point, 0755);
-  if ( mount(crypto_blkdev, tmp_mount_point, "ext4", MS_RDONLY, "") ) {
+  if (fs_mgr_do_mount(get_fstab_filename(), DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) {
     SLOGE("Error temp mounting decrypted block device\n");
     delete_crypto_blk_dev(label);
     crypt_ftr.failed_decrypt_count++;
@@ -923,9 +917,6 @@
     unsigned char encrypted_master_key[32], decrypted_master_key[32];
     unsigned char salt[SALT_LEN];
     char real_blkdev[MAXPATHLEN];
-    char fs_type[PROPERTY_VALUE_MAX];
-    char fs_options[PROPERTY_VALUE_MAX];
-    unsigned long mnt_flags;
     char encrypted_state[PROPERTY_VALUE_MAX];
     int rc;
 
@@ -945,10 +936,7 @@
         return -1;
     }
 
-    if (get_orig_mount_parms(saved_mount_point, fs_type, real_blkdev, &mnt_flags, fs_options)) {
-        SLOGE("Error reading original mount parms for mount point %s\n", saved_mount_point);
-        return -1;
-    }
+    fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
 
     if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
         SLOGE("Error getting crypt footer and key\n");
@@ -1128,9 +1116,7 @@
 {
     int how = 0;
     char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN], sd_crypto_blkdev[MAXPATHLEN];
-    char fs_type[PROPERTY_VALUE_MAX], fs_options[PROPERTY_VALUE_MAX],
-         mount_point[PROPERTY_VALUE_MAX];
-    unsigned long mnt_flags, nr_sec;
+    unsigned long nr_sec;
     unsigned char master_key[KEY_LEN_BYTES], decrypted_master_key[KEY_LEN_BYTES];
     unsigned char salt[SALT_LEN];
     int rc=-1, fd, i, ret;
@@ -1152,7 +1138,7 @@
         goto error_unencrypted;
     }
 
-    property_get(KEY_LOC_PROP, key_loc, KEY_IN_FOOTER);
+    fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
 
     if (!strcmp(howarg, "wipe")) {
       how = CRYPTO_ENABLE_WIPE;
@@ -1163,7 +1149,7 @@
       goto error_unencrypted;
     }
 
-    get_orig_mount_parms(mount_point, fs_type, real_blkdev, &mnt_flags, fs_options);
+    fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
 
     /* Get the size of the real block device */
     fd = open(real_blkdev, O_RDONLY);
@@ -1252,9 +1238,7 @@
          * /data, set a property saying we're doing inplace encryption,
          * and restart the framework.
          */
-        property_get("ro.crypto.tmpfs_options", tmpfs_options, "");
-        if (mount("tmpfs", DATA_MNT_POINT, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV,
-            tmpfs_options) < 0) {
+        if (fs_mgr_do_tmpfs_mount(DATA_MNT_POINT)) {
             goto error_shutting_down;
         }
         /* Tells the framework that inplace encryption is starting */
@@ -1372,8 +1356,26 @@
         sleep(2); /* Give the UI a chance to show 100% progress */
         android_reboot(ANDROID_RB_RESTART, 0, 0);
     } else {
-        property_set("vold.encrypt_progress", "error_partially_encrypted");
-        release_wake_lock(lockid);
+        char value[PROPERTY_VALUE_MAX];
+
+        property_get("ro.vold.wipe_on_cyrypt_fail", value, "0");
+        if (!strcmp(value, "1")) {
+            /* wipe data if encryption failed */
+            SLOGE("encryption failed - rebooting into recovery to wipe data\n");
+            mkdir("/cache/recovery", 0700);
+            int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC);
+            if (fd >= 0) {
+                write(fd, "--wipe_data", strlen("--wipe_data") + 1);
+                close(fd);
+            } else {
+                SLOGE("could not open /cache/recovery/command\n");
+            }
+            android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+        } else {
+            /* set property to trigger dialog */
+            property_set("vold.encrypt_progress", "error_partially_encrypted");
+            release_wake_lock(lockid);
+        }
         return -1;
     }
 
@@ -1423,7 +1425,7 @@
         return -1;
     }
 
-    property_get("ro.crypto.fs_real_blkdev", real_blkdev, "");
+    fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
     if (strlen(real_blkdev) == 0) {
         SLOGE("Can't find real blkdev");
         return -1;
diff --git a/logwrapper.c b/logwrapper.c
index 13c076d..34a1e5a 100644
--- a/logwrapper.c
+++ b/logwrapper.c
@@ -25,6 +25,7 @@
 
 #include "private/android_filesystem_config.h"
 #include "cutils/log.h"
+#include "cutils/sched_policy.h"
 
 int parent(const char *tag, int parent_read) {
     int status;
@@ -43,7 +44,7 @@
             } else if (buffer[b] == '\n') {
                 buffer[b] = '\0';
 
-                LOG(LOG_INFO, tag, "%s", &buffer[a]);
+                ALOG(LOG_INFO, tag, "%s", &buffer[a]);
                 a = b + 1;
             }
         }
@@ -51,7 +52,7 @@
         if (a == 0 && b == sizeof(buffer) - 1) {
             // buffer is full, flush
             buffer[b] = '\0';
-            LOG(LOG_INFO, tag, "%s", &buffer[a]);
+            ALOG(LOG_INFO, tag, "%s", &buffer[a]);
             b = 0;
         } else if (a != b) {
             // Keep left-overs
@@ -67,24 +68,24 @@
     // Flush remaining data
     if (a != b) {
         buffer[b] = '\0';
-        LOG(LOG_INFO, tag, "%s", &buffer[a]);
+        ALOG(LOG_INFO, tag, "%s", &buffer[a]);
     }
     status = 0xAAAA;
     if (wait(&status) != -1) {  // Wait for child
         if (WIFEXITED(status)) {
             if (WEXITSTATUS(status) != 0) {
-                LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
+                ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
                         WEXITSTATUS(status));
             }
             return WEXITSTATUS(status);
         } else if (WIFSIGNALED(status))
-            LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
+            ALOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
                     WTERMSIG(status));
         else if (WIFSTOPPED(status))
-            LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
+            ALOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
                     WSTOPSIG(status));
     } else
-        LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
+        ALOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
                 strerror(errno), errno);
     return -EAGAIN;
 }
@@ -97,7 +98,7 @@
 
     // XXX: PROTECT FROM VIKING KILLER
     if (execv(argv_child[0], argv_child)) {
-        LOG(LOG_ERROR, "logwrapper",
+        ALOG(LOG_ERROR, "logwrapper",
             "executing %s failed: %s", argv_child[0], strerror(errno));
         exit(-1);
     }
@@ -114,21 +115,21 @@
     /* Use ptty instead of socketpair so that STDOUT is not buffered */
     parent_ptty = open("/dev/ptmx", O_RDWR);
     if (parent_ptty < 0) {
-	LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
-	return -errno;
+        ALOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
+        return -errno;
     }
 
     if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
             ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
         close(parent_ptty);
-	LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
-	return -1;
+        ALOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
+        return -1;
     }
 
     pid = fork();
     if (pid < 0) {
         close(parent_ptty);
-	LOG(LOG_ERROR, "logwrapper", "Failed to fork");
+        ALOG(LOG_ERROR, "logwrapper", "Failed to fork");
         return -errno;
     } else if (pid == 0) {
         /*
@@ -137,7 +138,7 @@
         child_ptty = open(child_devname, O_RDWR);
         if (child_ptty < 0) {
             close(parent_ptty);
-	    LOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
+            ALOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
             return -errno;
         }
 
@@ -148,18 +149,10 @@
         close(child_ptty);
 
         if (background) {
-            int fd = open("/dev/cpuctl/bg_non_interactive/tasks", O_WRONLY);
-            if (fd >= 0) {
-                char text[64];
-                sprintf(text, "%d", getpid());
-                if (write(fd, text, strlen(text)) < 0) {
-                    LOG(LOG_WARN, "logwrapper",
-                        "Unable to background process (%s)", strerror(errno));
-                }
-                close(fd);
-            } else {
-                LOG(LOG_WARN, "logwrapper",
-                    "Unable to background process (%s)", strerror(errno));
+            int err = set_sched_policy(getpid(), SP_BACKGROUND);
+            if (err < 0) {
+                ALOG(LOG_WARN, "logwrapper",
+                    "Unable to background process (%s)", strerror(-err));
             }
         }
 
diff --git a/vdc.c b/vdc.c
index 1eb674c..7dad143 100644
--- a/vdc.c
+++ b/vdc.c
@@ -55,7 +55,7 @@
 }
 
 static int do_cmd(int sock, int argc, char **argv) {
-    char final_cmd[255] = { '\0' };
+    char final_cmd[255] = "0 "; /* 0 is a (now required) sequence number */
     int i;
     int ret;