Bind mount lower filesystem during FUSE mount

When mounting a FUSE device on /mnt/user/<userid>/<vol>,
bind mount the correspoinding lower filesystem path to
/mnt/pass_through/<userid>/<vol>. At Zygote fork time, an
app with the right privilege will have the pass_through path
bind mounted into /storage instead of the /mnt/user path.

This provides such an app direct access to the lower filesystem
without going through FUSE.

Bug: 140064376
Test: mount(8) shows /mnt/pass_through/0/emulated is a bind
mount of the lower fs

Change-Id: I32c3cad64138910fcec9fb8f66b206706b5fd139
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index adb4a5c..0bb87a4 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -487,6 +487,9 @@
         case VoldNativeService::REMOUNT_MODE_FULL:
             mode = "full";
             break;
+        case VoldNativeService::REMOUNT_MODE_PASS_THROUGH:
+            mode = "pass_through";
+            break;
         default:
             PLOG(ERROR) << "Unknown mode " << std::to_string(mountMode);
             return -1;
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index b1af587..ae5a3bc 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -157,6 +157,7 @@
     const int REMOUNT_MODE_LEGACY = 4;
     const int REMOUNT_MODE_INSTALLER = 5;
     const int REMOUNT_MODE_FULL = 6;
+    const int REMOUNT_MODE_PASS_THROUGH = 7;
 
     const int VOLUME_STATE_UNMOUNTED = 0;
     const int VOLUME_STATE_CHECKING = 1;
diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
index 022ff42..4910803 100644
--- a/model/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -89,13 +89,18 @@
     if (isFuse) {
         LOG(INFO) << "Mounting emulated fuse volume";
         android::base::unique_fd fd;
-        int result = MountUserFuse(getMountUserId(), label, &fd);
+        int user_id = getMountUserId();
+        int result = MountUserFuse(user_id, label, &fd);
+
         if (result != 0) {
             PLOG(ERROR) << "Failed to mount emulated fuse volume";
             return -result;
         }
         setFuseFd(std::move(fd));
-        return OK;
+
+        std::string pass_through_path(StringPrintf("/mnt/pass_through/%d/%s",
+                                                   user_id, label.c_str()));
+        return BindMount(getInternalPath(), pass_through_path);
     }
 
     if (!(mFusePid = fork())) {
diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp
index ebcb91a..d2fcc18 100644
--- a/model/PublicVolume.cpp
+++ b/model/PublicVolume.cpp
@@ -174,13 +174,18 @@
     if (isFuse) {
         LOG(INFO) << "Mounting public fuse volume";
         android::base::unique_fd fd;
-        int result = MountUserFuse(getMountUserId(), stableName, &fd);
+        int user_id = getMountUserId();
+        int result = MountUserFuse(user_id, stableName, &fd);
+
         if (result != 0) {
             LOG(ERROR) << "Failed to mount public fuse volume";
             return -result;
         }
         setFuseFd(std::move(fd));
-        return OK;
+
+        std::string pass_through_path(StringPrintf("/mnt/pass_through/%d/%s",
+                                                 user_id, stableName.c_str()));
+        return BindMount(getInternalPath(), pass_through_path);
     }
 
     if (!(mFusePid = fork())) {