Merge "Switch to new project ID constants."
diff --git a/Android.bp b/Android.bp
index 676c958..c2f8936 100644
--- a/Android.bp
+++ b/Android.bp
@@ -145,6 +145,7 @@
         "model/PublicVolume.cpp",
         "model/StubVolume.cpp",
         "model/VolumeBase.cpp",
+        "model/VolumeEncryption.cpp",
     ],
     product_variables: {
         arc: {
diff --git a/FsCrypt.cpp b/FsCrypt.cpp
index 8682bdc..276444c 100644
--- a/FsCrypt.cpp
+++ b/FsCrypt.cpp
@@ -66,7 +66,7 @@
 using android::vold::IsFilesystemSupported;
 using android::vold::kEmptyAuthentication;
 using android::vold::KeyBuffer;
-using android::vold::makeGen;
+using android::vold::KeyGeneration;
 using android::vold::retrieveKey;
 using android::vold::retrieveOrGenerateKey;
 using android::vold::SetQuotaInherit;
@@ -98,6 +98,11 @@
 
 }  // namespace
 
+// Returns KeyGeneration suitable for key as described in EncryptionOptions
+static KeyGeneration makeGen(const EncryptionOptions& options) {
+    return KeyGeneration{FSCRYPT_MAX_KEY_SIZE, true, options.use_hw_wrapped_key};
+}
+
 static bool fscrypt_is_emulated() {
     return property_get_bool("persist.sys.emulate_fbe", false);
 }
@@ -230,13 +235,18 @@
 
 // Retrieve the options to use for encryption policies on adoptable storage.
 static bool get_volume_file_encryption_options(EncryptionOptions* options) {
-    auto contents_mode =
-            android::base::GetProperty("ro.crypto.volume.contents_mode", "aes-256-xts");
+    // If we give the empty string, libfscrypt will use the default (currently XTS)
+    auto contents_mode = android::base::GetProperty("ro.crypto.volume.contents_mode", "");
+    // HEH as default was always a mistake. Use the libfscrypt default (CTS)
+    // for devices launching on versions above Android 10.
+    auto first_api_level = GetFirstApiLevel();
+    constexpr uint64_t pre_gki_level = 29;
     auto filenames_mode =
-            android::base::GetProperty("ro.crypto.volume.filenames_mode", "aes-256-heh");
+            android::base::GetProperty("ro.crypto.volume.filenames_mode",
+                                       first_api_level > pre_gki_level ? "" : "aes-256-heh");
     auto options_string = android::base::GetProperty("ro.crypto.volume.options",
-                                                     contents_mode + ":" + filenames_mode + ":v1");
-    if (!ParseOptions(options_string, options)) {
+                                                     contents_mode + ":" + filenames_mode);
+    if (!ParseOptionsForApiLevel(first_api_level, options_string, options)) {
         LOG(ERROR) << "Unable to parse volume encryption options: " << options_string;
         return false;
     }
diff --git a/KeyStorage.cpp b/KeyStorage.cpp
index a7582c2..951536b 100644
--- a/KeyStorage.cpp
+++ b/KeyStorage.cpp
@@ -122,7 +122,8 @@
             return false;
         }
         const hw_auth_token_t* at = reinterpret_cast<const hw_auth_token_t*>(auth.token.data());
-        paramBuilder.Authorization(km::TAG_USER_SECURE_ID, at->user_id);
+        auto user_id = at->user_id;  // Make a copy because at->user_id is unaligned.
+        paramBuilder.Authorization(km::TAG_USER_SECURE_ID, user_id);
         paramBuilder.Authorization(km::TAG_USER_AUTH_TYPE, km::HardwareAuthenticatorType::PASSWORD);
         paramBuilder.Authorization(km::TAG_AUTH_TIMEOUT, AUTH_TIMEOUT);
     }
diff --git a/KeyUtil.cpp b/KeyUtil.cpp
index 2e810ff..6200c42 100644
--- a/KeyUtil.cpp
+++ b/KeyUtil.cpp
@@ -36,14 +36,6 @@
 namespace android {
 namespace vold {
 
-const KeyGeneration makeGen(const EncryptionOptions& options) {
-    return KeyGeneration{FSCRYPT_MAX_KEY_SIZE, true, options.use_hw_wrapped_key};
-}
-
-const KeyGeneration makeGen(const CryptoType& crypto) {
-    return KeyGeneration{crypto.get_keysize(), true, false};
-}
-
 const KeyGeneration neverGen() {
     return KeyGeneration{0, false, false};
 }
diff --git a/KeyUtil.h b/KeyUtil.h
index 16aaf99..dcb1dc7 100644
--- a/KeyUtil.h
+++ b/KeyUtil.h
@@ -17,7 +17,6 @@
 #ifndef ANDROID_VOLD_KEYUTIL_H
 #define ANDROID_VOLD_KEYUTIL_H
 
-#include "CryptoType.h"
 #include "KeyBuffer.h"
 #include "KeyStorage.h"
 
@@ -41,12 +40,6 @@
 // Generate a key as specified in KeyGeneration
 bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key);
 
-// Returns KeyGeneration suitable for key as described in EncryptionOptions
-const KeyGeneration makeGen(const EncryptionOptions& options);
-
-// Returns KeyGeneration suitable for key as described in CryptoType
-const KeyGeneration makeGen(const CryptoType& crypto);
-
 // Returns a key with allow_gen false so generateStorageKey returns false;
 // this is used to indicate to retrieveOrGenerateKey that a key should not
 // be generated.
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index 938ba34..7891bee 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -30,6 +30,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/fs.h>
 #include <fs_mgr.h>
@@ -54,11 +55,20 @@
 using android::vold::KeyBuffer;
 using namespace android::dm;
 
+// Parsed from metadata options
+struct CryptoOptions {
+    struct CryptoType cipher = invalid_crypto_type;
+    bool is_legacy = false;
+    bool set_dun = true;  // Non-legacy driver always sets DUN
+    bool use_hw_wrapped_key = false;
+};
+
 static const std::string kDmNameUserdata = "userdata";
 
 static const char* kFn_keymaster_key_blob = "keymaster_key_blob";
 static const char* kFn_keymaster_key_blob_upgraded = "keymaster_key_blob_upgraded";
 
+// The first entry in this table is the default crypto type.
 constexpr CryptoType supported_crypto_types[] = {aes_256_xts, adiantum};
 
 static_assert(validateSupportedCryptoTypes(64, supported_crypto_types,
@@ -68,12 +78,14 @@
 constexpr CryptoType legacy_aes_256_xts =
         CryptoType().set_config_name("aes-256-xts").set_kernel_name("AES-256-XTS").set_keysize(64);
 
-constexpr CryptoType legacy_crypto_types[] = {legacy_aes_256_xts};
-
-static_assert(validateSupportedCryptoTypes(64, legacy_crypto_types,
-                                           array_length(legacy_crypto_types)),
+static_assert(isValidCryptoType(64, legacy_aes_256_xts),
               "We have a CryptoType which was incompletely constructed.");
 
+// Returns KeyGeneration suitable for key as described in CryptoOptions
+const KeyGeneration makeGen(const CryptoOptions& options) {
+    return KeyGeneration{options.cipher.get_keysize(), true, options.use_hw_wrapped_key};
+}
+
 static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
     // We're about to mount data not verified by verified boot.  Tell Keymaster that early boot has
     // ended.
@@ -173,21 +185,38 @@
 }
 
 static bool create_crypto_blk_dev(const std::string& dm_name, const std::string& blk_device,
-                                  bool is_legacy, const std::string& cipher, bool set_dun,
-                                  const KeyBuffer& key, std::string* crypto_blkdev) {
-    uint64_t nr_sec;
-    if (!get_number_of_sectors(blk_device, &nr_sec)) return false;
+                                  const KeyBuffer& key, const CryptoOptions& options,
+                                  std::string* crypto_blkdev, uint64_t* nr_sec) {
+    if (!get_number_of_sectors(blk_device, nr_sec)) return false;
+    // TODO(paulcrowley): don't hardcode that DmTargetDefaultKey uses 4096-byte
+    // sectors
+    *nr_sec &= ~7;
+
+    KeyBuffer module_key;
+    if (options.use_hw_wrapped_key) {
+        if (!exportWrappedStorageKey(key, &module_key)) {
+            LOG(ERROR) << "Failed to get ephemeral wrapped key";
+            return false;
+        }
+    } else {
+        module_key = key;
+    }
 
     KeyBuffer hex_key_buffer;
-    if (android::vold::StrToHex(key, hex_key_buffer) != android::OK) {
+    if (android::vold::StrToHex(module_key, hex_key_buffer) != android::OK) {
         LOG(ERROR) << "Failed to turn key to hex";
         return false;
     }
     std::string hex_key(hex_key_buffer.data(), hex_key_buffer.size());
 
+    auto target = std::make_unique<DmTargetDefaultKey>(0, *nr_sec, options.cipher.get_kernel_name(),
+                                                       hex_key, blk_device, 0);
+    if (options.is_legacy) target->SetIsLegacy();
+    if (options.set_dun) target->SetSetDun();
+    if (options.use_hw_wrapped_key) target->SetWrappedKeyV0();
+
     DmTable table;
-    table.Emplace<DmTargetDefaultKey>(0, nr_sec, cipher, hex_key, blk_device, 0, is_legacy,
-                                      set_dun);
+    table.AddTarget(std::move(target));
 
     auto& dm = DeviceMapper::Instance();
     for (int i = 0;; i++) {
@@ -209,25 +238,38 @@
     return true;
 }
 
-static const CryptoType& lookup_cipher_in_table(const CryptoType table[], int table_len,
-                                                const std::string& cipher_name) {
-    if (cipher_name.empty()) return table[0];
-    for (int i = 0; i < table_len; i++) {
-        if (cipher_name == table[i].get_config_name()) {
-            return table[i];
+static const CryptoType& lookup_cipher(const std::string& cipher_name) {
+    if (cipher_name.empty()) return supported_crypto_types[0];
+    for (size_t i = 0; i < array_length(supported_crypto_types); i++) {
+        if (cipher_name == supported_crypto_types[i].get_config_name()) {
+            return supported_crypto_types[i];
         }
     }
     return invalid_crypto_type;
 }
 
-static const CryptoType& lookup_cipher(const std::string& cipher_name, bool is_legacy) {
-    if (is_legacy) {
-        return lookup_cipher_in_table(legacy_crypto_types, array_length(legacy_crypto_types),
-                                      cipher_name);
-    } else {
-        return lookup_cipher_in_table(supported_crypto_types, array_length(supported_crypto_types),
-                                      cipher_name);
+static bool parse_options(const std::string& options_string, CryptoOptions* options) {
+    auto parts = android::base::Split(options_string, ":");
+    if (parts.size() < 1 || parts.size() > 2) {
+        LOG(ERROR) << "Invalid metadata encryption option: " << options_string;
+        return false;
     }
+    std::string cipher_name = parts[0];
+    options->cipher = lookup_cipher(cipher_name);
+    if (options->cipher.get_kernel_name() == nullptr) {
+        LOG(ERROR) << "No metadata cipher named " << cipher_name << " found";
+        return false;
+    }
+
+    if (parts.size() == 2) {
+        if (parts[1] == "wrappedkey_v0") {
+            options->use_hw_wrapped_key = true;
+        } else {
+            LOG(ERROR) << "Invalid metadata encryption flag: " << parts[1];
+            return false;
+        }
+    }
+    return true;
 }
 
 bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std::string& mount_point,
@@ -253,33 +295,36 @@
     bool is_legacy;
     if (!DmTargetDefaultKey::IsLegacy(&is_legacy)) return false;
 
-    // Non-legacy driver always sets DUN
-    bool set_dun = !is_legacy || android::base::GetBoolProperty("ro.crypto.set_dun", false);
-    if (!set_dun && data_rec->fs_mgr_flags.checkpoint_blk) {
-        LOG(ERROR) << "Block checkpoints and metadata encryption require ro.crypto.set_dun option";
-        return false;
+    CryptoOptions options;
+    if (is_legacy) {
+        if (!data_rec->metadata_encryption.empty()) {
+            LOG(ERROR) << "metadata_encryption options cannot be set in legacy mode";
+            return false;
+        }
+        options.cipher = legacy_aes_256_xts;
+        options.is_legacy = true;
+        options.set_dun = android::base::GetBoolProperty("ro.crypto.set_dun", false);
+        if (!options.set_dun && data_rec->fs_mgr_flags.checkpoint_blk) {
+            LOG(ERROR)
+                    << "Block checkpoints and metadata encryption require ro.crypto.set_dun option";
+            return false;
+        }
+    } else {
+        if (!parse_options(data_rec->metadata_encryption, &options)) return false;
     }
 
-    auto cipher = lookup_cipher(data_rec->metadata_cipher, is_legacy);
-    if (cipher.get_kernel_name() == nullptr) {
-        LOG(ERROR) << "No metadata cipher named " << data_rec->metadata_cipher
-                   << " found, is_legacy=" << is_legacy;
-        return false;
-    }
-
-    auto gen = needs_encrypt ? makeGen(cipher) : neverGen();
+    auto gen = needs_encrypt ? makeGen(options) : neverGen();
     KeyBuffer key;
     if (!read_key(data_rec->metadata_key_dir, gen, &key)) return false;
 
     std::string crypto_blkdev;
-    if (!create_crypto_blk_dev(kDmNameUserdata, data_rec->blk_device, is_legacy,
-                               cipher.get_kernel_name(), set_dun, key, &crypto_blkdev))
+    uint64_t nr_sec;
+    if (!create_crypto_blk_dev(kDmNameUserdata, data_rec->blk_device, key, options, &crypto_blkdev,
+                               &nr_sec))
         return false;
 
     // FIXME handle the corrupt case
     if (needs_encrypt) {
-        uint64_t nr_sec;
-        if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false;
         LOG(INFO) << "Beginning inplace encryption, nr_sec: " << nr_sec;
         off64_t size_already_done = 0;
         auto rc = cryptfs_enable_inplace(crypto_blkdev.data(), blk_device.data(), nr_sec,
@@ -300,5 +345,27 @@
     return true;
 }
 
+static bool get_volume_options(CryptoOptions* options) {
+    return parse_options(android::base::GetProperty("ro.crypto.volume.metadata.encryption", ""),
+                         options);
+}
+
+bool defaultkey_volume_keygen(KeyGeneration* gen) {
+    CryptoOptions options;
+    if (!get_volume_options(&options)) return false;
+    *gen = makeGen(options);
+    return true;
+}
+
+bool defaultkey_setup_ext_volume(const std::string& label, const std::string& blk_device,
+                                 const KeyBuffer& key, std::string* out_crypto_blkdev) {
+    LOG(DEBUG) << "defaultkey_setup_ext_volume: " << label << " " << blk_device;
+
+    CryptoOptions options;
+    if (!get_volume_options(&options)) return false;
+    uint64_t nr_sec;
+    return create_crypto_blk_dev(label, blk_device, key, options, out_crypto_blkdev, &nr_sec);
+}
+
 }  // namespace vold
 }  // namespace android
diff --git a/MetadataCrypt.h b/MetadataCrypt.h
index a1ce7d8..dc68e7c 100644
--- a/MetadataCrypt.h
+++ b/MetadataCrypt.h
@@ -19,12 +19,21 @@
 
 #include <string>
 
+#include "KeyBuffer.h"
+#include "KeyUtil.h"
+
 namespace android {
 namespace vold {
 
 bool fscrypt_mount_metadata_encrypted(const std::string& block_device,
                                       const std::string& mount_point, bool needs_encrypt);
 
+bool defaultkey_volume_keygen(KeyGeneration* gen);
+
+bool defaultkey_setup_ext_volume(const std::string& label, const std::string& blk_device,
+                                 const android::vold::KeyBuffer& key,
+                                 std::string* out_crypto_blkdev);
+
 }  // namespace vold
 }  // namespace android
 #endif
diff --git a/Process.cpp b/Process.cpp
index 3d8e3d7..277d6a3 100644
--- a/Process.cpp
+++ b/Process.cpp
@@ -29,6 +29,7 @@
 #include <unistd.h>
 
 #include <fstream>
+#include <mntent.h>
 #include <unordered_set>
 
 #include <android-base/file.h>
@@ -81,6 +82,51 @@
     return false;
 }
 
+// TODO: Refactor the code with KillProcessesWithOpenFiles().
+int KillProcessesWithMounts(const std::string& prefix, int signal) {
+    std::unordered_set<pid_t> pids;
+
+    auto proc_d = std::unique_ptr<DIR, int (*)(DIR*)>(opendir("/proc"), closedir);
+    if (!proc_d) {
+        PLOG(ERROR) << "Failed to open proc";
+        return -1;
+    }
+
+    struct dirent* proc_de;
+    while ((proc_de = readdir(proc_d.get())) != nullptr) {
+        // We only care about valid PIDs
+        pid_t pid;
+        if (proc_de->d_type != DT_DIR) continue;
+        if (!android::base::ParseInt(proc_de->d_name, &pid)) continue;
+
+        // Look for references to prefix
+        std::string mounts_file(StringPrintf("/proc/%d/mounts", pid));
+        auto fp = std::unique_ptr<FILE, int (*)(FILE*)>(
+                setmntent(mounts_file.c_str(), "r"), endmntent);
+        if (!fp) {
+            PLOG(WARNING) << "Failed to open " << mounts_file;
+            continue;
+        }
+
+        // Check if obb directory is mounted, and get all packages of mounted app data directory.
+        mntent* mentry;
+        while ((mentry = getmntent(fp.get())) != nullptr) {
+            if (android::base::StartsWith(mentry->mnt_dir, prefix)) {
+                pids.insert(pid);
+                break;
+            }
+        }
+    }
+    if (signal != 0) {
+        for (const auto& pid : pids) {
+            LOG(WARNING) << "Killing pid "<< pid << " with signal " << strsignal(signal) <<
+                    " because it has a mount with prefix " << prefix;
+            kill(pid, signal);
+        }
+    }
+    return pids.size();
+}
+
 int KillProcessesWithOpenFiles(const std::string& prefix, int signal) {
     std::unordered_set<pid_t> pids;
 
diff --git a/Process.h b/Process.h
index 1406782..1c59812 100644
--- a/Process.h
+++ b/Process.h
@@ -21,6 +21,7 @@
 namespace vold {
 
 int KillProcessesWithOpenFiles(const std::string& path, int signal);
+int KillProcessesWithMounts(const std::string& path, int signal);
 
 }  // namespace vold
 }  // namespace android
diff --git a/Utils.cpp b/Utils.cpp
index 0974a0b..82ad1f1 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -84,6 +84,9 @@
 static const char* kAppMediaDir = "/Android/media/";
 static const char* kAppObbDir = "/Android/obb/";
 
+static const char* kMediaProviderCtx = "u:r:mediaprovider:";
+static const char* kMediaProviderAppCtx = "u:r:mediaprovider_app:";
+
 // Lock used to protect process-level SELinux changes from racing with each
 // other between multiple threads.
 static std::mutex kSecurityLock;
@@ -426,6 +429,31 @@
     return -errno;
 }
 
+status_t KillProcessesWithMountPrefix(const std::string& path) {
+    if (KillProcessesWithMounts(path, SIGINT) == 0) {
+        return OK;
+    }
+    if (sSleepOnUnmount) sleep(5);
+
+    if (KillProcessesWithMounts(path, SIGTERM) == 0) {
+        return OK;
+    }
+    if (sSleepOnUnmount) sleep(5);
+
+    if (KillProcessesWithMounts(path, SIGKILL) == 0) {
+        return OK;
+    }
+    if (sSleepOnUnmount) sleep(5);
+
+    // Send SIGKILL a second time to determine if we've
+    // actually killed everyone mount
+    if (KillProcessesWithMounts(path, SIGKILL) == 0) {
+        return OK;
+    }
+    PLOG(ERROR) << "Failed to kill processes using " << path;
+    return -EBUSY;
+}
+
 status_t KillProcessesUsingPath(const std::string& path) {
     if (KillProcessesWithOpenFiles(path, SIGINT) == 0) {
         return OK;
@@ -883,6 +911,19 @@
     }
 }
 
+// TODO: Use a better way to determine if it's media provider app.
+bool IsFuseDaemon(const pid_t pid) {
+    auto path = StringPrintf("/proc/%d/mounts", pid);
+    char* tmp;
+    if (lgetfilecon(path.c_str(), &tmp) < 0) {
+        return false;
+    }
+    bool result = android::base::StartsWith(tmp, kMediaProviderAppCtx)
+            || android::base::StartsWith(tmp, kMediaProviderCtx);
+    freecon(tmp);
+    return result;
+}
+
 bool IsFilesystemSupported(const std::string& fsType) {
     std::string supported;
     if (!ReadFileToString(kProcFilesystems, &supported)) {
@@ -1242,6 +1283,16 @@
     return true;
 }
 
+status_t EnsureDirExists(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
+    if (access(path.c_str(), F_OK) != 0) {
+        PLOG(WARNING) << "Dir does not exist: " << path;
+        if (fs_prepare_dir(path.c_str(), mode, uid, gid) != 0) {
+            return -errno;
+        }
+    }
+    return OK;
+}
+
 status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path,
                        const std::string& relative_upper_path, android::base::unique_fd* fuse_fd) {
     std::string pre_fuse_path(StringPrintf("/mnt/user/%d", user_id));
diff --git a/Utils.h b/Utils.h
index 21abc4d..5e6ff1b 100644
--- a/Utils.h
+++ b/Utils.h
@@ -35,6 +35,7 @@
 namespace vold {
 
 static const char* kPropFuse = "persist.sys.fuse";
+static const char* kVoldAppDataIsolationEnabled = "persist.sys.vold_app_data_isolation_enabled";
 
 /* SELinux contexts used depending on the block device type */
 extern security_context_t sBlkidContext;
@@ -69,6 +70,9 @@
 /* Kills any processes using given path */
 status_t KillProcessesUsingPath(const std::string& path);
 
+/* Kills any processes using given mount prifix */
+status_t KillProcessesWithMountPrefix(const std::string& path);
+
 /* Creates bind mount from source to target */
 status_t BindMount(const std::string& source, const std::string& target);
 
@@ -120,6 +124,7 @@
 uint64_t GetTreeBytes(const std::string& path);
 
 bool IsFilesystemSupported(const std::string& fsType);
+bool IsFuseDaemon(const pid_t pid);
 
 /* Wipes contents of block device at given path */
 status_t WipeBlockDevice(const std::string& path);
@@ -143,6 +148,8 @@
 
 dev_t GetDevice(const std::string& path);
 
+status_t EnsureDirExists(const std::string& path, mode_t mode, uid_t uid, gid_t gid);
+
 status_t RestoreconRecursive(const std::string& path);
 
 // TODO: promote to android::base
diff --git a/VoldUtil.h b/VoldUtil.h
index 6ef8cb1..ce6b411 100644
--- a/VoldUtil.h
+++ b/VoldUtil.h
@@ -17,10 +17,7 @@
 #pragma once
 
 #include <fstab/fstab.h>
-#include <sys/cdefs.h>
 
 extern android::fs_mgr::Fstab fstab_default;
 
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
-
 #define DATA_MNT_POINT "/data"
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index f7b36bf..2b6565c 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -80,6 +80,7 @@
 using android::vold::CreateDir;
 using android::vold::DeleteDirContents;
 using android::vold::DeleteDirContentsAndDir;
+using android::vold::EnsureDirExists;
 using android::vold::IsFilesystemSupported;
 using android::vold::PrepareAndroidDirs;
 using android::vold::PrepareAppDirFromRoot;
@@ -104,6 +105,8 @@
 static const unsigned int kMajorBlockExperimentalMin = 240;
 static const unsigned int kMajorBlockExperimentalMax = 254;
 
+using ScanProcCallback = bool(*)(uid_t uid, pid_t pid, int nsFd, const char* name, void* params);
+
 VolumeManager* VolumeManager::sInstance = NULL;
 
 VolumeManager* VolumeManager::Instance() {
@@ -534,9 +537,9 @@
 // TODO: Get rid of this guesswork altogether and instead exec a process
 // immediately after fork to do our bindding for us.
 static bool childProcess(const char* storageSource, const char* userSource, int nsFd,
-                         struct dirent* de) {
+                         const char* name) {
     if (setns(nsFd, CLONE_NEWNS) != 0) {
-        async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns for %s :%s", de->d_name,
+        async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns for %s :%s", name,
                               strerror(errno));
         return false;
     }
@@ -553,59 +556,82 @@
 
     if (TEMP_FAILURE_RETRY(mount(storageSource, "/storage", NULL, MS_BIND | MS_REC, NULL)) == -1) {
         async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s for %s :%s",
-                              storageSource, de->d_name, strerror(errno));
+                              storageSource, name, strerror(errno));
         return false;
     }
 
     if (TEMP_FAILURE_RETRY(mount(NULL, "/storage", NULL, MS_REC | MS_SLAVE, NULL)) == -1) {
         async_safe_format_log(ANDROID_LOG_ERROR, "vold",
-                              "Failed to set MS_SLAVE to /storage for %s :%s", de->d_name,
+                              "Failed to set MS_SLAVE to /storage for %s :%s", name,
                               strerror(errno));
         return false;
     }
 
     if (TEMP_FAILURE_RETRY(mount(userSource, "/storage/self", NULL, MS_BIND, NULL)) == -1) {
         async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s for %s :%s",
-                              userSource, de->d_name, strerror(errno));
+                              userSource, name, strerror(errno));
         return false;
     }
 
     return true;
 }
 
-int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
-    if (GetBoolProperty(android::vold::kPropFuse, false)) {
-        // TODO(135341433): Implement fuse specific logic.
-        return 0;
-    }
-    std::string mode;
+// Fork the process and remount storage
+bool forkAndRemountChild(uid_t uid, pid_t pid, int nsFd, const char* name, void* params) {
+    int32_t mountMode = *static_cast<int32_t*>(params);
+    std::string userSource;
+    std::string storageSource;
+    pid_t child;
+    // Need to fix these paths to account for when sdcardfs is gone
     switch (mountMode) {
         case VoldNativeService::REMOUNT_MODE_NONE:
-            mode = "none";
-            break;
+            return true;
         case VoldNativeService::REMOUNT_MODE_DEFAULT:
-            mode = "default";
+            storageSource = "/mnt/runtime/default";
             break;
         case VoldNativeService::REMOUNT_MODE_READ:
-            mode = "read";
+            storageSource = "/mnt/runtime/read";
             break;
         case VoldNativeService::REMOUNT_MODE_WRITE:
         case VoldNativeService::REMOUNT_MODE_LEGACY:
         case VoldNativeService::REMOUNT_MODE_INSTALLER:
-            mode = "write";
+            storageSource = "/mnt/runtime/write";
             break;
         case VoldNativeService::REMOUNT_MODE_FULL:
-            mode = "full";
+            storageSource = "/mnt/runtime/full";
             break;
         case VoldNativeService::REMOUNT_MODE_PASS_THROUGH:
-            mode = "pass_through";
-            break;
+            return true;
         default:
             PLOG(ERROR) << "Unknown mode " << std::to_string(mountMode);
-            return -1;
+            return false;
     }
-    LOG(DEBUG) << "Remounting " << uid << " as mode " << mode;
+    LOG(DEBUG) << "Remounting " << uid << " as " << storageSource;
 
+    // Fork a child to mount user-specific symlink helper into place
+    userSource = StringPrintf("/mnt/user/%d", multiuser_get_user_id(uid));
+    if (!(child = fork())) {
+        if (childProcess(storageSource.c_str(), userSource.c_str(), nsFd, name)) {
+            _exit(0);
+        } else {
+            _exit(1);
+        }
+    }
+
+    if (child == -1) {
+        PLOG(ERROR) << "Failed to fork";
+        return false;
+    } else {
+        TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0));
+    }
+    return true;
+}
+
+// Helper function to scan all processes in /proc and call the callback if:
+// 1). pid belongs to an app process
+// 2). If input uid is 0 or it matches the process uid
+// 3). If userId is not -1 or userId matches the process userId
+bool scanProcProcesses(uid_t uid, userid_t userId, ScanProcCallback callback, void* params) {
     DIR* dir;
     struct dirent* de;
     std::string rootName;
@@ -613,24 +639,22 @@
     int pidFd;
     int nsFd;
     struct stat sb;
-    pid_t child;
-    std::string userSource;
-    std::string storageSource;
 
     static bool apexUpdatable = android::sysprop::ApexProperties::updatable().value_or(false);
 
     if (!(dir = opendir("/proc"))) {
-        PLOG(ERROR) << "Failed to opendir";
-        return -1;
+        async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to opendir");
+        return false;
     }
 
     // Figure out root namespace to compare against below
     if (!android::vold::Readlinkat(dirfd(dir), "1/ns/mnt", &rootName)) {
-        PLOG(ERROR) << "Failed to read root namespace";
+        async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to read root namespace");
         closedir(dir);
-        return -1;
+        return false;
     }
 
+    async_safe_format_log(ANDROID_LOG_INFO, "vold", "Start scanning all processes");
     // Poke through all running PIDs look for apps running as UID
     while ((de = readdir(dir))) {
         pid_t pid;
@@ -645,21 +669,23 @@
             goto next;
         }
         if (fstat(pidFd, &sb) != 0) {
-            PLOG(WARNING) << "Failed to stat " << de->d_name;
+            async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to stat %s", de->d_name);
             goto next;
         }
-        if (sb.st_uid != uid) {
+        if (uid != 0 && sb.st_uid != uid) {
+            goto next;
+        }
+        if (userId != static_cast<userid_t>(-1) && multiuser_get_user_id(sb.st_uid) != userId) {
             goto next;
         }
 
         // Matches so far, but refuse to touch if in root namespace
-        LOG(DEBUG) << "Found matching PID " << de->d_name;
         if (!android::vold::Readlinkat(pidFd, "ns/mnt", &pidName)) {
-            PLOG(WARNING) << "Failed to read namespace for " << de->d_name;
+            async_safe_format_log(ANDROID_LOG_ERROR, "vold",
+                    "Failed to read namespacefor %s", de->d_name);
             goto next;
         }
         if (rootName == pidName) {
-            LOG(WARNING) << "Skipping due to root namespace";
             goto next;
         }
 
@@ -674,11 +700,9 @@
             // non-Java process whose UID is < AID_APP_START. (The UID condition
             // is required to not filter out child processes spawned by apps.)
             if (!android::vold::Readlinkat(pidFd, "exe", &exeName)) {
-                PLOG(WARNING) << "Failed to read exe name for " << de->d_name;
                 goto next;
             }
             if (!StartsWith(exeName, "/system/bin/app_process") && sb.st_uid < AID_APP_START) {
-                LOG(WARNING) << "Skipping due to native system process";
                 goto next;
             }
         }
@@ -687,39 +711,13 @@
         // NOLINTNEXTLINE(android-cloexec-open): Deliberately not O_CLOEXEC
         nsFd = openat(pidFd, "ns/mnt", O_RDONLY);
         if (nsFd < 0) {
-            PLOG(WARNING) << "Failed to open namespace for " << de->d_name;
+            async_safe_format_log(ANDROID_LOG_ERROR, "vold",
+                    "Failed to open namespace for %s", de->d_name);
             goto next;
         }
 
-        if (mode == "default") {
-            storageSource = "/mnt/runtime/default";
-        } else if (mode == "read") {
-            storageSource = "/mnt/runtime/read";
-        } else if (mode == "write") {
-            storageSource = "/mnt/runtime/write";
-        } else if (mode == "full") {
-            storageSource = "/mnt/runtime/full";
-        } else {
-            // Sane default of no storage visible. No need to fork a child
-            // to remount uid.
-            goto next;
-        }
-
-        // Mount user-specific symlink helper into place
-        userSource = StringPrintf("/mnt/user/%d", multiuser_get_user_id(uid));
-        if (!(child = fork())) {
-            if (childProcess(storageSource.c_str(), userSource.c_str(), nsFd, de)) {
-                _exit(0);
-            } else {
-                _exit(1);
-            }
-        }
-
-        if (child == -1) {
-            PLOG(ERROR) << "Failed to fork";
-            goto next;
-        } else {
-            TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0));
+        if (!callback(sb.st_uid, pid, nsFd, de->d_name, params)) {
+            async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed in callback");
         }
 
     next:
@@ -727,9 +725,204 @@
         close(pidFd);
     }
     closedir(dir);
+    async_safe_format_log(ANDROID_LOG_INFO, "vold", "Finished scanning all processes");
+    return true;
+}
+
+int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
+    if (GetBoolProperty(android::vold::kPropFuse, false)) {
+        // TODO(135341433): Implement fuse specific logic.
+        return 0;
+    }
+    return scanProcProcesses(uid, static_cast<userid_t>(-1),
+            forkAndRemountChild, &mountMode) ? 0 : -1;
+}
+
+// Bind mount obb dir for an app if necessary.
+// How it works:
+// 1). Check if a pid is an app uid and not the FuseDaemon, if not then return.
+// 2). Get the mounts for that pid.
+// 3). If obb is already mounted then return, otherwise we need to mount obb for this pid.
+// 4). Get all packages and uid mounted for jit profile. These packages are all packages with
+// same uid or whitelisted apps.
+// 5a). If there's no package, it means it's not a process running app data isolation, so
+// just bind mount Android/obb dir.
+// 5b). Otherwise, for each package, create obb dir if it's not created and bind mount it.
+// TODO: Should we get some reliable data from system server instead of scanning /proc ?
+static bool bindMountAppObbDir(uid_t uid, pid_t pid, int nsFd, const char* name, void* params) {
+    if (uid < AID_APP_START || uid > AID_APP_END) {
+        return true;
+    }
+    if (android::vold::IsFuseDaemon(pid)) {
+        return true;
+    }
+    async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Start mounting obb for uid:%d, pid:%d", uid,
+                          pid);
+
+    userid_t userId = multiuser_get_user_id(uid);
+    if (setns(nsFd, CLONE_NEWNS) != 0) {
+        async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns %s", strerror(errno));
+        return false;
+    }
+
+    std::string profiles_path(StringPrintf("/data/misc/profiles/cur/%d/", userId));
+    // We search both .../obb and .../obb/$PKG paths here.
+    std::string obb_path(StringPrintf("/storage/emulated/%d/Android/obb", userId));
+    int profiles_path_len = profiles_path.length();
+    int obb_path_len = obb_path.length();
+
+    // TODO: Refactor the code as a util function so we can reuse the mount parsing code.
+    std::string mounts_file(StringPrintf("/proc/%d/mounts", pid));
+    auto fp = std::unique_ptr<FILE, int (*)(FILE*)>(
+            setmntent(mounts_file.c_str(), "r"), endmntent);
+    if (!fp) {
+        async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Error opening %s: %s",
+                              mounts_file.c_str(), strerror(errno));
+        return false;
+    }
+
+    // Check if obb directory is mounted, and get all packages of mounted app data directory.
+    bool obb_mounted = false;
+    std::vector<std::string> pkg_name_list;
+    mntent* mentry;
+    while ((mentry = getmntent(fp.get())) != nullptr) {
+        if (strncmp(mentry->mnt_dir, profiles_path.c_str(), profiles_path_len) == 0) {
+            pkg_name_list.push_back(std::string(mentry->mnt_dir + profiles_path_len));
+        }
+        if (strncmp(mentry->mnt_dir, obb_path.c_str(), obb_path_len) == 0) {
+            obb_mounted = true;
+        }
+    }
+
+    // Obb mounted in zygote already, so skip it
+    if (obb_mounted) {
+        return true;
+    }
+
+    // Ensure obb parent directory exists
+    std::string obbSource;
+    if (IsFilesystemSupported("sdcardfs")) {
+        obbSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb", userId);
+    } else {
+        obbSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb", userId, userId);
+    }
+    std::string obbTarget(StringPrintf("/storage/emulated/%d/Android/obb", userId));
+    auto status = EnsureDirExists(obbSource, 0771, AID_MEDIA_RW, AID_MEDIA_RW);
+    if (status != OK) {
+        async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to create dir %s %s",
+                              obbSource.c_str(), strerror(-status));
+        return false;
+    }
+
+    // It means app data isolation is not applied to this, so we can just bind the whole obb
+    // directory instead.
+    if (pkg_name_list.empty()) {
+        async_safe_format_log(ANDROID_LOG_INFO, "vold",
+                              "Bind mounting whole obb directory for pid %d", pid);
+        status = BindMount(obbSource, obbTarget);
+        if (status != OK) {
+            async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s",
+                                  obbSource.c_str(), obbTarget.c_str(), strerror(-status));
+            return false;
+        }
+        return true;
+    }
+
+    // Bind mount each app's obb directory
+    for (const auto& pkg_name : pkg_name_list) {
+        std::string appObbSource;
+        if (IsFilesystemSupported("sdcardfs")) {
+            appObbSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb/%s",
+                    userId, pkg_name.c_str());
+        } else {
+            appObbSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb/%s",
+                    userId, userId, pkg_name.c_str());
+        }
+        std::string appObbTarget(StringPrintf("/storage/emulated/%d/Android/obb/%s",
+                userId, pkg_name.c_str()));
+
+        status = EnsureDirExists(appObbSource, 0770, uid, AID_MEDIA_RW);
+        if (status != OK) {
+            async_safe_format_log(ANDROID_LOG_INFO, "vold", "Failed to ensure dir %s exists",
+                                  appObbSource.c_str());
+            continue;
+        }
+        async_safe_format_log(ANDROID_LOG_INFO, "vold",
+                              "Bind mounting app obb directory(%s) for pid %d", pkg_name.c_str(),
+                              pid);
+        status = BindMount(appObbSource, appObbTarget);
+        if (status != OK) {
+            async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s",
+                                  obbSource.c_str(), obbTarget.c_str(), strerror(-status));
+            continue;
+        }
+    }
+    return true;
+}
+
+int VolumeManager::remountAppObb(userid_t userId) {
+    if (!GetBoolProperty(android::vold::kPropFuse, false)) {
+        return 0;
+    }
+    LOG(INFO) << "Start remounting app obb";
+    pid_t child;
+    if (!(child = fork())) {
+        // Child process
+        if (daemon(0, 0) == -1) {
+            PLOG(FATAL) << "Cannot create daemon";
+        }
+        // TODO(149548518): Refactor the code so minimize the work after fork to prevent deadlock.
+        if (scanProcProcesses(0, userId, bindMountAppObbDir, nullptr)) {
+            // As some forked zygote processes may not setuid and recognized as an app yet, sleep
+            // 3s and try again to catch 'em all.
+            usleep(3 * 1000 * 1000);  // 3s
+            async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Retry remounting app obb");
+            scanProcProcesses(0, userId, bindMountAppObbDir, nullptr);
+            _exit(0);
+        } else {
+            _exit(1);
+        }
+    }
+    if (child == -1) {
+        PLOG(ERROR) << "Failed to fork";
+        return -1;
+    } else if (child == 0) {
+        // Parent
+        int stat_loc;
+        for (;;) {
+            if (waitpid(child, &stat_loc, 0) != -1 || errno != EINTR) {
+                break;
+            }
+        }
+    }
     return 0;
 }
 
+bool VolumeManager::updateFuseMountedProperty() {
+    if (mFuseMountedUsers.size() == 0) {
+        android::base::SetProperty("vold.fuse_running_users", "");
+        return true;
+    }
+    std::stringstream stream;
+    char const * sep = "";
+    for (const auto& userId : mFuseMountedUsers) {
+        stream << sep;
+        stream << userId;
+        sep = ", ";
+    }
+    return android::base::SetProperty("vold.fuse_running_users", stream.str());
+}
+
+bool VolumeManager::addFuseMountedUser(userid_t userId) {
+    mFuseMountedUsers.insert(userId);
+    return updateFuseMountedProperty();
+}
+
+bool VolumeManager::removeFuseMountedUser(userid_t userId) {
+    mFuseMountedUsers.erase(userId);
+    return updateFuseMountedProperty();
+}
+
 int VolumeManager::reset() {
     // Tear down all existing disks/volumes and start from a blank slate so
     // newly connected framework hears all events.
@@ -745,6 +938,8 @@
     updateVirtualDisk();
     mAddedUsers.clear();
     mStartedUsers.clear();
+    mFuseMountedUsers.clear();
+    updateFuseMountedProperty();
     return 0;
 }
 
@@ -764,6 +959,8 @@
     mInternalEmulatedVolumes.clear();
     mDisks.clear();
     mPendingDisks.clear();
+    mFuseMountedUsers.clear();
+    updateFuseMountedProperty();
     android::vold::sSleepOnUnmount = true;
     return 0;
 }
diff --git a/VolumeManager.h b/VolumeManager.h
index afea54e..a094eae 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -118,6 +118,10 @@
     int setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol);
 
     int remountUid(uid_t uid, int32_t remountMode);
+    int remountAppObb(userid_t userId);
+
+    bool addFuseMountedUser(userid_t userId);
+    bool removeFuseMountedUser(userid_t userId);
 
     /* Reset all internal state, typically during framework boot */
     int reset();
@@ -201,6 +205,8 @@
     void handleDiskChanged(dev_t device);
     void handleDiskRemoved(dev_t device);
 
+    bool updateFuseMountedProperty();
+
     std::mutex mLock;
     std::mutex mCryptLock;
 
@@ -224,6 +230,9 @@
     int mNextObbId;
     int mNextStubId;
     bool mSecureKeyguardShowing;
+
+    // Set of all user id that fuse is ready to use.
+    std::unordered_set<userid_t> mFuseMountedUsers;
 };
 
 #endif
diff --git a/cryptfs.cpp b/cryptfs.cpp
index 4487d3b..1431459 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -325,7 +325,7 @@
 }
 
 const KeyGeneration cryptfs_get_keygen() {
-    return makeGen(get_crypto_type());
+    return KeyGeneration{get_crypto_type().get_keysize(), true, false};
 }
 
 /* Should we use keymaster? */
diff --git a/model/Disk.cpp b/model/Disk.cpp
index b2ecc50..a4324db 100644
--- a/model/Disk.cpp
+++ b/model/Disk.cpp
@@ -16,11 +16,11 @@
 
 #include "Disk.h"
 #include "FsCrypt.h"
-#include "KeyUtil.h"
 #include "PrivateVolume.h"
 #include "PublicVolume.h"
 #include "Utils.h"
 #include "VolumeBase.h"
+#include "VolumeEncryption.h"
 #include "VolumeManager.h"
 
 #include <android-base/file.h>
@@ -31,8 +31,6 @@
 #include <android-base/strings.h>
 #include <fscrypt/fscrypt.h>
 
-#include "cryptfs.h"
-
 #include <fcntl.h>
 #include <inttypes.h>
 #include <stdio.h>
@@ -537,7 +535,7 @@
     }
 
     KeyBuffer key;
-    if (!generateStorageKey(cryptfs_get_keygen(), &key)) {
+    if (!generate_volume_key(&key)) {
         LOG(ERROR) << "Failed to generate key";
         return -EIO;
     }
diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
index 8f8c87a..c2f92e4 100644
--- a/model/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -49,6 +49,7 @@
     mLabel = "emulated";
     mFuseMounted = false;
     mUseSdcardFs = IsFilesystemSupported("sdcardfs");
+    mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false);
 }
 
 EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid,
@@ -59,6 +60,7 @@
     mLabel = fsUuid;
     mFuseMounted = false;
     mUseSdcardFs = IsFilesystemSupported("sdcardfs");
+    mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false);
 }
 
 EmulatedVolume::~EmulatedVolume() {}
@@ -94,14 +96,19 @@
     } else {
         androidSource = StringPrintf("/%s/%d/Android", mRawPath.c_str(), userId);
     }
-    std::string androidTarget(
-            StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
 
-    auto status = doFuseBindMount(androidSource, androidTarget);
+    status_t status = OK;
+    // When app data isolation is enabled, obb/ will be mounted per app, otherwise we should
+    // bind mount the whole Android/ to speed up reading.
+    if (!mAppDataIsolationEnabled) {
+        std::string androidTarget(
+            StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
+        status = doFuseBindMount(androidSource, androidTarget);
+    }
+
     if (status != OK) {
         return status;
     }
-
     // Installers get the same view as all other apps, with the sole exception that the
     // OBB dirs (Android/obb) are writable to them. On sdcardfs devices, this requires
     // a special bind mount, since app-private and OBB dirs share the same GID, but we
@@ -118,6 +125,19 @@
     if (status != OK) {
         return status;
     }
+
+    if (mAppDataIsolationEnabled) {
+        // Starting from now, fuse is running, and zygote will bind app obb data directory
+        if (!VolumeManager::Instance()->addFuseMountedUser(userId)) {
+            return UNKNOWN_ERROR;
+        }
+
+        // As all new processes created by zygote will bind app obb data directory, we just need
+        // to have a snapshot of all existing processes and see if any existing process needs to
+        // remount obb data directory.
+        VolumeManager::Instance()->remountAppObb(userId);
+    }
+
     return OK;
 }
 
@@ -135,16 +155,22 @@
             // Intentional continue to try to unmount the other bind mount
         }
     }
+    // When app data isolation is enabled, kill all apps that obb/ is mounted, otherwise we should
+    // umount the whole Android/ dir.
+    if (mAppDataIsolationEnabled) {
+        std::string appObbDir(StringPrintf("%s/%d/Android/obb", getPath().c_str(), userId));
+        KillProcessesWithMountPrefix(appObbDir);
+    } else {
+        std::string androidTarget(
+                StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
 
-    std::string androidTarget(
-            StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
-
-    LOG(INFO) << "Unmounting " << androidTarget;
-    auto status = UnmountTree(androidTarget);
-    if (status != OK) {
-        return status;
+        LOG(INFO) << "Unmounting " << androidTarget;
+        auto status = UnmountTree(androidTarget);
+        if (status != OK) {
+            return status;
+        }
+        LOG(INFO) << "Unmounted " << androidTarget;
     }
-    LOG(INFO) << "Unmounted " << androidTarget;
 
     return OK;
 }
@@ -281,9 +307,15 @@
 
     if (mFuseMounted) {
         std::string label = getLabel();
+
+        // Update fuse mounted record
+        if (mAppDataIsolationEnabled &&
+                !VolumeManager::Instance()->removeFuseMountedUser(userId)) {
+            return UNKNOWN_ERROR;
+        }
+
         // Ignoring unmount return status because we do want to try to unmount
         // the rest cleanly.
-
         unmountFuseBindMounts();
         if (UnmountUserFuse(userId, getInternalPath(), label) != OK) {
             PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h
index 3f1b2e3..12d01ec 100644
--- a/model/EmulatedVolume.h
+++ b/model/EmulatedVolume.h
@@ -65,6 +65,9 @@
     /* Whether to use sdcardfs for this volume */
     bool mUseSdcardFs;
 
+    /* Whether to use app data isolation is enabled tor this volume */
+    bool mAppDataIsolationEnabled;
+
     DISALLOW_COPY_AND_ASSIGN(EmulatedVolume);
 };
 
diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp
index 75aa938..a54b05e 100644
--- a/model/PrivateVolume.cpp
+++ b/model/PrivateVolume.cpp
@@ -17,8 +17,8 @@
 #include "PrivateVolume.h"
 #include "EmulatedVolume.h"
 #include "Utils.h"
+#include "VolumeEncryption.h"
 #include "VolumeManager.h"
-#include "cryptfs.h"
 #include "fs/Ext4.h"
 #include "fs/F2fs.h"
 
@@ -87,9 +87,8 @@
 
     // TODO: figure out better SELinux labels for private volumes
 
-    int res = cryptfs_setup_ext_volume(getId().c_str(), mRawDevPath.c_str(), mKeyRaw, &mDmDevPath);
-    if (res != 0) {
-        PLOG(ERROR) << getId() << " failed to setup cryptfs";
+    if (!setup_ext_volume(getId(), mRawDevPath, mKeyRaw, &mDmDevPath)) {
+        LOG(ERROR) << getId() << " failed to setup metadata encryption";
         return -EIO;
     }
 
diff --git a/model/VolumeEncryption.cpp b/model/VolumeEncryption.cpp
new file mode 100644
index 0000000..5b0e73d
--- /dev/null
+++ b/model/VolumeEncryption.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 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 "VolumeEncryption.h"
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+#include "KeyBuffer.h"
+#include "KeyUtil.h"
+#include "MetadataCrypt.h"
+#include "cryptfs.h"
+
+namespace android {
+namespace vold {
+
+enum class VolumeMethod { kFailed, kCrypt, kDefaultKey };
+
+static VolumeMethod lookup_volume_method() {
+    constexpr uint64_t pre_gki_level = 29;
+    auto first_api_level =
+            android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+    auto method = android::base::GetProperty("ro.crypto.volume.metadata.method", "default");
+    if (method == "default") {
+        return first_api_level > pre_gki_level ? VolumeMethod::kDefaultKey : VolumeMethod::kCrypt;
+    } else if (method == "dm-default-key") {
+        return VolumeMethod::kDefaultKey;
+    } else if (method == "dm-crypt") {
+        if (first_api_level > pre_gki_level) {
+            LOG(ERROR) << "volume encryption method dm-crypt cannot be used, "
+                          "ro.product.first_api_level = "
+                       << first_api_level;
+            return VolumeMethod::kFailed;
+        }
+        return VolumeMethod::kCrypt;
+    } else {
+        LOG(ERROR) << "Unknown volume encryption method: " << method;
+        return VolumeMethod::kFailed;
+    }
+}
+
+static VolumeMethod volume_method() {
+    static VolumeMethod method = lookup_volume_method();
+    return method;
+}
+
+bool generate_volume_key(android::vold::KeyBuffer* key) {
+    KeyGeneration gen;
+    switch (volume_method()) {
+        case VolumeMethod::kFailed:
+            LOG(ERROR) << "Volume encryption setup failed";
+            return false;
+        case VolumeMethod::kCrypt:
+            gen = cryptfs_get_keygen();
+            break;
+        case VolumeMethod::kDefaultKey:
+            if (!defaultkey_volume_keygen(&gen)) return false;
+            break;
+    }
+    if (!generateStorageKey(gen, key)) return false;
+    return true;
+}
+
+bool setup_ext_volume(const std::string& label, const std::string& blk_device,
+                      const android::vold::KeyBuffer& key, std::string* out_crypto_blkdev) {
+    switch (volume_method()) {
+        case VolumeMethod::kFailed:
+            LOG(ERROR) << "Volume encryption setup failed";
+            return false;
+        case VolumeMethod::kCrypt:
+            return cryptfs_setup_ext_volume(label.c_str(), blk_device.c_str(), key,
+                                            out_crypto_blkdev) == 0;
+        case VolumeMethod::kDefaultKey:
+            return defaultkey_setup_ext_volume(label, blk_device, key, out_crypto_blkdev);
+    }
+}
+
+}  // namespace vold
+}  // namespace android
diff --git a/model/VolumeEncryption.h b/model/VolumeEncryption.h
new file mode 100644
index 0000000..d06c12b
--- /dev/null
+++ b/model/VolumeEncryption.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include "KeyBuffer.h"
+
+namespace android {
+namespace vold {
+
+bool generate_volume_key(android::vold::KeyBuffer* key);
+
+bool setup_ext_volume(const std::string& label, const std::string& blk_device,
+                      const android::vold::KeyBuffer& key, std::string* out_crypto_blkdev);
+
+}  // namespace vold
+}  // namespace android