Mount /dev/fuse on /mnt/user/<userid>/<volumeid>

Since system_server cannot mount devices by itself,
add a binder interface to vold that system_server
can call to initiate this mount when required.

BUG: 135341433
Test: manual
Test: atest --test-mapping packages/providers/MediaProvider
Test: ExternalStorageHostTest DownloadProviderTests

Change-Id: If4fd02a1f1a8d921a3f96783d8c73e085c5b7ca1
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 44bff5a..2eb1ed5 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -31,6 +31,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 #include <array>
+#include <thread>
 
 #include <linux/kdev_t.h>
 
@@ -100,6 +101,22 @@
 
 VolumeManager* VolumeManager::sInstance = NULL;
 
+static void* symlinkPrimary(void* data) {
+    std::unique_ptr<std::pair<std::string, std::string>> linkInfo(
+        static_cast<std::pair<std::string, std::string>*>(data));
+    std::string* source = &linkInfo->first;
+    std::string* target = &linkInfo->second;
+
+    fs_prepare_dir(source->c_str(), 0755, AID_ROOT, AID_ROOT);
+    fs_prepare_dir(target->c_str(), 0755, AID_ROOT, AID_ROOT);
+    *target = *target + "/primary";
+
+    // Link source to target
+    LOG(DEBUG) << "Linking " << *source << " to " << *target;
+    Symlink(*source, *target);
+    return nullptr;
+}
+
 VolumeManager* VolumeManager::Instance() {
     if (!sInstance) sInstance = new VolumeManager();
     return sInstance;
@@ -365,6 +382,21 @@
 }
 
 int VolumeManager::linkPrimary(userid_t userId) {
+    bool isFuse = GetBoolProperty(android::vold::kPropFuse, false);
+
+    if (isFuse) {
+        // Here we have to touch /mnt/user/userid>/<volumeid> which was already mounted as part of
+        // the boot sequence, requiring waiting till a fuse handler is available. If we do this work
+        // in foreground we could hang the caller, i.e. system server, which needs to start the fuse
+        // handler. So do it in the background.
+        std::string source(
+            StringPrintf("/mnt/user/%d/%s/%d", userId, mPrimary->getId().c_str(), userId));
+        std::string target(StringPrintf("/mnt/user/%d/self", userId));
+
+        auto symlinkInfo = new std::pair<std::string, std::string>(source, target);
+        std::thread(symlinkPrimary, symlinkInfo).detach();
+    }
+
     std::string source(mPrimary->getPath());
     if (mPrimary->isEmulated()) {
         source = StringPrintf("%s/%d", source.c_str(), userId);
@@ -431,6 +463,10 @@
 }
 
 int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
+    if (GetBoolProperty(android::vold::kPropFuse, false)) {
+        // TODO(135341433): Implement fuse specific logic.
+        return 0;
+    }
     std::string mode;
     switch (mountMode) {
         case VoldNativeService::REMOUNT_MODE_NONE: