Merge QP1A.181119.002

Change-Id: I1abb62e2234f8cf86116270d67e5051a57b6d72f
diff --git a/Android.bp b/Android.bp
index d4fff02..929bbcb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -48,6 +48,7 @@
         "libdiskconfig",
         "libext4_utils",
         "libf2fs_sparseblock",
+        "libfscrypt",
         "libhardware",
         "libhardware_legacy",
         "libhidlbase",
@@ -99,8 +100,8 @@
         "Checkpoint.cpp",
         "Devmapper.cpp",
         "EncryptInplace.cpp",
-        "Ext4Crypt.cpp",
         "FileDeviceUtils.cpp",
+        "FsCrypt.cpp",
         "IdleMaint.cpp",
         "KeyBuffer.cpp",
         "KeyStorage.cpp",
@@ -128,6 +129,7 @@
         "model/PrivateVolume.cpp",
         "model/PublicVolume.cpp",
         "model/VolumeBase.cpp",
+        "model/StubVolume.cpp",
         "secontext.cpp",
     ],
     product_variables: {
diff --git a/Ext4Crypt.cpp b/FsCrypt.cpp
similarity index 91%
rename from Ext4Crypt.cpp
rename to FsCrypt.cpp
index 5398b79..6fd611c 100644
--- a/Ext4Crypt.cpp
+++ b/FsCrypt.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "Ext4Crypt.h"
+#include "FsCrypt.h"
 
 #include "Keymaster.h"
 #include "KeyStorage.h"
@@ -51,13 +51,14 @@
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 
-#include <ext4_utils/ext4_crypt.h>
+#include <fscrypt/fscrypt.h>
 #include <keyutils.h>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
 
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
@@ -74,7 +75,7 @@
     std::string key_raw_ref;
 };
 
-const std::string device_key_dir = std::string() + DATA_MNT_POINT + e4crypt_unencrypted_folder;
+const std::string device_key_dir = std::string() + DATA_MNT_POINT + fscrypt_unencrypted_folder;
 const std::string device_key_path = device_key_dir + "/key";
 const std::string device_key_temp = device_key_dir + "/temp";
 
@@ -98,7 +99,7 @@
 
 }  // namespace
 
-static bool e4crypt_is_emulated() {
+static bool fscrypt_is_emulated() {
     return property_get_bool("persist.sys.emulate_fbe", false);
 }
 
@@ -175,8 +176,25 @@
     auto const current_path = get_ce_key_current_path(directory_path);
     if (to_fix != current_path) {
         LOG(DEBUG) << "Renaming " << to_fix << " to " << current_path;
+        android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+            open(to_fix.c_str(), O_RDONLY | O_CLOEXEC)));
+        if (fd == -1) {
+            PLOG(ERROR) << "Failed to open " << to_fix;
+            return;
+        }
+        if (fsync(fd) == -1) {
+            if (errno == EROFS || errno == EINVAL) {
+                PLOG(WARNING) << "Skip fsync " << to_fix
+                              << " on a file system does not support synchronization";
+            } else {
+                PLOG(ERROR) << "Failed to fsync " << to_fix;
+                unlink(to_fix.c_str());
+                return;
+            }
+        }
         if (rename(to_fix.c_str(), current_path.c_str()) != 0) {
             PLOG(WARNING) << "Unable to rename " << to_fix << " to " << current_path;
+            return;
         }
     }
 }
@@ -333,7 +351,7 @@
 }
 
 static bool ensure_policy(const PolicyKeyRef& key_ref, const std::string& path) {
-    return e4crypt_policy_ensure(path.c_str(), key_ref.key_raw_ref.data(),
+    return fscrypt_policy_ensure(path.c_str(), key_ref.key_raw_ref.data(),
                                  key_ref.key_raw_ref.size(), key_ref.contents_mode.c_str(),
                                  key_ref.filenames_mode.c_str()) == 0;
 }
@@ -385,13 +403,13 @@
             LOG(DEBUG) << "Installed de key for user " << user_id;
         }
     }
-    // ext4enc:TODO: go through all DE directories, ensure that all user dirs have the
+    // 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.
     return true;
 }
 
-bool e4crypt_initialize_global_de() {
-    LOG(INFO) << "e4crypt_initialize_global_de";
+bool fscrypt_initialize_global_de() {
+    LOG(INFO) << "fscrypt_initialize_global_de";
     bool wrapped_key_supported = false;
 
     if (s_global_de_initialized) {
@@ -409,13 +427,13 @@
     get_data_file_encryption_modes(&device_ref);
 
     std::string modestring = device_ref.contents_mode + ":" + device_ref.filenames_mode;
-    std::string mode_filename = std::string("/data") + e4crypt_key_mode;
+    std::string mode_filename = std::string("/data") + fscrypt_key_mode;
     if (!android::base::WriteStringToFile(modestring, mode_filename)) {
         PLOG(ERROR) << "Cannot save type";
         return false;
     }
 
-    std::string ref_filename = std::string("/data") + e4crypt_key_ref;
+    std::string ref_filename = std::string("/data") + fscrypt_key_ref;
     if (!android::base::WriteStringToFile(device_ref.key_raw_ref, ref_filename)) {
         PLOG(ERROR) << "Cannot save key reference to:" << ref_filename;
         return false;
@@ -426,9 +444,9 @@
     return true;
 }
 
-bool e4crypt_init_user0() {
-    LOG(DEBUG) << "e4crypt_init_user0";
-    if (e4crypt_is_native()) {
+bool fscrypt_init_user0() {
+    LOG(DEBUG) << "fscrypt_init_user0";
+    if (fscrypt_is_native()) {
         if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return false;
         if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return false;
         if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return false;
@@ -442,28 +460,28 @@
     // We can only safely prepare DE storage here, since CE keys are probably
     // entangled with user credentials.  The framework will always prepare CE
     // storage once CE keys are installed.
-    if (!e4crypt_prepare_user_storage("", 0, 0, android::os::IVold::STORAGE_FLAG_DE)) {
+    if (!fscrypt_prepare_user_storage("", 0, 0, android::os::IVold::STORAGE_FLAG_DE)) {
         LOG(ERROR) << "Failed to prepare user 0 storage";
         return false;
     }
 
     // If this is a non-FBE device that recently left an emulated mode,
     // restore user data directories to known-good state.
-    if (!e4crypt_is_native() && !e4crypt_is_emulated()) {
-        e4crypt_unlock_user_key(0, 0, "!", "!");
+    if (!fscrypt_is_native() && !fscrypt_is_emulated()) {
+        fscrypt_unlock_user_key(0, 0, "!", "!");
     }
 
     return true;
 }
 
-bool e4crypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral) {
-    LOG(DEBUG) << "e4crypt_vold_create_user_key for " << user_id << " serial " << serial;
-    if (!e4crypt_is_native()) {
+bool fscrypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral) {
+    LOG(DEBUG) << "fscrypt_vold_create_user_key for " << user_id << " serial " << serial;
+    if (!fscrypt_is_native()) {
         return true;
     }
     // FIXME test for existence of key that is not loaded yet
     if (s_ce_key_raw_refs.count(user_id) != 0) {
-        LOG(ERROR) << "Already exists, can't e4crypt_vold_create_user_key for " << user_id
+        LOG(ERROR) << "Already exists, can't fscrypt_vold_create_user_key for " << user_id
                    << " serial " << serial;
         // FIXME should we fail the command?
         return true;
@@ -496,9 +514,9 @@
     return success;
 }
 
-bool e4crypt_destroy_user_key(userid_t user_id) {
-    LOG(DEBUG) << "e4crypt_destroy_user_key(" << user_id << ")";
-    if (!e4crypt_is_native()) {
+bool fscrypt_destroy_user_key(userid_t user_id) {
+    LOG(DEBUG) << "fscrypt_destroy_user_key(" << user_id << ")";
+    if (!fscrypt_is_native()) {
         return true;
     }
     bool success = true;
@@ -542,13 +560,13 @@
     if (chmod(path.c_str(), mode) != 0) {
         PLOG(ERROR) << "Failed to chmod " << path;
         // FIXME temporary workaround for b/26713622
-        if (e4crypt_is_emulated()) return false;
+        if (fscrypt_is_emulated()) return false;
     }
 #if EMULATED_USES_SELINUX
     if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_FORCE) != 0) {
         PLOG(WARNING) << "Failed to restorecon " << path;
         // FIXME temporary workaround for b/26713622
-        if (e4crypt_is_emulated()) return false;
+        if (fscrypt_is_emulated()) return false;
     }
 #endif
     return true;
@@ -614,11 +632,11 @@
     return android::vold::destroyKey(path);
 }
 
-bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const std::string& token_hex,
+bool fscrypt_add_user_key_auth(userid_t user_id, int serial, const std::string& token_hex,
                                const std::string& secret_hex) {
-    LOG(DEBUG) << "e4crypt_add_user_key_auth " << user_id << " serial=" << serial
+    LOG(DEBUG) << "fscrypt_add_user_key_auth " << user_id << " serial=" << serial
                << " token_present=" << (token_hex != "!");
-    if (!e4crypt_is_native()) return true;
+    if (!fscrypt_is_native()) return true;
     if (s_ephemeral_users.count(user_id) != 0) return true;
     std::string token, secret;
     if (!parse_hex(token_hex, &token)) return false;
@@ -653,11 +671,11 @@
     return true;
 }
 
-bool e4crypt_clear_user_key_auth(userid_t user_id, int serial, const std::string& token_hex,
+bool fscrypt_clear_user_key_auth(userid_t user_id, int serial, const std::string& token_hex,
                                  const std::string& secret_hex) {
-    LOG(DEBUG) << "e4crypt_clear_user_key_auth " << user_id << " serial=" << serial
+    LOG(DEBUG) << "fscrypt_clear_user_key_auth " << user_id << " serial=" << serial
                << " token_present=" << (token_hex != "!");
-    if (!e4crypt_is_native()) return true;
+    if (!fscrypt_is_native()) return true;
     if (s_ephemeral_users.count(user_id) != 0) return true;
     std::string token, secret;
 
@@ -688,14 +706,14 @@
         if (!android::vold::storeKeyAtomically(ce_key_path, user_key_temp, kEmptyAuthentication, ce_key))
             return false;
     } else {
-        if(!e4crypt_add_user_key_auth(user_id, serial, "!", "!")) return false;
+        if(!fscrypt_add_user_key_auth(user_id, serial, "!", "!")) return false;
     }
     return true;
 }
 
-bool e4crypt_fixate_newest_user_key_auth(userid_t user_id) {
-    LOG(DEBUG) << "e4crypt_fixate_newest_user_key_auth " << user_id;
-    if (!e4crypt_is_native()) return true;
+bool fscrypt_fixate_newest_user_key_auth(userid_t user_id) {
+    LOG(DEBUG) << "fscrypt_fixate_newest_user_key_auth " << user_id;
+    if (!fscrypt_is_native()) return true;
     if (s_ephemeral_users.count(user_id) != 0) return true;
     auto const directory_path = get_ce_key_directory_path(user_id);
     auto const paths = get_ce_key_paths(directory_path);
@@ -708,11 +726,11 @@
 }
 
 // TODO: rename to 'install' for consistency, and take flags to know which keys to install
-bool e4crypt_unlock_user_key(userid_t user_id, int serial, const std::string& token_hex,
+bool fscrypt_unlock_user_key(userid_t user_id, int serial, const std::string& token_hex,
                              const std::string& secret_hex) {
-    LOG(DEBUG) << "e4crypt_unlock_user_key " << user_id << " serial=" << serial
+    LOG(DEBUG) << "fscrypt_unlock_user_key " << user_id << " serial=" << serial
                << " token_present=" << (token_hex != "!");
-    if (e4crypt_is_native()) {
+    if (fscrypt_is_native()) {
         if (s_ce_key_raw_refs.count(user_id) != 0) {
             LOG(WARNING) << "Tried to unlock already-unlocked key for user " << user_id;
             return true;
@@ -741,11 +759,11 @@
 }
 
 // TODO: rename to 'evict' for consistency
-bool e4crypt_lock_user_key(userid_t user_id) {
-    LOG(DEBUG) << "e4crypt_lock_user_key " << user_id;
-    if (e4crypt_is_native()) {
+bool fscrypt_lock_user_key(userid_t user_id) {
+    LOG(DEBUG) << "fscrypt_lock_user_key " << user_id;
+    if (fscrypt_is_native()) {
         return evict_ce_key(user_id);
-    } else if (e4crypt_is_emulated()) {
+    } else if (fscrypt_is_emulated()) {
         // When in emulation mode, we just use chmod
         if (!emulated_lock(android::vold::BuildDataSystemCePath(user_id)) ||
             !emulated_lock(android::vold::BuildDataMiscCePath(user_id)) ||
@@ -770,9 +788,9 @@
     return true;
 }
 
-bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_id, int serial,
+bool fscrypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_id, int serial,
                                   int flags) {
-    LOG(DEBUG) << "e4crypt_prepare_user_storage for volume " << escape_empty(volume_uuid)
+    LOG(DEBUG) << "fscrypt_prepare_user_storage for volume " << escape_empty(volume_uuid)
                << ", user " << user_id << ", serial " << serial << ", flags " << flags;
 
     if (flags & android::os::IVold::STORAGE_FLAG_DE) {
@@ -802,7 +820,7 @@
         }
         if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
 
-        if (e4crypt_is_native()) {
+        if (fscrypt_is_native()) {
             PolicyKeyRef de_ref;
             if (volume_uuid.empty()) {
                 if (!lookup_key_ref(s_de_key_raw_refs, user_id, &de_ref.key_raw_ref)) return false;
@@ -833,7 +851,7 @@
         if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
         if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
 
-        if (e4crypt_is_native()) {
+        if (fscrypt_is_native()) {
             PolicyKeyRef ce_ref;
             if (volume_uuid.empty()) {
                 if (!lookup_key_ref(s_ce_key_raw_refs, user_id, &ce_ref.key_raw_ref)) return false;
@@ -862,8 +880,8 @@
     return true;
 }
 
-bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_id, int flags) {
-    LOG(DEBUG) << "e4crypt_destroy_user_storage for volume " << escape_empty(volume_uuid)
+bool fscrypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_id, int flags) {
+    LOG(DEBUG) << "fscrypt_destroy_user_storage for volume " << escape_empty(volume_uuid)
                << ", user " << user_id << ", flags " << flags;
     bool res = true;
 
@@ -884,7 +902,7 @@
             res &= destroy_dir(misc_ce_path);
             res &= destroy_dir(vendor_ce_path);
         } else {
-            if (e4crypt_is_native()) {
+            if (fscrypt_is_native()) {
                 res &= destroy_volkey(misc_ce_path, volume_uuid);
             }
         }
@@ -913,7 +931,7 @@
             res &= destroy_dir(misc_de_path);
             res &= destroy_dir(vendor_de_path);
         } else {
-            if (e4crypt_is_native()) {
+            if (fscrypt_is_native()) {
                 res &= destroy_volkey(misc_de_path, volume_uuid);
             }
         }
@@ -948,9 +966,9 @@
     return res;
 }
 
-bool e4crypt_destroy_volume_keys(const std::string& volume_uuid) {
+bool fscrypt_destroy_volume_keys(const std::string& volume_uuid) {
     bool res = true;
-    LOG(DEBUG) << "e4crypt_destroy_volume_keys for volume " << escape_empty(volume_uuid);
+    LOG(DEBUG) << "fscrypt_destroy_volume_keys for volume " << escape_empty(volume_uuid);
     auto secdiscardable_path = volume_secdiscardable_path(volume_uuid);
     res &= android::vold::runSecdiscardSingle(secdiscardable_path);
     res &= destroy_volume_keys("/data/misc_ce", volume_uuid);
diff --git a/Ext4Crypt.h b/FsCrypt.h
similarity index 63%
rename from Ext4Crypt.h
rename to FsCrypt.h
index 5101bf6..d81271c 100644
--- a/Ext4Crypt.h
+++ b/FsCrypt.h
@@ -18,25 +18,25 @@
 
 #include <cutils/multiuser.h>
 
-bool e4crypt_initialize_global_de();
+bool fscrypt_initialize_global_de();
 
-bool e4crypt_init_user0();
-bool e4crypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral);
-bool e4crypt_destroy_user_key(userid_t user_id);
-bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const std::string& token,
+bool fscrypt_init_user0();
+bool fscrypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral);
+bool fscrypt_destroy_user_key(userid_t user_id);
+bool fscrypt_add_user_key_auth(userid_t user_id, int serial, const std::string& token,
                                const std::string& secret);
-bool e4crypt_clear_user_key_auth(userid_t user_id, int serial, const std::string& token_hex,
+bool fscrypt_clear_user_key_auth(userid_t user_id, int serial, const std::string& token_hex,
                                const std::string& secret_hex);
-bool e4crypt_fixate_newest_user_key_auth(userid_t user_id);
+bool fscrypt_fixate_newest_user_key_auth(userid_t user_id);
 
-bool e4crypt_unlock_user_key(userid_t user_id, int serial, const std::string& token,
+bool fscrypt_unlock_user_key(userid_t user_id, int serial, const std::string& token,
                              const std::string& secret);
-bool e4crypt_lock_user_key(userid_t user_id);
+bool fscrypt_lock_user_key(userid_t user_id);
 
-bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_id, int serial,
+bool fscrypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_id, int serial,
                                   int flags);
-bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_id, int flags);
+bool fscrypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_id, int flags);
 
-bool e4crypt_destroy_volume_keys(const std::string& volume_uuid);
+bool fscrypt_destroy_volume_keys(const std::string& volume_uuid);
 bool is_wrapped_key_supported();
 bool is_wrapped_key_supported_external();
diff --git a/KeyUtil.cpp b/KeyUtil.cpp
index 70a1952..cd2171b 100644
--- a/KeyUtil.cpp
+++ b/KeyUtil.cpp
@@ -16,6 +16,7 @@
 
 #include "KeyUtil.h"
 
+#include <linux/fs.h>
 #include <iomanip>
 #include <sstream>
 #include <string>
@@ -37,22 +38,10 @@
 namespace android {
 namespace vold {
 
-// ext4enc:TODO get this const from somewhere good
-const int EXT4_KEY_DESCRIPTOR_SIZE = 8;
-
-// ext4enc:TODO Include structure from somewhere sensible
-// MUST be in sync with ext4_crypto.c in kernel
-constexpr int EXT4_ENCRYPTION_MODE_AES_256_XTS = 1;
-constexpr int EXT4_AES_256_XTS_KEY_SIZE = 64;
-constexpr int EXT4_MAX_KEY_SIZE = 64;
-struct ext4_encryption_key {
-    uint32_t mode;
-    char raw[EXT4_MAX_KEY_SIZE];
-    uint32_t size;
-};
+constexpr int FS_AES_256_XTS_KEY_SIZE = 64;
 
 bool randomKey(KeyBuffer* key) {
-    *key = KeyBuffer(EXT4_AES_256_XTS_KEY_SIZE);
+    *key = KeyBuffer(FS_AES_256_XTS_KEY_SIZE);
     if (ReadRandomBytes(key->size(), key->data()) != 0) {
         // TODO status_t plays badly with PLOG, fix it.
         LOG(ERROR) << "Random read failed";
@@ -62,7 +51,7 @@
 }
 
 // Get raw keyref - used to make keyname and to pass to ioctl
-static std::string generateKeyRef(const char* key, int length) {
+static std::string generateKeyRef(const uint8_t* key, int length) {
     SHA512_CTX c;
 
     SHA512_Init(&c);
@@ -75,21 +64,20 @@
     unsigned char key_ref2[SHA512_DIGEST_LENGTH];
     SHA512_Final(key_ref2, &c);
 
-    static_assert(EXT4_KEY_DESCRIPTOR_SIZE <= SHA512_DIGEST_LENGTH,
-                  "Hash too short for descriptor");
-    return std::string((char*)key_ref2, EXT4_KEY_DESCRIPTOR_SIZE);
+    static_assert(FS_KEY_DESCRIPTOR_SIZE <= SHA512_DIGEST_LENGTH, "Hash too short for descriptor");
+    return std::string((char*)key_ref2, FS_KEY_DESCRIPTOR_SIZE);
 }
 
-static bool fillKey(const KeyBuffer& key, ext4_encryption_key* ext4_key) {
-    if (key.size() != EXT4_AES_256_XTS_KEY_SIZE) {
+static bool fillKey(const KeyBuffer& key, fscrypt_key* fs_key) {
+    if (key.size() != FS_AES_256_XTS_KEY_SIZE) {
         LOG(ERROR) << "Wrong size key " << key.size();
         return false;
     }
-    static_assert(EXT4_AES_256_XTS_KEY_SIZE <= sizeof(ext4_key->raw), "Key too long!");
-    ext4_key->mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
-    ext4_key->size = key.size();
-    memset(ext4_key->raw, 0, sizeof(ext4_key->raw));
-    memcpy(ext4_key->raw, key.data(), key.size());
+    static_assert(FS_AES_256_XTS_KEY_SIZE <= sizeof(fs_key->raw), "Key too long!");
+    fs_key->mode = FS_ENCRYPTION_MODE_AES_256_XTS;
+    fs_key->size = key.size();
+    memset(fs_key->raw, 0, sizeof(fs_key->raw));
+    memcpy(fs_key->raw, key.data(), key.size());
     return true;
 }
 
@@ -105,8 +93,8 @@
 }
 
 // Get the keyring we store all keys in
-static bool e4cryptKeyring(key_serial_t* device_keyring) {
-    *device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "e4crypt", 0);
+static bool fscryptKeyring(key_serial_t* device_keyring) {
+    *device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
     if (*device_keyring == -1) {
         PLOG(ERROR) << "Unable to find device keyring";
         return false;
@@ -117,25 +105,25 @@
 // Install password into global keyring
 // Return raw key reference for use in policy
 bool installKey(const KeyBuffer& key, std::string* raw_ref) {
-    // Place ext4_encryption_key into automatically zeroing buffer.
-    KeyBuffer ext4KeyBuffer(sizeof(ext4_encryption_key));
-    ext4_encryption_key& ext4_key = *reinterpret_cast<ext4_encryption_key*>(ext4KeyBuffer.data());
+    // Place fscrypt_key into automatically zeroing buffer.
+    KeyBuffer fsKeyBuffer(sizeof(fscrypt_key));
+    fscrypt_key& fs_key = *reinterpret_cast<fscrypt_key*>(fsKeyBuffer.data());
 
-    if (!fillKey(key, &ext4_key)) return false;
+    if (!fillKey(key, &fs_key)) return false;
     if (is_wrapped_key_supported()) {
         /* When wrapped key is supported, only the first 32 bytes are
            the same per boot. The second 32 bytes can change as the ephemeral
            key is different. */
-        *raw_ref = generateKeyRef(ext4_key.raw, (ext4_key.size)/2);
+        *raw_ref = generateKeyRef(fs_key.raw, (fs_key.size)/2);
     } else {
-        *raw_ref = generateKeyRef(ext4_key.raw, ext4_key.size);
+        *raw_ref = generateKeyRef(fs_key.raw, fs_key.size);
     }
     key_serial_t device_keyring;
-    if (!e4cryptKeyring(&device_keyring)) return false;
+    if (!fscryptKeyring(&device_keyring)) return false;
     for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
         auto ref = keyname(*name_prefix, *raw_ref);
         key_serial_t key_id =
-            add_key("logon", ref.c_str(), (void*)&ext4_key, sizeof(ext4_key), device_keyring);
+            add_key("logon", ref.c_str(), (void*)&fs_key, sizeof(fs_key), device_keyring);
         if (key_id == -1) {
             PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
             return false;
@@ -148,7 +136,7 @@
 
 bool evictKey(const std::string& raw_ref) {
     key_serial_t device_keyring;
-    if (!e4cryptKeyring(&device_keyring)) return false;
+    if (!fscryptKeyring(&device_keyring)) return false;
     bool success = true;
     for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
         auto ref = keyname(*name_prefix, raw_ref);
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index 0934563..e156424 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -194,11 +194,11 @@
     return true;
 }
 
-bool e4crypt_mount_metadata_encrypted(const std::string& mount_point, bool needs_encrypt) {
-    LOG(DEBUG) << "e4crypt_mount_metadata_encrypted: " << mount_point << " " << needs_encrypt;
+bool fscrypt_mount_metadata_encrypted(const std::string& mount_point, bool needs_encrypt) {
+    LOG(DEBUG) << "fscrypt_mount_metadata_encrypted: " << mount_point << " " << needs_encrypt;
     auto encrypted_state = android::base::GetProperty("ro.crypto.state", "");
     if (encrypted_state != "") {
-        LOG(DEBUG) << "e4crypt_enable_crypto got unexpected starting state: " << encrypted_state;
+        LOG(DEBUG) << "fscrypt_enable_crypto got unexpected starting state: " << encrypted_state;
         return false;
     }
     auto data_rec = fs_mgr_get_entry_for_mount_point(fstab_default, mount_point);
diff --git a/MetadataCrypt.h b/MetadataCrypt.h
index 841dc97..d82a43b 100644
--- a/MetadataCrypt.h
+++ b/MetadataCrypt.h
@@ -19,6 +19,6 @@
 
 #include <string>
 
-bool e4crypt_mount_metadata_encrypted(const std::string& mount_point, bool needs_encrypt);
+bool fscrypt_mount_metadata_encrypted(const std::string& mount_point, bool needs_encrypt);
 
 #endif
diff --git a/Utils.cpp b/Utils.cpp
index d348f71..f7afde5 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -19,6 +19,7 @@
 #include "Process.h"
 #include "sehandle.h"
 
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
@@ -41,13 +42,16 @@
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+
 #include <list>
 #include <mutex>
+#include <thread>
 
 #ifndef UMOUNT_NOFOLLOW
 #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
 #endif
 
+using namespace std::chrono_literals;
 using android::base::ReadFileToString;
 using android::base::StringPrintf;
 
@@ -814,7 +818,8 @@
                 result = -errno;
                 continue;
             }
-            std::unique_ptr<DIR, decltype(&closedir)> subdirp(fdopendir(subfd), closedir);
+            std::unique_ptr<DIR, decltype(&closedir)> subdirp(
+                android::base::Fdopendir(std::move(subfd)), closedir);
             if (!subdirp) {
                 PLOG(ERROR) << "Couldn't fdopendir " << name;
                 result = -errno;
@@ -858,5 +863,20 @@
     return OK;
 }
 
+// TODO(118708649): fix duplication with init/util.h
+status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout) {
+    android::base::Timer t;
+    while (t.duration() < timeout) {
+        struct stat sb;
+        if (stat(filename, &sb) != -1) {
+            LOG(INFO) << "wait for '" << filename << "' took " << t;
+            return 0;
+        }
+        std::this_thread::sleep_for(10ms);
+    }
+    LOG(WARNING) << "wait for '" << filename << "' timed out and took " << t;
+    return -1;
+}
+
 }  // namespace vold
 }  // namespace android
diff --git a/Utils.h b/Utils.h
index b097625..e6f4792 100644
--- a/Utils.h
+++ b/Utils.h
@@ -24,6 +24,7 @@
 #include <selinux/selinux.h>
 #include <utils/Errors.h>
 
+#include <chrono>
 #include <string>
 #include <vector>
 
@@ -134,6 +135,8 @@
 
 status_t DeleteDirContentsAndDir(const std::string& pathname);
 
+status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout);
+
 }  // namespace vold
 }  // namespace android
 
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index 056f29a..496a0b8 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -25,7 +25,7 @@
 #include "VolumeManager.h"
 
 #include "Checkpoint.h"
-#include "Ext4Crypt.h"
+#include "FsCrypt.h"
 #include "MetadataCrypt.h"
 #include "cryptfs.h"
 
@@ -35,8 +35,8 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <ext4_utils/ext4_crypt.h>
 #include <fs_mgr.h>
+#include <fscrypt/fscrypt.h>
 #include <private/android_filesystem_config.h>
 #include <utils/Trace.h>
 
@@ -191,11 +191,11 @@
 }
 
 binder::Status checkArgumentSandboxId(const std::string& sandboxId) {
-    // sandboxId will be in either the format shared:<shared-user-id> or <package-name>
+    // sandboxId will be in either the format shared-<shared-user-id> or <package-name>
     // and <shared-user-id> name has same requirements as <package-name>.
     std::size_t nameStartIndex = 0;
-    if (android::base::StartsWith(sandboxId, "shared:")) {
-        nameStartIndex = 7;  // len("shared:")
+    if (android::base::StartsWith(sandboxId, "shared-")) {
+        nameStartIndex = 7;  // len("shared-")
     }
     return checkArgumentPackageName(sandboxId.substr(nameStartIndex));
 }
@@ -358,12 +358,16 @@
 }
 
 binder::Status VoldNativeService::onUserStarted(int32_t userId,
-                                                const std::vector<std::string>& packageNames) {
+                                                const std::vector<std::string>& packageNames,
+                                                const std::vector<int>& appIds,
+                                                const std::vector<std::string>& sandboxIds) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAMES(packageNames);
+    CHECK_ARGUMENT_SANDBOX_IDS(sandboxIds);
     ACQUIRE_LOCK;
 
-    return translate(VolumeManager::Instance()->onUserStarted(userId, packageNames));
+    return translate(
+        VolumeManager::Instance()->onUserStarted(userId, packageNames, appIds, sandboxIds));
 }
 
 binder::Status VoldNativeService::onUserStopped(int32_t userId) {
@@ -600,6 +604,29 @@
     return translate(VolumeManager::Instance()->destroyObb(volId));
 }
 
+binder::Status VoldNativeService::createStubVolume(
+    const std::string& sourcePath, const std::string& mountPath, const std::string& fsType,
+    const std::string& fsUuid, const std::string& fsLabel, std::string* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(sourcePath);
+    CHECK_ARGUMENT_PATH(mountPath);
+    CHECK_ARGUMENT_HEX(fsUuid);
+    // Label limitation seems to be different between fs (including allowed characters), so checking
+    // is quite meaningless.
+    ACQUIRE_LOCK;
+
+    return translate(VolumeManager::Instance()->createStubVolume(sourcePath, mountPath, fsType,
+                                                                 fsUuid, fsLabel, _aidl_return));
+}
+
+binder::Status VoldNativeService::destroyStubVolume(const std::string& volId) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_ID(volId);
+    ACQUIRE_LOCK;
+
+    return translate(VolumeManager::Instance()->destroyStubVolume(volId));
+}
+
 binder::Status VoldNativeService::fstrim(
     int32_t fstrimFlags, const android::sp<android::os::IVoldTaskListener>& listener) {
     ENFORCE_UID(AID_SYSTEM);
@@ -695,11 +722,11 @@
     ACQUIRE_CRYPT_LOCK;
 
     LOG(DEBUG) << "fdeEnable(" << passwordType << ", *, " << encryptionFlags << ")";
-    if (e4crypt_is_native()) {
-        LOG(ERROR) << "e4crypt_is_native, fdeEnable invalid";
-        return error("e4crypt_is_native, fdeEnable invalid");
+    if (fscrypt_is_native()) {
+        LOG(ERROR) << "fscrypt_is_native, fdeEnable invalid";
+        return error("fscrypt_is_native, fdeEnable invalid");
     }
-    LOG(DEBUG) << "!e4crypt_is_native, spawning fdeEnableInternal";
+    LOG(DEBUG) << "!fscrypt_is_native, spawning fdeEnableInternal";
 
     // Spawn as thread so init can issue commands back to vold without
     // causing deadlock, usually as a result of prep_data_fs.
@@ -774,14 +801,14 @@
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_CRYPT_LOCK;
 
-    return translateBool(e4crypt_initialize_global_de());
+    return translateBool(fscrypt_initialize_global_de());
 }
 
 binder::Status VoldNativeService::mountDefaultEncrypted() {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_CRYPT_LOCK;
 
-    if (!e4crypt_is_native()) {
+    if (!fscrypt_is_native()) {
         // Spawn as thread so init can issue commands back to vold without
         // causing deadlock, usually as a result of prep_data_fs.
         std::thread(&cryptfs_mount_default_encrypted).detach();
@@ -793,7 +820,7 @@
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_CRYPT_LOCK;
 
-    return translateBool(e4crypt_init_user0());
+    return translateBool(fscrypt_init_user0());
 }
 
 binder::Status VoldNativeService::isConvertibleToFbe(bool* _aidl_return) {
@@ -808,28 +835,28 @@
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
 
-    return translateBool(e4crypt_mount_metadata_encrypted(mountPoint, false));
+    return translateBool(fscrypt_mount_metadata_encrypted(mountPoint, false));
 }
 
 binder::Status VoldNativeService::encryptFstab(const std::string& mountPoint) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
 
-    return translateBool(e4crypt_mount_metadata_encrypted(mountPoint, true));
+    return translateBool(fscrypt_mount_metadata_encrypted(mountPoint, true));
 }
 
 binder::Status VoldNativeService::createUserKey(int32_t userId, int32_t userSerial, bool ephemeral) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_CRYPT_LOCK;
 
-    return translateBool(e4crypt_vold_create_user_key(userId, userSerial, ephemeral));
+    return translateBool(fscrypt_vold_create_user_key(userId, userSerial, ephemeral));
 }
 
 binder::Status VoldNativeService::destroyUserKey(int32_t userId) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_CRYPT_LOCK;
 
-    return translateBool(e4crypt_destroy_user_key(userId));
+    return translateBool(fscrypt_destroy_user_key(userId));
 }
 
 binder::Status VoldNativeService::addUserKeyAuth(int32_t userId, int32_t userSerial,
@@ -838,7 +865,7 @@
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_CRYPT_LOCK;
 
-    return translateBool(e4crypt_add_user_key_auth(userId, userSerial, token, secret));
+    return translateBool(fscrypt_add_user_key_auth(userId, userSerial, token, secret));
 }
 
 binder::Status VoldNativeService::clearUserKeyAuth(int32_t userId, int32_t userSerial,
@@ -846,14 +873,14 @@
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_CRYPT_LOCK;
 
-    return translateBool(e4crypt_clear_user_key_auth(userId, userSerial, token, secret));
+    return translateBool(fscrypt_clear_user_key_auth(userId, userSerial, token, secret));
 }
 
 binder::Status VoldNativeService::fixateNewestUserKeyAuth(int32_t userId) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_CRYPT_LOCK;
 
-    return translateBool(e4crypt_fixate_newest_user_key_auth(userId));
+    return translateBool(fscrypt_fixate_newest_user_key_auth(userId));
 }
 
 binder::Status VoldNativeService::unlockUserKey(int32_t userId, int32_t userSerial,
@@ -862,14 +889,14 @@
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_CRYPT_LOCK;
 
-    return translateBool(e4crypt_unlock_user_key(userId, userSerial, token, secret));
+    return translateBool(fscrypt_unlock_user_key(userId, userSerial, token, secret));
 }
 
 binder::Status VoldNativeService::lockUserKey(int32_t userId) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_CRYPT_LOCK;
 
-    return translateBool(e4crypt_lock_user_key(userId));
+    return translateBool(fscrypt_lock_user_key(userId));
 }
 
 binder::Status VoldNativeService::prepareUserStorage(const std::unique_ptr<std::string>& uuid,
@@ -881,7 +908,7 @@
     CHECK_ARGUMENT_HEX(uuid_);
 
     ACQUIRE_CRYPT_LOCK;
-    return translateBool(e4crypt_prepare_user_storage(uuid_, userId, userSerial, flags));
+    return translateBool(fscrypt_prepare_user_storage(uuid_, userId, userSerial, flags));
 }
 
 binder::Status VoldNativeService::destroyUserStorage(const std::unique_ptr<std::string>& uuid,
@@ -892,7 +919,7 @@
     CHECK_ARGUMENT_HEX(uuid_);
 
     ACQUIRE_CRYPT_LOCK;
-    return translateBool(e4crypt_destroy_user_storage(uuid_, userId, flags));
+    return translateBool(fscrypt_destroy_user_storage(uuid_, userId, flags));
 }
 
 binder::Status VoldNativeService::prepareSandboxForApp(const std::string& packageName,
@@ -908,7 +935,7 @@
 }
 
 binder::Status VoldNativeService::destroySandboxForApp(const std::string& packageName,
-                                                       int32_t appId, const std::string& sandboxId,
+                                                       const std::string& sandboxId,
                                                        int32_t userId) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -916,7 +943,7 @@
     ACQUIRE_LOCK;
 
     return translate(
-        VolumeManager::Instance()->destroySandboxForApp(packageName, appId, sandboxId, userId));
+        VolumeManager::Instance()->destroySandboxForApp(packageName, sandboxId, userId));
 }
 
 binder::Status VoldNativeService::startCheckpoint(int32_t retry) {
diff --git a/VoldNativeService.h b/VoldNativeService.h
index b1f28c9..36b591a 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -39,7 +39,9 @@
 
     binder::Status onUserAdded(int32_t userId, int32_t userSerial);
     binder::Status onUserRemoved(int32_t userId);
-    binder::Status onUserStarted(int32_t userId, const std::vector<std::string>& packageNames);
+    binder::Status onUserStarted(int32_t userId, const std::vector<std::string>& packageNames,
+                                 const std::vector<int>& appIds,
+                                 const std::vector<std::string>& sandboxIds);
     binder::Status onUserStopped(int32_t userId);
 
     binder::Status addAppIds(const std::vector<std::string>& packageNames,
@@ -70,6 +72,11 @@
                              int32_t ownerGid, std::string* _aidl_return);
     binder::Status destroyObb(const std::string& volId);
 
+    binder::Status createStubVolume(const std::string& sourcePath, const std::string& mountPath,
+                                    const std::string& fsType, const std::string& fsUuid,
+                                    const std::string& fsLabel, std::string* _aidl_return);
+    binder::Status destroyStubVolume(const std::string& volId);
+
     binder::Status fstrim(int32_t fstrimFlags,
                           const android::sp<android::os::IVoldTaskListener>& listener);
     binder::Status runIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
@@ -122,7 +129,7 @@
 
     binder::Status prepareSandboxForApp(const std::string& packageName, int32_t appId,
                                         const std::string& sandboxId, int32_t userId);
-    binder::Status destroySandboxForApp(const std::string& packageName, int32_t appId,
+    binder::Status destroySandboxForApp(const std::string& packageName,
                                         const std::string& sandboxId, int32_t userId);
 
     binder::Status startCheckpoint(int32_t retry);
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 45158fe..f3604ee 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -49,10 +49,10 @@
 
 #include <private/android_filesystem_config.h>
 
-#include <ext4_utils/ext4_crypt.h>
+#include <fscrypt/fscrypt.h>
 
 #include "Devmapper.h"
-#include "Ext4Crypt.h"
+#include "FsCrypt.h"
 #include "Loop.h"
 #include "NetlinkManager.h"
 #include "Process.h"
@@ -65,6 +65,7 @@
 #include "fs/Vfat.h"
 #include "model/EmulatedVolume.h"
 #include "model/ObbVolume.h"
+#include "model/StubVolume.h"
 
 using android::base::GetBoolProperty;
 using android::base::StartsWith;
@@ -97,6 +98,7 @@
 VolumeManager::VolumeManager() {
     mDebug = false;
     mNextObbId = 0;
+    mNextStubVolumeId = 0;
     // For security reasons, assume that a secure keyguard is
     // showing until we hear otherwise
     mSecureKeyguardShowing = true;
@@ -310,6 +312,11 @@
             return vol;
         }
     }
+    for (const auto& vol : mStubVolumes) {
+        if (vol->getId() == id) {
+            return vol;
+        }
+    }
     for (const auto& vol : mObbVolumes) {
         if (vol->getId() == id) {
             return vol;
@@ -338,8 +345,8 @@
         LOG(ERROR) << "Failed to unlink " << keyPath;
         success = false;
     }
-    if (e4crypt_is_native()) {
-        if (!e4crypt_destroy_volume_keys(fsUuid)) {
+    if (fscrypt_is_native()) {
+        if (!fscrypt_destroy_volume_keys(fsUuid)) {
             success = false;
         }
     }
@@ -568,13 +575,6 @@
         if (sandboxRoot.empty()) {
             return -errno;
         }
-        std::string sharedSandboxRoot;
-        StringAppendF(&sharedSandboxRoot, "%s/shared", sandboxRoot.c_str());
-        // Create shared sandbox base dir for apps with sharedUserIds
-        if (fs_prepare_dir(sharedSandboxRoot.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
-            PLOG(ERROR) << "fs_prepare_dir failed on " << sharedSandboxRoot;
-            return -errno;
-        }
 
         if (!createPkgSpecificDirRoots(volumeRoot)) {
             return -errno;
@@ -691,11 +691,7 @@
 std::string VolumeManager::prepareSandboxSource(uid_t uid, const std::string& sandboxId,
                                                 const std::string& sandboxRootDir) {
     std::string sandboxSourceDir(sandboxRootDir);
-    if (StartsWith(sandboxId, "shared:")) {
-        StringAppendF(&sandboxSourceDir, "/shared/%s", sandboxId.substr(7).c_str());
-    } else {
-        StringAppendF(&sandboxSourceDir, "/%s", sandboxId.c_str());
-    }
+    StringAppendF(&sandboxSourceDir, "/%s", sandboxId.c_str());
     if (fs_prepare_dir(sandboxSourceDir.c_str(), 0755, uid, uid) != 0) {
         PLOG(ERROR) << "fs_prepare_dir failed on " << sandboxSourceDir;
         return kEmptyString;
@@ -772,7 +768,9 @@
     return 0;
 }
 
-int VolumeManager::onUserStarted(userid_t userId, const std::vector<std::string>& packageNames) {
+int VolumeManager::onUserStarted(userid_t userId, const std::vector<std::string>& packageNames,
+                                 const std::vector<int>& appIds,
+                                 const std::vector<std::string>& sandboxIds) {
     LOG(VERBOSE) << "onUserStarted: " << userId;
     // Note that sometimes the system will spin up processes from Zygote
     // before actually starting the user, so we're okay if Zygote
@@ -782,6 +780,10 @@
 
     mStartedUsers.insert(userId);
     mUserPackages[userId] = packageNames;
+    for (size_t i = 0; i < packageNames.size(); ++i) {
+        mAppIds[packageNames[i]] = appIds[i];
+        mSandboxIds[appIds[i]] = sandboxIds[i];
+    }
     if (mPrimary) {
         linkPrimary(userId);
     }
@@ -863,13 +865,13 @@
     return prepareSandboxes(userId, {packageName}, visibleVolLabels);
 }
 
-int VolumeManager::destroySandboxForApp(const std::string& packageName, appid_t appId,
+int VolumeManager::destroySandboxForApp(const std::string& packageName,
                                         const std::string& sandboxId, userid_t userId) {
     if (!GetBoolProperty(kIsolatedStorage, false)) {
         return 0;
     }
-    LOG(VERBOSE) << "destroySandboxForApp: " << packageName << ", appId=" << appId
-                 << ", sandboxId=" << sandboxId << ", userId=" << userId;
+    LOG(VERBOSE) << "destroySandboxForApp: " << packageName << ", sandboxId=" << sandboxId
+                 << ", userId=" << userId;
     auto& userPackages = mUserPackages[userId];
     std::remove(userPackages.begin(), userPackages.end(), packageName);
     // If the package is not uninstalled in any other users, remove appId and sandboxId
@@ -883,8 +885,11 @@
         }
     }
     if (!installedInAnyUser) {
-        mAppIds.erase(packageName);
-        mSandboxIds.erase(appId);
+        const auto& entry = mAppIds.find(packageName);
+        if (entry != mAppIds.end()) {
+            mSandboxIds.erase(entry->second);
+            mAppIds.erase(entry);
+        }
     }
 
     std::vector<std::string> visibleVolLabels;
@@ -915,11 +920,7 @@
     if (volLabel == mPrimary->getLabel() && mPrimary->isEmulated()) {
         StringAppendF(&sandboxDir, "/%d", userId);
     }
-    if (StartsWith(sandboxId, "shared:")) {
-        StringAppendF(&sandboxDir, "/Android/sandbox/shared/%s", sandboxId.substr(7).c_str());
-    } else {
-        StringAppendF(&sandboxDir, "/Android/sandbox/%s", sandboxId.c_str());
-    }
+    StringAppendF(&sandboxDir, "/Android/sandbox/%s", sandboxId.c_str());
 
     if (android::vold::DeleteDirContentsAndDir(sandboxDir) < 0) {
         PLOG(ERROR) << "DeleteDirContentsAndDir failed on " << sandboxDir;
@@ -1196,6 +1197,7 @@
     for (const auto& disk : mDisks) {
         disk->destroy();
     }
+    mStubVolumes.clear();
     mDisks.clear();
     mPendingDisks.clear();
     android::vold::sSleepOnUnmount = true;
@@ -1210,6 +1212,9 @@
     if (mInternalEmulated != nullptr) {
         mInternalEmulated->unmount();
     }
+    for (const auto& stub : mStubVolumes) {
+        stub->unmount();
+    }
     for (const auto& disk : mDisks) {
         disk->unmountAll();
     }
@@ -1423,6 +1428,32 @@
     return android::OK;
 }
 
+int VolumeManager::createStubVolume(const std::string& sourcePath, const std::string& mountPath,
+                                    const std::string& fsType, const std::string& fsUuid,
+                                    const std::string& fsLabel, std::string* outVolId) {
+    int id = mNextStubVolumeId++;
+    auto vol = std::shared_ptr<android::vold::VolumeBase>(
+        new android::vold::StubVolume(id, sourcePath, mountPath, fsType, fsUuid, fsLabel));
+    vol->create();
+
+    mStubVolumes.push_back(vol);
+    *outVolId = vol->getId();
+    return android::OK;
+}
+
+int VolumeManager::destroyStubVolume(const std::string& volId) {
+    auto i = mStubVolumes.begin();
+    while (i != mStubVolumes.end()) {
+        if ((*i)->getId() == volId) {
+            (*i)->destroy();
+            i = mStubVolumes.erase(i);
+        } else {
+            ++i;
+        }
+    }
+    return android::OK;
+}
+
 int VolumeManager::mountAppFuse(uid_t uid, pid_t pid, int mountId, unique_fd* device_fd) {
     std::string name = std::to_string(mountId);
 
diff --git a/VolumeManager.h b/VolumeManager.h
index 8982d8f..e25e244 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -90,7 +90,8 @@
 
     int onUserAdded(userid_t userId, int userSerialNumber);
     int onUserRemoved(userid_t userId);
-    int onUserStarted(userid_t userId, const std::vector<std::string>& packageNames);
+    int onUserStarted(userid_t userId, const std::vector<std::string>& packageNames,
+                      const std::vector<int>& appIds, const std::vector<std::string>& sandboxIds);
     int onUserStopped(userid_t userId);
 
     int addAppIds(const std::vector<std::string>& packageNames, const std::vector<int32_t>& appIds);
@@ -98,8 +99,8 @@
                       const std::vector<std::string>& sandboxIds);
     int prepareSandboxForApp(const std::string& packageName, appid_t appId,
                              const std::string& sandboxId, userid_t userId);
-    int destroySandboxForApp(const std::string& packageName, appid_t appId,
-                             const std::string& sandboxId, userid_t userId);
+    int destroySandboxForApp(const std::string& packageName, const std::string& sandboxId,
+                             userid_t userId);
 
     int onVolumeMounted(android::vold::VolumeBase* vol);
     int onVolumeUnmounted(android::vold::VolumeBase* vol);
@@ -135,6 +136,11 @@
                   std::string* outVolId);
     int destroyObb(const std::string& volId);
 
+    int createStubVolume(const std::string& sourcePath, const std::string& mountPath,
+                         const std::string& fsType, const std::string& fsUuid,
+                         const std::string& fsLabel, std::string* outVolId);
+    int destroyStubVolume(const std::string& volId);
+
     int mountAppFuse(uid_t uid, pid_t pid, int mountId, android::base::unique_fd* device_fd);
     int unmountAppFuse(uid_t uid, pid_t pid, int mountId);
 
@@ -180,6 +186,7 @@
     std::list<std::shared_ptr<android::vold::Disk>> mDisks;
     std::list<std::shared_ptr<android::vold::Disk>> mPendingDisks;
     std::list<std::shared_ptr<android::vold::VolumeBase>> mObbVolumes;
+    std::list<std::shared_ptr<android::vold::VolumeBase>> mStubVolumes;
 
     std::unordered_map<userid_t, int> mAddedUsers;
     std::unordered_set<userid_t> mStartedUsers;
@@ -195,6 +202,7 @@
     std::unordered_set<std::string> mVisibleVolumeIds;
 
     int mNextObbId;
+    int mNextStubVolumeId;
     bool mSecureKeyguardShowing;
 };
 
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index d8b36aa..ca0afdc 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -29,7 +29,8 @@
 
     void onUserAdded(int userId, int userSerial);
     void onUserRemoved(int userId);
-    void onUserStarted(int userId, in @utf8InCpp String[] packageNames);
+    void onUserStarted(int userId, in @utf8InCpp String[] packageNames, in int[] appIds,
+            in @utf8InCpp String[] sandboxIds);
     void onUserStopped(int userId);
 
     void addAppIds(in @utf8InCpp String[] packageNames, in int[] appIds);
@@ -102,7 +103,7 @@
 
     void prepareSandboxForApp(in @utf8InCpp String packageName, int appId,
                               in @utf8InCpp String sandboxId, int userId);
-    void destroySandboxForApp(in @utf8InCpp String packageName, int appId,
+    void destroySandboxForApp(in @utf8InCpp String packageName,
                               in @utf8InCpp String sandboxId, int userId);
 
     void startCheckpoint(int retry);
@@ -114,6 +115,11 @@
     void restoreCheckpoint(@utf8InCpp String device);
     void markBootAttempt();
 
+    @utf8InCpp String createStubVolume(@utf8InCpp String sourcePath,
+            @utf8InCpp String mountPath, @utf8InCpp String fsType,
+            @utf8InCpp String fsUuid, @utf8InCpp String fsLabel);
+    void destroyStubVolume(@utf8InCpp String volId);
+
     const int ENCRYPTION_FLAG_NO_UI = 4;
 
     const int ENCRYPTION_STATE_NONE = 1;
@@ -161,4 +167,5 @@
     const int VOLUME_TYPE_EMULATED = 2;
     const int VOLUME_TYPE_ASEC = 3;
     const int VOLUME_TYPE_OBB = 4;
+    const int VOLUME_TYPE_STUB = 5;
 }
diff --git a/cryptfs.cpp b/cryptfs.cpp
index 68f83da..21f434d 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -26,10 +26,11 @@
 
 #include "Checkpoint.h"
 #include "EncryptInplace.h"
-#include "Ext4Crypt.h"
+#include "FsCrypt.h"
 #include "Keymaster.h"
 #include "Process.h"
 #include "ScryptParameters.h"
+#include "Utils.h"
 #include "VoldUtil.h"
 #include "VolumeManager.h"
 #include "secontext.h"
@@ -38,10 +39,10 @@
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
 #include <cutils/properties.h>
-#include <ext4_utils/ext4_crypt.h>
 #include <ext4_utils/ext4_utils.h>
 #include <f2fs_sparseblock.h>
 #include <fs_mgr.h>
+#include <fscrypt/fscrypt.h>
 #include <hardware_legacy/power.h>
 #include <log/log.h>
 #include <logwrap/logwrap.h>
@@ -76,6 +77,8 @@
 #include <crypto_scrypt.h>
 }
 
+using namespace std::chrono_literals;
+
 #define UNUSED __attribute__((unused))
 
 #define DM_CRYPT_BUF_SIZE 4096
@@ -1321,6 +1324,12 @@
         goto errout;
     }
 
+    /* Ensure the dm device has been created before returning. */
+    if (android::vold::WaitForFile(crypto_blk_name, 1s) < 0) {
+        // WaitForFile generates a suitable log message
+        goto errout;
+    }
+
     /* We made it here with no errors.  Woot! */
     retval = 0;
 
@@ -1874,7 +1883,7 @@
 
 int cryptfs_restart(void) {
     SLOGI("cryptfs_restart");
-    if (e4crypt_is_native()) {
+    if (fscrypt_is_native()) {
         SLOGE("cryptfs_restart not valid for file encryption:");
         return -1;
     }
@@ -1895,7 +1904,7 @@
     }
 
     // crypto_complete is full disk encrypted status
-    if (e4crypt_is_native()) {
+    if (fscrypt_is_native()) {
         return CRYPTO_COMPLETE_NOT_ENCRYPTED;
     }
 
@@ -2155,7 +2164,7 @@
     strlcpy((char*)ext_crypt_ftr.crypto_type_name, cryptfs_get_crypto_name(),
             MAX_CRYPTO_TYPE_NAME_LEN);
     uint32_t flags = 0;
-    if (e4crypt_is_native() &&
+    if (fscrypt_is_native() &&
         android::base::GetBoolProperty("ro.crypto.allow_encrypt_override", false))
         flags |= CREATE_CRYPTO_BLK_DEV_FLAGS_ALLOW_ENCRYPT_OVERRIDE;
 
@@ -2254,7 +2263,7 @@
 
 int cryptfs_check_passwd(const char* passwd) {
     SLOGI("cryptfs_check_passwd");
-    if (e4crypt_is_native()) {
+    if (fscrypt_is_native()) {
         SLOGE("cryptfs_check_passwd not valid for file encryption");
         return -1;
     }
@@ -2890,7 +2899,7 @@
 }
 
 int cryptfs_changepw(int crypt_type, const char* currentpw, const char* newpw) {
-    if (e4crypt_is_native()) {
+    if (fscrypt_is_native()) {
         SLOGE("cryptfs_changepw not valid for file encryption");
         return -1;
     }
@@ -3158,7 +3167,7 @@
 
 /* Return the value of the specified field. */
 int cryptfs_getfield(const char* fieldname, char* value, int len) {
-    if (e4crypt_is_native()) {
+    if (fscrypt_is_native()) {
         SLOGE("Cannot get field when file encrypted");
         return -1;
     }
@@ -3223,7 +3232,7 @@
 
 /* Set the value of the specified field. */
 int cryptfs_setfield(const char* fieldname, const char* value) {
-    if (e4crypt_is_native()) {
+    if (fscrypt_is_native()) {
         SLOGE("Cannot set field when file encrypted");
         return -1;
     }
@@ -3343,7 +3352,7 @@
 /* Returns type of the password, default, pattern, pin or password.
  */
 int cryptfs_get_password_type(void) {
-    if (e4crypt_is_native()) {
+    if (fscrypt_is_native()) {
         SLOGE("cryptfs_get_password_type not valid for file encryption");
         return -1;
     }
@@ -3363,7 +3372,7 @@
 }
 
 const char* cryptfs_get_password() {
-    if (e4crypt_is_native()) {
+    if (fscrypt_is_native()) {
         SLOGE("cryptfs_get_password not valid for file encryption");
         return 0;
     }
diff --git a/fs/Ext4.cpp b/fs/Ext4.cpp
index 7ac4853..806cfd1 100644
--- a/fs/Ext4.cpp
+++ b/fs/Ext4.cpp
@@ -36,12 +36,12 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <cutils/properties.h>
-#include <ext4_utils/ext4_crypt.h>
+#include <fscrypt/fscrypt.h>
 #include <logwrap/logwrap.h>
 #include <selinux/selinux.h>
 
 #include "Ext4.h"
-#include "Ext4Crypt.h"
+#include "FsCrypt.h"
 #include "Utils.h"
 #include "VoldUtil.h"
 
@@ -175,7 +175,7 @@
     if (android::base::GetBoolProperty("vold.has_quota", false)) {
         options += ",quota";
     }
-    if (e4crypt_is_native()) {
+    if (fscrypt_is_native()) {
         options += ",encrypt";
     }
 
diff --git a/fs/F2fs.cpp b/fs/F2fs.cpp
index 9d72963..c6e0f52 100644
--- a/fs/F2fs.cpp
+++ b/fs/F2fs.cpp
@@ -20,7 +20,7 @@
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
-#include <ext4_utils/ext4_crypt.h>
+#include <fscrypt/fscrypt.h>
 
 #include <string>
 #include <vector>
@@ -81,7 +81,7 @@
         cmd.push_back("-O");
         cmd.push_back("quota");
     }
-    if (e4crypt_is_native()) {
+    if (fscrypt_is_native()) {
         cmd.push_back("-O");
         cmd.push_back("encrypt");
     }
diff --git a/model/Disk.cpp b/model/Disk.cpp
index 2b6773d..3d25e4c 100644
--- a/model/Disk.cpp
+++ b/model/Disk.cpp
@@ -15,7 +15,7 @@
  */
 
 #include "Disk.h"
-#include "Ext4Crypt.h"
+#include "FsCrypt.h"
 #include "PrivateVolume.h"
 #include "PublicVolume.h"
 #include "Utils.h"
@@ -28,7 +28,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <ext4_utils/ext4_crypt.h>
+#include <fscrypt/fscrypt.h>
 
 #include "cryptfs.h"
 
diff --git a/model/StubVolume.cpp b/model/StubVolume.cpp
new file mode 100644
index 0000000..edd0861
--- /dev/null
+++ b/model/StubVolume.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 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 "StubVolume.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace vold {
+
+StubVolume::StubVolume(int id, const std::string& sourcePath, const std::string& mountPath,
+                       const std::string& fsType, const std::string& fsUuid,
+                       const std::string& fsLabel)
+    : VolumeBase(Type::kStub),
+      mSourcePath(sourcePath),
+      mMountPath(mountPath),
+      mFsType(fsType),
+      mFsUuid(fsUuid),
+      mFsLabel(fsLabel) {
+    setId(StringPrintf("stub:%d", id));
+}
+
+StubVolume::~StubVolume() {}
+
+status_t StubVolume::doCreate() {
+    return OK;
+}
+
+status_t StubVolume::doDestroy() {
+    return OK;
+}
+
+status_t StubVolume::doMount() {
+    auto listener = getListener();
+    if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
+    setInternalPath(mSourcePath);
+    setPath(mMountPath);
+    return OK;
+}
+
+status_t StubVolume::doUnmount() {
+    return OK;
+}
+
+// TODO: return error instead.
+status_t StubVolume::doFormat(const std::string& fsType) {
+    return OK;
+}
+
+}  // namespace vold
+}  // namespace android
diff --git a/model/StubVolume.h b/model/StubVolume.h
new file mode 100644
index 0000000..538cae9
--- /dev/null
+++ b/model/StubVolume.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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 ANDROID_VOLD_STUB_VOLUME_H
+#define ANDROID_VOLD_STUB_VOLUME_H
+
+#include "VolumeBase.h"
+
+namespace android {
+namespace vold {
+
+/*
+ * A vold representation of volumes managed from outside Android (e.g., ARC++).
+ *
+ * Used for the case when events such that mounting and unmounting are
+ * actually handled from outside vold, and vold only need to keep track on those
+ * vents instead of talking to kernel directly.
+ */
+class StubVolume : public VolumeBase {
+  public:
+    StubVolume(int id, const std::string& sourcePath, const std::string& mountPath,
+               const std::string& fsType, const std::string& fsUuid, const std::string& fsLabel);
+    virtual ~StubVolume();
+
+  protected:
+    status_t doCreate() override;
+    status_t doDestroy() override;
+    status_t doMount() override;
+    status_t doUnmount() override;
+    status_t doFormat(const std::string& fsType) override;
+
+  private:
+    const std::string mSourcePath;
+    const std::string mMountPath;
+    const std::string mFsType;
+    const std::string mFsUuid;
+    const std::string mFsLabel;
+
+    DISALLOW_COPY_AND_ASSIGN(StubVolume);
+};
+
+}  // namespace vold
+}  // namespace android
+
+#endif
diff --git a/model/VolumeBase.h b/model/VolumeBase.h
index a9fd42d..ea187bd 100644
--- a/model/VolumeBase.h
+++ b/model/VolumeBase.h
@@ -56,6 +56,7 @@
         kEmulated,
         kAsec,
         kObb,
+        kStub,
     };
 
     enum MountFlags {