Unmount all asec apps before encrypting

Now that forward locked apps are stored on /data as asec image files
that are mounted, they need to be unmounted before /data can be unmounted
so it can be encrypted.

Change-Id: I7c87deb52aaed21c8ad8ce8aceb7c15c2338620a
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index f5c254f..1c48932 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -24,6 +24,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/mount.h>
+#include <dirent.h>
 
 #include <linux/kdev_t.h>
 
@@ -1360,6 +1361,62 @@
     return v->unmountVol(force, revert);
 }
 
+extern "C" int vold_unmountAllAsecs(void) {
+    int rc;
+
+    VolumeManager *vm = VolumeManager::Instance();
+    rc = vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
+    if (vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_INT)) {
+        rc = -1;
+    }
+    return rc;
+}
+
+#define ID_BUF_LEN 256
+#define ASEC_SUFFIX ".asec"
+#define ASEC_SUFFIX_LEN (sizeof(ASEC_SUFFIX) - 1)
+int VolumeManager::unmountAllAsecsInDir(const char *directory) {
+    DIR *d = opendir(directory);
+    int rc = 0;
+
+    if (!d) {
+        SLOGE("Could not open asec dir %s", directory);
+        return -1;
+    }
+
+    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) {
+        SLOGE("Failed to allocate memory for asec dir");
+        return -1;
+    }
+
+    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 < (ID_BUF_LEN + ASEC_SUFFIX_LEN - 1) &&
+                !strcmp(&dent->d_name[name_len - 5], ASEC_SUFFIX)) {
+            char id[ID_BUF_LEN];
+            strlcpy(id, dent->d_name, name_len - 4);
+            if (unmountAsec(id, true)) {
+                /* Register the error, but try to unmount more asecs */
+                rc = -1;
+            }
+        }
+    }
+    closedir(d);
+
+    free(dent);
+
+    return rc;
+}
+
 /*
  * Looks up a volume by it's label or mount-point
  */
diff --git a/VolumeManager.h b/VolumeManager.h
index 3802503..4399b76 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -136,6 +136,7 @@
     Volume *lookupVolume(const char *label);
     int getNumDirectVolumes(void);
     int getDirectVolumeList(struct volume_info *vol_list);
+    int unmountAllAsecsInDir(const char *directory);
 
 private:
     VolumeManager();
@@ -150,6 +151,7 @@
     int vold_disableVol(const char *label);
     int vold_getNumDirectVolumes(void);
     int vold_getDirectVolumeList(struct volume_info *v);
+    int vold_unmountAllAsecs(void);
 #ifdef __cplusplus
 }
 #endif
diff --git a/cryptfs.c b/cryptfs.c
index cc7797a..e1c177d 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -1214,6 +1214,13 @@
     property_set("vold.decrypt", "trigger_shutdown_framework");
     SLOGD("Just asked init to shut down class main\n");
 
+    if (vold_unmountAllAsecs()) {
+        /* Just report the error.  If any are left mounted,
+         * umounting /data below will fail and handle the error.
+         */
+        SLOGE("Error unmounting internal asecs");
+    }
+
     property_get("ro.crypto.fuse_sdcard", fuse_sdcard, "");
     if (!strcmp(fuse_sdcard, "true")) {
         /* This is a device using the fuse layer to emulate the sdcard semantics