Move even more vold commands over to Binder.

This moves fstrim, obb and appfuse commands over to the new Binder
interface.  This change also separates creating/destroying and
mounting/unmounting of OBB volumes, which means they finally flow
nicely into the modern VolumeInfo/VolumeBase design.

We now generate unique identifiers for all OBB volumes, instead of
using a shady MD5 hash.

Change all "loop" and "dm" devices to tag the kernel resources with
a vold-specific prefix so that we can clean them up if vold crashes;
there are new destroyAll() methods that handle this cleanup.

Move appfuse mounting/unmounting into VolumeManager so it can be
shared.  Move various model objects into a separate directory to
tidy things up.

Test: cts-tradefed run commandAndExit cts-dev -m CtsOsTestCases -t android.os.storage.cts.StorageManagerTest
Bug: 13758960
Change-Id: I7294e32b3fb6efe07cb3b77bd20166e70b66958f
diff --git a/Android.mk b/Android.mk
index f6a8da9..7263a5b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -18,11 +18,12 @@
 	Ext4Crypt.cpp \
 	VoldUtil.c \
 	cryptfs.cpp \
-	Disk.cpp \
-	VolumeBase.cpp \
-	PublicVolume.cpp \
-	PrivateVolume.cpp \
-	EmulatedVolume.cpp \
+	model/Disk.cpp \
+	model/VolumeBase.cpp \
+	model/PublicVolume.cpp \
+	model/PrivateVolume.cpp \
+	model/EmulatedVolume.cpp \
+	model/ObbVolume.cpp \
 	Utils.cpp \
 	MoveTask.cpp \
 	Benchmark.cpp \
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 8da3f69..60c0898 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -44,7 +44,7 @@
 
 #include "CommandListener.h"
 #include "VolumeManager.h"
-#include "VolumeBase.h"
+#include "model/VolumeBase.h"
 #include "ResponseCode.h"
 #include "Process.h"
 #include "Loop.h"
@@ -53,7 +53,6 @@
 #include "TrimTask.h"
 
 #define DUMP_ARGS 0
-#define DEBUG_APPFUSE 0
 
 using android::base::unique_fd;
 
@@ -617,157 +616,6 @@
     return sendGenericOkFail(cli, 0);
 }
 
-static size_t kAppFuseMaxMountPointName = 32;
-
-static android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) {
-    if (name.size() > kAppFuseMaxMountPointName) {
-        LOG(ERROR) << "AppFuse mount name is too long.";
-        return -EINVAL;
-    }
-    for (size_t i = 0; i < name.size(); i++) {
-        if (!isalnum(name[i])) {
-            LOG(ERROR) << "AppFuse mount name contains invalid character.";
-            return -EINVAL;
-        }
-    }
-    *path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str());
-    return android::OK;
-}
-
-static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
-    // Remove existing mount.
-    android::vold::ForceUnmount(path);
-
-    const auto opts = android::base::StringPrintf(
-            "fd=%i,"
-            "rootmode=40000,"
-            "default_permissions,"
-            "allow_other,"
-            "user_id=%d,group_id=%d,"
-            "context=\"u:object_r:app_fuse_file:s0\","
-            "fscontext=u:object_r:app_fusefs:s0",
-            device_fd,
-            uid,
-            uid);
-
-    const int result = TEMP_FAILURE_RETRY(mount(
-            "/dev/fuse", path.c_str(), "fuse",
-            MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()));
-    if (result != 0) {
-        PLOG(ERROR) << "Failed to mount " << path;
-        return -errno;
-    }
-
-    return android::OK;
-}
-
-static android::status_t runCommandInNamespace(const std::string& command,
-                                               uid_t uid,
-                                               pid_t pid,
-                                               const std::string& path,
-                                               int device_fd) {
-    if (DEBUG_APPFUSE) {
-        LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path
-                   << " in namespace " << uid;
-    }
-
-    unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
-    if (dir.get() == -1) {
-        PLOG(ERROR) << "Failed to open /proc";
-        return -errno;
-    }
-
-    // Obtains process file descriptor.
-    const std::string pid_str = android::base::StringPrintf("%d", pid);
-    const unique_fd pid_fd(
-            openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
-    if (pid_fd.get() == -1) {
-        PLOG(ERROR) << "Failed to open /proc/" << pid;
-        return -errno;
-    }
-
-    // Check UID of process.
-    {
-        struct stat sb;
-        const int result = fstat(pid_fd.get(), &sb);
-        if (result == -1) {
-            PLOG(ERROR) << "Failed to stat /proc/" << pid;
-            return -errno;
-        }
-        if (sb.st_uid != AID_SYSTEM) {
-            LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM
-                    << ", actual=" << sb.st_uid;
-            return -EPERM;
-        }
-    }
-
-    // Matches so far, but refuse to touch if in root namespace
-    {
-        char rootName[PATH_MAX];
-        char pidName[PATH_MAX];
-        const int root_result =
-                android::vold::SaneReadLinkAt(dir.get(), "1/ns/mnt", rootName, PATH_MAX);
-        const int pid_result =
-                android::vold::SaneReadLinkAt(pid_fd.get(), "ns/mnt", pidName, PATH_MAX);
-        if (root_result == -1) {
-            LOG(ERROR) << "Failed to readlink for /proc/1/ns/mnt";
-            return -EPERM;
-        }
-        if (pid_result == -1) {
-            LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt";
-            return -EPERM;
-        }
-        if (!strcmp(rootName, pidName)) {
-            LOG(ERROR) << "Don't mount appfuse in root namespace";
-            return -EPERM;
-        }
-    }
-
-    // We purposefully leave the namespace open across the fork
-    unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC
-    if (ns_fd.get() < 0) {
-        PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt";
-        return -errno;
-    }
-
-    int child = fork();
-    if (child == 0) {
-        if (setns(ns_fd.get(), CLONE_NEWNS) != 0) {
-            PLOG(ERROR) << "Failed to setns";
-            _exit(-errno);
-        }
-
-        if (command == "mount") {
-            _exit(mountInNamespace(uid, device_fd, path));
-        } else if (command == "unmount") {
-            // If it's just after all FD opened on mount point are closed, umount2 can fail with
-            // EBUSY. To avoid the case, specify MNT_DETACH.
-            if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 &&
-                    errno != EINVAL && errno != ENOENT) {
-                PLOG(ERROR) << "Failed to unmount directory.";
-                _exit(-errno);
-            }
-            if (rmdir(path.c_str()) != 0) {
-                PLOG(ERROR) << "Failed to remove the mount directory.";
-                _exit(-errno);
-            }
-            _exit(android::OK);
-        } else {
-            LOG(ERROR) << "Unknown appfuse command " << command;
-            _exit(-EPERM);
-        }
-    }
-
-    if (child == -1) {
-        PLOG(ERROR) << "Failed to folk child process";
-        return -errno;
-    }
-
-    android::status_t status;
-    TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
-
-    return status;
-}
 
 CommandListener::AppFuseCmd::AppFuseCmd() : VoldCommand("appfuse") {}
 
@@ -777,66 +625,32 @@
         return 0;
     }
 
-    const std::string command(argv[1]);
+    VolumeManager *vm = VolumeManager::Instance();
+    std::lock_guard<std::mutex> lock(vm->getLock());
 
+    const std::string command(argv[1]);
     if (command == "mount" && argc == 5) {
         const uid_t uid = atoi(argv[2]);
         const pid_t pid = atoi(argv[3]);
-        const std::string name(argv[4]);
+        const int mountId = atoi(argv[4]);
 
-        // Check mount point name.
-        std::string path;
-        if (getMountPath(uid, name, &path) != android::OK) {
-            return cli->sendMsg(ResponseCode::CommandParameterError,
-                                "Invalid mount point name.",
-                                false);
+        unique_fd device_fd;
+        int result = vm->mountAppFuse(uid, pid, mountId, &device_fd);
+        if (result != 0) {
+            return sendGenericOkFail(cli, result);
+        } else {
+            return sendFd(cli, device_fd.get());
         }
-
-        // Create directories.
-        {
-            const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0);
-            if (result != android::OK) {
-                PLOG(ERROR) << "Failed to prepare directory " << path;
-                return sendGenericOkFail(cli, result);
-            }
-        }
-
-        // Open device FD.
-        unique_fd device_fd(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC
-        if (device_fd.get() == -1) {
-            PLOG(ERROR) << "Failed to open /dev/fuse";
-            return sendGenericOkFail(cli, -errno);
-        }
-
-        // Mount.
-        {
-            const android::status_t result =
-                    runCommandInNamespace(command, uid, pid, path, device_fd.get());
-            if (result != android::OK) {
-                return sendGenericOkFail(cli, result);
-            }
-        }
-
-        return sendFd(cli, device_fd.get());
     } else if (command == "unmount" && argc == 5) {
         const uid_t uid = atoi(argv[2]);
         const uid_t pid = atoi(argv[3]);
-        const std::string name(argv[4]);
+        const int mountId = atoi(argv[4]);
 
-        // Check mount point name.
-        std::string path;
-        if (getMountPath(uid, name, &path) != android::OK) {
-            return cli->sendMsg(ResponseCode::CommandParameterError,
-                                "Invalid mount point name.",
-                                false);
-        }
-
-        const android::status_t result =
-                runCommandInNamespace(command, uid, pid, path, -1 /* device_fd */);
+        int result = vm->unmountAppFuse(uid, pid, mountId);
         return sendGenericOkFail(cli, result);
     }
 
-    return cli->sendMsg(ResponseCode::CommandSyntaxError,  "Unknown appfuse cmd", false);
+    return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown appfuse cmd", false);
 }
 
 android::status_t CommandListener::AppFuseCmd::sendFd(SocketClient *cli, int fd) {
diff --git a/Devmapper.cpp b/Devmapper.cpp
index 4b6942d..c945e9f 100644
--- a/Devmapper.cpp
+++ b/Devmapper.cpp
@@ -32,12 +32,18 @@
 
 #include <cutils/log.h>
 
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <sysutils/SocketClient.h>
 
 #include "Devmapper.h"
 
 #define DEVMAPPER_BUFFER_SIZE 4096
 
+using android::base::StringPrintf;
+
+static const char* kVoldPrefix = "vold:";
+
 int Devmapper::dumpState(SocketClient *c) {
 
     char *buffer = (char *) malloc(1024 * 64);
@@ -130,7 +136,10 @@
     }
 }
 
-int Devmapper::lookupActive(const char *name, char *ubuffer, size_t len) {
+int Devmapper::lookupActive(const char *name_raw, char *ubuffer, size_t len) {
+    auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
+    const char* name = name_string.c_str();
+
     char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
     if (!buffer) {
         SLOGE("Error allocating memory (%s)", strerror(errno));
@@ -163,8 +172,11 @@
     return 0;
 }
 
-int Devmapper::create(const char *name, const char *loopFile, const char *key,
+int Devmapper::create(const char *name_raw, const char *loopFile, const char *key,
                       unsigned long numSectors, char *ubuffer, size_t len) {
+    auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
+    const char* name = name_string.c_str();
+
     char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
     if (!buffer) {
         SLOGE("Error allocating memory (%s)", strerror(errno));
@@ -261,7 +273,10 @@
     return 0;
 }
 
-int Devmapper::destroy(const char *name) {
+int Devmapper::destroy(const char *name_raw) {
+    auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
+    const char* name = name_string.c_str();
+
     char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
     if (!buffer) {
         SLOGE("Error allocating memory (%s)", strerror(errno));
@@ -294,6 +309,74 @@
     return 0;
 }
 
+int Devmapper::destroyAll() {
+    char *buffer = (char *) malloc(1024 * 64);
+    if (!buffer) {
+        SLOGE("Error allocating memory (%s)", strerror(errno));
+        return -1;
+    }
+    memset(buffer, 0, (1024 * 64));
+
+    char *buffer2 = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
+    if (!buffer2) {
+        SLOGE("Error allocating memory (%s)", strerror(errno));
+        free(buffer);
+        return -1;
+    }
+
+    int fd;
+    if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
+        SLOGE("Error opening devmapper (%s)", strerror(errno));
+        free(buffer);
+        free(buffer2);
+        return -1;
+    }
+
+    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
+    ioctlInit(io, (1024 * 64), NULL, 0);
+
+    if (ioctl(fd, DM_LIST_DEVICES, io)) {
+        SLOGE("DM_LIST_DEVICES ioctl failed (%s)", strerror(errno));
+        free(buffer);
+        free(buffer2);
+        close(fd);
+        return -1;
+    }
+
+    struct dm_name_list *n = (struct dm_name_list *) (((char *) buffer) + io->data_start);
+    if (!n->dev) {
+        free(buffer);
+        free(buffer2);
+        close(fd);
+        return 0;
+    }
+
+    unsigned nxt = 0;
+    do {
+        n = (struct dm_name_list *) (((char *) n) + nxt);
+        if (strncmp(n->name, kVoldPrefix, strlen(kVoldPrefix)) == 0) {
+            LOG(DEBUG) << "Tearing down stale dm device named " << n->name;
+
+            memset(buffer2, 0, DEVMAPPER_BUFFER_SIZE);
+            struct dm_ioctl *io2 = (struct dm_ioctl *) buffer2;
+            ioctlInit(io2, DEVMAPPER_BUFFER_SIZE, n->name, 0);
+            if (ioctl(fd, DM_DEV_REMOVE, io2)) {
+                if (errno != ENXIO) {
+                    PLOG(WARNING) << "Failed to destroy dm device named " << n->name;
+                }
+            }
+        } else {
+            LOG(VERBOSE) << "Found unmanaged dm device named " << n->name;
+        }
+        nxt = n->next;
+    } while (nxt);
+
+    free(buffer);
+    free(buffer2);
+    close(fd);
+    return 0;
+}
+
 void *Devmapper::_align(void *ptr, unsigned int a)
 {
         unsigned long agn = --a;
diff --git a/Devmapper.h b/Devmapper.h
index 5b65b53..dcc39d8 100644
--- a/Devmapper.h
+++ b/Devmapper.h
@@ -27,6 +27,7 @@
     static int create(const char *name, const char *loopFile, const char *key,
                       unsigned long numSectors, char *buffer, size_t len);
     static int destroy(const char *name);
+    static int destroyAll();
     static int lookupActive(const char *name, char *buffer, size_t len);
     static int dumpState(SocketClient *c);
 
diff --git a/Loop.cpp b/Loop.cpp
index 6ec5e6d..325b0d3 100644
--- a/Loop.cpp
+++ b/Loop.cpp
@@ -45,6 +45,8 @@
 using android::base::StringPrintf;
 using android::base::unique_fd;
 
+static const char* kVoldPrefix = "vold:";
+
 int Loop::dumpState(SocketClient *c) {
     int i;
     int fd;
@@ -87,7 +89,10 @@
     return 0;
 }
 
-int Loop::lookupActive(const char *id, char *buffer, size_t len) {
+int Loop::lookupActive(const char *id_raw, char *buffer, size_t len) {
+    auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw);
+    const char* id = id_string.c_str();
+
     int i;
     int fd;
     char filename[256];
@@ -134,7 +139,10 @@
     return 0;
 }
 
-int Loop::create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len) {
+int Loop::create(const char *id_raw, const char *loopFile, char *loopDeviceBuffer, size_t len) {
+    auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw);
+    const char* id = id_string.c_str();
+
     int i;
     int fd;
     char filename[256];
@@ -267,6 +275,14 @@
         return -errno;
     }
 
+    struct loop_info64 li;
+    memset(&li, 0, sizeof(li));
+    strlcpy((char*) li.lo_crypt_name, kVoldPrefix, LO_NAME_SIZE);
+    if (ioctl(device_fd.get(), LOOP_SET_STATUS64, &li) == -1) {
+        PLOG(ERROR) << "Failed to LOOP_SET_STATUS64";
+        return -errno;
+    }
+
     return 0;
 }
 
@@ -289,9 +305,36 @@
     return 0;
 }
 
-int Loop::destroyByFile(const char * /*loopFile*/) {
-    errno = ENOSYS;
-    return -1;
+int Loop::destroyAll() {
+    for (int i = 0; i < LOOP_MAX; i++) {
+        auto path = StringPrintf("/dev/block/loop%d", i);
+
+        unique_fd fd(open(path.c_str(), O_RDWR | O_CLOEXEC));
+        if (fd.get() == -1) {
+            if (errno != ENOENT) {
+                PLOG(WARNING) << "Failed to open " << path;
+            }
+            continue;
+        }
+
+        struct loop_info64 li;
+        if (ioctl(fd.get(), LOOP_GET_STATUS64, &li) < 0) {
+            PLOG(WARNING) << "Failed to LOOP_GET_STATUS64 " << path;
+            continue;
+        }
+
+        char* id = (char*) li.lo_crypt_name;
+        if (strncmp(id, kVoldPrefix, strlen(kVoldPrefix)) == 0) {
+            LOG(DEBUG) << "Tearing down stale loop device at " << path << " named " << id;
+
+            if (ioctl(fd.get(), LOOP_CLR_FD, 0) < 0) {
+                PLOG(WARNING) << "Failed to LOOP_CLR_FD " << path;
+            }
+        } else {
+            LOG(VERBOSE) << "Found unmanaged loop device at " << path << " named " << id;
+        }
+    }
+    return 0;
 }
 
 int Loop::createImageFile(const char *file, unsigned long numSectors) {
diff --git a/Loop.h b/Loop.h
index 5d8f427..e3ad239 100644
--- a/Loop.h
+++ b/Loop.h
@@ -32,7 +32,7 @@
     static int create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len);
     static int create(const std::string& file, std::string& out_device);
     static int destroyByDevice(const char *loopDevice);
-    static int destroyByFile(const char *loopFile);
+    static int destroyAll();
     static int createImageFile(const char *file, unsigned long numSectors);
     static int resizeImageFile(const char *file, unsigned long numSectors);
 
diff --git a/MoveTask.h b/MoveTask.h
index b1777c0..cb184c3 100644
--- a/MoveTask.h
+++ b/MoveTask.h
@@ -18,7 +18,7 @@
 #define ANDROID_VOLD_MOVE_TASK_H
 
 #include "Utils.h"
-#include "VolumeBase.h"
+#include "model/VolumeBase.h"
 
 #include <thread>
 
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index f98c15d..3585e96 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -17,12 +17,14 @@
 #include "VoldNativeService.h"
 #include "VolumeManager.h"
 #include "MoveTask.h"
+#include "TrimTask.h"
 
 #include <fstream>
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <fs_mgr.h>
 #include <private/android_filesystem_config.h>
 
 #ifndef LOG_TAG
@@ -56,7 +58,7 @@
     if (status == 0) {
         return binder::Status::ok();
     } else {
-        return binder::Status::fromExceptionCode(status);
+        return binder::Status::fromServiceSpecificError(status);
     }
 }
 
@@ -134,11 +136,14 @@
     return translate(VolumeManager::Instance()->shutdown());
 }
 
-binder::Status VoldNativeService::setDebug(bool debug) {
+binder::Status VoldNativeService::mountAll() {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
 
-    return translate(VolumeManager::Instance()->setDebug(debug));
+    struct fstab* fstab = fs_mgr_read_fstab_default();
+    int res = fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
+    fs_mgr_free_fstab(fstab);
+    return translate(res);
 }
 
 binder::Status VoldNativeService::onUserAdded(int32_t userId, int32_t userSerial) {
@@ -169,7 +174,8 @@
     return translate(VolumeManager::Instance()->onUserStopped(userId));
 }
 
-binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType, int32_t ratio) {
+binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType,
+        int32_t ratio) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
 
@@ -192,7 +198,8 @@
     return translate(VolumeManager::Instance()->forgetPartition(partGuid));
 }
 
-binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId) {
+binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags,
+        int32_t mountUserId) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
 
@@ -241,7 +248,8 @@
     return ok();
 }
 
-binder::Status VoldNativeService::moveStorage(const std::string& fromVolId, const std::string& toVolId) {
+binder::Status VoldNativeService::moveStorage(const std::string& fromVolId,
+        const std::string& toVolId) {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
 
@@ -278,5 +286,44 @@
     return translate(VolumeManager::Instance()->mkdirs(path.c_str()));
 }
 
+binder::Status VoldNativeService::createObb(const std::string& sourcePath,
+        const std::string& sourceKey, int32_t ownerGid, std::string* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    ACQUIRE_LOCK;
+
+    return translate(
+            VolumeManager::Instance()->createObb(sourcePath, sourceKey, ownerGid, _aidl_return));
+}
+
+binder::Status VoldNativeService::destroyObb(const std::string& volId) {
+    ENFORCE_UID(AID_SYSTEM);
+    ACQUIRE_LOCK;
+
+    return translate(VolumeManager::Instance()->destroyObb(volId));
+}
+
+binder::Status VoldNativeService::fstrim(int32_t fstrimFlags) {
+    ENFORCE_UID(AID_SYSTEM);
+    ACQUIRE_LOCK;
+
+    (new android::vold::TrimTask(fstrimFlags))->start();
+    return ok();
+}
+
+binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t pid, int32_t mountId,
+        android::base::unique_fd* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    ACQUIRE_LOCK;
+
+    return translate(VolumeManager::Instance()->mountAppFuse(uid, pid, mountId, _aidl_return));
+}
+
+binder::Status VoldNativeService::unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId) {
+    ENFORCE_UID(AID_SYSTEM);
+    ACQUIRE_LOCK;
+
+    return translate(VolumeManager::Instance()->unmountAppFuse(uid, pid, mountId));
+}
+
 }  // namespace vold
 }  // namespace android
diff --git a/VoldNativeService.h b/VoldNativeService.h
index d3bce67..f412bfc 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -17,6 +17,7 @@
 #ifndef _VOLD_NATIVE_SERVICE_H_
 #define _VOLD_NATIVE_SERVICE_H_
 
+#include <android-base/unique_fd.h>
 #include <binder/BinderService.h>
 
 #include "android/os/BnVold.h"
@@ -32,8 +33,7 @@
 
     binder::Status reset();
     binder::Status shutdown();
-
-    binder::Status setDebug(bool debug);
+    binder::Status mountAll();
 
     binder::Status onUserAdded(int32_t userId, int32_t userSerial);
     binder::Status onUserRemoved(int32_t userId);
@@ -53,6 +53,16 @@
     binder::Status remountUid(int32_t uid, int32_t remountMode);
 
     binder::Status mkdirs(const std::string& path);
+
+    binder::Status createObb(const std::string& sourcePath, const std::string& sourceKey,
+            int32_t ownerGid, std::string* _aidl_return);
+    binder::Status destroyObb(const std::string& volId);
+
+    binder::Status fstrim(int32_t fstrimFlags);
+
+    binder::Status mountAppFuse(int32_t uid, int32_t pid, int32_t mountId,
+            android::base::unique_fd* _aidl_return);
+    binder::Status unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId);
 };
 
 }  // namespace vold
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index ddf06eb..022caff 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -48,7 +48,8 @@
 #include <private/android_filesystem_config.h>
 
 #include "Benchmark.h"
-#include "EmulatedVolume.h"
+#include "model/EmulatedVolume.h"
+#include "model/ObbVolume.h"
 #include "VolumeManager.h"
 #include "NetlinkManager.h"
 #include "ResponseCode.h"
@@ -68,6 +69,7 @@
                                          + ((number) & (~((1U << (po2)) - 1))))
 
 using android::base::StringPrintf;
+using android::base::unique_fd;
 
 /*
  * Path to external storage where *only* root can access ASEC image files
@@ -220,6 +222,7 @@
     mSavedDirtyRatio = -1;
     // set dirty ratio to 0 when UMS is active
     mUmsDirtyRatio = 0;
+    mNextObbId = 0;
 }
 
 VolumeManager::~VolumeManager() {
@@ -317,6 +320,9 @@
     // directories that we own, in case we crashed.
     unmountAll();
 
+    Devmapper::destroyAll();
+    Loop::destroyAll();
+
     // Assume that we always have an emulated volume on internal
     // storage; the framework will decide if it should be mounted.
     CHECK(mInternalEmulated == nullptr);
@@ -437,6 +443,11 @@
             return vol;
         }
     }
+    for (const auto& vol : mObbVolumes) {
+        if (vol->getId() == id) {
+            return vol;
+        }
+    }
     return nullptr;
 }
 
@@ -754,7 +765,7 @@
     endmntent(fp);
 
     for (const auto& path : toUnmount) {
-        SLOGW("Tearing down stale mount %s", path.c_str());
+        LOG(DEBUG) << "Tearing down stale mount " << path;
         android::vold::ForceUnmount(path);
     }
 
@@ -1962,3 +1973,223 @@
         return -EINVAL;
     }
 }
+
+static size_t kAppFuseMaxMountPointName = 32;
+
+static android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) {
+    if (name.size() > kAppFuseMaxMountPointName) {
+        LOG(ERROR) << "AppFuse mount name is too long.";
+        return -EINVAL;
+    }
+    for (size_t i = 0; i < name.size(); i++) {
+        if (!isalnum(name[i])) {
+            LOG(ERROR) << "AppFuse mount name contains invalid character.";
+            return -EINVAL;
+        }
+    }
+    *path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str());
+    return android::OK;
+}
+
+static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
+    // Remove existing mount.
+    android::vold::ForceUnmount(path);
+
+    const auto opts = android::base::StringPrintf(
+            "fd=%i,"
+            "rootmode=40000,"
+            "default_permissions,"
+            "allow_other,"
+            "user_id=%d,group_id=%d,"
+            "context=\"u:object_r:app_fuse_file:s0\","
+            "fscontext=u:object_r:app_fusefs:s0",
+            device_fd,
+            uid,
+            uid);
+
+    const int result = TEMP_FAILURE_RETRY(mount(
+            "/dev/fuse", path.c_str(), "fuse",
+            MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()));
+    if (result != 0) {
+        PLOG(ERROR) << "Failed to mount " << path;
+        return -errno;
+    }
+
+    return android::OK;
+}
+
+static android::status_t runCommandInNamespace(const std::string& command,
+                                               uid_t uid,
+                                               pid_t pid,
+                                               const std::string& path,
+                                               int device_fd) {
+    if (DEBUG_APPFUSE) {
+        LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path
+                   << " in namespace " << uid;
+    }
+
+    unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+    if (dir.get() == -1) {
+        PLOG(ERROR) << "Failed to open /proc";
+        return -errno;
+    }
+
+    // Obtains process file descriptor.
+    const std::string pid_str = android::base::StringPrintf("%d", pid);
+    const unique_fd pid_fd(
+            openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+    if (pid_fd.get() == -1) {
+        PLOG(ERROR) << "Failed to open /proc/" << pid;
+        return -errno;
+    }
+
+    // Check UID of process.
+    {
+        struct stat sb;
+        const int result = fstat(pid_fd.get(), &sb);
+        if (result == -1) {
+            PLOG(ERROR) << "Failed to stat /proc/" << pid;
+            return -errno;
+        }
+        if (sb.st_uid != AID_SYSTEM) {
+            LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM
+                    << ", actual=" << sb.st_uid;
+            return -EPERM;
+        }
+    }
+
+    // Matches so far, but refuse to touch if in root namespace
+    {
+        char rootName[PATH_MAX];
+        char pidName[PATH_MAX];
+        const int root_result =
+                android::vold::SaneReadLinkAt(dir.get(), "1/ns/mnt", rootName, PATH_MAX);
+        const int pid_result =
+                android::vold::SaneReadLinkAt(pid_fd.get(), "ns/mnt", pidName, PATH_MAX);
+        if (root_result == -1) {
+            LOG(ERROR) << "Failed to readlink for /proc/1/ns/mnt";
+            return -EPERM;
+        }
+        if (pid_result == -1) {
+            LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt";
+            return -EPERM;
+        }
+        if (!strcmp(rootName, pidName)) {
+            LOG(ERROR) << "Don't mount appfuse in root namespace";
+            return -EPERM;
+        }
+    }
+
+    // We purposefully leave the namespace open across the fork
+    unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC
+    if (ns_fd.get() < 0) {
+        PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt";
+        return -errno;
+    }
+
+    int child = fork();
+    if (child == 0) {
+        if (setns(ns_fd.get(), CLONE_NEWNS) != 0) {
+            PLOG(ERROR) << "Failed to setns";
+            _exit(-errno);
+        }
+
+        if (command == "mount") {
+            _exit(mountInNamespace(uid, device_fd, path));
+        } else if (command == "unmount") {
+            // If it's just after all FD opened on mount point are closed, umount2 can fail with
+            // EBUSY. To avoid the case, specify MNT_DETACH.
+            if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 &&
+                    errno != EINVAL && errno != ENOENT) {
+                PLOG(ERROR) << "Failed to unmount directory.";
+                _exit(-errno);
+            }
+            if (rmdir(path.c_str()) != 0) {
+                PLOG(ERROR) << "Failed to remove the mount directory.";
+                _exit(-errno);
+            }
+            _exit(android::OK);
+        } else {
+            LOG(ERROR) << "Unknown appfuse command " << command;
+            _exit(-EPERM);
+        }
+    }
+
+    if (child == -1) {
+        PLOG(ERROR) << "Failed to folk child process";
+        return -errno;
+    }
+
+    android::status_t status;
+    TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
+
+    return status;
+}
+
+int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,
+        int32_t ownerGid, std::string* outVolId) {
+    int id = mNextObbId++;
+
+    auto vol = std::shared_ptr<android::vold::VolumeBase>(
+            new android::vold::ObbVolume(id, sourcePath, sourceKey, ownerGid));
+    vol->create();
+
+    mObbVolumes.push_back(vol);
+    *outVolId = vol->getId();
+    return android::OK;
+}
+
+int VolumeManager::destroyObb(const std::string& volId) {
+    auto i = mObbVolumes.begin();
+    while (i != mObbVolumes.end()) {
+        if ((*i)->getId() == volId) {
+            (*i)->destroy();
+            i = mObbVolumes.erase(i);
+        } else {
+            ++i;
+        }
+    }
+    return android::OK;
+}
+
+int VolumeManager::mountAppFuse(uid_t uid, pid_t pid, int mountId,
+        android::base::unique_fd* device_fd) {
+    std::string name = std::to_string(mountId);
+
+    // Check mount point name.
+    std::string path;
+    if (getMountPath(uid, name, &path) != android::OK) {
+        LOG(ERROR) << "Invalid mount point name";
+        return -1;
+    }
+
+    // Create directories.
+    const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0);
+    if (result != android::OK) {
+        PLOG(ERROR) << "Failed to prepare directory " << path;
+        return -1;
+    }
+
+    // Open device FD.
+    device_fd->reset(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC
+    if (device_fd->get() == -1) {
+        PLOG(ERROR) << "Failed to open /dev/fuse";
+        return -1;
+    }
+
+    // Mount.
+    return runCommandInNamespace("mount", uid, pid, path, device_fd->get());
+}
+
+int VolumeManager::unmountAppFuse(uid_t uid, pid_t pid, int mountId) {
+    std::string name = std::to_string(mountId);
+
+    // Check mount point name.
+    std::string path;
+    if (getMountPath(uid, name, &path) != android::OK) {
+        LOG(ERROR) << "Invalid mount point name";
+        return -1;
+    }
+
+    return runCommandInNamespace("unmount", uid, pid, path, -1 /* device_fd */);
+}
diff --git a/VolumeManager.h b/VolumeManager.h
index 72c470a..097ce6a 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -29,18 +29,21 @@
 #include <unordered_map>
 #include <unordered_set>
 
+#include <android-base/unique_fd.h>
 #include <cutils/multiuser.h>
 #include <utils/List.h>
 #include <utils/Timers.h>
 #include <sysutils/SocketListener.h>
 #include <sysutils/NetlinkEvent.h>
 
-#include "Disk.h"
-#include "VolumeBase.h"
+#include "model/Disk.h"
+#include "model/VolumeBase.h"
 
 /* The length of an MD5 hash when encoded into ASCII hex characters */
 #define MD5_ASCII_LENGTH_PLUS_NULL ((MD5_DIGEST_LENGTH*2)+1)
 
+#define DEBUG_APPFUSE 0
+
 typedef enum { ASEC, OBB } container_type_t;
 
 class ContainerData {
@@ -198,6 +201,13 @@
      */
     int mkdirs(const char* path);
 
+    int createObb(const std::string& path, const std::string& key, int32_t ownerGid,
+            std::string* outVolId);
+    int destroyObb(const std::string& volId);
+
+    int mountAppFuse(uid_t uid, pid_t pid, int mountId, android::base::unique_fd* device_fd);
+    int unmountAppFuse(uid_t uid, pid_t pid, int mountId);
+
 private:
     VolumeManager();
     void readInitialState();
@@ -211,6 +221,7 @@
 
     std::list<std::shared_ptr<DiskSource>> mDiskSources;
     std::list<std::shared_ptr<android::vold::Disk>> mDisks;
+    std::list<std::shared_ptr<android::vold::VolumeBase>> mObbVolumes;
 
     std::unordered_map<userid_t, int> mAddedUsers;
     std::unordered_set<userid_t> mStartedUsers;
@@ -219,6 +230,8 @@
     std::shared_ptr<android::vold::Disk> mVirtualDisk;
     std::shared_ptr<android::vold::VolumeBase> mInternalEmulated;
     std::shared_ptr<android::vold::VolumeBase> mPrimary;
+
+    int mNextObbId;
 };
 
 extern "C" {
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index 43d88bc..d945357 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -20,8 +20,7 @@
 interface IVold {
     void reset();
     void shutdown();
-
-    void setDebug(boolean debug);
+    void mountAll();
 
     void onUserAdded(int userId, int userSerial);
     void onUserRemoved(int userId);
@@ -42,6 +41,18 @@
 
     void mkdirs(@utf8InCpp String path);
 
+    @utf8InCpp String createObb(@utf8InCpp String sourcePath,
+            @utf8InCpp String sourceKey, int ownerGid);
+    void destroyObb(@utf8InCpp String volId);
+
+    void fstrim(int fstrimFlags);
+
+    FileDescriptor mountAppFuse(int uid, int pid, int mountId);
+    void unmountAppFuse(int uid, int pid, int mountId);
+
+    const int FSTRIM_FLAG_DEEP_TRIM = 1;
+    const int FSTRIM_FLAG_BENCHMARK_AFTER = 2;
+
     const int MOUNT_FLAG_PRIMARY = 1;
     const int MOUNT_FLAG_VISIBLE = 2;
 
diff --git a/main.cpp b/main.cpp
index ec240ef..8175dc5 100644
--- a/main.cpp
+++ b/main.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "Disk.h"
+#include "model/Disk.h"
 #include "VolumeManager.h"
 #include "CommandListener.h"
 #include "CryptCommandListener.h"
diff --git a/Disk.cpp b/model/Disk.cpp
similarity index 100%
rename from Disk.cpp
rename to model/Disk.cpp
diff --git a/Disk.h b/model/Disk.h
similarity index 100%
rename from Disk.h
rename to model/Disk.h
diff --git a/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
similarity index 100%
rename from EmulatedVolume.cpp
rename to model/EmulatedVolume.cpp
diff --git a/EmulatedVolume.h b/model/EmulatedVolume.h
similarity index 100%
rename from EmulatedVolume.h
rename to model/EmulatedVolume.h
diff --git a/model/ObbVolume.cpp b/model/ObbVolume.cpp
new file mode 100644
index 0000000..709c7a3
--- /dev/null
+++ b/model/ObbVolume.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fs/Vfat.h"
+#include "Devmapper.h"
+#include "Loop.h"
+#include "ObbVolume.h"
+#include "Utils.h"
+#include "VoldUtil.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <cutils/fs.h>
+#include <private/android_filesystem_config.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/wait.h>
+
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+namespace android {
+namespace vold {
+
+ObbVolume::ObbVolume(int id, const std::string& sourcePath, const std::string& sourceKey,
+        gid_t ownerGid) : VolumeBase(Type::kObb) {
+    setId(StringPrintf("obb:%d", id));
+    mSourcePath = sourcePath;
+    mSourceKey = sourceKey;
+    mOwnerGid = ownerGid;
+}
+
+ObbVolume::~ObbVolume() {
+}
+
+status_t ObbVolume::doCreate() {
+    if (Loop::create(mSourcePath, mLoopPath)) {
+        PLOG(ERROR) << getId() << " failed to create loop";
+        return -1;
+    }
+
+    if (!mSourceKey.empty()) {
+        unsigned long nr_sec = 0;
+        {
+            unique_fd loop_fd(open(mLoopPath.c_str(), O_RDWR | O_CLOEXEC));
+            if (loop_fd.get() == -1) {
+                PLOG(ERROR) << getId() << " failed to open loop";
+                return -1;
+            }
+
+            get_blkdev_size(loop_fd.get(), &nr_sec);
+            if (nr_sec == 0) {
+                PLOG(ERROR) << getId() << " failed to get loop size";
+                return -1;
+            }
+        }
+
+        char tmp[PATH_MAX];
+        if (Devmapper::create(getId().c_str(), mLoopPath.c_str(), mSourceKey.c_str(), nr_sec,
+                tmp, PATH_MAX)) {
+            PLOG(ERROR) << getId() << " failed to create dm";
+            return -1;
+        }
+        mDmPath = tmp;
+        mMountPath = mDmPath;
+    } else {
+        mMountPath = mLoopPath;
+    }
+    return OK;
+}
+
+status_t ObbVolume::doDestroy() {
+    if (!mDmPath.empty() && Devmapper::destroy(getId().c_str())) {
+        PLOG(WARNING) << getId() << " failed to destroy dm";
+    }
+    if (!mLoopPath.empty() && Loop::destroyByDevice(mLoopPath.c_str())) {
+        PLOG(WARNING) << getId() << " failed to destroy loop";
+    }
+    mDmPath.clear();
+    mLoopPath.clear();
+    return OK;
+}
+
+status_t ObbVolume::doMount() {
+    auto path = StringPrintf("/mnt/obb/%s", getId().c_str());
+    setPath(path);
+
+    if (fs_prepare_dir(path.c_str(), 0700, AID_ROOT, AID_ROOT)) {
+        PLOG(ERROR) << getId() << " failed to create mount point";
+        return -1;
+    }
+    if (android::vold::vfat::Mount(mMountPath, path,
+            true, false, true, 0, mOwnerGid, 0227, false)) {
+        PLOG(ERROR) << getId() << " failed to mount";
+        return -1;
+    }
+    return OK;
+}
+
+status_t ObbVolume::doUnmount() {
+    auto path = getPath();
+
+    KillProcessesUsingPath(path);
+    ForceUnmount(path);
+    rmdir(path.c_str());
+
+    return OK;
+}
+
+}  // namespace vold
+}  // namespace android
diff --git a/model/ObbVolume.h b/model/ObbVolume.h
new file mode 100644
index 0000000..5ec0cde
--- /dev/null
+++ b/model/ObbVolume.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VOLD_OBB_VOLUME_H
+#define ANDROID_VOLD_OBB_VOLUME_H
+
+#include "VolumeBase.h"
+
+#include <cutils/multiuser.h>
+
+namespace android {
+namespace vold {
+
+/*
+ * OBB container.
+ */
+class ObbVolume : public VolumeBase {
+public:
+    ObbVolume(int id, const std::string& sourcePath, const std::string& sourceKey,
+            gid_t ownerGid);
+    virtual ~ObbVolume();
+
+protected:
+    status_t doCreate() override;
+    status_t doDestroy() override;
+    status_t doMount() override;
+    status_t doUnmount() override;
+
+private:
+    std::string mSourcePath;
+    std::string mSourceKey;
+    gid_t mOwnerGid;
+
+    std::string mLoopPath;
+    std::string mDmPath;
+    std::string mMountPath;
+
+    DISALLOW_COPY_AND_ASSIGN(ObbVolume);
+};
+
+}  // namespace vold
+}  // namespace android
+
+#endif
diff --git a/PrivateVolume.cpp b/model/PrivateVolume.cpp
similarity index 100%
rename from PrivateVolume.cpp
rename to model/PrivateVolume.cpp
diff --git a/PrivateVolume.h b/model/PrivateVolume.h
similarity index 100%
rename from PrivateVolume.h
rename to model/PrivateVolume.h
diff --git a/PublicVolume.cpp b/model/PublicVolume.cpp
similarity index 100%
rename from PublicVolume.cpp
rename to model/PublicVolume.cpp
diff --git a/PublicVolume.h b/model/PublicVolume.h
similarity index 100%
rename from PublicVolume.h
rename to model/PublicVolume.h
diff --git a/VolumeBase.cpp b/model/VolumeBase.cpp
similarity index 100%
rename from VolumeBase.cpp
rename to model/VolumeBase.cpp
diff --git a/VolumeBase.h b/model/VolumeBase.h
similarity index 100%
rename from VolumeBase.h
rename to model/VolumeBase.h
diff --git a/tests/Android.mk b/tests/Android.mk
index 4b6573e..9cebd1a 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -5,9 +5,10 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_C_INCLUDES := \
-    system/core/fs_mgr/include
+    system/core/fs_mgr/include \
+    system/vold/
 
-LOCAL_STATIC_LIBRARIES := libselinux libvold liblog libcrypto
+LOCAL_STATIC_LIBRARIES := libbase libselinux libvold liblog libcrypto
 
 LOCAL_SRC_FILES := VolumeManager_test.cpp
 LOCAL_MODULE := vold_tests