Support for private (adopted) volumes.

This adds support for private volumes which is just a filesystem
wrapped in a dm-crypt layer.  For now we're using the exact same
configuration as internal encryption (aes-cbc-essiv:sha256), but we
don't store any key material on the removable media.  Instead, we
store the key on internal storage, and use the GPT partition GUID
to identify which key should be used.

This means that private external storage is effectively as secure as
the internal storage of the device.  That is, if the internal storage
is encrypted, then our external storage key is also encrypted.

When partitioning disks, we now support a "private" mode which has
a PrivateVolume partition, and a currently unused 16MB metadata
partition reserved for future use.  It also supports a "mixed" mode
which creates both a PublicVolume and PrivateVolume on the same
disk.  Mixed mode is currently experimental.

For now, just add ext4 support to PrivateVolume; we'll look at f2fs
in a future change.  Add VolumeBase lifecycle for setting up crypto
mappings, and extract blkid logic into shared method.  Sprinkle some
more "static" around the cryptfs code to improve invariants.

Bug: 19993667
Change-Id: Ibd1df6250735b706959a1eb9d9f7219ea85912a0
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 0404ce7..5296114 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -243,30 +243,7 @@
 int VolumeManager::start() {
     // Always start from a clean slate by unmounting everything in
     // directories that we own, in case we crashed.
-    FILE* fp = setmntent("/proc/mounts", "r");
-    if (fp == NULL) {
-        SLOGE("Error opening /proc/mounts: %s", strerror(errno));
-        return -errno;
-    }
-
-    // Some volumes can be stacked on each other, so force unmount in
-    // reverse order to give us the best chance of success.
-    std::list<std::string> toUnmount;
-    mntent* mentry;
-    while ((mentry = getmntent(fp)) != NULL) {
-        if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0
-                || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {
-            toUnmount.push_front(std::string(mentry->mnt_dir));
-        }
-    }
-    endmntent(fp);
-
-    for (auto path : toUnmount) {
-        SLOGW("Tearing down stale mount %s", path.c_str());
-        android::vold::ForceUnmount(path);
-    }
-
-    // TODO: nuke all files under mnt and storage tmpfs too?
+    unmountAll();
 
     // Assume that we always have an emulated volume on internal
     // storage; the framework will decide if it should be mounted.
@@ -440,6 +417,7 @@
 }
 
 int VolumeManager::shutdown() {
+    mInternalEmulated->destroy();
     for (auto disk : mDisks) {
         disk->destroy();
     }
@@ -447,6 +425,43 @@
     return 0;
 }
 
+int VolumeManager::unmountAll() {
+    // First, try gracefully unmounting all known devices
+    if (mInternalEmulated != nullptr) {
+        mInternalEmulated->unmount();
+    }
+    for (auto disk : mDisks) {
+        disk->unmountAll();
+    }
+
+    // Worst case we might have some stale mounts lurking around, so
+    // force unmount those just to be safe.
+    FILE* fp = setmntent("/proc/mounts", "r");
+    if (fp == NULL) {
+        SLOGE("Error opening /proc/mounts: %s", strerror(errno));
+        return -errno;
+    }
+
+    // Some volumes can be stacked on each other, so force unmount in
+    // reverse order to give us the best chance of success.
+    std::list<std::string> toUnmount;
+    mntent* mentry;
+    while ((mentry = getmntent(fp)) != NULL) {
+        if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0
+                || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {
+            toUnmount.push_front(std::string(mentry->mnt_dir));
+        }
+    }
+    endmntent(fp);
+
+    for (auto path : toUnmount) {
+        SLOGW("Tearing down stale mount %s", path.c_str());
+        android::vold::ForceUnmount(path);
+    }
+
+    return 0;
+}
+
 int VolumeManager::listVolumes(SocketClient *cli, bool broadcast) {
     VolumeCollection::iterator i;
     char msg[256];
@@ -1831,35 +1846,6 @@
     return 0;
 }
 
-extern "C" int vold_disableVol(const char *label) {
-    VolumeManager *vm = VolumeManager::Instance();
-    vm->disableVolumeManager();
-    vm->unshareVolume(label, "ums");
-    return vm->unmountVolume(label, true, false);
-}
-
-extern "C" int vold_getNumDirectVolumes(void) {
-    VolumeManager *vm = VolumeManager::Instance();
-    return vm->getNumDirectVolumes();
-}
-
-int VolumeManager::getNumDirectVolumes(void) {
-    VolumeCollection::iterator i;
-    int n=0;
-
-    for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
-        if ((*i)->getShareDevice() != (dev_t)0) {
-            n++;
-        }
-    }
-    return n;
-}
-
-extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
-    VolumeManager *vm = VolumeManager::Instance();
-    return vm->getDirectVolumeList(vol_list);
-}
-
 int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
     VolumeCollection::iterator i;
     int n=0;
@@ -1902,15 +1888,9 @@
     return v->unmountVol(force, revert);
 }
 
-extern "C" int vold_unmountAllAsecs(void) {
-    int rc;
-
+extern "C" int vold_unmountAll(void) {
     VolumeManager *vm = VolumeManager::Instance();
-    rc = vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
-    if (vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_INT)) {
-        rc = -1;
-    }
-    return rc;
+    return vm->unmountAll();
 }
 
 #define ID_BUF_LEN 256