Merge QP1A.190107.001

Change-Id: If019c75ac81f35d72fc2aab573557e325e2dfcb0
diff --git a/Android.bp b/Android.bp
index f8f8d5a..f2012ef 100644
--- a/Android.bp
+++ b/Android.bp
@@ -144,7 +144,6 @@
                 "arc_services_aidl",
                 "libarcappfuse",
                 "libarcobbvolume",
-                "libparcelfiledescriptor",
             ],
         },
         debuggable: {
@@ -179,7 +178,6 @@
                 "arc_services_aidl",
                 "libarcappfuse",
                 "libarcobbvolume",
-                "libparcelfiledescriptor",
             ],
         },
         device_support_hwfde: {
diff --git a/Checkpoint.cpp b/Checkpoint.cpp
index e238acf..28855e6 100644
--- a/Checkpoint.cpp
+++ b/Checkpoint.cpp
@@ -26,6 +26,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
+#include <android-base/properties.h>
 #include <android-base/unique_fd.h>
 #include <android/hardware/boot/1.0/IBootControl.h>
 #include <cutils/android_reboot.h>
@@ -36,6 +37,7 @@
 #include <sys/mount.h>
 #include <sys/stat.h>
 
+using android::base::SetProperty;
 using android::binder::Status;
 using android::hardware::hidl_string;
 using android::hardware::boot::V1_0::BoolResult;
@@ -81,8 +83,15 @@
     return Status::ok();
 }
 
+namespace {
+
+bool isCheckpointing = false;
+}
+
 Status cp_commitChanges() {
-    if (!cp_needsCheckpoint()) return Status::ok();
+    if (!isCheckpointing) {
+        return Status::ok();
+    }
     // Must take action for list of mounted checkpointed things here
     // To do this, we walk the list of mounted file systems.
     // But we also need to get the matching fstab entries to see
@@ -115,6 +124,8 @@
                 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
         }
     }
+    SetProperty("vold.checkpoint_committed", "1");
+    isCheckpointing = false;
     if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
         return Status::fromExceptionCode(errno, err_str.c_str());
     return Status::ok();
@@ -152,10 +163,16 @@
     std::string content;
     sp<IBootControl> module = IBootControl::getService();
 
-    if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE)
+    if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
+        isCheckpointing = true;
         return true;
+    }
     ret = android::base::ReadFileToString(kMetadataCPFile, &content);
-    if (ret) return content != "0";
+    if (ret) {
+        ret = content != "0";
+        isCheckpointing = ret;
+        return ret;
+    }
     return false;
 }
 
@@ -279,9 +296,9 @@
         PLOG(ERROR) << "Cannot open " << blockDevice;
         return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
     }
-    char buffer[kBlockSize];
-    device.read(buffer, kBlockSize);
-    log_sector& ls = *(log_sector*)buffer;
+    alignas(alignof(log_sector)) char ls_buffer[kBlockSize];
+    device.read(ls_buffer, kBlockSize);
+    log_sector& ls = *reinterpret_cast<log_sector*>(ls_buffer);
     if (ls.magic != kMagic) {
         LOG(ERROR) << "No magic";
         return Status::fromExceptionCode(EINVAL, "No magic");
@@ -290,10 +307,9 @@
     LOG(INFO) << "Restoring " << ls.sequence << " log sectors";
 
     for (int sequence = ls.sequence; sequence >= 0; sequence--) {
-        char buffer[kBlockSize];
         device.seekg(0);
-        device.read(buffer, kBlockSize);
-        log_sector& ls = *(log_sector*)buffer;
+        device.read(ls_buffer, kBlockSize);
+        ls = *reinterpret_cast<log_sector*>(ls_buffer);
         if (ls.magic != kMagic) {
             LOG(ERROR) << "No magic!";
             return Status::fromExceptionCode(EINVAL, "No magic");
diff --git a/EncryptInplace.cpp b/EncryptInplace.cpp
index 63a8e15..cfad84e 100644
--- a/EncryptInplace.cpp
+++ b/EncryptInplace.cpp
@@ -596,11 +596,11 @@
     for (i /= CRYPT_SECTORS_PER_BUFSIZE; i < numblocks; i++) {
         new_pct = (i + blocks_already_done) / one_pct;
         if (set_progress_properties && new_pct > cur_pct) {
-            char buf[8];
+            char property_buf[8];
 
             cur_pct = new_pct;
-            snprintf(buf, sizeof(buf), "%" PRId64, cur_pct);
-            android::base::SetProperty("vold.encrypt_progress", buf);
+            snprintf(property_buf, sizeof(property_buf), "%" PRId64, cur_pct);
+            android::base::SetProperty("vold.encrypt_progress", property_buf);
         }
         if (unix_read(realfd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
             PLOG(ERROR) << "Error reading real_blkdev " << real_blkdev << " for inplace encrypt";
diff --git a/KeyStorage.cpp b/KeyStorage.cpp
index f1a1167..97ee468 100644
--- a/KeyStorage.cpp
+++ b/KeyStorage.cpp
@@ -244,7 +244,7 @@
                                 km::KeyPurpose purpose, const km::AuthorizationSet& keyParams,
                                 const km::AuthorizationSet& opParams,
                                 const km::HardwareAuthToken& authToken,
-                                km::AuthorizationSet* outParams) {
+                                km::AuthorizationSet* outParams, bool keepOld) {
     auto kmKeyPath = dir + "/" + kFn_keymaster_key_blob;
     std::string kmKey;
     if (!readFileToString(kmKeyPath, &kmKey)) return KeymasterOperation();
@@ -261,12 +261,14 @@
         if (!keymaster.upgradeKey(kmKey, keyParams, &newKey)) return KeymasterOperation();
         auto newKeyPath = dir + "/" + kFn_keymaster_key_blob_upgraded;
         if (!writeStringToFile(newKey, newKeyPath)) return KeymasterOperation();
-        if (rename(newKeyPath.c_str(), kmKeyPath.c_str()) != 0) {
-            PLOG(ERROR) << "Unable to move upgraded key to location: " << kmKeyPath;
-            return KeymasterOperation();
-        }
-        if (!keymaster.deleteKey(kmKey)) {
-            LOG(ERROR) << "Key deletion failed during upgrade, continuing anyway: " << dir;
+        if (!keepOld) {
+            if (rename(newKeyPath.c_str(), kmKeyPath.c_str()) != 0) {
+                PLOG(ERROR) << "Unable to move upgraded key to location: " << kmKeyPath;
+                return KeymasterOperation();
+            }
+            if (!keymaster.deleteKey(kmKey)) {
+                LOG(ERROR) << "Key deletion failed during upgrade, continuing anyway: " << dir;
+            }
         }
         kmKey = newKey;
         LOG(INFO) << "Key upgraded: " << dir;
@@ -275,12 +277,12 @@
 
 static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
                                     const km::AuthorizationSet& keyParams,
-                                    const km::HardwareAuthToken& authToken,
-                                    const KeyBuffer& message, std::string* ciphertext) {
+                                    const km::HardwareAuthToken& authToken, const KeyBuffer& message,
+                                    std::string* ciphertext, bool keepOld) {
     km::AuthorizationSet opParams;
     km::AuthorizationSet outParams;
-    auto opHandle =
-        begin(keymaster, dir, km::KeyPurpose::ENCRYPT, keyParams, opParams, authToken, &outParams);
+    auto opHandle = begin(keymaster, dir, km::KeyPurpose::ENCRYPT, keyParams, opParams, authToken,
+                          &outParams, keepOld);
     if (!opHandle) return false;
     auto nonceBlob = outParams.GetTagValue(km::TAG_NONCE);
     if (!nonceBlob.isOk()) {
@@ -304,13 +306,14 @@
 static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
                                     const km::AuthorizationSet& keyParams,
                                     const km::HardwareAuthToken& authToken,
-                                    const std::string& ciphertext, KeyBuffer* message) {
+                                    const std::string& ciphertext, KeyBuffer* message,
+                                    bool keepOld) {
     auto nonce = ciphertext.substr(0, GCM_NONCE_BYTES);
     auto bodyAndMac = ciphertext.substr(GCM_NONCE_BYTES);
     auto opParams = km::AuthorizationSetBuilder().Authorization(km::TAG_NONCE,
                                                                 km::support::blob2hidlVec(nonce));
-    auto opHandle =
-        begin(keymaster, dir, km::KeyPurpose::DECRYPT, keyParams, opParams, authToken, nullptr);
+    auto opHandle = begin(keymaster, dir, km::KeyPurpose::DECRYPT, keyParams, opParams, authToken,
+                          nullptr, keepOld);
     if (!opHandle) return false;
     if (!opHandle.updateCompletely(bodyAndMac, message)) return false;
     if (!opHandle.finish(nullptr)) return false;
@@ -516,7 +519,8 @@
         km::AuthorizationSet keyParams;
         km::HardwareAuthToken authToken;
         std::tie(keyParams, authToken) = beginParams(auth, appId);
-        if (!encryptWithKeymasterKey(keymaster, dir, keyParams, authToken, key, &encryptedKey))
+        if (!encryptWithKeymasterKey(keymaster, dir, keyParams, authToken, key, &encryptedKey,
+                                     false))
             return false;
     } else {
         if (!encryptWithoutKeymaster(appId, key, &encryptedKey)) return false;
@@ -544,7 +548,8 @@
     return true;
 }
 
-bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffer* key) {
+bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffer* key,
+                 bool keepOld) {
     std::string version;
     if (!readFileToString(dir + "/" + kFn_version, &version)) return false;
     if (version != kCurrentVersion) {
@@ -569,7 +574,8 @@
         km::AuthorizationSet keyParams;
         km::HardwareAuthToken authToken;
         std::tie(keyParams, authToken) = beginParams(auth, appId);
-        if (!decryptWithKeymasterKey(keymaster, dir, keyParams, authToken, encryptedMessage, key))
+        if (!decryptWithKeymasterKey(keymaster, dir, keyParams, authToken, encryptedMessage, key,
+                                     keepOld))
             return false;
     } else {
         if (!decryptWithoutKeymaster(appId, encryptedMessage, key)) return false;
diff --git a/KeyStorage.h b/KeyStorage.h
index d452589..72ddfc4 100644
--- a/KeyStorage.h
+++ b/KeyStorage.h
@@ -32,7 +32,7 @@
 // If only "secret" is nonempty, it is used to decrypt in a non-Keymaster process.
 class KeyAuthentication {
   public:
-    KeyAuthentication(std::string t, std::string s) : token{t}, secret{s} {};
+    KeyAuthentication(const std::string& t, const std::string& s) : token{t}, secret{s} {};
 
     bool usesKeymaster() const { return !token.empty() || secret.empty(); };
 
@@ -68,7 +68,8 @@
                         const KeyAuthentication& auth, const KeyBuffer& key);
 
 // Retrieve the key from the named directory.
-bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffer* key);
+bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffer* key,
+                 bool keepOld = false);
 
 // Securely destroy the key stored in the named directory and delete the directory.
 bool destroyKey(const std::string& dir);
diff --git a/KeyUtil.cpp b/KeyUtil.cpp
index 1f35f3a..b1f4c3d 100644
--- a/KeyUtil.cpp
+++ b/KeyUtil.cpp
@@ -194,10 +194,10 @@
 }
 
 bool retrieveKey(bool create_if_absent, const std::string& key_path, const std::string& tmp_path,
-                 KeyBuffer* key) {
+                 KeyBuffer* key, bool keepOld) {
     if (pathExists(key_path)) {
         LOG(DEBUG) << "Key exists, using: " << key_path;
-        if (!retrieveKey(key_path, kEmptyAuthentication, key)) return false;
+        if (!retrieveKey(key_path, kEmptyAuthentication, key, keepOld)) return false;
     } else {
         if (!create_if_absent) {
             LOG(ERROR) << "No key found in " << key_path;
diff --git a/KeyUtil.h b/KeyUtil.h
index f0b2856..2839b4a 100644
--- a/KeyUtil.h
+++ b/KeyUtil.h
@@ -34,7 +34,7 @@
                            const std::string& key_path, const std::string& tmp_path,
                            std::string* key_ref, bool wrapped_key_supported);
 bool retrieveKey(bool create_if_absent, const std::string& key_path, const std::string& tmp_path,
-                 KeyBuffer* key);
+                 KeyBuffer* key, bool keepOld = true);
 
 }  // namespace vold
 }  // namespace android
diff --git a/Keymaster.h b/Keymaster.h
index c0ec4d3..a75fd56 100644
--- a/Keymaster.h
+++ b/Keymaster.h
@@ -46,8 +46,8 @@
     ~KeymasterOperation();
     // Is this instance valid? This is false if creation fails, and becomes
     // false on finish or if an update fails.
-    explicit operator bool() { return mError == km::ErrorCode::OK; }
-    km::ErrorCode errorCode() { return mError; }
+    explicit operator bool() const { return mError == km::ErrorCode::OK; }
+    km::ErrorCode errorCode() const { return mError; }
     // Call "update" repeatedly until all of the input is consumed, and
     // concatenate the output. Return true on success.
     template <class TI, class TO>
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index e156424..5c8a075 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -30,6 +30,7 @@
 
 #include <linux/dm-ioctl.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/unique_fd.h>
@@ -40,6 +41,7 @@
 #include "EncryptInplace.h"
 #include "KeyStorage.h"
 #include "KeyUtil.h"
+#include "Keymaster.h"
 #include "Utils.h"
 #include "VoldUtil.h"
 #include "secontext.h"
@@ -52,6 +54,9 @@
 
 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";
+
 static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
     // fs_mgr_do_mount runs fsck. Use setexeccon to run trusted
     // partitions in the fsck domain.
@@ -74,12 +79,41 @@
     return true;
 }
 
+namespace android {
+namespace vold {
+
+// Note: It is possible to orphan a key if it is removed before deleting
+// Update this once keymaster APIs change, and we have a proper commit.
+static void commit_key(const std::string& dir) {
+    while (!android::base::WaitForProperty("vold.checkpoint_committed", "1")) {
+        LOG(ERROR) << "Wait for boot timed out";
+    }
+    Keymaster keymaster;
+    auto keyPath = dir + "/" + kFn_keymaster_key_blob;
+    auto newKeyPath = dir + "/" + kFn_keymaster_key_blob_upgraded;
+    std::string key;
+
+    if (!android::base::ReadFileToString(keyPath, &key)) {
+        LOG(ERROR) << "Failed to read old key: " << dir;
+        return;
+    }
+    if (rename(newKeyPath.c_str(), keyPath.c_str()) != 0) {
+        PLOG(ERROR) << "Unable to move upgraded key to location: " << keyPath;
+        return;
+    }
+    if (!keymaster.deleteKey(key)) {
+        LOG(ERROR) << "Key deletion failed during upgrade, continuing anyway: " << dir;
+    }
+    LOG(INFO) << "Old Key deleted: " << dir;
+}
+
 static bool read_key(struct fstab_rec const* data_rec, bool create_if_absent, KeyBuffer* key) {
     if (!data_rec->key_dir) {
         LOG(ERROR) << "Failed to get key_dir";
         return false;
     }
     std::string key_dir = data_rec->key_dir;
+    std::string sKey;
     auto dir = key_dir + "/key";
     LOG(DEBUG) << "key_dir/key: " << dir;
     if (fs_mkdirs(dir.c_str(), 0700)) {
@@ -87,10 +121,30 @@
         return false;
     }
     auto temp = key_dir + "/tmp";
-    if (!android::vold::retrieveKey(create_if_absent, dir, temp, key)) return false;
+    auto newKeyPath = dir + "/" + kFn_keymaster_key_blob_upgraded;
+    /* If we have a leftover upgraded key, delete it.
+     * We either failed an update and must return to the old key,
+     * or we rebooted before commiting the keys in a freak accident.
+     * Either way, we can re-upgrade the key if we need to.
+     */
+    Keymaster keymaster;
+    if (pathExists(newKeyPath)) {
+        if (!android::base::ReadFileToString(newKeyPath, &sKey))
+            LOG(ERROR) << "Failed to read old key: " << dir;
+        else if (!keymaster.deleteKey(sKey))
+            LOG(ERROR) << "Old key deletion failed, continuing anyway: " << dir;
+        else
+            unlink(newKeyPath.c_str());
+    }
+    bool needs_cp = cp_needsCheckpoint();
+    if (!android::vold::retrieveKey(create_if_absent, dir, temp, key, needs_cp)) return false;
+    if (needs_cp && pathExists(newKeyPath)) std::thread(commit_key, dir).detach();
     return true;
 }
 
+}  // namespace vold
+}  // namespace android
+
 static KeyBuffer default_key_params(const std::string& real_blkdev, const KeyBuffer& key) {
     KeyBuffer hex_key;
     if (android::vold::StrToHex(key, hex_key) != android::OK) {
diff --git a/Utils.cpp b/Utils.cpp
index 57417d6..4ec2679 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -236,7 +236,7 @@
     cmd.push_back(path);
 
     std::vector<std::string> output;
-    status_t res = ForkExecvp(cmd, output, untrusted ? sBlkidUntrustedContext : sBlkidContext);
+    status_t res = ForkExecvp(cmd, &output, untrusted ? sBlkidUntrustedContext : sBlkidContext);
     if (res != OK) {
         LOG(WARNING) << "blkid failed to identify " << path;
         return res;
@@ -262,101 +262,92 @@
     return readMetadata(path, fsType, fsUuid, fsLabel, true);
 }
 
-status_t ForkExecvp(const std::vector<std::string>& args) {
-    return ForkExecvp(args, nullptr);
-}
-
-status_t ForkExecvp(const std::vector<std::string>& args, security_context_t context) {
-    std::lock_guard<std::mutex> lock(kSecurityLock);
-    size_t argc = args.size();
-    char** argv = (char**)calloc(argc, sizeof(char*));
-    for (size_t i = 0; i < argc; i++) {
-        argv[i] = (char*)args[i].c_str();
-        if (i == 0) {
-            LOG(DEBUG) << args[i];
+static std::vector<const char*> ConvertToArgv(const std::vector<std::string>& args) {
+    std::vector<const char*> argv;
+    argv.reserve(args.size() + 1);
+    for (const auto& arg : args) {
+        if (argv.empty()) {
+            LOG(DEBUG) << arg;
         } else {
-            LOG(DEBUG) << "    " << args[i];
+            LOG(DEBUG) << "    " << arg;
         }
+        argv.emplace_back(arg.data());
     }
-
-    if (context) {
-        if (setexeccon(context)) {
-            LOG(ERROR) << "Failed to setexeccon";
-            abort();
-        }
-    }
-    status_t res = android_fork_execvp(argc, argv, NULL, false, true);
-    if (context) {
-        if (setexeccon(nullptr)) {
-            LOG(ERROR) << "Failed to setexeccon";
-            abort();
-        }
-    }
-
-    free(argv);
-    return res;
+    argv.emplace_back(nullptr);
+    return argv;
 }
 
-status_t ForkExecvp(const std::vector<std::string>& args, std::vector<std::string>& output) {
-    return ForkExecvp(args, output, nullptr);
-}
-
-status_t ForkExecvp(const std::vector<std::string>& args, std::vector<std::string>& output,
-                    security_context_t context) {
-    std::lock_guard<std::mutex> lock(kSecurityLock);
-    std::string cmd;
-    for (size_t i = 0; i < args.size(); i++) {
-        cmd += args[i] + " ";
-        if (i == 0) {
-            LOG(DEBUG) << args[i];
-        } else {
-            LOG(DEBUG) << "    " << args[i];
-        }
-    }
-    output.clear();
-
-    if (context) {
-        if (setexeccon(context)) {
-            LOG(ERROR) << "Failed to setexeccon";
-            abort();
-        }
-    }
-    FILE* fp = popen(cmd.c_str(), "r");  // NOLINT
-    if (context) {
-        if (setexeccon(nullptr)) {
-            LOG(ERROR) << "Failed to setexeccon";
-            abort();
-        }
-    }
-
+static status_t ReadLinesFromFdAndLog(std::vector<std::string>* output,
+                                      android::base::unique_fd ufd) {
+    std::unique_ptr<FILE, int (*)(FILE*)> fp(android::base::Fdopen(std::move(ufd), "r"), fclose);
     if (!fp) {
-        PLOG(ERROR) << "Failed to popen " << cmd;
+        PLOG(ERROR) << "fdopen in ReadLinesFromFdAndLog";
         return -errno;
     }
+    if (output) output->clear();
     char line[1024];
-    while (fgets(line, sizeof(line), fp) != nullptr) {
+    while (fgets(line, sizeof(line), fp.get()) != nullptr) {
         LOG(DEBUG) << line;
-        output.push_back(std::string(line));
+        if (output) output->emplace_back(line);
     }
-    if (pclose(fp) != 0) {
-        PLOG(ERROR) << "Failed to pclose " << cmd;
+    return OK;
+}
+
+status_t ForkExecvp(const std::vector<std::string>& args, std::vector<std::string>* output,
+                    security_context_t context) {
+    auto argv = ConvertToArgv(args);
+
+    android::base::unique_fd pipe_read, pipe_write;
+    if (!android::base::Pipe(&pipe_read, &pipe_write)) {
+        PLOG(ERROR) << "Pipe in ForkExecvp";
         return -errno;
     }
 
+    pid_t pid = fork();
+    if (pid == 0) {
+        if (context) {
+            if (setexeccon(context)) {
+                LOG(ERROR) << "Failed to setexeccon in ForkExecvp";
+                abort();
+            }
+        }
+        pipe_read.reset();
+        if (dup2(pipe_write.get(), STDOUT_FILENO) == -1) {
+            PLOG(ERROR) << "dup2 in ForkExecvp";
+            _exit(EXIT_FAILURE);
+        }
+        pipe_write.reset();
+        execvp(argv[0], const_cast<char**>(argv.data()));
+        PLOG(ERROR) << "exec in ForkExecvp";
+        _exit(EXIT_FAILURE);
+    }
+    if (pid == -1) {
+        PLOG(ERROR) << "fork in ForkExecvp";
+        return -errno;
+    }
+
+    pipe_write.reset();
+    auto st = ReadLinesFromFdAndLog(output, std::move(pipe_read));
+    if (st != 0) return st;
+
+    int status;
+    if (waitpid(pid, &status, 0) == -1) {
+        PLOG(ERROR) << "waitpid in ForkExecvp";
+        return -errno;
+    }
+    if (!WIFEXITED(status)) {
+        LOG(ERROR) << "Process did not exit normally, status: " << status;
+        return -ECHILD;
+    }
+    if (WEXITSTATUS(status)) {
+        LOG(ERROR) << "Process exited with code: " << WEXITSTATUS(status);
+        return WEXITSTATUS(status);
+    }
     return OK;
 }
 
 pid_t ForkExecvpAsync(const std::vector<std::string>& args) {
-    size_t argc = args.size();
-    char** argv = (char**)calloc(argc + 1, sizeof(char*));
-    for (size_t i = 0; i < argc; i++) {
-        argv[i] = (char*)args[i].c_str();
-        if (i == 0) {
-            LOG(DEBUG) << args[i];
-        } else {
-            LOG(DEBUG) << "    " << args[i];
-        }
-    }
+    auto argv = ConvertToArgv(args);
 
     pid_t pid = fork();
     if (pid == 0) {
@@ -364,18 +355,14 @@
         close(STDOUT_FILENO);
         close(STDERR_FILENO);
 
-        if (execvp(argv[0], argv)) {
-            PLOG(ERROR) << "Failed to exec";
-        }
-
-        _exit(1);
+        execvp(argv[0], const_cast<char**>(argv.data()));
+        PLOG(ERROR) << "exec in ForkExecvpAsync";
+        _exit(EXIT_FAILURE);
     }
-
     if (pid == -1) {
-        PLOG(ERROR) << "Failed to exec";
+        PLOG(ERROR) << "fork in ForkExecvpAsync";
+        return -1;
     }
-
-    free(argv);
     return pid;
 }
 
@@ -767,29 +754,10 @@
 }
 
 status_t UnmountTree(const std::string& prefix) {
-    FILE* fp = setmntent("/proc/mounts", "re");
-    if (fp == NULL) {
-        PLOG(ERROR) << "Failed to open /proc/mounts";
+    if (umount2(prefix.c_str(), MNT_DETACH)) {
+        PLOG(ERROR) << "Failed to unmount " << prefix;
         return -errno;
     }
-
-    // Some volumes can be stacked on each other, so force unmount in
-    // reverse order to give us the best chance of success.
-    std::list<std::string> toUnmount;
-    mntent* mentry;
-    while ((mentry = getmntent(fp)) != NULL) {
-        auto test = std::string(mentry->mnt_dir) + "/";
-        if (android::base::StartsWith(test, prefix)) {
-            toUnmount.push_front(test);
-        }
-    }
-    endmntent(fp);
-
-    for (const auto& path : toUnmount) {
-        if (umount2(path.c_str(), MNT_DETACH)) {
-            PLOG(ERROR) << "Failed to unmount " << path;
-        }
-    }
     return OK;
 }
 
diff --git a/Utils.h b/Utils.h
index e6f4792..68c82eb 100644
--- a/Utils.h
+++ b/Utils.h
@@ -68,12 +68,8 @@
                                std::string* fsLabel);
 
 /* Returns either WEXITSTATUS() status, or a negative errno */
-status_t ForkExecvp(const std::vector<std::string>& args);
-status_t ForkExecvp(const std::vector<std::string>& args, security_context_t context);
-
-status_t ForkExecvp(const std::vector<std::string>& args, std::vector<std::string>& output);
-status_t ForkExecvp(const std::vector<std::string>& args, std::vector<std::string>& output,
-                    security_context_t context);
+status_t ForkExecvp(const std::vector<std::string>& args, std::vector<std::string>* output = nullptr,
+                    security_context_t context = nullptr);
 
 pid_t ForkExecvpAsync(const std::vector<std::string>& args);
 
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index e9ab8a5..58fdc74 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -556,24 +556,7 @@
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
 
-    std::string tmp;
-    switch (remountMode) {
-        case REMOUNT_MODE_NONE:
-            tmp = "none";
-            break;
-        case REMOUNT_MODE_DEFAULT:
-            tmp = "default";
-            break;
-        case REMOUNT_MODE_READ:
-            tmp = "read";
-            break;
-        case REMOUNT_MODE_WRITE:
-            tmp = "write";
-            break;
-        default:
-            return error("Unknown mode " + std::to_string(remountMode));
-    }
-    return translate(VolumeManager::Instance()->remountUid(uid, tmp));
+    return translate(VolumeManager::Instance()->remountUid(uid, remountMode));
 }
 
 binder::Status VoldNativeService::mkdirs(const std::string& path) {
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 0b2f1bf..d113cf9 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -73,6 +73,7 @@
 using android::base::StringAppendF;
 using android::base::StringPrintf;
 using android::base::unique_fd;
+using android::vold::VoldNativeService;
 
 static const char* kPathUserMount = "/mnt/user";
 static const char* kPathVirtualDisk = "/data/misc/vold/virtual_disk";
@@ -326,7 +327,8 @@
     return nullptr;
 }
 
-void VolumeManager::listVolumes(android::vold::VolumeBase::Type type, std::list<std::string>& list) {
+void VolumeManager::listVolumes(android::vold::VolumeBase::Type type,
+                                std::list<std::string>& list) const {
     list.clear();
     for (const auto& disk : mDisks) {
         disk->listVolumes(type, list);
@@ -401,7 +403,7 @@
 
 int VolumeManager::mountPkgSpecificDirsForRunningProcs(
     userid_t userId, const std::vector<std::string>& packageNames,
-    const std::vector<std::string>& visibleVolLabels) {
+    const std::vector<std::string>& visibleVolLabels, int remountMode) {
     // TODO: New processes could be started while traversing over the existing
     // processes which would end up not having the necessary bind mounts. This
     // issue needs to be fixed, may be by doing multiple passes here?
@@ -496,38 +498,32 @@
                 _exit(1);
             }
 
-            struct stat storageSb;
-            if (TEMP_FAILURE_RETRY(stat("/storage", &storageSb)) == -1) {
-                PLOG(ERROR) << "Failed to stat /storage";
-                _exit(1);
-            }
-
-            // Some packages have access to full external storage, identify processes belonging
-            // to those packages by comparing inode no.s of /mnt/runtime/write and /storage
-            if (storageSb.st_dev == fullWriteSb.st_dev && storageSb.st_ino == fullWriteSb.st_ino) {
-                _exit(0);
+            int mountMode;
+            if (remountMode == -1) {
+                mountMode = getMountModeForRunningProc(packagesForUid, userId, fullWriteSb);
+                if (mountMode == -1) {
+                    _exit(1);
+                }
             } else {
-                // Some packages don't have access to external storage and processes belonging to
-                // those packages don't have anything mounted at /storage. So, identify those
-                // processes by comparing inode no.s of /mnt/user/%d/package/%s
-                // and /storage
-                std::string pkgStorageSource;
-                for (auto& package : packagesForUid) {
-                    std::string sandbox =
-                        StringPrintf("/mnt/user/%d/package/%s", userId, package.c_str());
-                    struct stat s;
-                    if (TEMP_FAILURE_RETRY(stat(sandbox.c_str(), &s)) == -1) {
-                        PLOG(ERROR) << "Failed to stat " << sandbox;
-                        _exit(1);
+                mountMode = remountMode;
+                std::string obbMountFile = StringPrintf("/mnt/user/%d/package/%s/obb_mount", userId,
+                                                        packagesForUid[0].c_str());
+                if (mountMode == VoldNativeService::REMOUNT_MODE_INSTALLER) {
+                    if (access(obbMountFile.c_str(), F_OK) != 0) {
+                        const unique_fd fd(
+                            TEMP_FAILURE_RETRY(open(obbMountFile.c_str(), O_RDWR | O_CREAT, 0660)));
                     }
-                    if (storageSb.st_dev == s.st_dev && storageSb.st_ino == s.st_ino) {
-                        pkgStorageSource = sandbox;
-                        break;
+                } else {
+                    if (access(obbMountFile.c_str(), F_OK) == 0) {
+                        remove(obbMountFile.c_str());
                     }
                 }
-                if (pkgStorageSource.empty()) {
-                    _exit(0);
-                }
+            }
+            if (mountMode == VoldNativeService::REMOUNT_MODE_FULL ||
+                mountMode == VoldNativeService::REMOUNT_MODE_NONE) {
+                // These mount modes are not going to change dynamically, so don't bother
+                // unmounting/remounting dirs.
+                _exit(0);
             }
 
             for (auto& volumeLabel : visibleVolLabels) {
@@ -537,10 +533,31 @@
                     StringAppendF(&mntSource, "/%d", userId);
                     StringAppendF(&mntTarget, "/%d", userId);
                 }
+                std::string obbSourceDir = StringPrintf("%s/Android/obb", mntSource.c_str());
+                std::string obbTargetDir = StringPrintf("%s/Android/obb", mntTarget.c_str());
+                if (umount2(obbTargetDir.c_str(), MNT_DETACH) == -1 && errno != EINVAL &&
+                    errno != ENOENT) {
+                    PLOG(ERROR) << "Failed to unmount " << obbTargetDir;
+                    continue;
+                }
                 for (auto& package : packagesForUid) {
                     mountPkgSpecificDir(mntSource, mntTarget, package, "data");
                     mountPkgSpecificDir(mntSource, mntTarget, package, "media");
-                    mountPkgSpecificDir(mntSource, mntTarget, package, "obb");
+                    if (mountMode != VoldNativeService::REMOUNT_MODE_INSTALLER) {
+                        mountPkgSpecificDir(mntSource, mntTarget, package, "obb");
+                    }
+                }
+                if (mountMode == VoldNativeService::REMOUNT_MODE_INSTALLER) {
+                    if (TEMP_FAILURE_RETRY(mount(obbSourceDir.c_str(), obbTargetDir.c_str(),
+                                                 nullptr, MS_BIND | MS_REC, nullptr)) == -1) {
+                        PLOG(ERROR) << "Failed to mount " << obbSourceDir << " to " << obbTargetDir;
+                        continue;
+                    }
+                    if (TEMP_FAILURE_RETRY(mount(nullptr, obbTargetDir.c_str(), nullptr,
+                                                 MS_REC | MS_SLAVE, nullptr)) == -1) {
+                        PLOG(ERROR) << "Failed to set MS_SLAVE at " << obbTargetDir.c_str();
+                        continue;
+                    }
                 }
             }
             _exit(0);
@@ -555,6 +572,44 @@
     return 0;
 }
 
+int VolumeManager::getMountModeForRunningProc(const std::vector<std::string>& packagesForUid,
+                                              userid_t userId, struct stat& mntWriteStat) {
+    struct stat storageSb;
+    if (TEMP_FAILURE_RETRY(stat("/storage", &storageSb)) == -1) {
+        PLOG(ERROR) << "Failed to stat /storage";
+        return -1;
+    }
+
+    // Some packages have access to full external storage, identify processes belonging
+    // to those packages by comparing inode no.s of /mnt/runtime/write and /storage
+    if (storageSb.st_dev == mntWriteStat.st_dev && storageSb.st_ino == mntWriteStat.st_ino) {
+        return VoldNativeService::REMOUNT_MODE_FULL;
+    }
+
+    std::string obbMountFile =
+        StringPrintf("/mnt/user/%d/package/%s/obb_mount", userId, packagesForUid[0].c_str());
+    if (access(obbMountFile.c_str(), F_OK) == 0) {
+        return VoldNativeService::REMOUNT_MODE_INSTALLER;
+    }
+
+    // Some packages don't have access to external storage and processes belonging to
+    // those packages don't have anything mounted at /storage. So, identify those
+    // processes by comparing inode no.s of /mnt/user/%d/package/%s
+    // and /storage
+    for (auto& package : packagesForUid) {
+        std::string sandbox = StringPrintf("/mnt/user/%d/package/%s", userId, package.c_str());
+        struct stat sandboxStat;
+        if (TEMP_FAILURE_RETRY(stat(sandbox.c_str(), &sandboxStat)) == -1) {
+            PLOG(ERROR) << "Failed to stat " << sandbox;
+            return -1;
+        }
+        if (storageSb.st_dev == sandboxStat.st_dev && storageSb.st_ino == sandboxStat.st_ino) {
+            return VoldNativeService::REMOUNT_MODE_WRITE;
+        }
+    }
+    return VoldNativeService::REMOUNT_MODE_NONE;
+}
+
 int VolumeManager::prepareSandboxes(userid_t userId, const std::vector<std::string>& packageNames,
                                     const std::vector<std::string>& visibleVolLabels) {
     if (visibleVolLabels.empty()) {
@@ -667,7 +722,7 @@
             }
         }
     }
-    mountPkgSpecificDirsForRunningProcs(userId, packageNames, visibleVolLabels);
+    mountPkgSpecificDirsForRunningProcs(userId, packageNames, visibleVolLabels, -1);
     return 0;
 }
 
@@ -874,7 +929,8 @@
     LOG(VERBOSE) << "destroySandboxForApp: " << packageName << ", sandboxId=" << sandboxId
                  << ", userId=" << userId;
     auto& userPackages = mUserPackages[userId];
-    std::remove(userPackages.begin(), userPackages.end(), packageName);
+    userPackages.erase(std::remove(userPackages.begin(), userPackages.end(), packageName),
+                       userPackages.end());
     // If the package is not uninstalled in any other users, remove appId and sandboxId
     // corresponding to it from the internal state.
     bool installedInAnyUser = false;
@@ -1038,12 +1094,56 @@
     return 0;
 }
 
-int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
-    // If the isolated storage is enabled, return -1 since in the isolated storage world, there
-    // are no longer any runtime storage permissions, so this shouldn't be called anymore.
-    if (GetBoolProperty(kIsolatedStorage, false)) {
+int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
+    if (!GetBoolProperty(kIsolatedStorage, false)) {
+        return remountUidLegacy(uid, mountMode);
+    }
+
+    appid_t appId = multiuser_get_app_id(uid);
+    userid_t userId = multiuser_get_user_id(uid);
+    std::vector<std::string> visibleVolLabels;
+    for (auto& volId : mVisibleVolumeIds) {
+        auto vol = findVolume(volId);
+        userid_t mountUserId = vol->getMountUserId();
+        if (mountUserId == userId || vol->isEmulated()) {
+            visibleVolLabels.push_back(vol->getLabel());
+        }
+    }
+
+    // Finding one package with appId is enough
+    std::vector<std::string> packageNames;
+    for (auto it = mAppIds.begin(); it != mAppIds.end(); ++it) {
+        if (it->second == appId) {
+            packageNames.push_back(it->first);
+            break;
+        }
+    }
+    if (packageNames.empty()) {
+        PLOG(ERROR) << "Failed to find packageName for " << uid;
         return -1;
     }
+    return mountPkgSpecificDirsForRunningProcs(userId, packageNames, visibleVolLabels, mountMode);
+}
+
+int VolumeManager::remountUidLegacy(uid_t uid, int32_t mountMode) {
+    std::string mode;
+    switch (mountMode) {
+        case VoldNativeService::REMOUNT_MODE_NONE:
+            mode = "none";
+            break;
+        case VoldNativeService::REMOUNT_MODE_DEFAULT:
+            mode = "default";
+            break;
+        case VoldNativeService::REMOUNT_MODE_READ:
+            mode = "read";
+            break;
+        case VoldNativeService::REMOUNT_MODE_WRITE:
+            mode = "write";
+            break;
+        default:
+            PLOG(ERROR) << "Unknown mode " << std::to_string(mountMode);
+            return -1;
+    }
     LOG(DEBUG) << "Remounting " << uid << " as mode " << mode;
 
     DIR* dir;
diff --git a/VolumeManager.h b/VolumeManager.h
index 9e990d0..3a7bae4 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -52,7 +52,7 @@
     std::mutex& getCryptLock() { return mCryptLock; }
 
     void setListener(android::sp<android::os::IVoldListener> listener) { mListener = listener; }
-    android::sp<android::os::IVoldListener> getListener() { return mListener; }
+    android::sp<android::os::IVoldListener> getListener() const { return mListener; }
 
     int start();
     int stop();
@@ -68,8 +68,8 @@
             return !fnmatch(mSysPattern.c_str(), sysPath.c_str(), 0);
         }
 
-        const std::string& getNickname() { return mNickname; }
-        int getFlags() { return mFlags; }
+        const std::string& getNickname() const { return mNickname; }
+        int getFlags() const { return mFlags; }
 
       private:
         std::string mSysPattern;
@@ -82,7 +82,7 @@
     std::shared_ptr<android::vold::Disk> findDisk(const std::string& id);
     std::shared_ptr<android::vold::VolumeBase> findVolume(const std::string& id);
 
-    void listVolumes(android::vold::VolumeBase::Type type, std::list<std::string>& list);
+    void listVolumes(android::vold::VolumeBase::Type type, std::list<std::string>& list) const;
 
     int forgetPartition(const std::string& partGuid, const std::string& fsUuid);
 
@@ -107,7 +107,8 @@
 
     int setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol);
 
-    int remountUid(uid_t uid, const std::string& mode);
+    int remountUid(uid_t uid, int32_t remountMode);
+    int remountUidLegacy(uid_t uid, int32_t remountMode);
 
     /* Reset all internal state, typically during framework boot */
     int reset();
@@ -153,7 +154,8 @@
                          const std::vector<std::string>& visibleVolLabels);
     int mountPkgSpecificDirsForRunningProcs(userid_t userId,
                                             const std::vector<std::string>& packageNames,
-                                            const std::vector<std::string>& visibleVolLabels);
+                                            const std::vector<std::string>& visibleVolLabels,
+                                            int remountMode);
     int destroySandboxesForVol(android::vold::VolumeBase* vol, userid_t userId);
     std::string prepareSandboxSource(uid_t uid, const std::string& sandboxId,
                                      const std::string& sandboxRootDir);
@@ -171,6 +173,8 @@
                             const std::string& packageName, const char* dirName);
     int destroySandboxForAppOnVol(const std::string& packageName, const std::string& sandboxId,
                                   userid_t userId, const std::string& volLabel);
+    int getMountModeForRunningProc(const std::vector<std::string>& packagesForUid, userid_t userId,
+                                   struct stat& mntWriteStat);
 
     void handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk);
     void handleDiskChanged(dev_t device);
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index e399141..59e8795 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -152,7 +152,8 @@
     const int REMOUNT_MODE_DEFAULT = 1;
     const int REMOUNT_MODE_READ = 2;
     const int REMOUNT_MODE_WRITE = 3;
-    const int REMOUNT_MODE_FULL = 4;
+    const int REMOUNT_MODE_INSTALLER = 4;
+    const int REMOUNT_MODE_FULL = 5;
 
     const int VOLUME_STATE_UNMOUNTED = 0;
     const int VOLUME_STATE_CHECKING = 1;
diff --git a/cryptfs.cpp b/cryptfs.cpp
index 21f434d..5d88a49 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -36,6 +36,7 @@
 #include "secontext.h"
 
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
 #include <cutils/properties.h>
@@ -77,6 +78,7 @@
 #include <crypto_scrypt.h>
 }
 
+using android::base::StringPrintf;
 using namespace std::chrono_literals;
 
 #define UNUSED __attribute__((unused))
@@ -466,6 +468,10 @@
 
 constexpr CryptoType supported_crypto_types[] = {
     default_crypto_type,
+    CryptoType()
+        .set_property_name("adiantum")
+        .set_crypto_name("xchacha12,aes-adiantum-plain64")
+        .set_keysize(32),
     // Add new CryptoTypes here.  Order is not important.
 };
 
@@ -1216,6 +1222,21 @@
 }
 #endif
 
+// Only adds parameters if the property is set.
+static void add_sector_size_param(std::vector<std::string>* extra_params_vec) {
+    constexpr char DM_CRYPT_SECTOR_SIZE[] = "ro.crypto.fde_sector_size";
+    char sector_size[PROPERTY_VALUE_MAX];
+
+    if (property_get(DM_CRYPT_SECTOR_SIZE, sector_size, "") > 0) {
+        std::string param = StringPrintf("sector_size:%s", sector_size);
+        extra_params_vec->push_back(std::move(param));
+
+        // With this option, IVs will match the sector numbering, instead
+        // of being hard-coded to being based on 512-byte sectors.
+        extra_params_vec->emplace_back("iv_large_sectors");
+    }
+}
+
 static int create_crypto_blk_dev(struct crypt_mnt_ftr* crypt_ftr, const unsigned char* master_key,
                                  const char* real_blk_name, char* crypto_blk_name, const char* name,
                                  uint32_t flags) {
@@ -1306,6 +1327,7 @@
     if (flags & CREATE_CRYPTO_BLK_DEV_FLAGS_ALLOW_ENCRYPT_OVERRIDE) {
         extra_params_vec.emplace_back("allow_encrypt_override");
     }
+    add_sector_size_param(&extra_params_vec);
     load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name, fd,
                                            extra_params_as_string(extra_params_vec).c_str());
 #endif
diff --git a/fs/Exfat.cpp b/fs/Exfat.cpp
index 5c15075..c624eb9 100644
--- a/fs/Exfat.cpp
+++ b/fs/Exfat.cpp
@@ -43,7 +43,7 @@
     cmd.push_back(kFsckPath);
     cmd.push_back(source);
 
-    int rc = ForkExecvp(cmd, sFsckUntrustedContext);
+    int rc = ForkExecvp(cmd, nullptr, sFsckUntrustedContext);
     if (rc == 0) {
         LOG(INFO) << "Check OK";
         return 0;
diff --git a/fs/Ext4.cpp b/fs/Ext4.cpp
index 806cfd1..0059233 100644
--- a/fs/Ext4.cpp
+++ b/fs/Ext4.cpp
@@ -117,7 +117,7 @@
         cmd.push_back(c_source);
 
         // ext4 devices are currently always trusted
-        return ForkExecvp(cmd, sFsckContext);
+        return ForkExecvp(cmd, nullptr, sFsckContext);
     }
 
     return 0;
diff --git a/fs/F2fs.cpp b/fs/F2fs.cpp
index c6e0f52..9517dc9 100644
--- a/fs/F2fs.cpp
+++ b/fs/F2fs.cpp
@@ -48,7 +48,7 @@
     cmd.push_back(source);
 
     // f2fs devices are currently always trusted
-    return ForkExecvp(cmd, sFsckContext);
+    return ForkExecvp(cmd, nullptr, sFsckContext);
 }
 
 status_t Mount(const std::string& source, const std::string& target) {
diff --git a/fs/Vfat.cpp b/fs/Vfat.cpp
index 7b833d1..14c42d6 100644
--- a/fs/Vfat.cpp
+++ b/fs/Vfat.cpp
@@ -67,7 +67,7 @@
         cmd.push_back(source);
 
         // Fat devices are currently always untrusted
-        rc = ForkExecvp(cmd, sFsckUntrustedContext);
+        rc = ForkExecvp(cmd, nullptr, sFsckUntrustedContext);
 
         if (rc < 0) {
             LOG(ERROR) << "Filesystem check failed due to logwrap error";
diff --git a/model/Disk.cpp b/model/Disk.cpp
index 3d25e4c..b66c336 100644
--- a/model/Disk.cpp
+++ b/model/Disk.cpp
@@ -153,7 +153,7 @@
     return nullptr;
 }
 
-void Disk::listVolumes(VolumeBase::Type type, std::list<std::string>& list) {
+void Disk::listVolumes(VolumeBase::Type type, std::list<std::string>& list) const {
     for (const auto& vol : mVolumes) {
         if (vol->getType() == type) {
             list.push_back(vol->getId());
@@ -341,7 +341,7 @@
     cmd.push_back(mDevPath);
 
     std::vector<std::string> output;
-    status_t res = ForkExecvp(cmd, output);
+    status_t res = ForkExecvp(cmd, &output);
     if (res != OK) {
         LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
 
diff --git a/model/Disk.h b/model/Disk.h
index 3140144..889e906 100644
--- a/model/Disk.h
+++ b/model/Disk.h
@@ -54,18 +54,18 @@
         kEmmc = 1 << 4,
     };
 
-    const std::string& getId() { return mId; }
-    const std::string& getEventPath() { return mEventPath; }
-    const std::string& getSysPath() { return mSysPath; }
-    const std::string& getDevPath() { return mDevPath; }
-    dev_t getDevice() { return mDevice; }
-    uint64_t getSize() { return mSize; }
-    const std::string& getLabel() { return mLabel; }
-    int getFlags() { return mFlags; }
+    const std::string& getId() const { return mId; }
+    const std::string& getEventPath() const { return mEventPath; }
+    const std::string& getSysPath() const { return mSysPath; }
+    const std::string& getDevPath() const { return mDevPath; }
+    dev_t getDevice() const { return mDevice; }
+    uint64_t getSize() const { return mSize; }
+    const std::string& getLabel() const { return mLabel; }
+    int getFlags() const { return mFlags; }
 
     std::shared_ptr<VolumeBase> findVolume(const std::string& id);
 
-    void listVolumes(VolumeBase::Type type, std::list<std::string>& list);
+    void listVolumes(VolumeBase::Type type, std::list<std::string>& list) const;
 
     status_t create();
     status_t destroy();
diff --git a/model/PrivateVolume.h b/model/PrivateVolume.h
index 85aa4dc..cb8e75d 100644
--- a/model/PrivateVolume.h
+++ b/model/PrivateVolume.h
@@ -39,9 +39,9 @@
   public:
     PrivateVolume(dev_t device, const std::string& keyRaw);
     virtual ~PrivateVolume();
-    const std::string& getFsType() { return mFsType; };
-    const std::string& getRawDevPath() { return mRawDevPath; };
-    const std::string& getRawDmDevPath() { return mDmDevPath; };
+    const std::string& getFsType() const { return mFsType; };
+    const std::string& getRawDevPath() const { return mRawDevPath; };
+    const std::string& getRawDmDevPath() const { return mDmDevPath; };
 
   protected:
     status_t doCreate() override;
diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp
index 29bc32c..a9c7fa3 100644
--- a/model/VolumeBase.cpp
+++ b/model/VolumeBase.cpp
@@ -153,7 +153,7 @@
     return OK;
 }
 
-android::sp<android::os::IVoldListener> VolumeBase::getListener() {
+android::sp<android::os::IVoldListener> VolumeBase::getListener() const {
     if (mSilent) {
         return nullptr;
     } else {
diff --git a/model/VolumeBase.h b/model/VolumeBase.h
index ea187bd..e6c47f0 100644
--- a/model/VolumeBase.h
+++ b/model/VolumeBase.h
@@ -78,16 +78,16 @@
         kBadRemoval,
     };
 
-    const std::string& getId() { return mId; }
-    const std::string& getDiskId() { return mDiskId; }
-    const std::string& getPartGuid() { return mPartGuid; }
-    Type getType() { return mType; }
-    int getMountFlags() { return mMountFlags; }
-    userid_t getMountUserId() { return mMountUserId; }
-    State getState() { return mState; }
-    const std::string& getPath() { return mPath; }
-    const std::string& getInternalPath() { return mInternalPath; }
-    const std::string& getLabel() { return mLabel; }
+    const std::string& getId() const { return mId; }
+    const std::string& getDiskId() const { return mDiskId; }
+    const std::string& getPartGuid() const { return mPartGuid; }
+    Type getType() const { return mType; }
+    int getMountFlags() const { return mMountFlags; }
+    userid_t getMountUserId() const { return mMountUserId; }
+    State getState() const { return mState; }
+    const std::string& getPath() const { return mPath; }
+    const std::string& getInternalPath() const { return mInternalPath; }
+    const std::string& getLabel() const { return mLabel; }
 
     status_t setDiskId(const std::string& diskId);
     status_t setPartGuid(const std::string& partGuid);
@@ -124,7 +124,7 @@
     status_t setInternalPath(const std::string& internalPath);
     status_t setLabel(const std::string& label);
 
-    android::sp<android::os::IVoldListener> getListener();
+    android::sp<android::os::IVoldListener> getListener() const;
 
   private:
     /* ID that uniquely references volume while alive */
diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp
index 8c3df30..b8e5cb6 100644
--- a/vold_prepare_subdirs.cpp
+++ b/vold_prepare_subdirs.cpp
@@ -133,6 +133,10 @@
             if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, vendor_de_path + "/fpdata")) {
                 return false;
             }
+            auto facedata_path = vendor_de_path + "/facedata";
+            if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, facedata_path)) {
+                return false;
+            }
         }
         if (flags & android::os::IVold::STORAGE_FLAG_CE) {
             auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);