Bionic libs and the dynamic linker are bind mounted
This change makes the bionic libs and the dynamic linker from the
runtime APEX (com.android.runtime) available to all processes started
after apexd finishes activating APEXes.
Specifically, the device has two sets of bionic libs and the dynamic
linker: one in the system partition for pre-apexd processes and another
in the runtime APEX for post-apexd processes. The former is referred as
the 'bootstrap' bionic and are located at
/system/lib/{libc|libdl|libm}.so and /system/bin/linker. The latter is
referred as the 'runtime' bionic and are located at
/apex/com.android.runtime/lib/bionic/{libc|libdl|libm}.so and
/apex/com.android.runtime/bin/linker.
Although the two sets are located in different directories, at runtime,
they are accessed via the same path: /system/lib/* and
/system/bin/linker ... for both pre/post-apexd processes. This is done
by bind-mounting the bootstrap or the runtime bionic to the same path.
Keeping the same path is necessary because there are many modules and
apps that explicitly or implicitly depend on the fact that bionic libs
are located in /system/lib and are loaded into the default linker
namespace (which has /system/lib in its search paths).
Before the apexd is started, init executes a built-in action
'prepare_bootstrap_bionic' that bind-mounts the bootstrap bionic to the
mount points. Processes started during this time are provided with the
bootstrap bionic. Then after the apexd is finished, init executes
another built-in action 'setup_runtime_bionic' which again mounts the
runtime bionic to the same mount points, thus hiding the previous mounts
that target the bootstrap bionic. The mounting of the runtime bionic
(which is only for post-apexd processes) is hidden from pre-apexd
processes by changing propagation type of the mount points to 'private'
and execute the pre-apexd processes with a new mount namespace using
unshare(2). If a pre-apexd process crashes and re-launched after the
apexd is on, the process still gets the bootstrap bionic by unmounting
the runtime bionic which effectively un-hides the previous bind-mounts
targeting the bootstrap bionic.
Bug: 120266448
Test: device boots
Test: cat /proc/`pidof zygote`/mountinfo shows that
/system/lib/{libc|libdl|libm}.so and /system/bin/linker are from the
runtime APEX
Test: cat /proc/'pidof vold`/mountinfo shows that the same mount points
are from system partition.
Change-Id: I7ca67755dc0656c0f0c834ba94bf23ba9b1aca68
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 52828c0..4a66e46 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1093,6 +1093,86 @@
}
}
+static Result<Success> bind_mount_file(const char* source, const char* mount_point,
+ bool remount_private) {
+ if (remount_private && mount(nullptr, mount_point, nullptr, MS_PRIVATE, nullptr) == -1) {
+ return ErrnoError() << "Could not change " << mount_point << " to a private mount point";
+ }
+ if (mount(source, mount_point, nullptr, MS_BIND, nullptr) == -1) {
+ return ErrnoError() << "Could not bind-mount " << source << " to " << mount_point;
+ }
+ return Success();
+}
+
+static Result<Success> bind_mount_bionic(const char* linker_source, const char* lib_dir_source,
+ const char* linker_mount_point, const char* lib_mount_dir,
+ bool remount_private) {
+ if (access(linker_source, F_OK) != 0) {
+ return Success();
+ }
+ if (auto result = bind_mount_file(linker_source, linker_mount_point, remount_private);
+ !result) {
+ return result;
+ }
+ for (auto libname : kBionicLibFileNames) {
+ std::string mount_point = lib_mount_dir + libname;
+ std::string source = lib_dir_source + libname;
+ if (auto result = bind_mount_file(source.c_str(), mount_point.c_str(), remount_private);
+ !result) {
+ return result;
+ }
+ }
+ return Success();
+}
+
+// The bootstrap bionic libs and the bootstrap linker are bind-mounted to
+// the mount points for pre-apexd processes.
+static Result<Success> do_prepare_bootstrap_bionic(const BuiltinArguments& args) {
+ static bool prepare_bootstrap_bionic_done = false;
+ if (prepare_bootstrap_bionic_done) {
+ return Error() << "prepare_bootstrap_bionic was already executed. Cannot be executed again";
+ }
+ if (auto result = bind_mount_bionic(kBootstrapLinkerPath, kBootstrapBionicLibsDir,
+ kLinkerMountPoint, kBionicLibsMountPointDir, false);
+ !result) {
+ return result;
+ }
+ if (auto result = bind_mount_bionic(kBootstrapLinkerPath64, kBootstrapBionicLibsDir64,
+ kLinkerMountPoint64, kBionicLibsMountPointDir64, false);
+ !result) {
+ return result;
+ }
+
+ LOG(INFO) << "prepare_bootstrap_bionic done";
+ prepare_bootstrap_bionic_done = true;
+ return Success();
+}
+
+// The bionic libs and the dynamic linker from the runtime APEX are bind-mounted
+// to the mount points. As a result, the previous mounts done by
+// prepare_bootstrap_bionic become hidden.
+static Result<Success> do_setup_runtime_bionic(const BuiltinArguments& args) {
+ static bool setup_runtime_bionic_done = false;
+ if (setup_runtime_bionic_done) {
+ return Error() << "setup_runtime_bionic was already executed. Cannot be executed again";
+ }
+ if (auto result = bind_mount_bionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir,
+ kLinkerMountPoint, kBionicLibsMountPointDir, true);
+ !result) {
+ return result;
+ }
+ if (auto result = bind_mount_bionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64,
+ kLinkerMountPoint64, kBionicLibsMountPointDir64, true);
+ !result) {
+ return result;
+ }
+
+ ServiceList::GetInstance().MarkRuntimeAvailable();
+ LOG(INFO) << "setup_runtime_bionic done";
+ setup_runtime_bionic_done = true;
+ return Success();
+}
+
// Builtin-function-map start
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
@@ -1131,6 +1211,7 @@
{"mount_all", {1, kMax, {false, do_mount_all}}},
{"mount", {3, kMax, {false, do_mount}}},
{"parse_apex_configs", {0, 0, {false, do_parse_apex_configs}}},
+ {"prepare_bootstrap_bionic",{0, 0, {false, do_prepare_bootstrap_bionic}}},
{"umount", {1, 1, {false, do_umount}}},
{"readahead", {1, 2, {true, do_readahead}}},
{"restart", {1, 1, {false, do_restart}}},
@@ -1139,6 +1220,7 @@
{"rm", {1, 1, {true, do_rm}}},
{"rmdir", {1, 1, {true, do_rmdir}}},
{"setprop", {2, 2, {true, do_setprop}}},
+ {"setup_runtime_bionic", {0, 0, {false, do_setup_runtime_bionic}}},
{"setrlimit", {3, 3, {false, do_setrlimit}}},
{"start", {1, 1, {false, do_start}}},
{"stop", {1, 1, {false, do_stop}}},