diff --git a/init/builtins.cpp b/init/builtins.cpp index 538ed00eb..6511d299e 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1119,13 +1119,21 @@ static Result do_parse_apex_configs(const BuiltinArguments& args) { } static Result do_setup_runtime_bionic(const BuiltinArguments& args) { - if (SwitchToDefaultMountNamespace()) { + if (SetupRuntimeBionic()) { return Success(); } else { return Error() << "Failed to setup runtime bionic"; } } +static Result do_enter_default_mount_ns(const BuiltinArguments& args) { + if (SwitchToDefaultMountNamespace()) { + return Success(); + } else { + return Error() << "Failed to enter into default mount namespace"; + } +} + // Builtin-function-map start const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { constexpr std::size_t kMax = std::numeric_limits::max(); @@ -1177,6 +1185,7 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"start", {1, 1, {false, do_start}}}, {"stop", {1, 1, {false, do_stop}}}, {"swapon_all", {1, 1, {false, do_swapon_all}}}, + {"enter_default_mount_ns", {0, 0, {false, do_enter_default_mount_ns}}}, {"symlink", {2, 2, {true, do_symlink}}}, {"sysclktz", {1, 1, {false, do_sysclktz}}}, {"trigger", {1, 1, {false, do_trigger}}}, diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index e11d89768..7cf4c3fbd 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -155,6 +155,10 @@ int FirstStageMain(int argc, char** argv) { // part of the product partition, e.g. because they are mounted read-write. CHECKCALL(mkdir("/mnt/product", 0755)); + // /apex is used to mount APEXes + CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, + "mode=0755,uid=0,gid=0")); + #undef CHECKCALL // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp index 413fe8f50..327446a30 100644 --- a/init/mount_namespace.cpp +++ b/init/mount_namespace.cpp @@ -172,6 +172,11 @@ bool SetupMountNamespaces() { kBionicLibsMountPointDir64)) return false; + // /apex is also a private mountpoint to give different sets of APEXes for + // the bootstrap and default mount namespaces. The processes running with + // the bootstrap namespace get APEXes from the read-only partition. + if (!(MakePrivate("/apex"))) return false; + bootstrap_ns_fd.reset(OpenMountNamespace()); bootstrap_ns_id = GetMountNamespaceId(); @@ -227,6 +232,17 @@ bool SwitchToDefaultMountNamespace() { } } + LOG(INFO) << "Switched to default mount namespace"; + return true; +} + +// TODO(jiyong): remove this when /system/lib/libc.so becomes +// a symlink to /apex/com.android.runtime/lib/bionic/libc.so +bool SetupRuntimeBionic() { + if (IsRecoveryMode()) { + // We don't have multiple namespaces in recovery mode + return true; + } // Bind-mount bionic from the runtime APEX since it is now available. Note // that in case of IsBionicUpdatable() == false, these mounts are over the // existing existing bind mounts for the bootstrap bionic, which effectively @@ -238,7 +254,7 @@ bool SwitchToDefaultMountNamespace() { kBionicLibsMountPointDir64)) return false; - LOG(INFO) << "Switched to default mount namespace"; + LOG(INFO) << "Runtime bionic is set up"; return true; } diff --git a/init/mount_namespace.h b/init/mount_namespace.h index c41a449f3..4eef7853e 100644 --- a/init/mount_namespace.h +++ b/init/mount_namespace.h @@ -20,6 +20,7 @@ namespace android { namespace init { bool SetupMountNamespaces(); +bool SetupRuntimeBionic(); bool SwitchToDefaultMountNamespace(); bool SwitchToBootstrapMountNamespaceIfNeeded(); diff --git a/init/selinux.cpp b/init/selinux.cpp index ee302c168..3fadfedbe 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -459,6 +459,8 @@ void SelinuxRestoreContext() { selinux_android_restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE); selinux_android_restorecon("/dev/device-mapper", 0); + + selinux_android_restorecon("/apex", 0); } int SelinuxKlogCallback(int type, const char* fmt, ...) { diff --git a/rootdir/init.rc b/rootdir/init.rc index ce4b380f2..b44cc3efa 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -13,12 +13,6 @@ import /init.${ro.zygote}.rc # Cgroups are mounted right before early-init using list from /etc/cgroups.json on early-init - # Mount shared so changes propagate into child namespaces - # Do this before other processes are started from init. Otherwise, - # processes launched while the propagation type of / is 'private' - # won't get mount events from others. - mount rootfs rootfs / shared rec - # Set init and its forked children's oom_adj. write /proc/1/oom_score_adj -1000 @@ -43,6 +37,11 @@ on early-init start ueventd + # Run apexd-bootstrap so that APEXes that provide critical libraries + # become available. Note that this is executed as exec_start to ensure that + # the libraries are available to the processes started after this statement. + exec_start apexd-bootstrap + on init sysclktz 0 @@ -278,18 +277,9 @@ on init write /dev/cpu_variant:${ro.bionic.2nd_arch} ${ro.bionic.2nd_cpu_variant} chmod 0444 /dev/cpu_variant:${ro.bionic.2nd_arch} - # Setup APEX mount point and its security context - mount tmpfs tmpfs /apex nodev noexec nosuid - chmod 0755 /apex - chown root root /apex - restorecon /apex - # Start logd before any other services run to ensure we capture all of their logs. start logd - # Start apexd as soon as we can - start apexd - # Start essential services. start servicemanager start hwservicemanager @@ -425,8 +415,16 @@ on post-fs-data mkdir /data/bootchart 0755 shell shell bootchart start - # /data/apex is now available. Let apexd to scan and activate APEXes. - setprop apexd.data.status ready + # Make sure that apexd is started in the default namespace + enter_default_mount_ns + + # /data/apex is now available. Start apexd to scan and activate APEXes. + mkdir /data/apex 0750 root system + mkdir /data/apex/active 0750 root system + mkdir /data/apex/backup 0700 root system + mkdir /data/apex/sessions 0700 root system + mkdir /data/pkg_staging 0750 system system + start apexd # Avoid predictable entropy pool. Carry over entropy from previous boot. copy /data/system/entropy.dat /dev/urandom @@ -543,12 +541,6 @@ on post-fs-data mkdir /data/anr 0775 system system - mkdir /data/apex 0750 root system - mkdir /data/apex/active 0750 root system - mkdir /data/apex/backup 0700 root system - mkdir /data/apex/sessions 0700 root system - mkdir /data/pkg_staging 0750 system system - # NFC: create data/nfc for nv storage mkdir /data/nfc 0770 nfc nfc mkdir /data/nfc/param 0770 nfc nfc @@ -581,6 +573,12 @@ on post-fs-data mkdir /data/cache/backup_stage 0700 system system mkdir /data/cache/backup 0700 system system + # Wait for apexd to finish activating APEXes before starting more processes. + wait_for_prop apexd.status ready + # TODO(jiyong): remove setup_runtime_bionic + setup_runtime_bionic + parse_apex_configs + init_user0 # Set SELinux security contexts on upgrade or policy update. @@ -589,14 +587,6 @@ on post-fs-data # load fsverity keys exec -- /system/bin/mini-keyctl -c /product/etc/security/cacerts_fsverity,/vendor/etc/security/cacerts_fsverity -k .fs-verity - # Wait for apexd to finish activating APEXes before starting more processes. - # This certainly reduces the parallelism but is required to make as many processes - # as possible to use the bionic libs from the runtime APEX. This takes less than 50ms - # so the impact on the booting time is not significant. - wait_for_prop apexd.status ready - setup_runtime_bionic - parse_apex_configs - # Check any timezone data in /data is newer than the copy in the runtime module, delete if not. exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo