Merge "Merged-In Revert "vold: use RAII wake locks"" am: 2ebb5c5b96
am: fce081efa6

Change-Id: If58a55eecb04453f69e51cdc242f5ab71fb7ddc1
diff --git a/AppFuseUtil.cpp b/AppFuseUtil.cpp
index c491ecd..711e70b 100644
--- a/AppFuseUtil.cpp
+++ b/AppFuseUtil.cpp
@@ -49,9 +49,6 @@
 }
 
 static android::status_t Mount(int device_fd, const std::string& path) {
-    // Remove existing mount.
-    android::vold::ForceUnmount(path);
-
     const auto opts = StringPrintf(
         "fd=%i,"
         "rootmode=40000,"
@@ -115,6 +112,11 @@
         return -1;
     }
 
+    // Forcibly remove the existing mount before we attempt to prepare the
+    // directory. If we have a dangling mount, then PrepareDir may fail if the
+    // indirection to FUSE doesn't work.
+    android::vold::ForceUnmount(path);
+
     // Create directories.
     const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0);
     if (result != android::OK) {
diff --git a/Checkpoint.cpp b/Checkpoint.cpp
index 56ec782..0605c72 100644
--- a/Checkpoint.cpp
+++ b/Checkpoint.cpp
@@ -153,6 +153,11 @@
     if (!isCheckpointing) {
         return Status::ok();
     }
+    if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
+        LOG(WARNING)
+            << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
+        return Status::ok();
+    }
     sp<IBootControl> module = IBootControl::getService();
     if (module) {
         CommandResult cr;
diff --git a/FsCrypt.cpp b/FsCrypt.cpp
index 5f659a8..3028b60 100644
--- a/FsCrypt.cpp
+++ b/FsCrypt.cpp
@@ -269,7 +269,7 @@
                            std::string* raw_ref) {
     auto refi = key_map.find(user_id);
     if (refi == key_map.end()) {
-        LOG(ERROR) << "Cannot find key for " << user_id;
+        LOG(DEBUG) << "Cannot find key for " << user_id;
         return false;
     }
     *raw_ref = refi->second;
diff --git a/IdleMaint.cpp b/IdleMaint.cpp
index a2d0f91..bca22f6 100644
--- a/IdleMaint.cpp
+++ b/IdleMaint.cpp
@@ -49,8 +49,8 @@
 using android::fs_mgr::ReadDefaultFstab;
 using android::hardware::Return;
 using android::hardware::Void;
-using android::hardware::health::storage::V1_0::IGarbageCollectCallback;
 using android::hardware::health::storage::V1_0::IStorage;
+using android::hardware::health::storage::V1_0::IGarbageCollectCallback;
 using android::hardware::health::storage::V1_0::Result;
 
 namespace android {
diff --git a/Utils.cpp b/Utils.cpp
index 6a3830f..1616d80 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -36,6 +36,7 @@
 #include <mntent.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
@@ -194,13 +195,55 @@
 }
 
 status_t BindMount(const std::string& source, const std::string& target) {
-    if (::mount(source.c_str(), target.c_str(), "", MS_BIND, NULL)) {
+    if (UnmountTree(target) < 0) {
+        return -errno;
+    }
+    if (TEMP_FAILURE_RETRY(mount(source.c_str(), target.c_str(), nullptr, MS_BIND, nullptr)) < 0) {
         PLOG(ERROR) << "Failed to bind mount " << source << " to " << target;
         return -errno;
     }
     return OK;
 }
 
+status_t Symlink(const std::string& target, const std::string& linkpath) {
+    if (Unlink(linkpath) < 0) {
+        return -errno;
+    }
+    if (TEMP_FAILURE_RETRY(symlink(target.c_str(), linkpath.c_str())) < 0) {
+        PLOG(ERROR) << "Failed to create symlink " << linkpath << " to " << target;
+        return -errno;
+    }
+    return OK;
+}
+
+status_t Unlink(const std::string& linkpath) {
+    if (TEMP_FAILURE_RETRY(unlink(linkpath.c_str())) < 0 && errno != EINVAL && errno != ENOENT) {
+        PLOG(ERROR) << "Failed to unlink " << linkpath;
+        return -errno;
+    }
+    return OK;
+}
+
+status_t CreateDir(const std::string& dir, mode_t mode) {
+    struct stat sb;
+    if (TEMP_FAILURE_RETRY(stat(dir.c_str(), &sb)) == 0) {
+        if (S_ISDIR(sb.st_mode)) {
+            return OK;
+        } else if (TEMP_FAILURE_RETRY(unlink(dir.c_str())) == -1) {
+            PLOG(ERROR) << "Failed to unlink " << dir;
+            return -errno;
+        }
+    } else if (errno != ENOENT) {
+        PLOG(ERROR) << "Failed to stat " << dir;
+        return -errno;
+    }
+    if (TEMP_FAILURE_RETRY(mkdir(dir.c_str(), mode)) == -1 && errno != EEXIST) {
+        PLOG(ERROR) << "Failed to mkdir " << dir;
+        return -errno;
+    }
+    return OK;
+}
+
 bool FindValue(const std::string& raw, const std::string& key, std::string* value) {
     auto qual = key + "=\"";
     size_t start = 0;
@@ -801,13 +844,87 @@
 }
 
 status_t UnmountTree(const std::string& mountPoint) {
-    if (umount2(mountPoint.c_str(), MNT_DETACH)) {
+    if (TEMP_FAILURE_RETRY(umount2(mountPoint.c_str(), MNT_DETACH)) < 0 && errno != EINVAL &&
+        errno != ENOENT) {
         PLOG(ERROR) << "Failed to unmount " << mountPoint;
         return -errno;
     }
     return OK;
 }
 
+static status_t delete_dir_contents(DIR* dir) {
+    // Shamelessly borrowed from android::installd
+    int dfd = dirfd(dir);
+    if (dfd < 0) {
+        return -errno;
+    }
+
+    status_t result = OK;
+    struct dirent* de;
+    while ((de = readdir(dir))) {
+        const char* name = de->d_name;
+        if (de->d_type == DT_DIR) {
+            /* always skip "." and ".." */
+            if (name[0] == '.') {
+                if (name[1] == 0) continue;
+                if ((name[1] == '.') && (name[2] == 0)) continue;
+            }
+
+            android::base::unique_fd subfd(
+                openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC));
+            if (subfd.get() == -1) {
+                PLOG(ERROR) << "Couldn't openat " << name;
+                result = -errno;
+                continue;
+            }
+            std::unique_ptr<DIR, decltype(&closedir)> subdirp(
+                android::base::Fdopendir(std::move(subfd)), closedir);
+            if (!subdirp) {
+                PLOG(ERROR) << "Couldn't fdopendir " << name;
+                result = -errno;
+                continue;
+            }
+            result = delete_dir_contents(subdirp.get());
+            if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
+                PLOG(ERROR) << "Couldn't unlinkat " << name;
+                result = -errno;
+            }
+        } else {
+            if (unlinkat(dfd, name, 0) < 0) {
+                PLOG(ERROR) << "Couldn't unlinkat " << name;
+                result = -errno;
+            }
+        }
+    }
+    return result;
+}
+
+status_t DeleteDirContentsAndDir(const std::string& pathname) {
+    status_t res = DeleteDirContents(pathname);
+    if (res < 0) {
+        return res;
+    }
+    if (TEMP_FAILURE_RETRY(rmdir(pathname.c_str())) < 0 && errno != ENOENT) {
+        PLOG(ERROR) << "rmdir failed on " << pathname;
+        return -errno;
+    }
+    LOG(VERBOSE) << "Success: rmdir on " << pathname;
+    return OK;
+}
+
+status_t DeleteDirContents(const std::string& pathname) {
+    // Shamelessly borrowed from android::installd
+    std::unique_ptr<DIR, decltype(&closedir)> dirp(opendir(pathname.c_str()), closedir);
+    if (!dirp) {
+        if (errno == ENOENT) {
+            return OK;
+        }
+        PLOG(ERROR) << "Failed to opendir " << pathname;
+        return -errno;
+    }
+    return delete_dir_contents(dirp.get());
+}
+
 // TODO(118708649): fix duplication with init/util.h
 status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout) {
     android::base::Timer t;
diff --git a/Utils.h b/Utils.h
index c083021..af4e401 100644
--- a/Utils.h
+++ b/Utils.h
@@ -57,6 +57,15 @@
 /* Creates bind mount from source to target */
 status_t BindMount(const std::string& source, const std::string& target);
 
+/** Creates a symbolic link to target */
+status_t Symlink(const std::string& target, const std::string& linkpath);
+
+/** Calls unlink(2) at linkpath */
+status_t Unlink(const std::string& linkpath);
+
+/** Creates the given directory if it is not already available */
+status_t CreateDir(const std::string& dir, mode_t mode);
+
 bool FindValue(const std::string& raw, const std::string& key, std::string* value);
 
 /* Reads filesystem metadata from device at path */
@@ -130,6 +139,9 @@
 status_t UnmountTreeWithPrefix(const std::string& prefix);
 status_t UnmountTree(const std::string& mountPoint);
 
+status_t DeleteDirContentsAndDir(const std::string& pathname);
+status_t DeleteDirContents(const std::string& pathname);
+
 status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout);
 
 bool FsyncDirectory(const std::string& dirname);
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index 623cced..84c06f1 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -276,6 +276,16 @@
     return translate(VolumeManager::Instance()->onUserStopped(userId));
 }
 
+binder::Status VoldNativeService::addAppIds(const std::vector<std::string>& packageNames,
+                                            const std::vector<int32_t>& appIds) {
+    return ok();
+}
+
+binder::Status VoldNativeService::addSandboxIds(const std::vector<int32_t>& appIds,
+                                                const std::vector<std::string>& sandboxIds) {
+    return ok();
+}
+
 binder::Status VoldNativeService::onSecureKeyguardStateChanged(bool isShowing) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
@@ -330,10 +340,16 @@
     vol->setMountUserId(mountUserId);
 
     int res = vol->mount();
-    if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) {
-        VolumeManager::Instance()->setPrimary(vol);
+    if (res != OK) {
+        return translate(res);
     }
-    return translate(res);
+    if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) {
+        res = VolumeManager::Instance()->setPrimary(vol);
+        if (res != OK) {
+            return translate(res);
+        }
+    }
+    return translate(OK);
 }
 
 binder::Status VoldNativeService::unmount(const std::string& volId) {
@@ -431,24 +447,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) {
@@ -805,6 +804,18 @@
     return translateBool(fscrypt_destroy_user_storage(uuid_, userId, flags));
 }
 
+binder::Status VoldNativeService::prepareSandboxForApp(const std::string& packageName,
+                                                       int32_t appId, const std::string& sandboxId,
+                                                       int32_t userId) {
+    return ok();
+}
+
+binder::Status VoldNativeService::destroySandboxForApp(const std::string& packageName,
+                                                       const std::string& sandboxId,
+                                                       int32_t userId) {
+    return ok();
+}
+
 binder::Status VoldNativeService::startCheckpoint(int32_t retry) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
diff --git a/VoldNativeService.h b/VoldNativeService.h
index b90c5b8..5ca298e 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -42,6 +42,11 @@
     binder::Status onUserStarted(int32_t userId);
     binder::Status onUserStopped(int32_t userId);
 
+    binder::Status addAppIds(const std::vector<std::string>& packageNames,
+                             const std::vector<int32_t>& appIds);
+    binder::Status addSandboxIds(const std::vector<int32_t>& appIds,
+                                 const std::vector<std::string>& sandboxIds);
+
     binder::Status onSecureKeyguardStateChanged(bool isShowing);
 
     binder::Status partition(const std::string& diskId, int32_t partitionType, int32_t ratio);
@@ -118,8 +123,10 @@
     binder::Status destroyUserStorage(const std::unique_ptr<std::string>& uuid, int32_t userId,
                                       int32_t flags);
 
-    binder::Status mountExternalStorageForApp(const std::string& packageName, int32_t appId,
-                                              const std::string& sandboxId, int32_t userId);
+    binder::Status prepareSandboxForApp(const std::string& packageName, int32_t appId,
+                                        const std::string& sandboxId, int32_t userId);
+    binder::Status destroySandboxForApp(const std::string& packageName,
+                                        const std::string& sandboxId, int32_t userId);
 
     binder::Status startCheckpoint(int32_t retry);
     binder::Status needsCheckpoint(bool* _aidl_return);
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 897c2a8..44bff5a 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#include <array>
 
 #include <linux/kdev_t.h>
 
@@ -58,6 +59,7 @@
 #include "NetlinkManager.h"
 #include "Process.h"
 #include "Utils.h"
+#include "VoldNativeService.h"
 #include "VoldUtil.h"
 #include "VolumeManager.h"
 #include "cryptfs.h"
@@ -67,15 +69,28 @@
 #include "model/ObbVolume.h"
 #include "model/StubVolume.h"
 
+using android::OK;
+using android::base::GetBoolProperty;
 using android::base::StartsWith;
+using android::base::StringAppendF;
 using android::base::StringPrintf;
 using android::base::unique_fd;
+using android::vold::BindMount;
+using android::vold::CreateDir;
+using android::vold::DeleteDirContents;
+using android::vold::DeleteDirContentsAndDir;
+using android::vold::Symlink;
+using android::vold::Unlink;
+using android::vold::UnmountTree;
+using android::vold::VoldNativeService;
 
 static const char* kPathUserMount = "/mnt/user";
 static const char* kPathVirtualDisk = "/data/misc/vold/virtual_disk";
 
 static const char* kPropVirtualDisk = "persist.sys.virtual_disk";
 
+static const std::string kEmptyString("");
+
 /* 512MiB is large enough for testing purposes */
 static const unsigned int kSizeVirtualDisk = 536870912;
 
@@ -103,7 +118,7 @@
 
 int VolumeManager::updateVirtualDisk() {
     ATRACE_NAME("VolumeManager::updateVirtualDisk");
-    if (android::base::GetBoolProperty(kPropVirtualDisk, false)) {
+    if (GetBoolProperty(kPropVirtualDisk, false)) {
         if (access(kPathVirtualDisk, F_OK) != 0) {
             Loop::createImageFile(kPathVirtualDisk, kSizeVirtualDisk / 512);
         }
@@ -351,22 +366,14 @@
 
 int VolumeManager::linkPrimary(userid_t userId) {
     std::string source(mPrimary->getPath());
-    if (mPrimary->getType() == android::vold::VolumeBase::Type::kEmulated) {
+    if (mPrimary->isEmulated()) {
         source = StringPrintf("%s/%d", source.c_str(), userId);
         fs_prepare_dir(source.c_str(), 0755, AID_ROOT, AID_ROOT);
     }
 
     std::string target(StringPrintf("/mnt/user/%d/primary", userId));
-    if (TEMP_FAILURE_RETRY(unlink(target.c_str()))) {
-        if (errno != ENOENT) {
-            PLOG(WARNING) << "Failed to unlink " << target;
-        }
-    }
     LOG(DEBUG) << "Linking " << source << " to " << target;
-    if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) {
-        PLOG(WARNING) << "Failed to link";
-        return -errno;
-    }
+    Symlink(source, target);
     return 0;
 }
 
@@ -381,6 +388,7 @@
 }
 
 int VolumeManager::onUserStarted(userid_t userId) {
+    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
     // already created this directory.
@@ -395,6 +403,7 @@
 }
 
 int VolumeManager::onUserStopped(userid_t userId) {
+    LOG(VERBOSE) << "onUserStopped: " << userId;
     mStartedUsers.erase(userId);
     return 0;
 }
@@ -421,7 +430,30 @@
     return 0;
 }
 
-int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
+int VolumeManager::remountUid(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:
+        case VoldNativeService::REMOUNT_MODE_LEGACY:
+        case VoldNativeService::REMOUNT_MODE_INSTALLER:
+            mode = "write";
+            break;
+        case VoldNativeService::REMOUNT_MODE_FULL:
+            mode = "full";
+            break;
+        default:
+            PLOG(ERROR) << "Unknown mode " << std::to_string(mountMode);
+            return -1;
+    }
     LOG(DEBUG) << "Remounting " << uid << " as mode " << mode;
 
     DIR* dir;
@@ -522,6 +554,8 @@
                 storageSource = "/mnt/runtime/read";
             } else if (mode == "write") {
                 storageSource = "/mnt/runtime/write";
+            } else if (mode == "full") {
+                storageSource = "/mnt/runtime/full";
             } else {
                 // Sane default of no storage visible
                 _exit(0);
diff --git a/VolumeManager.h b/VolumeManager.h
index e0a1bd6..9bf7599 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -95,7 +95,7 @@
 
     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);
 
     /* Reset all internal state, typically during framework boot */
     int reset();
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index 72f2643..75fef06 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -32,6 +32,9 @@
     void onUserStarted(int userId);
     void onUserStopped(int userId);
 
+    void addAppIds(in @utf8InCpp String[] packageNames, in int[] appIds);
+    void addSandboxIds(in int[] appIds, in @utf8InCpp String[] sandboxIds);
+
     void onSecureKeyguardStateChanged(boolean isShowing);
 
     void partition(@utf8InCpp String diskId, int partitionType, int ratio);
@@ -96,6 +99,11 @@
                             int storageFlags);
     void destroyUserStorage(@nullable @utf8InCpp String uuid, int userId, int storageFlags);
 
+    void prepareSandboxForApp(in @utf8InCpp String packageName, int appId,
+                              in @utf8InCpp String sandboxId, int userId);
+    void destroySandboxForApp(in @utf8InCpp String packageName,
+                              in @utf8InCpp String sandboxId, int userId);
+
     void startCheckpoint(int retry);
     boolean needsCheckpoint();
     boolean needsRollback();
@@ -146,6 +154,9 @@
     const int REMOUNT_MODE_DEFAULT = 1;
     const int REMOUNT_MODE_READ = 2;
     const int REMOUNT_MODE_WRITE = 3;
+    const int REMOUNT_MODE_LEGACY = 4;
+    const int REMOUNT_MODE_INSTALLER = 5;
+    const int REMOUNT_MODE_FULL = 6;
 
     const int VOLUME_STATE_UNMOUNTED = 0;
     const int VOLUME_STATE_CHECKING = 1;
diff --git a/main.cpp b/main.cpp
index accaa01..7555276 100644
--- a/main.cpp
+++ b/main.cpp
@@ -54,7 +54,7 @@
 
 int main(int argc, char** argv) {
     atrace_set_tracing_enabled(false);
-    setenv("ANDROID_LOG_TAGS", "*:d", 1);
+    setenv("ANDROID_LOG_TAGS", "*:d", 1);  // Do not submit with verbose logs enabled
     android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
 
     LOG(INFO) << "Vold 3.0 (the awakening) firing up";
diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
index f933982..552fe2f 100644
--- a/model/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -16,9 +16,10 @@
 
 #include "EmulatedVolume.h"
 #include "Utils.h"
+#include "VolumeManager.h"
 
-#include <android-base/stringprintf.h>
 #include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <cutils/fs.h>
 #include <private/android_filesystem_config.h>
 #include <utils/Timers.h>
@@ -89,6 +90,7 @@
                 "-w",
                 "-G",
                 "-i",
+                "-o",
                 mRawPath.c_str(),
                 label.c_str(),
                 NULL)) {
diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp
index 1339eb3..0a6b351 100644
--- a/model/PublicVolume.cpp
+++ b/model/PublicVolume.cpp
@@ -21,6 +21,7 @@
 #include "fs/Vfat.h"
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <cutils/fs.h>
 #include <private/android_filesystem_config.h>
@@ -34,6 +35,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+using android::base::GetBoolProperty;
 using android::base::StringPrintf;
 
 namespace android {
diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp
index b04dd70..ffc7900 100644
--- a/model/VolumeBase.cpp
+++ b/model/VolumeBase.cpp
@@ -35,7 +35,7 @@
 VolumeBase::VolumeBase(Type type)
     : mType(type),
       mMountFlags(0),
-      mMountUserId(-1),
+      mMountUserId(USER_UNKNOWN),
       mCreated(false),
       mState(State::kUnmounted),
       mSilent(false) {}
@@ -219,11 +219,7 @@
 
     setState(State::kChecking);
     status_t res = doMount();
-    if (res == OK) {
-        setState(State::kMounted);
-    } else {
-        setState(State::kUnmountable);
-    }
+    setState(res == OK ? State::kMounted : State::kUnmountable);
 
     return res;
 }
@@ -267,5 +263,10 @@
     return -ENOTSUP;
 }
 
+std::ostream& VolumeBase::operator<<(std::ostream& stream) const {
+    return stream << " VolumeBase{id=" << mId << ",mountFlags=" << mMountFlags
+                  << ",mountUserId=" << mMountUserId << "}";
+}
+
 }  // namespace vold
 }  // namespace android
diff --git a/model/VolumeBase.h b/model/VolumeBase.h
index 28802d4..53eeb6f 100644
--- a/model/VolumeBase.h
+++ b/model/VolumeBase.h
@@ -27,6 +27,8 @@
 #include <list>
 #include <string>
 
+static constexpr userid_t USER_UNKNOWN = ((userid_t)-1);
+
 namespace android {
 namespace vold {
 
@@ -97,12 +99,16 @@
 
     std::shared_ptr<VolumeBase> findVolume(const std::string& id);
 
+    bool isEmulated() { return mType == Type::kEmulated; }
+
     status_t create();
     status_t destroy();
     status_t mount();
     status_t unmount();
     status_t format(const std::string& fsType);
 
+    std::ostream& operator<<(std::ostream& stream) const;
+
   protected:
     explicit VolumeBase(Type type);
 
diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp
index a7c5e3d..a620edd 100644
--- a/vold_prepare_subdirs.cpp
+++ b/vold_prepare_subdirs.cpp
@@ -134,6 +134,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);
@@ -149,6 +153,11 @@
                              system_ce_path + "/backup_stage")) {
                 return false;
             }
+            auto vendor_ce_path = android::vold::BuildDataVendorCePath(user_id);
+            auto facedata_path = vendor_ce_path + "/facedata";
+            if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, facedata_path)) {
+                return false;
+            }
         }
     }
     return true;