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/Android.bp b/Android.bp
index 8f2ba34..44e2317 100644
--- a/Android.bp
+++ b/Android.bp
@@ -129,6 +129,7 @@
         "model/PrivateVolume.cpp",
         "model/PublicVolume.cpp",
         "model/VolumeBase.cpp",
+        "model/StubVolume.cpp",
         "secontext.cpp",
     ],
     product_variables: {
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index 5987849..a06b357 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -479,6 +479,29 @@
     return translate(VolumeManager::Instance()->destroyObb(volId));
 }
 
+binder::Status VoldNativeService::createStubVolume(
+    const std::string& sourcePath, const std::string& mountPath, const std::string& fsType,
+    const std::string& fsUuid, const std::string& fsLabel, std::string* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(sourcePath);
+    CHECK_ARGUMENT_PATH(mountPath);
+    CHECK_ARGUMENT_HEX(fsUuid);
+    // Label limitation seems to be different between fs (including allowed characters), so checking
+    // is quite meaningless.
+    ACQUIRE_LOCK;
+
+    return translate(VolumeManager::Instance()->createStubVolume(sourcePath, mountPath, fsType,
+                                                                 fsUuid, fsLabel, _aidl_return));
+}
+
+binder::Status VoldNativeService::destroyStubVolume(const std::string& volId) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_ID(volId);
+    ACQUIRE_LOCK;
+
+    return translate(VolumeManager::Instance()->destroyStubVolume(volId));
+}
+
 binder::Status VoldNativeService::fstrim(
     int32_t fstrimFlags, const android::sp<android::os::IVoldTaskListener>& listener) {
     ENFORCE_UID(AID_SYSTEM);
diff --git a/VoldNativeService.h b/VoldNativeService.h
index 40ce3a4..a02fa70 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -65,6 +65,11 @@
                              int32_t ownerGid, std::string* _aidl_return);
     binder::Status destroyObb(const std::string& volId);
 
+    binder::Status createStubVolume(const std::string& sourcePath, const std::string& mountPath,
+                                    const std::string& fsType, const std::string& fsUuid,
+                                    const std::string& fsLabel, std::string* _aidl_return);
+    binder::Status destroyStubVolume(const std::string& volId);
+
     binder::Status fstrim(int32_t fstrimFlags,
                           const android::sp<android::os::IVoldTaskListener>& listener);
     binder::Status runIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
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);
 
diff --git a/VolumeManager.h b/VolumeManager.h
index eedb1cb..2f76ddc 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -124,6 +124,11 @@
                   std::string* outVolId);
     int destroyObb(const std::string& volId);
 
+    int 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 destroyStubVolume(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);
 
@@ -146,6 +151,7 @@
     std::list<std::shared_ptr<android::vold::Disk>> mDisks;
     std::list<std::shared_ptr<android::vold::Disk>> mPendingDisks;
     std::list<std::shared_ptr<android::vold::VolumeBase>> mObbVolumes;
+    std::list<std::shared_ptr<android::vold::VolumeBase>> mStubVolumes;
 
     std::unordered_map<userid_t, int> mAddedUsers;
     std::unordered_set<userid_t> mStartedUsers;
@@ -156,6 +162,7 @@
     std::shared_ptr<android::vold::VolumeBase> mPrimary;
 
     int mNextObbId;
+    int mNextStubVolumeId;
     bool mSecureKeyguardShowing;
 };
 
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index 4ed861f..ea98450 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -105,6 +105,11 @@
     void restoreCheckpoint(@utf8InCpp String device);
     void markBootAttempt();
 
+    @utf8InCpp String createStubVolume(@utf8InCpp String sourcePath,
+            @utf8InCpp String mountPath, @utf8InCpp String fsType,
+            @utf8InCpp String fsUuid, @utf8InCpp String fsLabel);
+    void destroyStubVolume(@utf8InCpp String volId);
+
     const int ENCRYPTION_FLAG_NO_UI = 4;
 
     const int ENCRYPTION_STATE_NONE = 1;
@@ -151,4 +156,5 @@
     const int VOLUME_TYPE_EMULATED = 2;
     const int VOLUME_TYPE_ASEC = 3;
     const int VOLUME_TYPE_OBB = 4;
+    const int VOLUME_TYPE_STUB = 5;
 }
diff --git a/model/StubVolume.cpp b/model/StubVolume.cpp
new file mode 100644
index 0000000..edd0861
--- /dev/null
+++ b/model/StubVolume.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 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 "StubVolume.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace vold {
+
+StubVolume::StubVolume(int id, const std::string& sourcePath, const std::string& mountPath,
+                       const std::string& fsType, const std::string& fsUuid,
+                       const std::string& fsLabel)
+    : VolumeBase(Type::kStub),
+      mSourcePath(sourcePath),
+      mMountPath(mountPath),
+      mFsType(fsType),
+      mFsUuid(fsUuid),
+      mFsLabel(fsLabel) {
+    setId(StringPrintf("stub:%d", id));
+}
+
+StubVolume::~StubVolume() {}
+
+status_t StubVolume::doCreate() {
+    return OK;
+}
+
+status_t StubVolume::doDestroy() {
+    return OK;
+}
+
+status_t StubVolume::doMount() {
+    auto listener = getListener();
+    if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
+    setInternalPath(mSourcePath);
+    setPath(mMountPath);
+    return OK;
+}
+
+status_t StubVolume::doUnmount() {
+    return OK;
+}
+
+// TODO: return error instead.
+status_t StubVolume::doFormat(const std::string& fsType) {
+    return OK;
+}
+
+}  // namespace vold
+}  // namespace android
diff --git a/model/StubVolume.h b/model/StubVolume.h
new file mode 100644
index 0000000..538cae9
--- /dev/null
+++ b/model/StubVolume.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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_STUB_VOLUME_H
+#define ANDROID_VOLD_STUB_VOLUME_H
+
+#include "VolumeBase.h"
+
+namespace android {
+namespace vold {
+
+/*
+ * A vold representation of volumes managed from outside Android (e.g., ARC++).
+ *
+ * Used for the case when events such that mounting and unmounting are
+ * actually handled from outside vold, and vold only need to keep track on those
+ * vents instead of talking to kernel directly.
+ */
+class StubVolume : public VolumeBase {
+  public:
+    StubVolume(int id, const std::string& sourcePath, const std::string& mountPath,
+               const std::string& fsType, const std::string& fsUuid, const std::string& fsLabel);
+    virtual ~StubVolume();
+
+  protected:
+    status_t doCreate() override;
+    status_t doDestroy() override;
+    status_t doMount() override;
+    status_t doUnmount() override;
+    status_t doFormat(const std::string& fsType) override;
+
+  private:
+    const std::string mSourcePath;
+    const std::string mMountPath;
+    const std::string mFsType;
+    const std::string mFsUuid;
+    const std::string mFsLabel;
+
+    DISALLOW_COPY_AND_ASSIGN(StubVolume);
+};
+
+}  // namespace vold
+}  // namespace android
+
+#endif
diff --git a/model/VolumeBase.h b/model/VolumeBase.h
index 6532a80..92a83f0 100644
--- a/model/VolumeBase.h
+++ b/model/VolumeBase.h
@@ -54,6 +54,7 @@
         kEmulated,
         kAsec,
         kObb,
+        kStub,
     };
 
     enum MountFlags {