Use /bootstrap-apex for bootstrap APEXes

This new directory is bind-mounted to /apex in the bootstrap mount
namespace so that apexd-bootstrap mounts bootstrap APEXes there via
/apex.

The directory is shared between two mount namespaces, hence visible
in the default mount namespace.

Bug: 290148078
Test: VendorApexHostTestCases
Change-Id: I841480e41be8def5a4c6a4aa874c4e21465a71d3
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 5b53d50..7918f23 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -66,15 +66,6 @@
     return ret;
 }
 
-// In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount
-// namespaces.
-static bool NeedsTwoMountNamespaces() {
-    if (IsRecoveryMode()) return false;
-    // In microdroid, there's only one set of APEXes in built-in directories include block devices.
-    if (IsMicrodroid()) return false;
-    return true;
-}
-
 static android::base::unique_fd bootstrap_ns_fd;
 static android::base::unique_fd default_ns_fd;
 
@@ -83,6 +74,15 @@
 
 }  // namespace
 
+// In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount
+// namespaces.
+bool NeedsTwoMountNamespaces() {
+    if (IsRecoveryMode()) return false;
+    // In microdroid, there's only one set of APEXes in built-in directories include block devices.
+    if (IsMicrodroid()) return false;
+    return true;
+}
+
 bool SetupMountNamespaces() {
     // Set the propagation type of / as shared so that any mounting event (e.g.
     // /data) is by default visible to all processes. When private mounting is
@@ -163,6 +163,23 @@
             PLOG(ERROR) << "Cannot switch back to bootstrap mount namespace";
             return false;
         }
+
+        // Some components (e.g. servicemanager) need to access bootstrap
+        // APEXes from the default mount namespace. To achieve that, we bind-mount
+        // /apex to /bootstrap-apex in the bootstrap mount namespace. Since /bootstrap-apex
+        // is "shared", the mounts are visible in the default mount namespace as well.
+        //
+        // The end result will look like:
+        //   in the bootstrap mount namespace:
+        //     /apex  (== /bootstrap-apex)
+        //       {bootstrap APEXes from the read-only partition}
+        //
+        //   in the default mount namespace:
+        //     /bootstrap-apex
+        //       {bootstrap APEXes from the read-only partition}
+        //     /apex
+        //       {APEXes, can be from /data partition}
+        if (!(BindMount("/bootstrap-apex", "/apex"))) return false;
     } else {
         // Otherwise, default == bootstrap
         default_ns_fd.reset(OpenMountNamespace());