diff options
Diffstat (limited to 'init/init.cpp')
-rw-r--r-- | init/init.cpp | 166 |
1 files changed, 94 insertions, 72 deletions
diff --git a/init/init.cpp b/init/init.cpp index b29dfa3f6..a9d63013f 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -22,6 +22,7 @@ #include <signal.h> #include <stdlib.h> #include <string.h> +#include <sys/eventfd.h> #include <sys/mount.h> #include <sys/signalfd.h> #include <sys/types.h> @@ -45,6 +46,7 @@ #include <android-base/properties.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> +#include <backtrace/Backtrace.h> #include <fs_avb/fs_avb.h> #include <fs_mgr_vendor_overlay.h> #include <keyutils.h> @@ -81,6 +83,7 @@ using namespace std::chrono_literals; using namespace std::string_literals; using android::base::boot_clock; +using android::base::ConsumePrefix; using android::base::GetProperty; using android::base::ReadFileToString; using android::base::SetProperty; @@ -113,30 +116,26 @@ static std::queue<PendingControlMessage> pending_control_messages; // to fill that socket and deadlock the system. Now we use locks to handle the property changes // directly in the property thread, however we still must wake the epoll to inform init that there // is a change to process, so we use this FD. It is non-blocking, since we do not care how many -// times WakeEpoll() is called, only that the epoll will wake. -static int wake_epoll_fd = -1; +// times WakeMainInitThread() is called, only that the epoll will wake. +static int wake_main_thread_fd = -1; static void InstallInitNotifier(Epoll* epoll) { - int sockets[2]; - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, sockets) != 0) { - PLOG(FATAL) << "Failed to socketpair() between property_service and init"; + wake_main_thread_fd = eventfd(0, EFD_CLOEXEC); + if (wake_main_thread_fd == -1) { + PLOG(FATAL) << "Failed to create eventfd for waking init"; } - int epoll_fd = sockets[0]; - wake_epoll_fd = sockets[1]; - - auto drain_socket = [epoll_fd] { - char buf[512]; - while (read(epoll_fd, buf, sizeof(buf)) > 0) { - } + auto clear_eventfd = [] { + uint64_t counter; + TEMP_FAILURE_RETRY(read(wake_main_thread_fd, &counter, sizeof(counter))); }; - if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result.ok()) { + if (auto result = epoll->RegisterHandler(wake_main_thread_fd, clear_eventfd); !result.ok()) { LOG(FATAL) << result.error(); } } -static void WakeEpoll() { - constexpr char value[] = "1"; - write(wake_epoll_fd, value, sizeof(value)); +static void WakeMainInitThread() { + uint64_t counter = 1; + TEMP_FAILURE_RETRY(write(wake_main_thread_fd, &counter, sizeof(counter))); } static class PropWaiterState { @@ -180,7 +179,7 @@ static class PropWaiterState { LOG(INFO) << "Wait for property '" << wait_prop_name_ << "=" << wait_prop_value_ << "' took " << *waiting_for_prop_; ResetWaitForPropLocked(); - WakeEpoll(); + WakeMainInitThread(); } } } @@ -217,6 +216,16 @@ void ResetWaitForProp() { prop_waiter_state.ResetWaitForProp(); } +static void UnwindMainThreadStack() { + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 1)); + if (!backtrace->Unwind(0)) { + LOG(ERROR) << __FUNCTION__ << ": Failed to unwind callstack."; + } + for (size_t i = 0; i < backtrace->NumFrames(); i++) { + LOG(ERROR) << backtrace->FormatFrameData(i); + } +} + static class ShutdownState { public: void TriggerShutdown(const std::string& command) { @@ -228,7 +237,7 @@ static class ShutdownState { auto lock = std::lock_guard{shutdown_command_lock_}; shutdown_command_ = command; do_shutdown_ = true; - WakeEpoll(); + WakeMainInitThread(); } std::optional<std::string> CheckShutdown() { @@ -240,12 +249,27 @@ static class ShutdownState { return {}; } + bool do_shutdown() const { return do_shutdown_; } + private: std::mutex shutdown_command_lock_; std::string shutdown_command_; bool do_shutdown_ = false; } shutdown_state; +void DebugRebootLogging() { + LOG(INFO) << "do_shutdown: " << shutdown_state.do_shutdown() + << " IsShuttingDown: " << IsShuttingDown(); + if (shutdown_state.do_shutdown()) { + LOG(ERROR) << "sys.powerctl set while a previous shutdown command has not been handled"; + UnwindMainThreadStack(); + } + if (IsShuttingDown()) { + LOG(ERROR) << "sys.powerctl set while init is already shutting down"; + UnwindMainThreadStack(); + } +} + void DumpState() { ServiceList::GetInstance().DumpState(); ActionManager::GetInstance().DumpState(); @@ -312,7 +336,7 @@ void PropertyChanged(const std::string& name, const std::string& value) { if (property_triggers_enabled) { ActionManager::GetInstance().QueuePropertyChange(name, value); - WakeEpoll(); + WakeMainInitThread(); } prop_waiter_state.CheckAndResetWait(name, value); @@ -367,40 +391,27 @@ enum class ControlTarget { INTERFACE, // action gets called for every service that holds this interface }; -struct ControlMessageFunction { - ControlTarget target; - std::function<Result<void>(Service*)> action; -}; +using ControlMessageFunction = std::function<Result<void>(Service*)>; -static const std::map<std::string, ControlMessageFunction>& get_control_message_map() { +static const std::map<std::string, ControlMessageFunction, std::less<>>& GetControlMessageMap() { // clang-format off - static const std::map<std::string, ControlMessageFunction> control_message_functions = { - {"sigstop_on", {ControlTarget::SERVICE, - [](auto* service) { service->set_sigstop(true); return Result<void>{}; }}}, - {"sigstop_off", {ControlTarget::SERVICE, - [](auto* service) { service->set_sigstop(false); return Result<void>{}; }}}, - {"start", {ControlTarget::SERVICE, DoControlStart}}, - {"stop", {ControlTarget::SERVICE, DoControlStop}}, - {"restart", {ControlTarget::SERVICE, DoControlRestart}}, - {"interface_start", {ControlTarget::INTERFACE, DoControlStart}}, - {"interface_stop", {ControlTarget::INTERFACE, DoControlStop}}, - {"interface_restart", {ControlTarget::INTERFACE, DoControlRestart}}, + static const std::map<std::string, ControlMessageFunction, std::less<>> control_message_functions = { + {"sigstop_on", [](auto* service) { service->set_sigstop(true); return Result<void>{}; }}, + {"sigstop_off", [](auto* service) { service->set_sigstop(false); return Result<void>{}; }}, + {"oneshot_on", [](auto* service) { service->set_oneshot(true); return Result<void>{}; }}, + {"oneshot_off", [](auto* service) { service->set_oneshot(false); return Result<void>{}; }}, + {"start", DoControlStart}, + {"stop", DoControlStop}, + {"restart", DoControlRestart}, }; // clang-format on return control_message_functions; } -bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t pid) { - const auto& map = get_control_message_map(); - const auto it = map.find(msg); - - if (it == map.end()) { - LOG(ERROR) << "Unknown control msg '" << msg << "'"; - return false; - } - - std::string cmdline_path = StringPrintf("proc/%d/cmdline", pid); +static bool HandleControlMessage(std::string_view message, const std::string& name, + pid_t from_pid) { + std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid); std::string process_cmdline; if (ReadFileToString(cmdline_path, &process_cmdline)) { std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' '); @@ -409,37 +420,37 @@ bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t process_cmdline = "unknown process"; } - const ControlMessageFunction& function = it->second; - - Service* svc = nullptr; + Service* service = nullptr; + auto action = message; + if (ConsumePrefix(&action, "interface_")) { + service = ServiceList::GetInstance().FindInterface(name); + } else { + service = ServiceList::GetInstance().FindService(name); + } - switch (function.target) { - case ControlTarget::SERVICE: - svc = ServiceList::GetInstance().FindService(name); - break; - case ControlTarget::INTERFACE: - svc = ServiceList::GetInstance().FindInterface(name); - break; - default: - LOG(ERROR) << "Invalid function target from static map key ctl." << msg << ": " - << static_cast<std::underlying_type<ControlTarget>::type>(function.target); - return false; + if (service == nullptr) { + LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << message + << " from pid: " << from_pid << " (" << process_cmdline << ")"; + return false; } - if (svc == nullptr) { - LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << msg - << " from pid: " << pid << " (" << process_cmdline << ")"; + const auto& map = GetControlMessageMap(); + const auto it = map.find(action); + if (it == map.end()) { + LOG(ERROR) << "Unknown control msg '" << message << "'"; return false; } + const auto& function = it->second; - if (auto result = function.action(svc); !result.ok()) { - LOG(ERROR) << "Control message: Could not ctl." << msg << " for '" << name - << "' from pid: " << pid << " (" << process_cmdline << "): " << result.error(); + if (auto result = function(service); !result.ok()) { + LOG(ERROR) << "Control message: Could not ctl." << message << " for '" << name + << "' from pid: " << from_pid << " (" << process_cmdline + << "): " << result.error(); return false; } - LOG(INFO) << "Control message: Processed ctl." << msg << " for '" << name - << "' from pid: " << pid << " (" << process_cmdline << ")"; + LOG(INFO) << "Control message: Processed ctl." << message << " for '" << name + << "' from pid: " << from_pid << " (" << process_cmdline << ")"; return true; } @@ -451,7 +462,7 @@ bool QueueControlMessage(const std::string& message, const std::string& name, pi return false; } pending_control_messages.push({message, name, pid, fd}); - WakeEpoll(); + WakeMainInitThread(); return true; } @@ -477,7 +488,7 @@ static void HandleControlMessages() { } // If we still have items to process, make sure we wake back up to do so. if (!pending_control_messages.empty()) { - WakeEpoll(); + WakeMainInitThread(); } } @@ -713,8 +724,15 @@ int SecondStageMain(int argc, char** argv) { InitKernelLogging(argv); LOG(INFO) << "init second stage started!"; - // Will handle EPIPE at the time of write by checking the errno - signal(SIGPIPE, SIG_IGN); + // Init should not crash because of a dependence on any other process, therefore we ignore + // SIGPIPE and handle EPIPE at the call site directly. Note that setting a signal to SIG_IGN + // is inherited across exec, but custom signal handlers are not. Since we do not want to + // ignore SIGPIPE for child processes, we set a no-op function for the signal handler instead. + { + struct sigaction action = {.sa_flags = SA_RESTART}; + action.sa_handler = [](int) {}; + sigaction(SIGPIPE, &action, nullptr); + } // Set init and its forked children's oom_adj. if (auto result = @@ -853,6 +871,8 @@ int SecondStageMain(int argc, char** argv) { auto shutdown_command = shutdown_state.CheckShutdown(); if (shutdown_command) { + LOG(INFO) << "Got shutdown_command '" << *shutdown_command + << "' Calling HandlePowerctlMessage()"; HandlePowerctlMessage(*shutdown_command); } @@ -887,7 +907,9 @@ int SecondStageMain(int argc, char** argv) { (*function)(); } } - HandleControlMessages(); + if (!IsShuttingDown()) { + HandleControlMessages(); + } } return 0; |