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
This commit is contained in:
Kiyoung Kim 2021-03-02 16:45:27 +09:00
parent 5060516c6f
commit 0cbee0de2a
7 changed files with 46 additions and 12 deletions

View file

@ -1278,6 +1278,14 @@ static Result<void> 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";

View file

@ -301,5 +301,20 @@ Result<void> SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespac
return {};
}
base::Result<MountNamespace> 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

View file

@ -26,5 +26,7 @@ enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT };
bool SetupMountNamespaces();
base::Result<void> SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace);
base::Result<MountNamespace> GetCurrentMountNamespace();
} // namespace init
} // namespace android

View file

@ -125,11 +125,6 @@ static bool ExpandArgsAndExecv(const std::vector<std::string>& 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<void> 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<void> Service::Start() {
std::optional<MountNamespace> 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;
}

View file

@ -207,7 +207,7 @@ class Service {
std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
bool pre_apexd_ = false;
bool use_bootstrap_ns_ = false;
bool post_data_ = false;

View file

@ -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

View file

@ -100,5 +100,8 @@ Result<std::string> ParseUmountAll(const std::vector<std::string>& args);
void SetStdioToDevNull(char** argv);
void InitKernelLogging(char** argv);
bool IsRecoveryMode();
bool IsDefaultMountNamespaceReady();
void SetDefaultMountNamespaceReady();
} // namespace init
} // namespace android