StubVolume as first class Volume in Vold

StubVolume is a Volume that is maintained by external party such as the
ChromeOS processes in ARC++.

Bug: 110380403
Test: Tested on ARC++

Change-Id: I3198bd7283d5f60a524da3707dea7385ffec599d
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index f5eea7e..1fb7ce7 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -63,6 +63,7 @@
 #include "fs/Vfat.h"
 #include "model/EmulatedVolume.h"
 #include "model/ObbVolume.h"
+#include "model/StubVolume.h"
 
 using android::base::StartsWith;
 using android::base::StringPrintf;
@@ -90,6 +91,7 @@
 VolumeManager::VolumeManager() {
     mDebug = false;
     mNextObbId = 0;
+    mNextStubVolumeId = 0;
     // For security reasons, assume that a secure keyguard is
     // showing until we hear otherwise
     mSecureKeyguardShowing = true;
@@ -303,6 +305,11 @@
             return vol;
         }
     }
+    for (const auto& vol : mStubVolumes) {
+        if (vol->getId() == id) {
+            return vol;
+        }
+    }
     for (const auto& vol : mObbVolumes) {
         if (vol->getId() == id) {
             return vol;
@@ -558,6 +565,7 @@
     for (const auto& disk : mDisks) {
         disk->destroy();
     }
+    mStubVolumes.clear();
     mDisks.clear();
     mPendingDisks.clear();
     android::vold::sSleepOnUnmount = true;
@@ -572,6 +580,9 @@
     if (mInternalEmulated != nullptr) {
         mInternalEmulated->unmount();
     }
+    for (const auto& stub : mStubVolumes) {
+        stub->unmount();
+    }
     for (const auto& disk : mDisks) {
         disk->unmountAll();
     }
@@ -785,6 +796,32 @@
     return android::OK;
 }
 
+int VolumeManager::createStubVolume(const std::string& sourcePath, const std::string& mountPath,
+                                    const std::string& fsType, const std::string& fsUuid,
+                                    const std::string& fsLabel, std::string* outVolId) {
+    int id = mNextStubVolumeId++;
+    auto vol = std::shared_ptr<android::vold::VolumeBase>(
+        new android::vold::StubVolume(id, sourcePath, mountPath, fsType, fsUuid, fsLabel));
+    vol->create();
+
+    mStubVolumes.push_back(vol);
+    *outVolId = vol->getId();
+    return android::OK;
+}
+
+int VolumeManager::destroyStubVolume(const std::string& volId) {
+    auto i = mStubVolumes.begin();
+    while (i != mStubVolumes.end()) {
+        if ((*i)->getId() == volId) {
+            (*i)->destroy();
+            i = mStubVolumes.erase(i);
+        } else {
+            ++i;
+        }
+    }
+    return android::OK;
+}
+
 int VolumeManager::mountAppFuse(uid_t uid, pid_t pid, int mountId, unique_fd* device_fd) {
     std::string name = std::to_string(mountId);