Bind mount Android/ directory in FUSE.

For apps seeing the FUSE filesystem, we want to bind-mount the Android/
directory to the lower filesystem. The main reason for this is game
performance - Android/ contains both OBBs and app-private external data,
and both are heavily accessed during game startup. This is a pretty
straightforward bind-mount on top of /mnt/user.

Bug: 137890172
Test: Running the following:
df /storge/emulated/0 ==> /dev/fuse (FUSE)
df /storage/emulated/0/Android ==> /data/media (sdcardfs)
Test: atest AdoptableHostTest

Change-Id: Ic17a5751b5a94846ee565ff935644a078044ab06
diff --git a/Utils.cpp b/Utils.cpp
index 841aab6..d483418 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -1076,6 +1076,7 @@
     if (status != android::OK) {
         LOG(ERROR) << "Failed to unmount " << pass_through_path;
     }
+    rmdir(pass_through_path.c_str());
 
     LOG(INFO) << "Unmounting fuse path " << fuse_path;
     android::status_t result = ForceUnmount(fuse_path);
@@ -1089,8 +1090,10 @@
             PLOG(ERROR) << "Failed to unmount with MNT_DETACH " << fuse_path;
             return -errno;
         }
-        return android::OK;
+        result = android::OK;
     }
+    rmdir(fuse_path.c_str());
+
     return result;
 }
 
diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
index 99abdd5..9abab89 100644
--- a/model/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -69,6 +69,46 @@
     }
 }
 
+static status_t mountFuseBindMounts(int userId, const std::string& label) {
+    // TODO(b/134706060) we don't actually want to mount the "write" view by
+    // default, since it gives write access to all OBB dirs.
+    std::string androidSource(
+            StringPrintf("/mnt/runtime/write/%s/%d/Android", label.c_str(), userId));
+    std::string androidTarget(
+            StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
+
+    if (access(androidSource.c_str(), F_OK) != 0) {
+        // Android path may not exist yet if users has just been created; create it on
+        // the lower fs.
+        if (fs_prepare_dir(androidSource.c_str(), 0771, AID_ROOT, AID_ROOT) != 0) {
+            PLOG(ERROR) << "Failed to create " << androidSource;
+            return -errno;
+        }
+    }
+    LOG(INFO) << "Bind mounting " << androidSource << " on " << androidTarget;
+    auto status = BindMount(androidSource, androidTarget);
+    if (status != OK) {
+        return status;
+    }
+    LOG(INFO) << "Bind mounted " << androidSource << " on " << androidTarget;
+
+    return OK;
+}
+
+static status_t unmountFuseBindMounts(int userId, const std::string& label) {
+    std::string androidTarget(
+            StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
+
+    LOG(INFO) << "Unmounting " << androidTarget;
+    auto status = UnmountTree(androidTarget);
+    if (status != OK) {
+        return status;
+    }
+    LOG(INFO) << "Unmounted " << androidTarget;
+
+    return OK;
+}
+
 status_t EmulatedVolume::doMount() {
     std::string label = getLabel();
     bool isVisible = getMountFlags() & MountFlags::kVisible;
@@ -159,6 +199,9 @@
                 return -EIO;
             }
         }
+
+        // Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path.
+        return mountFuseBindMounts(user_id, label);
     }
 
     return OK;
@@ -171,20 +214,18 @@
     // error code and might cause broken behaviour in applications.
     KillProcessesUsingPath(getPath());
 
+    int userId = getMountUserId();
     if (mFuseMounted) {
         std::string label = getLabel();
+        // Ignoring unmount return status because we do want to try to unmount
+        // the rest cleanly.
 
-        std::string fuse_path(StringPrintf("/mnt/user/%d/%s", getMountUserId(), label.c_str()));
-        std::string pass_through_path(
-                StringPrintf("/mnt/pass_through/%d/%s", getMountUserId(), label.c_str()));
-        if (UnmountUserFuse(getMountUserId(), getInternalPath(), label) != OK) {
+        unmountFuseBindMounts(userId, label);
+        if (UnmountUserFuse(userId, getInternalPath(), label) != OK) {
             PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
             return -errno;
         }
 
-        rmdir(fuse_path.c_str());
-        rmdir(pass_through_path.c_str());
-
         mFuseMounted = false;
     }
     if (getMountUserId() != 0) {
diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp
index e1606a3..3b5e6f0 100644
--- a/model/PublicVolume.cpp
+++ b/model/PublicVolume.cpp
@@ -269,13 +269,6 @@
             return -errno;
         }
 
-        std::string fuse_path(
-                StringPrintf("/mnt/user/%d/%s", getMountUserId(), stableName.c_str()));
-        std::string pass_through_path(
-                StringPrintf("/mnt/pass_through/%d/%s", getMountUserId(), stableName.c_str()));
-        rmdir(fuse_path.c_str());
-        rmdir(pass_through_path.c_str());
-
         mFuseMounted = false;
     }