From ba6968e63618ab5e37d3fb163e9ea27dc0aa3247 Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Mon, 7 Oct 2019 16:26:33 +0100 Subject: [PATCH] Add a skeleton of userspace reboot This CL only draws boundaries between userspace and full reboots, and adds some functionality that will be required for userspace reboot: * Whenever device is shutting down is now controlled in reboot.cpp, since during userspace reboot this state can change. * Now it's also possible to restart handling of control messages inside property service. In case of userspace reboot, init will restart it after stopping post-data services. * New userspace-reboot-requested trigger is added similar to shutdown one for full reboot. Test: adb reboot Test: adb reboot userspace Bug: 135984674 Change-Id: Id55a53ba781d2b90ce40449037b6d8d47e72c476 --- init/init.cpp | 19 ++++++--- init/init.h | 1 + init/property_service.cpp | 12 ++++-- init/property_service.proto | 1 + init/reboot.cpp | 85 +++++++++++++++++++++++++++++-------- init/reboot.h | 3 +- rootdir/init.rc | 12 ++++++ 7 files changed, 104 insertions(+), 29 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index ad31fa07e..ab6dbcf3c 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -98,7 +98,6 @@ static int property_fd = -1; static std::unique_ptr waiting_for_prop(nullptr); static std::string wait_prop_name; static std::string wait_prop_value; -static bool shutting_down; static std::string shutdown_command; static bool do_shutdown = false; static bool load_debug_prop = false; @@ -624,7 +623,15 @@ void SendStopSendingMessagesMessage() { auto init_message = InitMessage{}; init_message.set_stop_sending_messages(true); if (auto result = SendMessage(property_fd, init_message); !result) { - LOG(ERROR) << "Failed to send load persistent properties message: " << result.error(); + LOG(ERROR) << "Failed to send 'stop sending messages' message: " << result.error(); + } +} + +void SendStartSendingMessagesMessage() { + auto init_message = InitMessage{}; + init_message.set_start_sending_messages(true); + if (auto result = SendMessage(property_fd, init_message); !result) { + LOG(ERROR) << "Failed to send 'start sending messages' message: " << result.error(); } } @@ -811,18 +818,16 @@ int SecondStageMain(int argc, char** argv) { // By default, sleep until something happens. auto epoll_timeout = std::optional{}; - if (do_shutdown && !shutting_down) { + if (do_shutdown && !IsShuttingDown()) { do_shutdown = false; - if (HandlePowerctlMessage(shutdown_command)) { - shutting_down = true; - } + HandlePowerctlMessage(shutdown_command); } if (!(waiting_for_prop || Service::is_exec_service_running())) { am.ExecuteOneCommand(); } if (!(waiting_for_prop || Service::is_exec_service_running())) { - if (!shutting_down) { + if (!IsShuttingDown()) { auto next_process_action_time = HandleProcessActions(); // If there's a process that needs restarting, wake up in time for that. diff --git a/init/init.h b/init/init.h index 61fb110ea..c7918e7e7 100644 --- a/init/init.h +++ b/init/init.h @@ -41,6 +41,7 @@ void ResetWaitForProp(); void SendLoadPersistentPropertiesMessage(); void SendStopSendingMessagesMessage(); +void SendStartSendingMessagesMessage(); int SecondStageMain(int argc, char** argv); diff --git a/init/property_service.cpp b/init/property_service.cpp index d7e402175..c6bbc1488 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -93,6 +93,7 @@ static bool persistent_properties_loaded = false; static int property_set_fd = -1; static int init_socket = -1; +static bool accept_messages = false; static PropertyInfoAreaFile property_info_area; @@ -211,7 +212,7 @@ static uint32_t PropertySet(const std::string& name, const std::string& value, s } // If init hasn't started its main loop, then it won't be handling property changed messages // anyway, so there's no need to try to send them. - if (init_socket != -1) { + if (accept_messages) { SendPropertyChanged(name, value); } return PROP_SUCCESS; @@ -389,7 +390,7 @@ class SocketConnection { static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid, SocketConnection* socket, std::string* error) { - if (init_socket == -1) { + if (!accept_messages) { *error = "Received control message after shutdown, ignoring"; return PROP_ERROR_HANDLE_CONTROL_MESSAGE; } @@ -1035,7 +1036,11 @@ static void HandleInitSocket() { break; } case InitMessage::kStopSendingMessages: { - init_socket = -1; + accept_messages = false; + break; + } + case InitMessage::kStartSendingMessages: { + accept_messages = true; break; } default: @@ -1078,6 +1083,7 @@ void StartPropertyService(int* epoll_socket) { } *epoll_socket = sockets[0]; init_socket = sockets[1]; + accept_messages = true; if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, false, 0666, 0, 0, {})) { diff --git a/init/property_service.proto b/init/property_service.proto index ea454d402..08268d9bb 100644 --- a/init/property_service.proto +++ b/init/property_service.proto @@ -40,5 +40,6 @@ message InitMessage { oneof msg { bool load_persistent_properties = 1; bool stop_sending_messages = 2; + bool start_sending_messages = 3; }; } diff --git a/init/reboot.cpp b/init/reboot.cpp index 30836d2b7..41965a19a 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -50,7 +50,9 @@ #include #include +#include "action.h" #include "action_manager.h" +#include "builtin_arguments.h" #include "init.h" #include "property_service.h" #include "reboot_utils.h" @@ -71,6 +73,8 @@ using android::base::WriteStringToFile; namespace android { namespace init { +static bool shutting_down = false; + // represents umount status during reboot / shutdown. enum UmountStat { /* umount succeeded. */ @@ -655,12 +659,58 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str abort(); } -bool HandlePowerctlMessage(const std::string& command) { +static void EnterShutdown() { + shutting_down = true; + // Skip wait for prop if it is in progress + ResetWaitForProp(); + // Clear EXEC flag if there is one pending + for (const auto& s : ServiceList::GetInstance()) { + s->UnSetExec(); + } + // We no longer process messages about properties changing coming from property service, so we + // need to tell property service to stop sending us these messages, otherwise it'll fill the + // buffers and block indefinitely, causing future property sets, including those that init makes + // during shutdown in Service::NotifyStateChange() to also block indefinitely. + SendStopSendingMessagesMessage(); +} + +static void LeaveShutdown() { + shutting_down = false; + SendStartSendingMessagesMessage(); +} + +static void DoUserspaceReboot() { + // Triggering userspace-reboot-requested will result in a bunch of set_prop + // actions. We should make sure, that all of them are propagated before + // proceeding with userspace reboot. + // TODO(b/135984674): implement proper synchronization logic. + std::this_thread::sleep_for(500ms); + EnterShutdown(); + // TODO(b/135984674): tear down post-data services + LeaveShutdown(); + // TODO(b/135984674): remount userdata + ActionManager::GetInstance().QueueEventTrigger("userspace-reboot-resume"); +} + +static void HandleUserspaceReboot() { + LOG(INFO) << "Clearing queue and starting userspace-reboot-requested trigger"; + auto& am = ActionManager::GetInstance(); + am.ClearQueue(); + am.QueueEventTrigger("userspace-reboot-requested"); + auto handler = [](const BuiltinArguments&) { + DoUserspaceReboot(); + return Result{}; + }; + am.QueueBuiltinAction(handler, "userspace-reboot"); +} + +void HandlePowerctlMessage(const std::string& command) { unsigned int cmd = 0; std::vector cmd_params = Split(command, ","); std::string reboot_target = ""; bool run_fsck = false; bool command_invalid = false; + bool userspace_reboot = false; if (cmd_params[0] == "shutdown") { cmd = ANDROID_RB_POWEROFF; @@ -680,6 +730,10 @@ bool HandlePowerctlMessage(const std::string& command) { cmd = ANDROID_RB_RESTART2; if (cmd_params.size() >= 2) { reboot_target = cmd_params[1]; + if (reboot_target == "userspace") { + LOG(INFO) << "Userspace reboot requested"; + userspace_reboot = true; + } // adb reboot fastboot should boot into bootloader for devices not // supporting logical partitions. if (reboot_target == "fastboot" && @@ -706,7 +760,7 @@ bool HandlePowerctlMessage(const std::string& command) { strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); if (std::string err; !write_bootloader_message(boot, &err)) { LOG(ERROR) << "Failed to set bootloader message: " << err; - return false; + return; } } } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" || @@ -719,7 +773,7 @@ bool HandlePowerctlMessage(const std::string& command) { std::string err; if (!write_bootloader_message(options, &err)) { LOG(ERROR) << "Failed to set bootloader message: " << err; - return false; + return; } reboot_target = "recovery"; } @@ -734,7 +788,12 @@ bool HandlePowerctlMessage(const std::string& command) { } if (command_invalid) { LOG(ERROR) << "powerctl: unrecognized command '" << command << "'"; - return false; + return; + } + + if (userspace_reboot) { + HandleUserspaceReboot(); + return; } LOG(INFO) << "Clear action queue and start shutdown trigger"; @@ -748,21 +807,11 @@ bool HandlePowerctlMessage(const std::string& command) { }; ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done"); - // Skip wait for prop if it is in progress - ResetWaitForProp(); + EnterShutdown(); +} - // Clear EXEC flag if there is one pending - for (const auto& s : ServiceList::GetInstance()) { - s->UnSetExec(); - } - - // We no longer process messages about properties changing coming from property service, so we - // need to tell property service to stop sending us these messages, otherwise it'll fill the - // buffers and block indefinitely, causing future property sets, including those that init makes - // during shutdown in Service::NotifyStateChange() to also block indefinitely. - SendStopSendingMessagesMessage(); - - return true; +bool IsShuttingDown() { + return shutting_down; } } // namespace init diff --git a/init/reboot.h b/init/reboot.h index 07dcb6e34..81c3edc12 100644 --- a/init/reboot.h +++ b/init/reboot.h @@ -23,8 +23,9 @@ namespace android { namespace init { // Parses and handles a setprop sys.powerctl message. -bool HandlePowerctlMessage(const std::string& command); +void HandlePowerctlMessage(const std::string& command); +bool IsShuttingDown(); } // namespace init } // namespace android diff --git a/rootdir/init.rc b/rootdir/init.rc index 3b64b8275..4f9b93e10 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -917,3 +917,15 @@ on property:ro.debuggable=1 on init && property:ro.debuggable=1 start console + +on userspace-reboot: + # TODO(b/135984674): reset all necessary properties here. + setprop sys.init.userspace_reboot_in_progress 1 + +on userspace-reboot-resume: + # TODO(b/135984674): remount userdata and reset checkpointing + trigger nonencrypted + trigger post-fs-data + trigger zygote-start + trigger early-boot + trigger boot