Merge "Add missing null terminator for getopt_long()" am: 4d05e017f9
am: 4e3300374b

Change-Id: Ic91066f2abfdc191fe4d0b517fd65d9744387e7b
diff --git a/FsCrypt.cpp b/FsCrypt.cpp
index e810d58..b7d3928 100644
--- a/FsCrypt.cpp
+++ b/FsCrypt.cpp
@@ -60,10 +60,10 @@
 #include <android-base/unique_fd.h>
 
 using android::base::StringPrintf;
-using android::base::WriteStringToFile;
 using android::fs_mgr::GetEntryForMountPoint;
 using android::vold::kEmptyAuthentication;
 using android::vold::KeyBuffer;
+using android::vold::writeStringToFile;
 
 namespace {
 
@@ -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;
@@ -351,18 +351,14 @@
 
     std::string modestring = device_ref.contents_mode + ":" + device_ref.filenames_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;
-    }
+    if (!android::vold::writeStringToFile(modestring, mode_filename)) return false;
 
     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;
-    }
+    if (!android::vold::writeStringToFile(device_ref.key_raw_ref, ref_filename)) return false;
+
     LOG(INFO) << "Wrote system DE key reference to:" << ref_filename;
 
+    if (!android::vold::FsyncDirectory(device_key_dir)) return false;
     s_global_de_initialized = true;
     return true;
 }
@@ -419,7 +415,7 @@
     // Clean any dirty pages (otherwise they won't be dropped).
     sync();
     // Drop inode and page caches.
-    if (!WriteStringToFile("3", "/proc/sys/vm/drop_caches")) {
+    if (!writeStringToFile("3", "/proc/sys/vm/drop_caches")) {
         PLOG(ERROR) << "Failed to drop caches during key eviction";
     }
 }
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/KeyStorage.cpp b/KeyStorage.cpp
index 42890ca..d00225b 100644
--- a/KeyStorage.cpp
+++ b/KeyStorage.cpp
@@ -147,33 +147,6 @@
     return true;
 }
 
-static bool writeStringToFile(const std::string& payload, const std::string& filename) {
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(
-        open(filename.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0666)));
-    if (fd == -1) {
-        PLOG(ERROR) << "Failed to open " << filename;
-        return false;
-    }
-    if (!android::base::WriteStringToFd(payload, fd)) {
-        PLOG(ERROR) << "Failed to write to " << filename;
-        unlink(filename.c_str());
-        return false;
-    }
-    // fsync as close won't guarantee flush data
-    // see close(2), fsync(2) and b/68901441
-    if (fsync(fd) == -1) {
-        if (errno == EROFS || errno == EINVAL) {
-            PLOG(WARNING) << "Skip fsync " << filename
-                          << " on a file system does not support synchronization";
-        } else {
-            PLOG(ERROR) << "Failed to fsync " << filename;
-            unlink(filename.c_str());
-            return false;
-        }
-    }
-    return true;
-}
-
 static bool readRandomBytesOrLog(size_t count, std::string* out) {
     auto status = ReadRandomBytes(count, *out);
     if (status != OK) {
diff --git a/Utils.cpp b/Utils.cpp
index a8273d7..df50658 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>
@@ -193,13 +194,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;
@@ -800,13 +843,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;
@@ -840,5 +957,32 @@
     return true;
 }
 
+bool writeStringToFile(const std::string& payload, const std::string& filename) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+        open(filename.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0666)));
+    if (fd == -1) {
+        PLOG(ERROR) << "Failed to open " << filename;
+        return false;
+    }
+    if (!android::base::WriteStringToFd(payload, fd)) {
+        PLOG(ERROR) << "Failed to write to " << filename;
+        unlink(filename.c_str());
+        return false;
+    }
+    // fsync as close won't guarantee flush data
+    // see close(2), fsync(2) and b/68901441
+    if (fsync(fd) == -1) {
+        if (errno == EROFS || errno == EINVAL) {
+            PLOG(WARNING) << "Skip fsync " << filename
+                          << " on a file system does not support synchronization";
+        } else {
+            PLOG(ERROR) << "Failed to fsync " << filename;
+            unlink(filename.c_str());
+            return false;
+        }
+    }
+    return true;
+}
+
 }  // namespace vold
 }  // namespace android
diff --git a/Utils.h b/Utils.h
index 48a57d9..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,10 +139,14 @@
 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);
 
+bool writeStringToFile(const std::string& payload, const std::string& filename);
 }  // namespace vold
 }  // namespace android
 
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index 623cced..eb40d84 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -147,6 +147,69 @@
     return ok();
 }
 
+binder::Status checkArgumentPackageName(const std::string& packageName) {
+    // This logic is borrowed from PackageParser.java
+    bool hasSep = false;
+    bool front = true;
+
+    for (size_t i = 0; i < packageName.length(); ++i) {
+        char c = packageName[i];
+        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+            front = false;
+            continue;
+        }
+        if (!front) {
+            if ((c >= '0' && c <= '9') || c == '_') {
+                continue;
+            }
+        }
+        if (c == '.') {
+            hasSep = true;
+            front = true;
+            continue;
+        }
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+                         StringPrintf("Bad package character %c in %s", c, packageName.c_str()));
+    }
+
+    if (front) {
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+                         StringPrintf("Missing separator in %s", packageName.c_str()));
+    }
+
+    return ok();
+}
+
+binder::Status checkArgumentPackageNames(const std::vector<std::string>& packageNames) {
+    for (size_t i = 0; i < packageNames.size(); ++i) {
+        binder::Status status = checkArgumentPackageName(packageNames[i]);
+        if (!status.isOk()) {
+            return status;
+        }
+    }
+    return ok();
+}
+
+binder::Status checkArgumentSandboxId(const std::string& sandboxId) {
+    // 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-")
+    }
+    return checkArgumentPackageName(sandboxId.substr(nameStartIndex));
+}
+
+binder::Status checkArgumentSandboxIds(const std::vector<std::string>& sandboxIds) {
+    for (size_t i = 0; i < sandboxIds.size(); ++i) {
+        binder::Status status = checkArgumentSandboxId(sandboxIds[i]);
+        if (!status.isOk()) {
+            return status;
+        }
+    }
+    return ok();
+}
+
 #define ENFORCE_UID(uid)                         \
     {                                            \
         binder::Status status = checkUid((uid)); \
@@ -179,6 +242,38 @@
         }                                                \
     }
 
+#define CHECK_ARGUMENT_PACKAGE_NAMES(packageNames)                         \
+    {                                                                      \
+        binder::Status status = checkArgumentPackageNames((packageNames)); \
+        if (!status.isOk()) {                                              \
+            return status;                                                 \
+        }                                                                  \
+    }
+
+#define CHECK_ARGUMENT_SANDBOX_IDS(sandboxIds)                         \
+    {                                                                  \
+        binder::Status status = checkArgumentSandboxIds((sandboxIds)); \
+        if (!status.isOk()) {                                          \
+            return status;                                             \
+        }                                                              \
+    }
+
+#define CHECK_ARGUMENT_PACKAGE_NAME(packageName)                         \
+    {                                                                    \
+        binder::Status status = checkArgumentPackageName((packageName)); \
+        if (!status.isOk()) {                                            \
+            return status;                                               \
+        }                                                                \
+    }
+
+#define CHECK_ARGUMENT_SANDBOX_ID(sandboxId)                         \
+    {                                                                \
+        binder::Status status = checkArgumentSandboxId((sandboxId)); \
+        if (!status.isOk()) {                                        \
+            return status;                                           \
+        }                                                            \
+    }
+
 #define ACQUIRE_LOCK                                                        \
     std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock()); \
     ATRACE_CALL();
@@ -262,11 +357,17 @@
     return translate(VolumeManager::Instance()->onUserRemoved(userId));
 }
 
-binder::Status VoldNativeService::onUserStarted(int32_t userId) {
+binder::Status VoldNativeService::onUserStarted(int32_t userId,
+                                                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));
+    return translate(
+        VolumeManager::Instance()->onUserStarted(userId, packageNames, appIds, sandboxIds));
 }
 
 binder::Status VoldNativeService::onUserStopped(int32_t userId) {
@@ -276,6 +377,24 @@
     return translate(VolumeManager::Instance()->onUserStopped(userId));
 }
 
+binder::Status VoldNativeService::addAppIds(const std::vector<std::string>& packageNames,
+                                            const std::vector<int32_t>& appIds) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAMES(packageNames);
+    ACQUIRE_LOCK;
+
+    return translate(VolumeManager::Instance()->addAppIds(packageNames, appIds));
+}
+
+binder::Status VoldNativeService::addSandboxIds(const std::vector<int32_t>& appIds,
+                                                const std::vector<std::string>& sandboxIds) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_SANDBOX_IDS(sandboxIds);
+    ACQUIRE_LOCK;
+
+    return translate(VolumeManager::Instance()->addSandboxIds(appIds, sandboxIds));
+}
+
 binder::Status VoldNativeService::onSecureKeyguardStateChanged(bool isShowing) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
@@ -330,10 +449,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 +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) {
@@ -805,6 +913,30 @@
     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) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    CHECK_ARGUMENT_SANDBOX_ID(sandboxId);
+    ACQUIRE_LOCK;
+
+    return translate(
+        VolumeManager::Instance()->prepareSandboxForApp(packageName, appId, sandboxId, userId));
+}
+
+binder::Status VoldNativeService::destroySandboxForApp(const std::string& packageName,
+                                                       const std::string& sandboxId,
+                                                       int32_t userId) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    CHECK_ARGUMENT_SANDBOX_ID(sandboxId);
+    ACQUIRE_LOCK;
+
+    return translate(
+        VolumeManager::Instance()->destroySandboxForApp(packageName, sandboxId, userId));
+}
+
 binder::Status VoldNativeService::startCheckpoint(int32_t retry) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
diff --git a/VoldNativeService.h b/VoldNativeService.h
index b90c5b8..3f5ae83 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -39,9 +39,16 @@
 
     binder::Status onUserAdded(int32_t userId, int32_t userSerial);
     binder::Status onUserRemoved(int32_t userId);
-    binder::Status onUserStarted(int32_t userId);
+    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,
+                             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 +125,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..fad59f1 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,30 @@
 #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* kIsolatedStorage = "persist.sys.isolated_storage";
+static const char* kIsolatedStorageSnapshot = "sys.isolated_storage_snapshot";
 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;
 
@@ -101,9 +118,13 @@
 
 VolumeManager::~VolumeManager() {}
 
+static bool hasIsolatedStorage() {
+    return GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, true));
+}
+
 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,25 +372,410 @@
 
 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;
+    Symlink(source, target);
+    return 0;
+}
+
+int VolumeManager::mountPkgSpecificDir(const std::string& mntSourceRoot,
+                                       const std::string& mntTargetRoot,
+                                       const std::string& packageName, const char* dirName) {
+    std::string mntSourceDir =
+        StringPrintf("%s/Android/%s/%s", mntSourceRoot.c_str(), dirName, packageName.c_str());
+    if (CreateDir(mntSourceDir, 0755) < 0) {
+        return -errno;
+    }
+    std::string mntTargetDir =
+        StringPrintf("%s/Android/%s/%s", mntTargetRoot.c_str(), dirName, packageName.c_str());
+    if (CreateDir(mntTargetDir, 0755) < 0) {
+        return -errno;
+    }
+    return BindMount(mntSourceDir, mntTargetDir);
+}
+
+int VolumeManager::mountPkgSpecificDirsForRunningProcs(
+    userid_t userId, const std::vector<std::string>& packageNames,
+    const std::vector<std::string>& visibleVolLabels, int remountMode) {
+    std::unique_ptr<DIR, decltype(&closedir)> dirp(opendir("/proc"), closedir);
+    if (!dirp) {
+        PLOG(ERROR) << "Failed to opendir /proc";
+        return -1;
+    }
+
+    std::string rootName;
+    // Figure out root namespace to compare against below
+    if (!android::vold::Readlinkat(dirfd(dirp.get()), "1/ns/mnt", &rootName)) {
+        PLOG(ERROR) << "Failed to read root namespace";
+        return -1;
+    }
+
+    struct stat mntFullSb;
+    struct stat mntWriteSb;
+    if (TEMP_FAILURE_RETRY(stat("/mnt/runtime/full", &mntFullSb)) == -1) {
+        PLOG(ERROR) << "Failed to stat /mnt/runtime/full";
+        return -1;
+    }
+    if (TEMP_FAILURE_RETRY(stat("/mnt/runtime/write", &mntWriteSb)) == -1) {
+        PLOG(ERROR) << "Failed to stat /mnt/runtime/write";
+        return -1;
+    }
+
+    std::string obbMountDir = StringPrintf("/mnt/user/%d/obb_mount", userId);
+    if (fs_prepare_dir(obbMountDir.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+        PLOG(ERROR) << "Failed to fs_prepare_dir " << obbMountDir;
+        return -1;
+    }
+    const unique_fd obbMountDirFd(
+        TEMP_FAILURE_RETRY(open(obbMountDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC)));
+    if (obbMountDirFd.get() < 0) {
+        PLOG(ERROR) << "Failed to open " << obbMountDir;
+        return -1;
+    }
+
+    std::unordered_set<appid_t> validAppIds;
+    for (auto& package : packageNames) {
+        validAppIds.insert(mAppIds[package]);
+    }
+    std::vector<std::string>& userPackages = mUserPackages[userId];
+
+    std::vector<pid_t> childPids;
+
+    struct dirent* de;
+    // Poke through all running PIDs look for apps running in userId
+    while ((de = readdir(dirp.get()))) {
+        pid_t pid;
+        if (de->d_type != DT_DIR) continue;
+        if (!android::base::ParseInt(de->d_name, &pid)) continue;
+
+        const unique_fd pidFd(
+            openat(dirfd(dirp.get()), de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+        if (pidFd.get() < 0) {
+            PLOG(WARNING) << "Failed to open /proc/" << pid;
+            continue;
+        }
+        struct stat sb;
+        if (fstat(pidFd.get(), &sb) != 0) {
+            PLOG(WARNING) << "Failed to stat " << de->d_name;
+            continue;
+        }
+        if (multiuser_get_user_id(sb.st_uid) != userId) {
+            continue;
+        }
+
+        // Matches so far, but refuse to touch if in root namespace
+        LOG(VERBOSE) << "Found matching PID " << de->d_name;
+        std::string pidName;
+        if (!android::vold::Readlinkat(pidFd.get(), "ns/mnt", &pidName)) {
+            PLOG(WARNING) << "Failed to read namespace for " << de->d_name;
+            continue;
+        }
+        if (rootName == pidName) {
+            LOG(WARNING) << "Skipping due to root namespace";
+            continue;
+        }
+
+        // Only update the mount points of processes running with one of validAppIds.
+        // This should skip any isolated uids.
+        appid_t appId = multiuser_get_app_id(sb.st_uid);
+        if (validAppIds.find(appId) == validAppIds.end()) {
+            continue;
+        }
+
+        std::vector<std::string> packagesForUid;
+        for (auto& package : userPackages) {
+            if (mAppIds[package] == appId) {
+                packagesForUid.push_back(package);
+            }
+        }
+        if (packagesForUid.empty()) {
+            continue;
+        }
+        const std::string& sandboxId = mSandboxIds[appId];
+
+        // We purposefully leave the namespace open across the fork
+        // NOLINTNEXTLINE(android-cloexec-open): Deliberately not O_CLOEXEC
+        unique_fd nsFd(openat(pidFd.get(), "ns/mnt", O_RDONLY));
+        if (nsFd.get() < 0) {
+            PLOG(WARNING) << "Failed to open namespace for " << de->d_name;
+            continue;
+        }
+
+        pid_t child;
+        if (!(child = fork())) {
+            if (setns(nsFd.get(), CLONE_NEWNS) != 0) {
+                PLOG(ERROR) << "Failed to setns for " << de->d_name;
+                _exit(1);
+            }
+
+            int mountMode;
+            if (remountMode == -1) {
+                mountMode =
+                    getMountModeForRunningProc(packagesForUid, userId, mntWriteSb, mntFullSb);
+                if (mountMode == -1) {
+                    _exit(1);
+                }
+            } else {
+                mountMode = remountMode;
+                if (handleMountModeInstaller(mountMode, obbMountDirFd.get(), obbMountDir,
+                                             sandboxId) < 0) {
+                    _exit(1);
+                }
+            }
+            if (mountMode == VoldNativeService::REMOUNT_MODE_FULL ||
+                mountMode == VoldNativeService::REMOUNT_MODE_LEGACY ||
+                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) {
+                std::string mntSource = StringPrintf("/mnt/runtime/write/%s", volumeLabel.c_str());
+                std::string mntTarget = StringPrintf("/storage/%s", volumeLabel.c_str());
+                if (volumeLabel == "emulated") {
+                    StringAppendF(&mntSource, "/%d", userId);
+                    StringAppendF(&mntTarget, "/%d", userId);
+                }
+
+                std::string sandboxSource =
+                    StringPrintf("%s/Android/sandbox/%s", mntSource.c_str(), sandboxId.c_str());
+                if (CreateDir(sandboxSource, 0755) < 0) {
+                    continue;
+                }
+                if (BindMount(sandboxSource, mntTarget) < 0) {
+                    continue;
+                }
+
+                std::string obbSourceDir = StringPrintf("%s/Android/obb", mntSource.c_str());
+                std::string obbTargetDir = StringPrintf("%s/Android/obb", mntTarget.c_str());
+                if (UnmountTree(obbTargetDir) < 0) {
+                    continue;
+                }
+                if (!createPkgSpecificDirRoots(mntSource) || !createPkgSpecificDirRoots(mntTarget)) {
+                    continue;
+                }
+                for (auto& package : packagesForUid) {
+                    mountPkgSpecificDir(mntSource, mntTarget, package, "data");
+                    mountPkgSpecificDir(mntSource, mntTarget, package, "media");
+                    if (mountMode != VoldNativeService::REMOUNT_MODE_INSTALLER) {
+                        mountPkgSpecificDir(mntSource, mntTarget, package, "obb");
+                    }
+                }
+                if (mountMode == VoldNativeService::REMOUNT_MODE_INSTALLER) {
+                    if (BindMount(obbSourceDir, obbTargetDir) < 0) {
+                        continue;
+                    }
+                }
+            }
+            _exit(0);
+        }
+
+        if (child == -1) {
+            PLOG(ERROR) << "Failed to fork";
+        } else {
+            childPids.push_back(child);
         }
     }
-    LOG(DEBUG) << "Linking " << source << " to " << target;
-    if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) {
-        PLOG(WARNING) << "Failed to link";
+    for (auto& child : childPids) {
+        TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0));
+    }
+    return 0;
+}
+
+int VolumeManager::getMountModeForRunningProc(const std::vector<std::string>& packagesForUid,
+                                              userid_t userId, struct stat& mntWriteStat,
+                                              struct stat& mntFullStat) {
+    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/full and /storage
+    if (storageSb.st_dev == mntFullStat.st_dev && storageSb.st_ino == mntFullStat.st_ino) {
+        return VoldNativeService::REMOUNT_MODE_FULL;
+    } else if (storageSb.st_dev == mntWriteStat.st_dev && storageSb.st_ino == mntWriteStat.st_ino) {
+        return VoldNativeService::REMOUNT_MODE_LEGACY;
+    }
+
+    std::string obbMountFile =
+        StringPrintf("/mnt/user/%d/obb_mount/%s", userId, packagesForUid[0].c_str());
+    if (TEMP_FAILURE_RETRY(access(obbMountFile.c_str(), F_OK)) != -1) {
+        return VoldNativeService::REMOUNT_MODE_INSTALLER;
+    } else if (errno != ENOENT) {
+        PLOG(ERROR) << "Failed to access " << obbMountFile;
+        return -1;
+    }
+
+    // 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
+    // and /storage
+    std::string sandbox = StringPrintf("/mnt/user/%d/package", userId);
+    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::handleMountModeInstaller(int mountMode, int obbMountDirFd,
+                                            const std::string& obbMountDir,
+                                            const std::string& sandboxId) {
+    if (mountMode == VoldNativeService::REMOUNT_MODE_INSTALLER) {
+        if (TEMP_FAILURE_RETRY(faccessat(obbMountDirFd, sandboxId.c_str(), F_OK, 0)) != -1) {
+            return 0;
+        } else if (errno != ENOENT) {
+            PLOG(ERROR) << "Failed to access " << obbMountDir << "/" << sandboxId;
+            return -errno;
+        }
+        const unique_fd fd(TEMP_FAILURE_RETRY(
+            openat(obbMountDirFd, sandboxId.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600)));
+        if (fd.get() < 0) {
+            PLOG(ERROR) << "Failed to create " << obbMountDir << "/" << sandboxId;
+            return -errno;
+        }
+    } else {
+        if (TEMP_FAILURE_RETRY(faccessat(obbMountDirFd, sandboxId.c_str(), F_OK, 0)) != -1) {
+            if (TEMP_FAILURE_RETRY(unlinkat(obbMountDirFd, sandboxId.c_str(), 0)) == -1) {
+                PLOG(ERROR) << "Failed to unlink " << obbMountDir << "/" << sandboxId;
+                return -errno;
+            }
+        } else if (errno != ENOENT) {
+            PLOG(ERROR) << "Failed to access " << obbMountDir << "/" << sandboxId;
+            return -errno;
+        }
+    }
+    return 0;
+}
+
+int VolumeManager::prepareSandboxes(userid_t userId, const std::vector<std::string>& packageNames,
+                                    const std::vector<std::string>& visibleVolLabels) {
+    if (visibleVolLabels.empty()) {
+        return 0;
+    }
+    for (auto& volumeLabel : visibleVolLabels) {
+        std::string volumeRoot(StringPrintf("/mnt/runtime/write/%s", volumeLabel.c_str()));
+        bool isVolPrimaryEmulated = (volumeLabel == mPrimary->getLabel() && mPrimary->isEmulated());
+        if (isVolPrimaryEmulated) {
+            StringAppendF(&volumeRoot, "/%d", userId);
+            if (CreateDir(volumeRoot, 0755) < 0) {
+                return -errno;
+            }
+        }
+
+        std::string sandboxRoot =
+            prepareSubDirs(volumeRoot, "Android/sandbox/", 0700, AID_ROOT, AID_ROOT);
+        if (sandboxRoot.empty()) {
+            return -errno;
+        }
+    }
+
+    if (prepareSandboxTargets(userId, visibleVolLabels) < 0) {
+        return -errno;
+    }
+
+    if (mountPkgSpecificDirsForRunningProcs(userId, packageNames, visibleVolLabels, -1) < 0) {
+        PLOG(ERROR) << "Failed to setup sandboxes for already running processes";
         return -errno;
     }
     return 0;
 }
 
+int VolumeManager::prepareSandboxTargets(userid_t userId,
+                                         const std::vector<std::string>& visibleVolLabels) {
+    std::string mntTargetRoot = StringPrintf("/mnt/user/%d", userId);
+    if (fs_prepare_dir(mntTargetRoot.c_str(), 0751, AID_ROOT, AID_ROOT) != 0) {
+        PLOG(ERROR) << "Failed to fs_prepare_dir " << mntTargetRoot;
+        return -errno;
+    }
+
+    StringAppendF(&mntTargetRoot, "/package");
+    if (fs_prepare_dir(mntTargetRoot.c_str(), 0755, AID_ROOT, AID_ROOT) != 0) {
+        PLOG(ERROR) << "Failed to fs_prepare_dir " << mntTargetRoot;
+        return -errno;
+    }
+
+    for (auto& volumeLabel : visibleVolLabels) {
+        std::string sandboxTarget =
+            StringPrintf("%s/%s", mntTargetRoot.c_str(), volumeLabel.c_str());
+        if (fs_prepare_dir(sandboxTarget.c_str(), 0755, AID_ROOT, AID_ROOT) != 0) {
+            PLOG(ERROR) << "Failed to fs_prepare_dir " << sandboxTarget;
+            return -errno;
+        }
+
+        if (mPrimary && volumeLabel == mPrimary->getLabel() && mPrimary->isEmulated()) {
+            StringAppendF(&sandboxTarget, "/%d", userId);
+            if (fs_prepare_dir(sandboxTarget.c_str(), 0755, AID_ROOT, AID_ROOT) != 0) {
+                PLOG(ERROR) << "Failed to fs_prepare_dir " << sandboxTarget;
+                return -errno;
+            }
+        }
+    }
+
+    StringAppendF(&mntTargetRoot, "/self");
+    if (fs_prepare_dir(mntTargetRoot.c_str(), 0755, AID_ROOT, AID_ROOT) != 0) {
+        PLOG(ERROR) << "Failed to fs_prepare_dir " << mntTargetRoot;
+        return -errno;
+    }
+
+    if (mPrimary) {
+        std::string pkgPrimarySource(mPrimary->getPath());
+        if (mPrimary->isEmulated()) {
+            StringAppendF(&pkgPrimarySource, "/%d", userId);
+        }
+        StringAppendF(&mntTargetRoot, "/primary");
+        if (Symlink(pkgPrimarySource, mntTargetRoot) < 0) {
+            return -errno;
+        }
+    }
+    return 0;
+}
+
+std::string VolumeManager::prepareSubDirs(const std::string& pathPrefix, const std::string& subDirs,
+                                          mode_t mode, uid_t uid, gid_t gid) {
+    std::string path(pathPrefix);
+    std::vector<std::string> subDirList = android::base::Split(subDirs, "/");
+    for (size_t i = 0; i < subDirList.size(); ++i) {
+        std::string subDir = subDirList[i];
+        if (subDir.empty()) {
+            continue;
+        }
+        StringAppendF(&path, "/%s", subDir.c_str());
+        if (CreateDir(path, mode) < 0) {
+            return kEmptyString;
+        }
+    }
+    return path;
+}
+
+bool VolumeManager::createPkgSpecificDirRoots(const std::string& volumeRoot) {
+    std::string volumeAndroidRoot = StringPrintf("%s/Android", volumeRoot.c_str());
+    if (CreateDir(volumeAndroidRoot, 0700) < 0) {
+        return false;
+    }
+    std::array<std::string, 3> dirs = {"data", "media", "obb"};
+    for (auto& dir : dirs) {
+        std::string path = StringPrintf("%s/%s", volumeAndroidRoot.c_str(), dir.c_str());
+        if (CreateDir(path, 0700) < 0) {
+            return false;
+        }
+    }
+    return true;
+}
+
 int VolumeManager::onUserAdded(userid_t userId, int userSerialNumber) {
     mAddedUsers[userId] = userSerialNumber;
     return 0;
@@ -380,7 +786,10 @@
     return 0;
 }
 
-int VolumeManager::onUserStarted(userid_t userId) {
+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
     // already created this directory.
@@ -388,14 +797,159 @@
     fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT);
 
     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);
     }
+    if (hasIsolatedStorage()) {
+        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());
+            }
+        }
+        if (prepareSandboxes(userId, packageNames, visibleVolLabels) != 0) {
+            return -errno;
+        }
+    }
     return 0;
 }
 
 int VolumeManager::onUserStopped(userid_t userId) {
+    LOG(VERBOSE) << "onUserStopped: " << userId;
     mStartedUsers.erase(userId);
+
+    if (hasIsolatedStorage()) {
+        auto& userPackages = mUserPackages[userId];
+        std::string userMntTargetRoot = StringPrintf("/mnt/user/%d", userId);
+        std::string pkgPrimaryDir =
+            StringPrintf("%s/package/self/primary", userMntTargetRoot.c_str());
+        if (Unlink(pkgPrimaryDir) < 0) {
+            return -errno;
+        }
+        mUserPackages.erase(userId);
+        if (DeleteDirContentsAndDir(userMntTargetRoot) < 0) {
+            PLOG(ERROR) << "DeleteDirContentsAndDir failed on " << userMntTargetRoot;
+            return -errno;
+        }
+        LOG(VERBOSE) << "Success: DeleteDirContentsAndDir on " << userMntTargetRoot;
+    }
+    return 0;
+}
+
+int VolumeManager::addAppIds(const std::vector<std::string>& packageNames,
+                             const std::vector<int32_t>& appIds) {
+    for (size_t i = 0; i < packageNames.size(); ++i) {
+        mAppIds[packageNames[i]] = appIds[i];
+    }
+    return 0;
+}
+
+int VolumeManager::addSandboxIds(const std::vector<int32_t>& appIds,
+                                 const std::vector<std::string>& sandboxIds) {
+    for (size_t i = 0; i < appIds.size(); ++i) {
+        mSandboxIds[appIds[i]] = sandboxIds[i];
+    }
+    return 0;
+}
+
+int VolumeManager::prepareSandboxForApp(const std::string& packageName, appid_t appId,
+                                        const std::string& sandboxId, userid_t userId) {
+    if (!hasIsolatedStorage()) {
+        return 0;
+    } else if (mStartedUsers.find(userId) == mStartedUsers.end()) {
+        // User not started, no need to do anything now. Required bind mounts for the package will
+        // be created when the user starts.
+        return 0;
+    }
+
+    auto& userPackages = mUserPackages[userId];
+    if (std::find(userPackages.begin(), userPackages.end(), packageName) != userPackages.end()) {
+        return 0;
+    }
+
+    LOG(VERBOSE) << "prepareSandboxForApp: " << packageName << ", appId=" << appId
+                 << ", sandboxId=" << sandboxId << ", userId=" << userId;
+    mUserPackages[userId].push_back(packageName);
+    mAppIds[packageName] = appId;
+    mSandboxIds[appId] = sandboxId;
+
+    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());
+        }
+    }
+    return prepareSandboxes(userId, {packageName}, visibleVolLabels);
+}
+
+int VolumeManager::destroySandboxForApp(const std::string& packageName,
+                                        const std::string& sandboxId, userid_t userId) {
+    if (!hasIsolatedStorage()) {
+        return 0;
+    }
+    LOG(VERBOSE) << "destroySandboxForApp: " << packageName << ", sandboxId=" << sandboxId
+                 << ", userId=" << userId;
+    auto& userPackages = mUserPackages[userId];
+    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;
+    for (auto& it : mUserPackages) {
+        auto& packages = it.second;
+        if (std::find(packages.begin(), packages.end(), packageName) != packages.end()) {
+            installedInAnyUser = true;
+            break;
+        }
+    }
+    if (!installedInAnyUser) {
+        const auto& entry = mAppIds.find(packageName);
+        if (entry != mAppIds.end()) {
+            mSandboxIds.erase(entry->second);
+            mAppIds.erase(entry);
+        }
+    }
+
+    std::vector<std::string> visibleVolLabels;
+    for (auto& volId : mVisibleVolumeIds) {
+        auto vol = findVolume(volId);
+        userid_t mountUserId = vol->getMountUserId();
+        if (mountUserId == userId || vol->isEmulated()) {
+            if (destroySandboxForAppOnVol(packageName, sandboxId, userId, vol->getLabel()) < 0) {
+                return -errno;
+            }
+        }
+    }
+
+    return 0;
+}
+
+int VolumeManager::destroySandboxForAppOnVol(const std::string& packageName,
+                                             const std::string& sandboxId, userid_t userId,
+                                             const std::string& volLabel) {
+    LOG(VERBOSE) << "destroySandboxOnVol: " << packageName << ", userId=" << userId
+                 << ", volLabel=" << volLabel;
+
+    std::string sandboxDir = StringPrintf("/mnt/runtime/write/%s", volLabel.c_str());
+    if (volLabel == mPrimary->getLabel() && mPrimary->isEmulated()) {
+        StringAppendF(&sandboxDir, "/%d", userId);
+    }
+    StringAppendF(&sandboxDir, "/Android/sandbox/%s", sandboxId.c_str());
+
+    if (DeleteDirContentsAndDir(sandboxDir) < 0) {
+        PLOG(ERROR) << "DeleteDirContentsAndDir failed on " << sandboxDir;
+        return -errno;
+    }
+
     return 0;
 }
 
@@ -413,7 +967,86 @@
     return 0;
 }
 
+int VolumeManager::onVolumeMounted(android::vold::VolumeBase* vol) {
+    if (!hasIsolatedStorage()) {
+        return 0;
+    }
+
+    if ((vol->getMountFlags() & android::vold::VoldNativeService::MOUNT_FLAG_VISIBLE) == 0) {
+        return 0;
+    }
+
+    mVisibleVolumeIds.insert(vol->getId());
+    userid_t mountUserId = vol->getMountUserId();
+    if ((vol->getMountFlags() & android::vold::VoldNativeService::MOUNT_FLAG_PRIMARY) != 0) {
+        // We don't want to create another shared_ptr here because then we will end up with
+        // two shared_ptrs owning the underlying pointer without sharing it.
+        mPrimary = findVolume(vol->getId());
+        for (userid_t userId : mStartedUsers) {
+            if (linkPrimary(userId) != 0) {
+                return -errno;
+            }
+        }
+    }
+    if (vol->isEmulated()) {
+        for (userid_t userId : mStartedUsers) {
+            if (prepareSandboxes(userId, mUserPackages[userId], {vol->getLabel()}) != 0) {
+                return -errno;
+            }
+        }
+    } else if (mStartedUsers.find(mountUserId) != mStartedUsers.end()) {
+        if (prepareSandboxes(mountUserId, mUserPackages[mountUserId], {vol->getLabel()}) != 0) {
+            return -errno;
+        }
+    }
+    return 0;
+}
+
+int VolumeManager::onVolumeUnmounted(android::vold::VolumeBase* vol) {
+    if (!hasIsolatedStorage()) {
+        return 0;
+    }
+
+    if (mVisibleVolumeIds.erase(vol->getId()) == 0) {
+        return 0;
+    }
+
+    if ((vol->getMountFlags() & android::vold::VoldNativeService::MOUNT_FLAG_PRIMARY) != 0) {
+        mPrimary = nullptr;
+    }
+
+    LOG(VERBOSE) << "visibleVolumeUnmounted: " << vol;
+    userid_t mountUserId = vol->getMountUserId();
+    if (vol->isEmulated()) {
+        for (userid_t userId : mStartedUsers) {
+            if (destroySandboxesForVol(vol, userId) != 0) {
+                return -errno;
+            }
+        }
+    } else if (mStartedUsers.find(mountUserId) != mStartedUsers.end()) {
+        if (destroySandboxesForVol(vol, mountUserId) != 0) {
+            return -errno;
+        }
+    }
+    return 0;
+}
+
+int VolumeManager::destroySandboxesForVol(android::vold::VolumeBase* vol, userid_t userId) {
+    LOG(VERBOSE) << "destroysandboxesForVol: " << vol << " for user=" << userId;
+    std::string volSandboxRoot =
+        StringPrintf("/mnt/user/%d/package/%s", userId, vol->getLabel().c_str());
+    if (android::vold::DeleteDirContentsAndDir(volSandboxRoot) < 0) {
+        PLOG(ERROR) << "DeleteDirContentsAndDir failed on " << volSandboxRoot;
+        return -errno;
+    }
+    LOG(VERBOSE) << "Success: DeleteDirContentsAndDir on " << volSandboxRoot;
+    return 0;
+}
+
 int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol) {
+    if (hasIsolatedStorage()) {
+        return 0;
+    }
     mPrimary = vol;
     for (userid_t userId : mStartedUsers) {
         linkPrimary(userId);
@@ -421,7 +1054,56 @@
     return 0;
 }
 
-int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
+int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
+    if (!hasIsolatedStorage()) {
+        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;
@@ -576,6 +1258,15 @@
     }
     updateVirtualDisk();
     mAddedUsers.clear();
+
+    mUserPackages.clear();
+    mAppIds.clear();
+    mSandboxIds.clear();
+    mVisibleVolumeIds.clear();
+
+    for (userid_t userId : mStartedUsers) {
+        DeleteDirContents(StringPrintf("/mnt/user/%d/package", userId));
+    }
     mStartedUsers.clear();
     return 0;
 }
diff --git a/VolumeManager.h b/VolumeManager.h
index e0a1bd6..bb93b13 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -88,14 +88,27 @@
 
     int onUserAdded(userid_t userId, int userSerialNumber);
     int onUserRemoved(userid_t userId);
-    int onUserStarted(userid_t userId);
+    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);
+    int addSandboxIds(const std::vector<int32_t>& appIds,
+                      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, const std::string& sandboxId,
+                             userid_t userId);
+
+    int onVolumeMounted(android::vold::VolumeBase* vol);
+    int onVolumeUnmounted(android::vold::VolumeBase* vol);
+
     int onSecureKeyguardStateChanged(bool isShowing);
 
     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();
@@ -137,6 +150,26 @@
 
     int linkPrimary(userid_t userId);
 
+    int prepareSandboxes(userid_t userId, const std::vector<std::string>& packageNames,
+                         const std::vector<std::string>& visibleVolLabels);
+    int prepareSandboxTargets(userid_t userId, const std::vector<std::string>& visibleVolLabels);
+    int handleMountModeInstaller(int mountMode, int obbMountDirFd, const std::string& obbMountDir,
+                                 const std::string& sandboxId);
+    int mountPkgSpecificDirsForRunningProcs(userid_t userId,
+                                            const std::vector<std::string>& packageNames,
+                                            const std::vector<std::string>& visibleVolLabels,
+                                            int remountMode);
+    int destroySandboxesForVol(android::vold::VolumeBase* vol, userid_t userId);
+    std::string prepareSubDirs(const std::string& pathPrefix, const std::string& subDirs,
+                               mode_t mode, uid_t uid, gid_t gid);
+    bool createPkgSpecificDirRoots(const std::string& volumeRoot);
+    int mountPkgSpecificDir(const std::string& mntSourceRoot, const std::string& mntTargetRoot,
+                            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, struct stat& mntFullStat);
+
     void handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk);
     void handleDiskChanged(dev_t device);
     void handleDiskRemoved(dev_t device);
@@ -160,6 +193,11 @@
     std::shared_ptr<android::vold::VolumeBase> mInternalEmulated;
     std::shared_ptr<android::vold::VolumeBase> mPrimary;
 
+    std::unordered_map<std::string, appid_t> mAppIds;
+    std::unordered_map<appid_t, std::string> mSandboxIds;
+    std::unordered_map<userid_t, std::vector<std::string>> mUserPackages;
+    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 72f2643..cc23498 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -29,9 +29,13 @@
 
     void onUserAdded(int userId, int userSerial);
     void onUserRemoved(int userId);
-    void onUserStarted(int userId);
+    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);
+    void addSandboxIds(in int[] appIds, in @utf8InCpp String[] sandboxIds);
+
     void onSecureKeyguardStateChanged(boolean isShowing);
 
     void partition(@utf8InCpp String diskId, int partitionType, int ratio);
@@ -96,6 +100,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 +155,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..73bf6d1 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>
@@ -69,6 +70,7 @@
 
     setInternalPath(mRawPath);
     setPath(StringPrintf("/storage/%s", label.c_str()));
+    setLabel(label);
 
     if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
         fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
@@ -89,6 +91,7 @@
                 "-w",
                 "-G",
                 "-i",
+                "-o",
                 mRawPath.c_str(),
                 label.c_str(),
                 NULL)) {
diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp
index 1339eb3..1eb6008 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 {
@@ -127,6 +129,7 @@
     } else {
         setPath(mRawPath);
     }
+    setLabel(stableName);
 
     if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
         PLOG(ERROR) << getId() << " failed to create mount points";
diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp
index b04dd70..a9c7fa3 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) {}
@@ -143,6 +143,16 @@
     return OK;
 }
 
+status_t VolumeBase::setLabel(const std::string& label) {
+    if (mState != State::kChecking) {
+        LOG(WARNING) << getId() << " label change requires state checking";
+        return -EBUSY;
+    }
+
+    mLabel = label;
+    return OK;
+}
+
 android::sp<android::os::IVoldListener> VolumeBase::getListener() const {
     if (mSilent) {
         return nullptr;
@@ -220,10 +230,9 @@
     setState(State::kChecking);
     status_t res = doMount();
     if (res == OK) {
-        setState(State::kMounted);
-    } else {
-        setState(State::kUnmountable);
+        res = VolumeManager::Instance()->onVolumeMounted(this);
     }
+    setState(res == OK ? State::kMounted : State::kUnmountable);
 
     return res;
 }
@@ -242,8 +251,11 @@
     }
     mVolumes.clear();
 
-    status_t res = doUnmount();
-    setState(State::kUnmounted);
+    status_t res = VolumeManager::Instance()->onVolumeUnmounted(this);
+    if (res == OK) {
+        res = doUnmount();
+        setState(State::kUnmounted);
+    }
     return res;
 }
 
@@ -267,5 +279,10 @@
     return -ENOTSUP;
 }
 
+std::ostream& VolumeBase::operator<<(std::ostream& stream) const {
+    return stream << " VolumeBase{id=" << mId << ",label=" << mLabel
+                  << ",mountFlags=" << mMountFlags << ",mountUserId=" << mMountUserId << "}";
+}
+
 }  // namespace vold
 }  // namespace android
diff --git a/model/VolumeBase.h b/model/VolumeBase.h
index 28802d4..e6c47f0 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 {
 
@@ -85,6 +87,7 @@
     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);
@@ -97,12 +100,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);
 
@@ -115,6 +122,7 @@
     status_t setId(const std::string& id);
     status_t setPath(const std::string& path);
     status_t setInternalPath(const std::string& internalPath);
+    status_t setLabel(const std::string& label);
 
     android::sp<android::os::IVoldListener> getListener() const;
 
@@ -141,6 +149,12 @@
     std::string mInternalPath;
     /* Flag indicating that volume should emit no events */
     bool mSilent;
+    /**
+     * Label used for representing the package sandboxes on external storage volumes.
+     * For emulated volume, this would be "emulated" and for public volumes, UUID if available,
+     * otherwise some other unique id.
+     */
+    std::string mLabel;
 
     /* Volumes stacked on top of this volume */
     std::list<std::shared_ptr<VolumeBase>> mVolumes;
diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp
index a7c5e3d..1dd5e85 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);