From 0cbee0de2af658508f7ea97e47ffef69e0e7119f Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Tue, 2 Mar 2021 16:45:27 +0900 Subject: [PATCH] Check if service is executed before APEX is ready Any service which is executed when Runtime apex is mounted, but linkerconfig is not updated can fail to be executed due to missing information in ld.config.txt. This change updates init to have a status variable which contains if current mount namespace is default and APEX is not ready from ld.config.txt, and use bootstrap namespace if it is not ready. Bug: 181348374 Test: cuttlefish boot succeeded Change-Id: Ia574b1fad2110d4e68586680dacbe6137186546e --- init/builtins.cpp | 8 ++++++++ init/mount_namespace.cpp | 15 +++++++++++++++ init/mount_namespace.h | 2 ++ init/service.cpp | 17 ++++++----------- init/service.h | 2 +- init/util.cpp | 11 +++++++++++ init/util.h | 3 +++ 7 files changed, 46 insertions(+), 12 deletions(-) diff --git a/init/builtins.cpp b/init/builtins.cpp index dcc9582e2..035038f32 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1278,6 +1278,14 @@ static Result GenerateLinkerConfiguration() { return ErrnoError() << "failed to execute linkerconfig"; } + auto current_mount_ns = GetCurrentMountNamespace(); + if (!current_mount_ns.ok()) { + return current_mount_ns.error(); + } + if (*current_mount_ns == NS_DEFAULT) { + SetDefaultMountNamespaceReady(); + } + LOG(INFO) << "linkerconfig generated " << linkerconfig_target << " with mounted APEX modules info"; diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp index ec48cde02..15252a622 100644 --- a/init/mount_namespace.cpp +++ b/init/mount_namespace.cpp @@ -301,5 +301,20 @@ Result SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespac return {}; } +base::Result GetCurrentMountNamespace() { + std::string current_namespace_id = GetMountNamespaceId(); + if (current_namespace_id == "") { + return Error() << "Failed to get current mount namespace ID"; + } + + if (current_namespace_id == bootstrap_ns_id) { + return NS_BOOTSTRAP; + } else if (current_namespace_id == default_ns_id) { + return NS_DEFAULT; + } + + return Error() << "Failed to find current mount namespace"; +} + } // namespace init } // namespace android diff --git a/init/mount_namespace.h b/init/mount_namespace.h index d4d6f82da..5e3dab241 100644 --- a/init/mount_namespace.h +++ b/init/mount_namespace.h @@ -26,5 +26,7 @@ enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT }; bool SetupMountNamespaces(); base::Result SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace); +base::Result GetCurrentMountNamespace(); + } // namespace init } // namespace android diff --git a/init/service.cpp b/init/service.cpp index cfb82842d..836dc4722 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -125,11 +125,6 @@ static bool ExpandArgsAndExecv(const std::vector& args, bool sigsto return execv(c_strings[0], c_strings.data()) == 0; } -static bool AreRuntimeApexesReady() { - struct stat buf; - return stat("/apex/com.android.runtime/", &buf) == 0; -} - unsigned long Service::next_start_order_ = 1; bool Service::is_exec_service_running_ = false; @@ -312,7 +307,7 @@ void Service::Reap(const siginfo_t& siginfo) { #else static bool is_apex_updatable = false; #endif - const bool is_process_updatable = !pre_apexd_ && is_apex_updatable; + const bool is_process_updatable = !use_bootstrap_ns_ && is_apex_updatable; // If we crash > 4 times in 'fatal_crash_window_' minutes or before boot_completed, // reboot into bootloader or set crashing property @@ -465,12 +460,12 @@ Result Service::Start() { scon = *result; } - if (!AreRuntimeApexesReady() && !pre_apexd_) { - // If this service is started before the Runtime and ART APEXes get - // available, mark it as pre-apexd one. Note that this marking is + if (!IsDefaultMountNamespaceReady() && name_ != "apexd") { + // If this service is started before APEXes and corresponding linker configuration + // get available, mark it as pre-apexd one. Note that this marking is // permanent. So for example, if the service is re-launched (e.g., due // to crash), it is still recognized as pre-apexd... for consistency. - pre_apexd_ = true; + use_bootstrap_ns_ = true; } // For pre-apexd services, override mount namespace as "bootstrap" one before starting. @@ -479,7 +474,7 @@ Result Service::Start() { std::optional override_mount_namespace; if (name_ == "ueventd") { override_mount_namespace = NS_DEFAULT; - } else if (pre_apexd_) { + } else if (use_bootstrap_ns_) { override_mount_namespace = NS_BOOTSTRAP; } diff --git a/init/service.h b/init/service.h index aee1e5dfa..043555fa4 100644 --- a/init/service.h +++ b/init/service.h @@ -207,7 +207,7 @@ class Service { std::vector> reap_callbacks_; - bool pre_apexd_ = false; + bool use_bootstrap_ns_ = false; bool post_data_ = false; diff --git a/init/util.cpp b/init/util.cpp index e69b43f8c..eab99d4e3 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -735,5 +735,16 @@ bool IsRecoveryMode() { return access("/system/bin/recovery", F_OK) == 0; } +// Check if default mount namespace is ready to be used with APEX modules +static bool is_default_mount_namespace_ready = false; + +bool IsDefaultMountNamespaceReady() { + return is_default_mount_namespace_ready; +} + +void SetDefaultMountNamespaceReady() { + is_default_mount_namespace_ready = true; +} + } // namespace init } // namespace android diff --git a/init/util.h b/init/util.h index 7745d775a..daba85247 100644 --- a/init/util.h +++ b/init/util.h @@ -100,5 +100,8 @@ Result ParseUmountAll(const std::vector& args); void SetStdioToDevNull(char** argv); void InitKernelLogging(char** argv); bool IsRecoveryMode(); + +bool IsDefaultMountNamespaceReady(); +void SetDefaultMountNamespaceReady(); } // namespace init } // namespace android