Have `otapreopt_chroot` bind-mount Bionic artifacts from the Runtime APEX.
Have `otapreopt_chroot` bind-mount Bionic artifacts (`linker(64)`,
`libc.so`, `libm.so`, `libdl.so`) from the Runtime APEX
(`/postinstall/apex/com.android.runtime`) into `/postinstall/bionic/`,
much the same way `init` sets up Bionic bind-mounts in the default
mount namespace.
Test: m otapreopt_chroot
Test: A/B OTA update test (asit/dexoptota/self_full).
Bug: 113373927
Bug: 120266448
Change-Id: Ie254a94ae35e62f88375bc89380456f15796566a
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 1c99663..609ddaf 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -41,6 +41,23 @@
namespace android {
namespace installd {
+// Configuration for bind-mounted Bionic artifacts.
+
+static constexpr const char* kLinkerMountPoint = "/bionic/bin/linker";
+static constexpr const char* kRuntimeLinkerPath = "/apex/com.android.runtime/bin/linker";
+
+static constexpr const char* kBionicLibsMountPointDir = "/bionic/lib/";
+static constexpr const char* kRuntimeBionicLibsDir = "/apex/com.android.runtime/lib/bionic/";
+
+static constexpr const char* kLinkerMountPoint64 = "/bionic/bin/linker64";
+static constexpr const char* kRuntimeLinkerPath64 = "/apex/com.android.runtime/bin/linker64";
+
+static constexpr const char* kBionicLibsMountPointDir64 = "/bionic/lib64/";
+static constexpr const char* kRuntimeBionicLibsDir64 = "/apex/com.android.runtime/lib64/bionic/";
+
+static const std::vector<std::string> kBionicLibFileNames = {"libc.so", "libm.so", "libdl.so"};
+
+
static void CloseDescriptor(int fd) {
if (fd >= 0) {
int result = close(fd);
@@ -79,6 +96,43 @@
}
}
+// Copied from system/core/init/mount_namespace.cpp.
+static bool BindMount(const std::string& source, const std::string& mount_point,
+ bool recursive = false) {
+ unsigned long mountflags = MS_BIND;
+ if (recursive) {
+ mountflags |= MS_REC;
+ }
+ if (mount(source.c_str(), mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+ PLOG(ERROR) << "Could not bind-mount " << source << " to " << mount_point;
+ return false;
+ }
+ return true;
+}
+
+// Copied from system/core/init/mount_namespace.cpp and and adjusted (bind
+// mounts are not made private, as the /postinstall is already private (see
+// `android::installd::otapreopt_chroot`).
+static bool BindMountBionic(const std::string& linker_source, const std::string& lib_dir_source,
+ const std::string& linker_mount_point,
+ const std::string& lib_mount_dir) {
+ if (access(linker_source.c_str(), F_OK) != 0) {
+ PLOG(INFO) << linker_source << " does not exist. Skipping mounting Bionic there.";
+ return true;
+ }
+ if (!BindMount(linker_source, linker_mount_point)) {
+ return false;
+ }
+ for (const auto& libname : kBionicLibFileNames) {
+ std::string mount_point = lib_mount_dir + libname;
+ std::string source = lib_dir_source + libname;
+ if (!BindMount(source, mount_point)) {
+ return false;
+ }
+ }
+ return true;
+}
+
// Entry for otapreopt_chroot. Expected parameters are:
// [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
// The file descriptor denoted by status-fd will be closed. The rest of the parameters will
@@ -222,6 +276,23 @@
// the Android Runtime APEX, as it is required by otapreopt to run dex2oat.
std::vector<apex::ApexFile> active_packages = ActivateApexPackages();
+ // Bind-mount Bionic artifacts from the Runtime APEX.
+ // This logic is copied and adapted from system/core/init/mount_namespace.cpp.
+ if (!BindMountBionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir, kLinkerMountPoint,
+ kBionicLibsMountPointDir)) {
+ LOG(ERROR) << "Failed to mount 32-bit Bionic artifacts from the Runtime APEX.";
+ // Clean up and exit.
+ DeactivateApexPackages(active_packages);
+ exit(215);
+ }
+ if (!BindMountBionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64, kLinkerMountPoint64,
+ kBionicLibsMountPointDir64)) {
+ LOG(ERROR) << "Failed to mount 64-bit Bionic artifacts from the Runtime APEX.";
+ // Clean up and exit.
+ DeactivateApexPackages(active_packages);
+ exit(216);
+ }
+
// Now go on and run otapreopt.
// Incoming: cmd + status-fd + target-slot + cmd... | Incoming | = argc