Merge "Use the blk_device supplied by vdc encryptFstab"
diff --git a/FsCrypt.cpp b/FsCrypt.cpp
index e31163f..a84756f 100644
--- a/FsCrypt.cpp
+++ b/FsCrypt.cpp
@@ -83,8 +83,6 @@
 const std::string systemwide_volume_key_dir =
     std::string() + DATA_MNT_POINT + "/misc/vold/volume_keys";
 
-bool s_systemwide_keys_initialized = false;
-
 // Some users are ephemeral, don't try to wipe their keys from disk
 std::set<userid_t> s_ephemeral_users;
 
@@ -359,15 +357,17 @@
             continue;
         }
         userid_t user_id = std::stoi(entry->d_name);
-        if (s_de_policies.count(user_id) == 0) {
-            auto key_path = de_dir + "/" + entry->d_name;
-            KeyBuffer de_key;
-            if (!retrieveKey(key_path, kEmptyAuthentication, &de_key)) return false;
-            EncryptionPolicy de_policy;
-            if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false;
-            s_de_policies[user_id] = de_policy;
-            LOG(DEBUG) << "Installed de key for user " << user_id;
+        auto key_path = de_dir + "/" + entry->d_name;
+        KeyBuffer de_key;
+        if (!retrieveKey(key_path, kEmptyAuthentication, &de_key)) return false;
+        EncryptionPolicy de_policy;
+        if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false;
+        auto ret = s_de_policies.insert({user_id, de_policy});
+        if (!ret.second && ret.first->second != de_policy) {
+            LOG(ERROR) << "DE policy for user" << user_id << " changed";
+            return false;
         }
+        LOG(DEBUG) << "Installed de key for user " << user_id;
     }
     // fscrypt:TODO: go through all DE directories, ensure that all user dirs have the
     // correct policy set on them, and that no rogue ones exist.
@@ -377,10 +377,6 @@
 bool fscrypt_initialize_systemwide_keys() {
     LOG(INFO) << "fscrypt_initialize_systemwide_keys";
 
-    if (s_systemwide_keys_initialized) {
-        LOG(INFO) << "Already initialized";
-        return true;
-    }
     EncryptionOptions options;
     if (!get_data_file_encryption_options(&options)) return false;
 
@@ -414,7 +410,6 @@
     LOG(INFO) << "Wrote per boot key reference to:" << per_boot_ref_filename;
 
     if (!android::vold::FsyncDirectory(device_key_dir)) return false;
-    s_systemwide_keys_initialized = true;
     return true;
 }
 
diff --git a/cryptfs.cpp b/cryptfs.cpp
index da748fd..5c075ac 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -32,6 +32,7 @@
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
 #include <cutils/properties.h>
@@ -54,6 +55,7 @@
 #include <libgen.h>
 #include <linux/kdev_t.h>
 #include <math.h>
+#include <mntent.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -1380,8 +1382,46 @@
     return encrypt_master_key(passwd, salt, key_buf, master_key, crypt_ftr);
 }
 
+static void ensure_subdirectory_unmounted(const char *prefix) {
+    std::vector<std::string> umount_points;
+    std::unique_ptr<FILE, int (*)(FILE*)> mnts(setmntent("/proc/mounts", "r"), endmntent);
+    if (!mnts) {
+        SLOGW("could not read mount files");
+        return;
+    }
+
+    //Find sudirectory mount point
+    mntent* mentry;
+    std::string top_directory(prefix);
+    if (!android::base::EndsWith(prefix, "/")) {
+        top_directory = top_directory + "/";
+    }
+    while ((mentry = getmntent(mnts.get())) != nullptr) {
+        if (strcmp(mentry->mnt_dir, top_directory.c_str()) == 0) {
+            continue;
+        }
+
+        if (android::base::StartsWith(mentry->mnt_dir, top_directory)) {
+            SLOGW("found sub-directory mount %s - %s\n", prefix, mentry->mnt_dir);
+            umount_points.push_back(mentry->mnt_dir);
+        }
+    }
+
+    //Sort by path length to umount longest path first
+    std::sort(std::begin(umount_points), std::end(umount_points),
+        [](const std::string& s1, const std::string& s2) {return s1.length() > s2.length(); });
+
+    for (std::string& mount_point : umount_points) {
+        umount(mount_point.c_str());
+        SLOGW("umount sub-directory mount %s\n", mount_point.c_str());
+    }
+}
+
 static int wait_and_unmount(const char* mountpoint, bool kill) {
     int i, err, rc;
+
+    // Subdirectory mount will cause a failure of umount.
+    ensure_subdirectory_unmounted(mountpoint);
 #define WAIT_UNMOUNT_COUNT 20
 
     /*  Now umount the tmpfs filesystem */