Loading init/Android.bp +0 −2 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ init_common_sources = [ "rlimit_parser.cpp", "service.cpp", "service_list.cpp", "service_lock.cpp", "service_parser.cpp", "service_utils.cpp", "subcontext.cpp", Loading Loading @@ -82,7 +81,6 @@ cc_defaults { "-Wextra", "-Wno-unused-parameter", "-Werror", "-Wthread-safety", "-DALLOW_FIRST_STAGE_CONSOLE=0", "-DALLOW_LOCAL_PROP_OVERRIDE=0", "-DALLOW_PERMISSIVE_SELINUX=0", Loading init/action_manager.cpp +7 −15 Original line number Diff line number Diff line Loading @@ -41,12 +41,10 @@ void ActionManager::AddAction(std::unique_ptr<Action> action) { } void ActionManager::QueueEventTrigger(const std::string& trigger) { auto lock = std::lock_guard{event_queue_lock_}; event_queue_.emplace(trigger); } void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) { auto lock = std::lock_guard{event_queue_lock_}; event_queue_.emplace(std::make_pair(name, value)); } Loading @@ -55,7 +53,6 @@ void ActionManager::QueueAllPropertyActions() { } void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) { auto lock = std::lock_guard{event_queue_lock_}; auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name, std::map<std::string, std::string>{}); action->AddCommand(std::move(func), {name}, 0); Loading @@ -65,8 +62,6 @@ void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& } void ActionManager::ExecuteOneCommand() { { auto lock = std::lock_guard{event_queue_lock_}; // Loop through the event queue until we have an action to execute while (current_executing_actions_.empty() && !event_queue_.empty()) { for (const auto& action : actions_) { Loading @@ -77,7 +72,6 @@ void ActionManager::ExecuteOneCommand() { } event_queue_.pop(); } } if (current_executing_actions_.empty()) { return; Loading Loading @@ -109,7 +103,6 @@ void ActionManager::ExecuteOneCommand() { } bool ActionManager::HasMoreCommands() const { auto lock = std::lock_guard{event_queue_lock_}; return !current_executing_actions_.empty() || !event_queue_.empty(); } Loading @@ -120,7 +113,6 @@ void ActionManager::DumpState() const { } void ActionManager::ClearQueue() { auto lock = std::lock_guard{event_queue_lock_}; // We are shutting down so don't claim the oneshot builtin actions back current_executing_actions_ = {}; event_queue_ = {}; Loading init/action_manager.h +1 −6 Original line number Diff line number Diff line Loading @@ -16,12 +16,9 @@ #pragma once #include <mutex> #include <string> #include <vector> #include <android-base/thread_annotations.h> #include "action.h" #include "builtins.h" Loading Loading @@ -51,9 +48,7 @@ class ActionManager { void operator=(ActionManager const&) = delete; std::vector<std::unique_ptr<Action>> actions_; std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_ GUARDED_BY(event_queue_lock_); mutable std::mutex event_queue_lock_; std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_; std::queue<const Action*> current_executing_actions_; std::size_t current_command_; }; Loading init/builtins.cpp +0 −15 Original line number Diff line number Diff line Loading @@ -151,7 +151,6 @@ static Result<void> reboot_into_recovery(const std::vector<std::string>& options template <typename F> static void ForEachServiceInClass(const std::string& classname, F function) { auto lock = std::lock_guard{service_lock}; for (const auto& service : ServiceList::GetInstance()) { if (service->classnames().count(classname)) std::invoke(function, service); } Loading @@ -163,7 +162,6 @@ static Result<void> do_class_start(const BuiltinArguments& args) { return {}; // Starting a class does not start services which are explicitly disabled. // They must be started individually. auto lock = std::lock_guard{service_lock}; for (const auto& service : ServiceList::GetInstance()) { if (service->classnames().count(args[1])) { if (auto result = service->StartIfNotDisabled(); !result.ok()) { Loading @@ -186,7 +184,6 @@ static Result<void> do_class_start_post_data(const BuiltinArguments& args) { // stopped either. return {}; } auto lock = std::lock_guard{service_lock}; for (const auto& service : ServiceList::GetInstance()) { if (service->classnames().count(args[1])) { if (auto result = service->StartIfPostData(); !result.ok()) { Loading Loading @@ -237,7 +234,6 @@ static Result<void> do_domainname(const BuiltinArguments& args) { } static Result<void> do_enable(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindService(args[1]); if (!svc) return Error() << "Could not find service"; Loading @@ -249,7 +245,6 @@ static Result<void> do_enable(const BuiltinArguments& args) { } static Result<void> do_exec(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; auto service = Service::MakeTemporaryOneshotService(args.args); if (!service.ok()) { return Error() << "Could not create exec service: " << service.error(); Loading @@ -263,7 +258,6 @@ static Result<void> do_exec(const BuiltinArguments& args) { } static Result<void> do_exec_background(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; auto service = Service::MakeTemporaryOneshotService(args.args); if (!service.ok()) { return Error() << "Could not create exec background service: " << service.error(); Loading @@ -277,7 +271,6 @@ static Result<void> do_exec_background(const BuiltinArguments& args) { } static Result<void> do_exec_start(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* service = ServiceList::GetInstance().FindService(args[1]); if (!service) { return Error() << "Service not found"; Loading Loading @@ -347,7 +340,6 @@ static Result<void> do_insmod(const BuiltinArguments& args) { } static Result<void> do_interface_restart(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindInterface(args[1]); if (!svc) return Error() << "interface " << args[1] << " not found"; svc->Restart(); Loading @@ -355,7 +347,6 @@ static Result<void> do_interface_restart(const BuiltinArguments& args) { } static Result<void> do_interface_start(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindInterface(args[1]); if (!svc) return Error() << "interface " << args[1] << " not found"; if (auto result = svc->Start(); !result.ok()) { Loading @@ -365,7 +356,6 @@ static Result<void> do_interface_start(const BuiltinArguments& args) { } static Result<void> do_interface_stop(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindInterface(args[1]); if (!svc) return Error() << "interface " << args[1] << " not found"; svc->Stop(); Loading Loading @@ -750,7 +740,6 @@ static Result<void> do_setrlimit(const BuiltinArguments& args) { } static Result<void> do_start(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindService(args[1]); if (!svc) return Error() << "service " << args[1] << " not found"; if (auto result = svc->Start(); !result.ok()) { Loading @@ -760,7 +749,6 @@ static Result<void> do_start(const BuiltinArguments& args) { } static Result<void> do_stop(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindService(args[1]); if (!svc) return Error() << "service " << args[1] << " not found"; svc->Stop(); Loading @@ -768,7 +756,6 @@ static Result<void> do_stop(const BuiltinArguments& args) { } static Result<void> do_restart(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindService(args[1]); if (!svc) return Error() << "service " << args[1] << " not found"; svc->Restart(); Loading Loading @@ -1124,7 +1111,6 @@ static Result<void> ExecWithFunctionOnFailure(const std::vector<std::string>& ar function(StringPrintf("Exec service failed, status %d", siginfo.si_status)); } }); auto lock = std::lock_guard{service_lock}; if (auto result = (*service)->ExecStart(); !result.ok()) { function("ExecStart failed: " + result.error().message()); } Loading Loading @@ -1264,7 +1250,6 @@ static Result<void> parse_apex_configs() { } success &= parser.ParseConfigFile(c); } auto lock = std::lock_guard{service_lock}; ServiceList::GetInstance().MarkServicesUpdate(); if (success) { return {}; Loading init/init.cpp +111 −168 Original line number Diff line number Diff line Loading @@ -33,9 +33,7 @@ #include <functional> #include <map> #include <memory> #include <mutex> #include <optional> #include <thread> #include <vector> #include <android-base/chrono_utils.h> Loading Loading @@ -97,148 +95,15 @@ static int property_triggers_enabled = 0; static int signal_fd = -1; static int property_fd = -1; static std::unique_ptr<Subcontext> subcontext; // Init epolls various FDs to wait for various inputs. It previously waited on property changes // with a blocking socket that contained the information related to the change, however, it was easy // 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; 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"; } 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) { } }; if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result) { LOG(FATAL) << result.error(); } } static void WakeEpoll() { constexpr char value[] = "1"; write(wake_epoll_fd, value, sizeof(value)); } static class PropWaiterState { public: bool StartWaiting(const char* name, const char* value) { auto lock = std::lock_guard{lock_}; if (waiting_for_prop_) { return false; } if (GetProperty(name, "") != value) { // Current property value is not equal to expected value wait_prop_name_ = name; wait_prop_value_ = value; waiting_for_prop_.reset(new Timer()); } else { LOG(INFO) << "start_waiting_for_property(\"" << name << "\", \"" << value << "\"): already set"; } return true; } void ResetWaitForProp() { auto lock = std::lock_guard{lock_}; ResetWaitForPropLocked(); } void CheckAndResetWait(const std::string& name, const std::string& value) { auto lock = std::lock_guard{lock_}; // We always record how long init waited for ueventd to tell us cold boot finished. // If we aren't waiting on this property, it means that ueventd finished before we even // started to wait. if (name == kColdBootDoneProp) { auto time_waited = waiting_for_prop_ ? waiting_for_prop_->duration().count() : 0; std::thread([time_waited] { SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited)); }).detach(); } if (waiting_for_prop_) { if (wait_prop_name_ == name && wait_prop_value_ == value) { LOG(INFO) << "Wait for property '" << wait_prop_name_ << "=" << wait_prop_value_ << "' took " << *waiting_for_prop_; ResetWaitForPropLocked(); WakeEpoll(); } } } // This is not thread safe because it releases the lock when it returns, so the waiting state // may change. However, we only use this function to prevent running commands in the main // thread loop when we are waiting, so we do not care about false positives; only false // negatives. StartWaiting() and this function are always called from the same thread, so false // negatives are not possible and therefore we're okay. bool MightBeWaiting() { auto lock = std::lock_guard{lock_}; return static_cast<bool>(waiting_for_prop_); } private: void ResetWaitForPropLocked() { wait_prop_name_.clear(); wait_prop_value_.clear(); waiting_for_prop_.reset(); } std::mutex lock_; std::unique_ptr<Timer> waiting_for_prop_{nullptr}; std::string wait_prop_name_; std::string wait_prop_value_; } prop_waiter_state; bool start_waiting_for_property(const char* name, const char* value) { return prop_waiter_state.StartWaiting(name, value); } void ResetWaitForProp() { prop_waiter_state.ResetWaitForProp(); } static class ShutdownState { public: void TriggerShutdown(const std::string& command) { // We can't call HandlePowerctlMessage() directly in this function, // because it modifies the contents of the action queue, which can cause the action queue // to get into a bad state if this function is called from a command being executed by the // action queue. Instead we set this flag and ensure that shutdown happens before the next // command is run in the main init loop. auto lock = std::lock_guard{shutdown_command_lock_}; shutdown_command_ = command; do_shutdown_ = true; WakeEpoll(); } static std::unique_ptr<Timer> waiting_for_prop(nullptr); static std::string wait_prop_name; static std::string wait_prop_value; static std::string shutdown_command; static bool do_shutdown = false; std::optional<std::string> CheckShutdown() { auto lock = std::lock_guard{shutdown_command_lock_}; if (do_shutdown_ && !IsShuttingDown()) { do_shutdown_ = false; return shutdown_command_; } return {}; } private: std::mutex shutdown_command_lock_; std::string shutdown_command_; bool do_shutdown_ = false; } shutdown_state; static std::unique_ptr<Subcontext> subcontext; void DumpState() { auto lock = std::lock_guard{service_lock}; ServiceList::GetInstance().DumpState(); ActionManager::GetInstance().DumpState(); } Loading Loading @@ -291,7 +156,39 @@ static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_ } } void PropertyChanged(const std::string& name, const std::string& value) { bool start_waiting_for_property(const char* name, const char* value) { if (waiting_for_prop) { return false; } if (GetProperty(name, "") != value) { // Current property value is not equal to expected value wait_prop_name = name; wait_prop_value = value; waiting_for_prop.reset(new Timer()); } else { LOG(INFO) << "start_waiting_for_property(\"" << name << "\", \"" << value << "\"): already set"; } return true; } void ResetWaitForProp() { wait_prop_name.clear(); wait_prop_value.clear(); waiting_for_prop.reset(); } static void TriggerShutdown(const std::string& command) { // We can't call HandlePowerctlMessage() directly in this function, // because it modifies the contents of the action queue, which can cause the action queue // to get into a bad state if this function is called from a command being executed by the // action queue. Instead we set this flag and ensure that shutdown happens before the next // command is run in the main init loop. shutdown_command = command; do_shutdown = true; } void property_changed(const std::string& name, const std::string& value) { // If the property is sys.powerctl, we bypass the event queue and immediately handle it. // This is to ensure that init will always and immediately shutdown/reboot, regardless of // if there are other pending events to process or if init is waiting on an exec service or Loading @@ -299,20 +196,30 @@ void PropertyChanged(const std::string& name, const std::string& value) { // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific // commands to be executed. if (name == "sys.powerctl") { trigger_shutdown(value); TriggerShutdown(value); } if (property_triggers_enabled) { ActionManager::GetInstance().QueuePropertyChange(name, value); WakeEpoll(); if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value); // We always record how long init waited for ueventd to tell us cold boot finished. // If we aren't waiting on this property, it means that ueventd finished before we even started // to wait. if (name == kColdBootDoneProp) { auto time_waited = waiting_for_prop ? waiting_for_prop->duration().count() : 0; SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited)); } prop_waiter_state.CheckAndResetWait(name, value); if (waiting_for_prop) { if (wait_prop_name == name && wait_prop_value == value) { LOG(INFO) << "Wait for property '" << wait_prop_name << "=" << wait_prop_value << "' took " << *waiting_for_prop; ResetWaitForProp(); } } } static std::optional<boot_clock::time_point> HandleProcessActions() { std::optional<boot_clock::time_point> next_process_action_time; auto lock = std::lock_guard{service_lock}; for (const auto& s : ServiceList::GetInstance()) { if ((s->flags() & SVC_RUNNING) && s->timeout_period()) { auto timeout_time = s->time_started() + *s->timeout_period(); Loading Loading @@ -341,7 +248,7 @@ static std::optional<boot_clock::time_point> HandleProcessActions() { return next_process_action_time; } static Result<void> DoControlStart(Service* service) REQUIRES(service_lock) { static Result<void> DoControlStart(Service* service) { return service->Start(); } Loading @@ -350,7 +257,7 @@ static Result<void> DoControlStop(Service* service) { return {}; } static Result<void> DoControlRestart(Service* service) REQUIRES(service_lock) { static Result<void> DoControlRestart(Service* service) { service->Restart(); return {}; } Loading Loading @@ -384,7 +291,7 @@ static const std::map<std::string, ControlMessageFunction>& get_control_message_ return control_message_functions; } bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid) { 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); Loading @@ -393,7 +300,7 @@ bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t return false; } std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid); std::string cmdline_path = StringPrintf("proc/%d/cmdline", pid); std::string process_cmdline; if (ReadFileToString(cmdline_path, &process_cmdline)) { std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' '); Loading @@ -404,8 +311,6 @@ bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t const ControlMessageFunction& function = it->second; auto lock = std::lock_guard{service_lock}; Service* svc = nullptr; switch (function.target) { Loading @@ -423,24 +328,23 @@ bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t if (svc == nullptr) { LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << msg << " from pid: " << from_pid << " (" << process_cmdline << ")"; << " from pid: " << pid << " (" << process_cmdline << ")"; return false; } if (auto result = function.action(svc); !result.ok()) { LOG(ERROR) << "Control message: Could not ctl." << msg << " for '" << name << "' from pid: " << from_pid << " (" << process_cmdline << "): " << result.error(); << "' from pid: " << pid << " (" << process_cmdline << "): " << result.error(); return false; } LOG(INFO) << "Control message: Processed ctl." << msg << " for '" << name << "' from pid: " << from_pid << " (" << process_cmdline << ")"; << "' from pid: " << pid << " (" << process_cmdline << ")"; return true; } static Result<void> wait_for_coldboot_done_action(const BuiltinArguments& args) { if (!prop_waiter_state.StartWaiting(kColdBootDoneProp, "true")) { if (!start_waiting_for_property(kColdBootDoneProp, "true")) { LOG(FATAL) << "Could not wait for '" << kColdBootDoneProp << "'"; } Loading Loading @@ -588,7 +492,6 @@ void HandleKeychord(const std::vector<int>& keycodes) { } auto found = false; auto lock = std::lock_guard{service_lock}; for (const auto& service : ServiceList::GetInstance()) { auto svc = service.get(); if (svc->keycodes() == keycodes) { Loading Loading @@ -675,6 +578,44 @@ void SendStartSendingMessagesMessage() { } } static void HandlePropertyFd() { auto message = ReadMessage(property_fd); if (!message.ok()) { LOG(ERROR) << "Could not read message from property service: " << message.error(); return; } auto property_message = PropertyMessage{}; if (!property_message.ParseFromString(*message)) { LOG(ERROR) << "Could not parse message from property service"; return; } switch (property_message.msg_case()) { case PropertyMessage::kControlMessage: { auto& control_message = property_message.control_message(); bool success = HandleControlMessage(control_message.msg(), control_message.name(), control_message.pid()); uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE; if (control_message.has_fd()) { int fd = control_message.fd(); TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0)); close(fd); } break; } case PropertyMessage::kChangedMessage: { auto& changed_message = property_message.changed_message(); property_changed(changed_message.name(), changed_message.value()); break; } default: LOG(ERROR) << "Unknown message type from property service: " << property_message.msg_case(); } } int SecondStageMain(int argc, char** argv) { if (REBOOT_BOOTLOADER_ON_PANIC) { InstallRebootSignalHandlers(); Loading @@ -682,7 +623,7 @@ int SecondStageMain(int argc, char** argv) { boot_clock::time_point start_time = boot_clock::now(); trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); }; trigger_shutdown = TriggerShutdown; SetStdioToDevNull(argv); InitKernelLogging(argv); Loading Loading @@ -742,8 +683,11 @@ int SecondStageMain(int argc, char** argv) { } InstallSignalFdHandler(&epoll); InstallInitNotifier(&epoll); StartPropertyService(&property_fd); if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result.ok()) { LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error(); } // Make the time that init stages started available for bootstat to log. RecordStageBoottimes(start_time); Loading Loading @@ -796,7 +740,6 @@ int SecondStageMain(int argc, char** argv) { Keychords keychords; am.QueueBuiltinAction( [&epoll, &keychords](const BuiltinArguments& args) -> Result<void> { auto lock = std::lock_guard{service_lock}; for (const auto& svc : ServiceList::GetInstance()) { keychords.Register(svc->keycodes()); } Loading Loading @@ -827,12 +770,12 @@ int SecondStageMain(int argc, char** argv) { // By default, sleep until something happens. auto epoll_timeout = std::optional<std::chrono::milliseconds>{}; auto shutdown_command = shutdown_state.CheckShutdown(); if (shutdown_command) { HandlePowerctlMessage(*shutdown_command); if (do_shutdown && !IsShuttingDown()) { do_shutdown = false; HandlePowerctlMessage(shutdown_command); } if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) { if (!(waiting_for_prop || Service::is_exec_service_running())) { am.ExecuteOneCommand(); } if (!IsShuttingDown()) { Loading @@ -846,7 +789,7 @@ int SecondStageMain(int argc, char** argv) { } } if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) { if (!(waiting_for_prop || Service::is_exec_service_running())) { // If there's more work to do, wake up again immediately. if (am.HasMoreCommands()) epoll_timeout = 0ms; } Loading Loading
init/Android.bp +0 −2 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ init_common_sources = [ "rlimit_parser.cpp", "service.cpp", "service_list.cpp", "service_lock.cpp", "service_parser.cpp", "service_utils.cpp", "subcontext.cpp", Loading Loading @@ -82,7 +81,6 @@ cc_defaults { "-Wextra", "-Wno-unused-parameter", "-Werror", "-Wthread-safety", "-DALLOW_FIRST_STAGE_CONSOLE=0", "-DALLOW_LOCAL_PROP_OVERRIDE=0", "-DALLOW_PERMISSIVE_SELINUX=0", Loading
init/action_manager.cpp +7 −15 Original line number Diff line number Diff line Loading @@ -41,12 +41,10 @@ void ActionManager::AddAction(std::unique_ptr<Action> action) { } void ActionManager::QueueEventTrigger(const std::string& trigger) { auto lock = std::lock_guard{event_queue_lock_}; event_queue_.emplace(trigger); } void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) { auto lock = std::lock_guard{event_queue_lock_}; event_queue_.emplace(std::make_pair(name, value)); } Loading @@ -55,7 +53,6 @@ void ActionManager::QueueAllPropertyActions() { } void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) { auto lock = std::lock_guard{event_queue_lock_}; auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name, std::map<std::string, std::string>{}); action->AddCommand(std::move(func), {name}, 0); Loading @@ -65,8 +62,6 @@ void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& } void ActionManager::ExecuteOneCommand() { { auto lock = std::lock_guard{event_queue_lock_}; // Loop through the event queue until we have an action to execute while (current_executing_actions_.empty() && !event_queue_.empty()) { for (const auto& action : actions_) { Loading @@ -77,7 +72,6 @@ void ActionManager::ExecuteOneCommand() { } event_queue_.pop(); } } if (current_executing_actions_.empty()) { return; Loading Loading @@ -109,7 +103,6 @@ void ActionManager::ExecuteOneCommand() { } bool ActionManager::HasMoreCommands() const { auto lock = std::lock_guard{event_queue_lock_}; return !current_executing_actions_.empty() || !event_queue_.empty(); } Loading @@ -120,7 +113,6 @@ void ActionManager::DumpState() const { } void ActionManager::ClearQueue() { auto lock = std::lock_guard{event_queue_lock_}; // We are shutting down so don't claim the oneshot builtin actions back current_executing_actions_ = {}; event_queue_ = {}; Loading
init/action_manager.h +1 −6 Original line number Diff line number Diff line Loading @@ -16,12 +16,9 @@ #pragma once #include <mutex> #include <string> #include <vector> #include <android-base/thread_annotations.h> #include "action.h" #include "builtins.h" Loading Loading @@ -51,9 +48,7 @@ class ActionManager { void operator=(ActionManager const&) = delete; std::vector<std::unique_ptr<Action>> actions_; std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_ GUARDED_BY(event_queue_lock_); mutable std::mutex event_queue_lock_; std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_; std::queue<const Action*> current_executing_actions_; std::size_t current_command_; }; Loading
init/builtins.cpp +0 −15 Original line number Diff line number Diff line Loading @@ -151,7 +151,6 @@ static Result<void> reboot_into_recovery(const std::vector<std::string>& options template <typename F> static void ForEachServiceInClass(const std::string& classname, F function) { auto lock = std::lock_guard{service_lock}; for (const auto& service : ServiceList::GetInstance()) { if (service->classnames().count(classname)) std::invoke(function, service); } Loading @@ -163,7 +162,6 @@ static Result<void> do_class_start(const BuiltinArguments& args) { return {}; // Starting a class does not start services which are explicitly disabled. // They must be started individually. auto lock = std::lock_guard{service_lock}; for (const auto& service : ServiceList::GetInstance()) { if (service->classnames().count(args[1])) { if (auto result = service->StartIfNotDisabled(); !result.ok()) { Loading @@ -186,7 +184,6 @@ static Result<void> do_class_start_post_data(const BuiltinArguments& args) { // stopped either. return {}; } auto lock = std::lock_guard{service_lock}; for (const auto& service : ServiceList::GetInstance()) { if (service->classnames().count(args[1])) { if (auto result = service->StartIfPostData(); !result.ok()) { Loading Loading @@ -237,7 +234,6 @@ static Result<void> do_domainname(const BuiltinArguments& args) { } static Result<void> do_enable(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindService(args[1]); if (!svc) return Error() << "Could not find service"; Loading @@ -249,7 +245,6 @@ static Result<void> do_enable(const BuiltinArguments& args) { } static Result<void> do_exec(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; auto service = Service::MakeTemporaryOneshotService(args.args); if (!service.ok()) { return Error() << "Could not create exec service: " << service.error(); Loading @@ -263,7 +258,6 @@ static Result<void> do_exec(const BuiltinArguments& args) { } static Result<void> do_exec_background(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; auto service = Service::MakeTemporaryOneshotService(args.args); if (!service.ok()) { return Error() << "Could not create exec background service: " << service.error(); Loading @@ -277,7 +271,6 @@ static Result<void> do_exec_background(const BuiltinArguments& args) { } static Result<void> do_exec_start(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* service = ServiceList::GetInstance().FindService(args[1]); if (!service) { return Error() << "Service not found"; Loading Loading @@ -347,7 +340,6 @@ static Result<void> do_insmod(const BuiltinArguments& args) { } static Result<void> do_interface_restart(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindInterface(args[1]); if (!svc) return Error() << "interface " << args[1] << " not found"; svc->Restart(); Loading @@ -355,7 +347,6 @@ static Result<void> do_interface_restart(const BuiltinArguments& args) { } static Result<void> do_interface_start(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindInterface(args[1]); if (!svc) return Error() << "interface " << args[1] << " not found"; if (auto result = svc->Start(); !result.ok()) { Loading @@ -365,7 +356,6 @@ static Result<void> do_interface_start(const BuiltinArguments& args) { } static Result<void> do_interface_stop(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindInterface(args[1]); if (!svc) return Error() << "interface " << args[1] << " not found"; svc->Stop(); Loading Loading @@ -750,7 +740,6 @@ static Result<void> do_setrlimit(const BuiltinArguments& args) { } static Result<void> do_start(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindService(args[1]); if (!svc) return Error() << "service " << args[1] << " not found"; if (auto result = svc->Start(); !result.ok()) { Loading @@ -760,7 +749,6 @@ static Result<void> do_start(const BuiltinArguments& args) { } static Result<void> do_stop(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindService(args[1]); if (!svc) return Error() << "service " << args[1] << " not found"; svc->Stop(); Loading @@ -768,7 +756,6 @@ static Result<void> do_stop(const BuiltinArguments& args) { } static Result<void> do_restart(const BuiltinArguments& args) { auto lock = std::lock_guard{service_lock}; Service* svc = ServiceList::GetInstance().FindService(args[1]); if (!svc) return Error() << "service " << args[1] << " not found"; svc->Restart(); Loading Loading @@ -1124,7 +1111,6 @@ static Result<void> ExecWithFunctionOnFailure(const std::vector<std::string>& ar function(StringPrintf("Exec service failed, status %d", siginfo.si_status)); } }); auto lock = std::lock_guard{service_lock}; if (auto result = (*service)->ExecStart(); !result.ok()) { function("ExecStart failed: " + result.error().message()); } Loading Loading @@ -1264,7 +1250,6 @@ static Result<void> parse_apex_configs() { } success &= parser.ParseConfigFile(c); } auto lock = std::lock_guard{service_lock}; ServiceList::GetInstance().MarkServicesUpdate(); if (success) { return {}; Loading
init/init.cpp +111 −168 Original line number Diff line number Diff line Loading @@ -33,9 +33,7 @@ #include <functional> #include <map> #include <memory> #include <mutex> #include <optional> #include <thread> #include <vector> #include <android-base/chrono_utils.h> Loading Loading @@ -97,148 +95,15 @@ static int property_triggers_enabled = 0; static int signal_fd = -1; static int property_fd = -1; static std::unique_ptr<Subcontext> subcontext; // Init epolls various FDs to wait for various inputs. It previously waited on property changes // with a blocking socket that contained the information related to the change, however, it was easy // 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; 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"; } 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) { } }; if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result) { LOG(FATAL) << result.error(); } } static void WakeEpoll() { constexpr char value[] = "1"; write(wake_epoll_fd, value, sizeof(value)); } static class PropWaiterState { public: bool StartWaiting(const char* name, const char* value) { auto lock = std::lock_guard{lock_}; if (waiting_for_prop_) { return false; } if (GetProperty(name, "") != value) { // Current property value is not equal to expected value wait_prop_name_ = name; wait_prop_value_ = value; waiting_for_prop_.reset(new Timer()); } else { LOG(INFO) << "start_waiting_for_property(\"" << name << "\", \"" << value << "\"): already set"; } return true; } void ResetWaitForProp() { auto lock = std::lock_guard{lock_}; ResetWaitForPropLocked(); } void CheckAndResetWait(const std::string& name, const std::string& value) { auto lock = std::lock_guard{lock_}; // We always record how long init waited for ueventd to tell us cold boot finished. // If we aren't waiting on this property, it means that ueventd finished before we even // started to wait. if (name == kColdBootDoneProp) { auto time_waited = waiting_for_prop_ ? waiting_for_prop_->duration().count() : 0; std::thread([time_waited] { SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited)); }).detach(); } if (waiting_for_prop_) { if (wait_prop_name_ == name && wait_prop_value_ == value) { LOG(INFO) << "Wait for property '" << wait_prop_name_ << "=" << wait_prop_value_ << "' took " << *waiting_for_prop_; ResetWaitForPropLocked(); WakeEpoll(); } } } // This is not thread safe because it releases the lock when it returns, so the waiting state // may change. However, we only use this function to prevent running commands in the main // thread loop when we are waiting, so we do not care about false positives; only false // negatives. StartWaiting() and this function are always called from the same thread, so false // negatives are not possible and therefore we're okay. bool MightBeWaiting() { auto lock = std::lock_guard{lock_}; return static_cast<bool>(waiting_for_prop_); } private: void ResetWaitForPropLocked() { wait_prop_name_.clear(); wait_prop_value_.clear(); waiting_for_prop_.reset(); } std::mutex lock_; std::unique_ptr<Timer> waiting_for_prop_{nullptr}; std::string wait_prop_name_; std::string wait_prop_value_; } prop_waiter_state; bool start_waiting_for_property(const char* name, const char* value) { return prop_waiter_state.StartWaiting(name, value); } void ResetWaitForProp() { prop_waiter_state.ResetWaitForProp(); } static class ShutdownState { public: void TriggerShutdown(const std::string& command) { // We can't call HandlePowerctlMessage() directly in this function, // because it modifies the contents of the action queue, which can cause the action queue // to get into a bad state if this function is called from a command being executed by the // action queue. Instead we set this flag and ensure that shutdown happens before the next // command is run in the main init loop. auto lock = std::lock_guard{shutdown_command_lock_}; shutdown_command_ = command; do_shutdown_ = true; WakeEpoll(); } static std::unique_ptr<Timer> waiting_for_prop(nullptr); static std::string wait_prop_name; static std::string wait_prop_value; static std::string shutdown_command; static bool do_shutdown = false; std::optional<std::string> CheckShutdown() { auto lock = std::lock_guard{shutdown_command_lock_}; if (do_shutdown_ && !IsShuttingDown()) { do_shutdown_ = false; return shutdown_command_; } return {}; } private: std::mutex shutdown_command_lock_; std::string shutdown_command_; bool do_shutdown_ = false; } shutdown_state; static std::unique_ptr<Subcontext> subcontext; void DumpState() { auto lock = std::lock_guard{service_lock}; ServiceList::GetInstance().DumpState(); ActionManager::GetInstance().DumpState(); } Loading Loading @@ -291,7 +156,39 @@ static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_ } } void PropertyChanged(const std::string& name, const std::string& value) { bool start_waiting_for_property(const char* name, const char* value) { if (waiting_for_prop) { return false; } if (GetProperty(name, "") != value) { // Current property value is not equal to expected value wait_prop_name = name; wait_prop_value = value; waiting_for_prop.reset(new Timer()); } else { LOG(INFO) << "start_waiting_for_property(\"" << name << "\", \"" << value << "\"): already set"; } return true; } void ResetWaitForProp() { wait_prop_name.clear(); wait_prop_value.clear(); waiting_for_prop.reset(); } static void TriggerShutdown(const std::string& command) { // We can't call HandlePowerctlMessage() directly in this function, // because it modifies the contents of the action queue, which can cause the action queue // to get into a bad state if this function is called from a command being executed by the // action queue. Instead we set this flag and ensure that shutdown happens before the next // command is run in the main init loop. shutdown_command = command; do_shutdown = true; } void property_changed(const std::string& name, const std::string& value) { // If the property is sys.powerctl, we bypass the event queue and immediately handle it. // This is to ensure that init will always and immediately shutdown/reboot, regardless of // if there are other pending events to process or if init is waiting on an exec service or Loading @@ -299,20 +196,30 @@ void PropertyChanged(const std::string& name, const std::string& value) { // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific // commands to be executed. if (name == "sys.powerctl") { trigger_shutdown(value); TriggerShutdown(value); } if (property_triggers_enabled) { ActionManager::GetInstance().QueuePropertyChange(name, value); WakeEpoll(); if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value); // We always record how long init waited for ueventd to tell us cold boot finished. // If we aren't waiting on this property, it means that ueventd finished before we even started // to wait. if (name == kColdBootDoneProp) { auto time_waited = waiting_for_prop ? waiting_for_prop->duration().count() : 0; SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited)); } prop_waiter_state.CheckAndResetWait(name, value); if (waiting_for_prop) { if (wait_prop_name == name && wait_prop_value == value) { LOG(INFO) << "Wait for property '" << wait_prop_name << "=" << wait_prop_value << "' took " << *waiting_for_prop; ResetWaitForProp(); } } } static std::optional<boot_clock::time_point> HandleProcessActions() { std::optional<boot_clock::time_point> next_process_action_time; auto lock = std::lock_guard{service_lock}; for (const auto& s : ServiceList::GetInstance()) { if ((s->flags() & SVC_RUNNING) && s->timeout_period()) { auto timeout_time = s->time_started() + *s->timeout_period(); Loading Loading @@ -341,7 +248,7 @@ static std::optional<boot_clock::time_point> HandleProcessActions() { return next_process_action_time; } static Result<void> DoControlStart(Service* service) REQUIRES(service_lock) { static Result<void> DoControlStart(Service* service) { return service->Start(); } Loading @@ -350,7 +257,7 @@ static Result<void> DoControlStop(Service* service) { return {}; } static Result<void> DoControlRestart(Service* service) REQUIRES(service_lock) { static Result<void> DoControlRestart(Service* service) { service->Restart(); return {}; } Loading Loading @@ -384,7 +291,7 @@ static const std::map<std::string, ControlMessageFunction>& get_control_message_ return control_message_functions; } bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid) { 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); Loading @@ -393,7 +300,7 @@ bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t return false; } std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid); std::string cmdline_path = StringPrintf("proc/%d/cmdline", pid); std::string process_cmdline; if (ReadFileToString(cmdline_path, &process_cmdline)) { std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' '); Loading @@ -404,8 +311,6 @@ bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t const ControlMessageFunction& function = it->second; auto lock = std::lock_guard{service_lock}; Service* svc = nullptr; switch (function.target) { Loading @@ -423,24 +328,23 @@ bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t if (svc == nullptr) { LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << msg << " from pid: " << from_pid << " (" << process_cmdline << ")"; << " from pid: " << pid << " (" << process_cmdline << ")"; return false; } if (auto result = function.action(svc); !result.ok()) { LOG(ERROR) << "Control message: Could not ctl." << msg << " for '" << name << "' from pid: " << from_pid << " (" << process_cmdline << "): " << result.error(); << "' from pid: " << pid << " (" << process_cmdline << "): " << result.error(); return false; } LOG(INFO) << "Control message: Processed ctl." << msg << " for '" << name << "' from pid: " << from_pid << " (" << process_cmdline << ")"; << "' from pid: " << pid << " (" << process_cmdline << ")"; return true; } static Result<void> wait_for_coldboot_done_action(const BuiltinArguments& args) { if (!prop_waiter_state.StartWaiting(kColdBootDoneProp, "true")) { if (!start_waiting_for_property(kColdBootDoneProp, "true")) { LOG(FATAL) << "Could not wait for '" << kColdBootDoneProp << "'"; } Loading Loading @@ -588,7 +492,6 @@ void HandleKeychord(const std::vector<int>& keycodes) { } auto found = false; auto lock = std::lock_guard{service_lock}; for (const auto& service : ServiceList::GetInstance()) { auto svc = service.get(); if (svc->keycodes() == keycodes) { Loading Loading @@ -675,6 +578,44 @@ void SendStartSendingMessagesMessage() { } } static void HandlePropertyFd() { auto message = ReadMessage(property_fd); if (!message.ok()) { LOG(ERROR) << "Could not read message from property service: " << message.error(); return; } auto property_message = PropertyMessage{}; if (!property_message.ParseFromString(*message)) { LOG(ERROR) << "Could not parse message from property service"; return; } switch (property_message.msg_case()) { case PropertyMessage::kControlMessage: { auto& control_message = property_message.control_message(); bool success = HandleControlMessage(control_message.msg(), control_message.name(), control_message.pid()); uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE; if (control_message.has_fd()) { int fd = control_message.fd(); TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0)); close(fd); } break; } case PropertyMessage::kChangedMessage: { auto& changed_message = property_message.changed_message(); property_changed(changed_message.name(), changed_message.value()); break; } default: LOG(ERROR) << "Unknown message type from property service: " << property_message.msg_case(); } } int SecondStageMain(int argc, char** argv) { if (REBOOT_BOOTLOADER_ON_PANIC) { InstallRebootSignalHandlers(); Loading @@ -682,7 +623,7 @@ int SecondStageMain(int argc, char** argv) { boot_clock::time_point start_time = boot_clock::now(); trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); }; trigger_shutdown = TriggerShutdown; SetStdioToDevNull(argv); InitKernelLogging(argv); Loading Loading @@ -742,8 +683,11 @@ int SecondStageMain(int argc, char** argv) { } InstallSignalFdHandler(&epoll); InstallInitNotifier(&epoll); StartPropertyService(&property_fd); if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result.ok()) { LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error(); } // Make the time that init stages started available for bootstat to log. RecordStageBoottimes(start_time); Loading Loading @@ -796,7 +740,6 @@ int SecondStageMain(int argc, char** argv) { Keychords keychords; am.QueueBuiltinAction( [&epoll, &keychords](const BuiltinArguments& args) -> Result<void> { auto lock = std::lock_guard{service_lock}; for (const auto& svc : ServiceList::GetInstance()) { keychords.Register(svc->keycodes()); } Loading Loading @@ -827,12 +770,12 @@ int SecondStageMain(int argc, char** argv) { // By default, sleep until something happens. auto epoll_timeout = std::optional<std::chrono::milliseconds>{}; auto shutdown_command = shutdown_state.CheckShutdown(); if (shutdown_command) { HandlePowerctlMessage(*shutdown_command); if (do_shutdown && !IsShuttingDown()) { do_shutdown = false; HandlePowerctlMessage(shutdown_command); } if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) { if (!(waiting_for_prop || Service::is_exec_service_running())) { am.ExecuteOneCommand(); } if (!IsShuttingDown()) { Loading @@ -846,7 +789,7 @@ int SecondStageMain(int argc, char** argv) { } } if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) { if (!(waiting_for_prop || Service::is_exec_service_running())) { // If there's more work to do, wake up again immediately. if (am.HasMoreCommands()) epoll_timeout = 0ms; } Loading