Merge "Add a skeleton of userspace reboot"

This commit is contained in:
Nikita Ioffe 2019-10-08 14:42:36 +00:00 committed by Gerrit Code Review
commit f1933c910d
7 changed files with 104 additions and 29 deletions

View File

@ -98,7 +98,6 @@ static int property_fd = -1;
static std::unique_ptr<Timer> 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<std::chrono::milliseconds>{};
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.

View File

@ -41,6 +41,7 @@ void ResetWaitForProp();
void SendLoadPersistentPropertiesMessage();
void SendStopSendingMessagesMessage();
void SendStartSendingMessagesMessage();
int SecondStageMain(int argc, char** argv);

View File

@ -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, {})) {

View File

@ -40,5 +40,6 @@ message InitMessage {
oneof msg {
bool load_persistent_properties = 1;
bool stop_sending_messages = 2;
bool start_sending_messages = 3;
};
}

View File

@ -50,7 +50,9 @@
#include <private/android_filesystem_config.h>
#include <selinux/selinux.h>
#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<void>{};
};
am.QueueBuiltinAction(handler, "userspace-reboot");
}
void HandlePowerctlMessage(const std::string& command) {
unsigned int cmd = 0;
std::vector<std::string> 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

View File

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

View File

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