Bind mount write view of Android/obb for installers.

Installers will be allowed to write OBB for any application; this is not
easy to achieve on sdcardfs, where the GID of Android/obb is the same as
the GID of Android/data (app-private data), meaning giving installers
write access to Android/obb would also give them write access to
Android/data.

Instead, we create a /mnt/installer view, which is exactly the same as
/mnt/user, with the sole exception that the write sdcardfs view of
Android/obb is mounted on top. This is what will allow installers to
write there, while still being restricted with respect to app-private
data in Android/data.

Bug: 134706060
Test: atest AdoptableHostTest
Change-Id: If2b93870a877efef182bdc06466552a7527499ad
diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
index d7b22e3..054a58b 100644
--- a/model/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -73,6 +73,26 @@
     }
 }
 
+// Creates a bind mount from source to target, creating the source (!) directory
+// if not yet present.
+static status_t doFuseBindMount(const std::string& source, const std::string& target) {
+    if (access(source.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(source.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) {
+            PLOG(ERROR) << "Failed to create " << source;
+            return -errno;
+        }
+    }
+    LOG(INFO) << "Bind mounting " << source << " on " << target;
+    auto status = BindMount(source, target);
+    if (status != OK) {
+        return status;
+    }
+    LOG(INFO) << "Bind mounted " << source << " on " << target;
+    return OK;
+}
+
 status_t EmulatedVolume::mountFuseBindMounts() {
     std::string androidSource;
     std::string label = getLabel();
@@ -86,21 +106,27 @@
     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_MEDIA_RW, AID_MEDIA_RW) != 0) {
-            PLOG(ERROR) << "Failed to create " << androidSource;
-            return -errno;
-        }
-    }
-    LOG(INFO) << "Bind mounting " << androidSource << " on " << androidTarget;
-    auto status = BindMount(androidSource, androidTarget);
+    auto status = doFuseBindMount(androidSource, androidTarget);
     if (status != OK) {
         return status;
     }
-    LOG(INFO) << "Bind mounted " << androidSource << " on " << androidTarget;
 
+    // Installers get the same view as all other apps, with the sole exception that the
+    // OBB dirs (Android/obb) are writable to them. On sdcardfs devices, this requires
+    // a special bind mount, since app-private and OBB dirs share the same GID, but we
+    // only want to give access to the latter.
+    if (!mUseSdcardFs) {
+        return OK;
+    }
+    std::string installerSource(
+            StringPrintf("/mnt/runtime/write/%s/%d/Android/obb", label.c_str(), userId));
+    std::string installerTarget(
+            StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", userId, label.c_str(), userId));
+
+    status = doFuseBindMount(installerSource, installerTarget);
+    if (status != OK) {
+        return status;
+    }
     return OK;
 }
 
@@ -108,6 +134,17 @@
     std::string label = getLabel();
     int userId = getMountUserId();
 
+    if (mUseSdcardFs) {
+        std::string installerTarget(
+                StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", userId, label.c_str(), userId));
+        LOG(INFO) << "Unmounting " << installerTarget;
+        auto status = UnmountTree(installerTarget);
+        if (status != OK) {
+            LOG(ERROR) << "Failed to unmount " << installerTarget;
+            // Intentional continue to try to unmount the other bind mount
+        }
+    }
+
     std::string androidTarget(
             StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));