Merge "Add a skeleton of userspace reboot"
This commit is contained in:
commit
f1933c910d
7 changed files with 104 additions and 29 deletions
|
|
@ -98,7 +98,6 @@ static int property_fd = -1;
|
||||||
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
|
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
|
||||||
static std::string wait_prop_name;
|
static std::string wait_prop_name;
|
||||||
static std::string wait_prop_value;
|
static std::string wait_prop_value;
|
||||||
static bool shutting_down;
|
|
||||||
static std::string shutdown_command;
|
static std::string shutdown_command;
|
||||||
static bool do_shutdown = false;
|
static bool do_shutdown = false;
|
||||||
static bool load_debug_prop = false;
|
static bool load_debug_prop = false;
|
||||||
|
|
@ -624,7 +623,15 @@ void SendStopSendingMessagesMessage() {
|
||||||
auto init_message = InitMessage{};
|
auto init_message = InitMessage{};
|
||||||
init_message.set_stop_sending_messages(true);
|
init_message.set_stop_sending_messages(true);
|
||||||
if (auto result = SendMessage(property_fd, init_message); !result) {
|
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.
|
// By default, sleep until something happens.
|
||||||
auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
|
auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
|
||||||
|
|
||||||
if (do_shutdown && !shutting_down) {
|
if (do_shutdown && !IsShuttingDown()) {
|
||||||
do_shutdown = false;
|
do_shutdown = false;
|
||||||
if (HandlePowerctlMessage(shutdown_command)) {
|
HandlePowerctlMessage(shutdown_command);
|
||||||
shutting_down = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(waiting_for_prop || Service::is_exec_service_running())) {
|
if (!(waiting_for_prop || Service::is_exec_service_running())) {
|
||||||
am.ExecuteOneCommand();
|
am.ExecuteOneCommand();
|
||||||
}
|
}
|
||||||
if (!(waiting_for_prop || Service::is_exec_service_running())) {
|
if (!(waiting_for_prop || Service::is_exec_service_running())) {
|
||||||
if (!shutting_down) {
|
if (!IsShuttingDown()) {
|
||||||
auto next_process_action_time = HandleProcessActions();
|
auto next_process_action_time = HandleProcessActions();
|
||||||
|
|
||||||
// If there's a process that needs restarting, wake up in time for that.
|
// If there's a process that needs restarting, wake up in time for that.
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ void ResetWaitForProp();
|
||||||
|
|
||||||
void SendLoadPersistentPropertiesMessage();
|
void SendLoadPersistentPropertiesMessage();
|
||||||
void SendStopSendingMessagesMessage();
|
void SendStopSendingMessagesMessage();
|
||||||
|
void SendStartSendingMessagesMessage();
|
||||||
|
|
||||||
int SecondStageMain(int argc, char** argv);
|
int SecondStageMain(int argc, char** argv);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ static bool persistent_properties_loaded = false;
|
||||||
|
|
||||||
static int property_set_fd = -1;
|
static int property_set_fd = -1;
|
||||||
static int init_socket = -1;
|
static int init_socket = -1;
|
||||||
|
static bool accept_messages = false;
|
||||||
|
|
||||||
static PropertyInfoAreaFile property_info_area;
|
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
|
// 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.
|
// anyway, so there's no need to try to send them.
|
||||||
if (init_socket != -1) {
|
if (accept_messages) {
|
||||||
SendPropertyChanged(name, value);
|
SendPropertyChanged(name, value);
|
||||||
}
|
}
|
||||||
return PROP_SUCCESS;
|
return PROP_SUCCESS;
|
||||||
|
|
@ -389,7 +390,7 @@ class SocketConnection {
|
||||||
|
|
||||||
static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
|
static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
|
||||||
SocketConnection* socket, std::string* error) {
|
SocketConnection* socket, std::string* error) {
|
||||||
if (init_socket == -1) {
|
if (!accept_messages) {
|
||||||
*error = "Received control message after shutdown, ignoring";
|
*error = "Received control message after shutdown, ignoring";
|
||||||
return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
|
return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
|
||||||
}
|
}
|
||||||
|
|
@ -1035,7 +1036,11 @@ static void HandleInitSocket() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InitMessage::kStopSendingMessages: {
|
case InitMessage::kStopSendingMessages: {
|
||||||
init_socket = -1;
|
accept_messages = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case InitMessage::kStartSendingMessages: {
|
||||||
|
accept_messages = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
@ -1078,6 +1083,7 @@ void StartPropertyService(int* epoll_socket) {
|
||||||
}
|
}
|
||||||
*epoll_socket = sockets[0];
|
*epoll_socket = sockets[0];
|
||||||
init_socket = sockets[1];
|
init_socket = sockets[1];
|
||||||
|
accept_messages = true;
|
||||||
|
|
||||||
if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||||
false, 0666, 0, 0, {})) {
|
false, 0666, 0, 0, {})) {
|
||||||
|
|
|
||||||
|
|
@ -40,5 +40,6 @@ message InitMessage {
|
||||||
oneof msg {
|
oneof msg {
|
||||||
bool load_persistent_properties = 1;
|
bool load_persistent_properties = 1;
|
||||||
bool stop_sending_messages = 2;
|
bool stop_sending_messages = 2;
|
||||||
|
bool start_sending_messages = 3;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,9 @@
|
||||||
#include <private/android_filesystem_config.h>
|
#include <private/android_filesystem_config.h>
|
||||||
#include <selinux/selinux.h>
|
#include <selinux/selinux.h>
|
||||||
|
|
||||||
|
#include "action.h"
|
||||||
#include "action_manager.h"
|
#include "action_manager.h"
|
||||||
|
#include "builtin_arguments.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "property_service.h"
|
#include "property_service.h"
|
||||||
#include "reboot_utils.h"
|
#include "reboot_utils.h"
|
||||||
|
|
@ -71,6 +73,8 @@ using android::base::WriteStringToFile;
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace init {
|
namespace init {
|
||||||
|
|
||||||
|
static bool shutting_down = false;
|
||||||
|
|
||||||
// represents umount status during reboot / shutdown.
|
// represents umount status during reboot / shutdown.
|
||||||
enum UmountStat {
|
enum UmountStat {
|
||||||
/* umount succeeded. */
|
/* umount succeeded. */
|
||||||
|
|
@ -655,12 +659,58 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
|
||||||
abort();
|
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;
|
unsigned int cmd = 0;
|
||||||
std::vector<std::string> cmd_params = Split(command, ",");
|
std::vector<std::string> cmd_params = Split(command, ",");
|
||||||
std::string reboot_target = "";
|
std::string reboot_target = "";
|
||||||
bool run_fsck = false;
|
bool run_fsck = false;
|
||||||
bool command_invalid = false;
|
bool command_invalid = false;
|
||||||
|
bool userspace_reboot = false;
|
||||||
|
|
||||||
if (cmd_params[0] == "shutdown") {
|
if (cmd_params[0] == "shutdown") {
|
||||||
cmd = ANDROID_RB_POWEROFF;
|
cmd = ANDROID_RB_POWEROFF;
|
||||||
|
|
@ -680,6 +730,10 @@ bool HandlePowerctlMessage(const std::string& command) {
|
||||||
cmd = ANDROID_RB_RESTART2;
|
cmd = ANDROID_RB_RESTART2;
|
||||||
if (cmd_params.size() >= 2) {
|
if (cmd_params.size() >= 2) {
|
||||||
reboot_target = cmd_params[1];
|
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
|
// adb reboot fastboot should boot into bootloader for devices not
|
||||||
// supporting logical partitions.
|
// supporting logical partitions.
|
||||||
if (reboot_target == "fastboot" &&
|
if (reboot_target == "fastboot" &&
|
||||||
|
|
@ -706,7 +760,7 @@ bool HandlePowerctlMessage(const std::string& command) {
|
||||||
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
|
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
|
||||||
if (std::string err; !write_bootloader_message(boot, &err)) {
|
if (std::string err; !write_bootloader_message(boot, &err)) {
|
||||||
LOG(ERROR) << "Failed to set bootloader message: " << err;
|
LOG(ERROR) << "Failed to set bootloader message: " << err;
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
|
} else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
|
||||||
|
|
@ -719,7 +773,7 @@ bool HandlePowerctlMessage(const std::string& command) {
|
||||||
std::string err;
|
std::string err;
|
||||||
if (!write_bootloader_message(options, &err)) {
|
if (!write_bootloader_message(options, &err)) {
|
||||||
LOG(ERROR) << "Failed to set bootloader message: " << err;
|
LOG(ERROR) << "Failed to set bootloader message: " << err;
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
reboot_target = "recovery";
|
reboot_target = "recovery";
|
||||||
}
|
}
|
||||||
|
|
@ -734,7 +788,12 @@ bool HandlePowerctlMessage(const std::string& command) {
|
||||||
}
|
}
|
||||||
if (command_invalid) {
|
if (command_invalid) {
|
||||||
LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
|
LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
|
||||||
return false;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userspace_reboot) {
|
||||||
|
HandleUserspaceReboot();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(INFO) << "Clear action queue and start shutdown trigger";
|
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");
|
ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
|
||||||
|
|
||||||
// Skip wait for prop if it is in progress
|
EnterShutdown();
|
||||||
ResetWaitForProp();
|
}
|
||||||
|
|
||||||
// Clear EXEC flag if there is one pending
|
bool IsShuttingDown() {
|
||||||
for (const auto& s : ServiceList::GetInstance()) {
|
return shutting_down;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace init
|
} // namespace init
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,9 @@ namespace android {
|
||||||
namespace init {
|
namespace init {
|
||||||
|
|
||||||
// Parses and handles a setprop sys.powerctl message.
|
// 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 init
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -917,3 +917,15 @@ on property:ro.debuggable=1
|
||||||
|
|
||||||
on init && property:ro.debuggable=1
|
on init && property:ro.debuggable=1
|
||||||
start console
|
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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue