init: make triggering shutdown from vendor_init better
Previously, we assumed that TriggerShutdown() should never be called from vendor_init and used property service as a back up in case it ever did. We have since then found out that vendor_init may indeed call TriggerShutdown() and we want to make it just as strict as it is in init, wherein it will immediately start the shutdown sequence without executing any further commands. Test: init unit tests, trigger shuttdown from init and vendor_init Change-Id: I1f44dae801a28269eb8127879a8b7d6adff6f353
This commit is contained in:
parent
e91c76b210
commit
18278d2e9c
11 changed files with 50 additions and 24 deletions
|
@ -140,14 +140,7 @@ static Result<void> reboot_into_recovery(const std::vector<std::string>& options
|
|||
if (!write_bootloader_message(options, &err)) {
|
||||
return Error() << "Failed to set bootloader message: " << err;
|
||||
}
|
||||
// This function should only be reached from init and not from vendor_init, and we want to
|
||||
// immediately trigger reboot instead of relaying through property_service. Older devices may
|
||||
// still have paths that reach here from vendor_init, so we keep the property_set as a fallback.
|
||||
if (getpid() == 1) {
|
||||
TriggerShutdown("reboot,recovery");
|
||||
} else {
|
||||
property_set("sys.powerctl", "reboot,recovery");
|
||||
}
|
||||
trigger_shutdown("reboot,recovery");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -554,7 +547,7 @@ static Result<void> queue_fs_event(int code, bool userdata_remount) {
|
|||
// support userdata remount on FDE devices, this should never been triggered. Time to
|
||||
// panic!
|
||||
LOG(ERROR) << "Userdata remount is not supported on FDE devices. How did you get here?";
|
||||
TriggerShutdown("reboot,requested-userdata-remount-on-fde-device");
|
||||
trigger_shutdown("reboot,requested-userdata-remount-on-fde-device");
|
||||
}
|
||||
ActionManager::GetInstance().QueueEventTrigger("encrypt");
|
||||
return {};
|
||||
|
@ -564,7 +557,7 @@ static Result<void> queue_fs_event(int code, bool userdata_remount) {
|
|||
// don't support userdata remount on FDE devices, this should never been triggered.
|
||||
// Time to panic!
|
||||
LOG(ERROR) << "Userdata remount is not supported on FDE devices. How did you get here?";
|
||||
TriggerShutdown("reboot,requested-userdata-remount-on-fde-device");
|
||||
trigger_shutdown("reboot,requested-userdata-remount-on-fde-device");
|
||||
}
|
||||
property_set("ro.crypto.state", "encrypted");
|
||||
property_set("ro.crypto.type", "block");
|
||||
|
@ -1148,7 +1141,7 @@ static Result<void> do_remount_userdata(const BuiltinArguments& args) {
|
|||
}
|
||||
// TODO(b/135984674): check that fstab contains /data.
|
||||
if (auto rc = fs_mgr_remount_userdata_into_checkpointing(&fstab); rc < 0) {
|
||||
TriggerShutdown("reboot,mount-userdata-failed");
|
||||
trigger_shutdown("reboot,mount-userdata-failed");
|
||||
}
|
||||
if (auto result = queue_fs_event(initial_mount_fstab_return_code, true); !result) {
|
||||
return Error() << "queue_fs_event() failed: " << result.error();
|
||||
|
|
|
@ -35,11 +35,6 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
// init.h
|
||||
inline void TriggerShutdown(const std::string&) {
|
||||
abort();
|
||||
}
|
||||
|
||||
// property_service.h
|
||||
inline bool CanReadProperty(const std::string&, const std::string&) {
|
||||
return true;
|
||||
|
|
|
@ -180,7 +180,7 @@ void ResetWaitForProp() {
|
|||
waiting_for_prop.reset();
|
||||
}
|
||||
|
||||
void TriggerShutdown(const std::string& command) {
|
||||
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
|
||||
|
@ -681,6 +681,8 @@ int SecondStageMain(int argc, char** argv) {
|
|||
|
||||
boot_clock::time_point start_time = boot_clock::now();
|
||||
|
||||
trigger_shutdown = TriggerShutdown;
|
||||
|
||||
SetStdioToDevNull(argv);
|
||||
InitKernelLogging(argv);
|
||||
LOG(INFO) << "init second stage started!";
|
||||
|
|
|
@ -31,8 +31,6 @@ namespace init {
|
|||
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
|
||||
Parser CreateServiceOnlyParser(ServiceList& service_list);
|
||||
|
||||
void TriggerShutdown(const std::string& command);
|
||||
|
||||
bool start_waiting_for_property(const char *name, const char *value);
|
||||
|
||||
void DumpState();
|
||||
|
|
|
@ -731,7 +731,7 @@ static Result<void> DoUserspaceReboot() {
|
|||
auto guard = android::base::make_scope_guard([] {
|
||||
// Leave shutdown so that we can handle a full reboot.
|
||||
LeaveShutdown();
|
||||
TriggerShutdown("reboot,abort-userspace-reboot");
|
||||
trigger_shutdown("reboot,abort-userspace-reboot");
|
||||
});
|
||||
// Triggering userspace-reboot-requested will result in a bunch of set_prop
|
||||
// actions. We should make sure, that all of them are propagated before
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#if defined(__ANDROID__)
|
||||
#include <ApexProperties.sysprop.h>
|
||||
|
||||
#include "init.h"
|
||||
#include "mount_namespace.h"
|
||||
#include "property_service.h"
|
||||
#else
|
||||
|
@ -260,7 +259,7 @@ void Service::Reap(const siginfo_t& siginfo) {
|
|||
|
||||
if ((siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) && on_failure_reboot_target_) {
|
||||
LOG(ERROR) << "Service with 'reboot_on_failure' option failed, shutting down system.";
|
||||
TriggerShutdown(*on_failure_reboot_target_);
|
||||
trigger_shutdown(*on_failure_reboot_target_);
|
||||
}
|
||||
|
||||
if (flags_ & SVC_EXEC) UnSetExec();
|
||||
|
@ -340,7 +339,7 @@ void Service::DumpState() const {
|
|||
Result<void> Service::ExecStart() {
|
||||
auto reboot_on_failure = make_scope_guard([this] {
|
||||
if (on_failure_reboot_target_) {
|
||||
TriggerShutdown(*on_failure_reboot_target_);
|
||||
trigger_shutdown(*on_failure_reboot_target_);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -371,7 +370,7 @@ Result<void> Service::ExecStart() {
|
|||
Result<void> Service::Start() {
|
||||
auto reboot_on_failure = make_scope_guard([this] {
|
||||
if (on_failure_reboot_target_) {
|
||||
TriggerShutdown(*on_failure_reboot_target_);
|
||||
trigger_shutdown(*on_failure_reboot_target_);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@ namespace android {
|
|||
namespace init {
|
||||
namespace {
|
||||
|
||||
std::string shutdown_command;
|
||||
|
||||
class SubcontextProcess {
|
||||
public:
|
||||
SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
|
||||
|
@ -153,6 +155,11 @@ void SubcontextProcess::MainLoop() {
|
|||
<< subcontext_command.command_case();
|
||||
}
|
||||
|
||||
if (!shutdown_command.empty()) {
|
||||
reply.set_trigger_shutdown(shutdown_command);
|
||||
shutdown_command.clear();
|
||||
}
|
||||
|
||||
if (auto result = SendMessage(init_fd_, reply); !result) {
|
||||
LOG(FATAL) << "Failed to send message to init: " << result.error();
|
||||
}
|
||||
|
@ -174,6 +181,8 @@ int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map
|
|||
return 0;
|
||||
};
|
||||
|
||||
trigger_shutdown = [](const std::string& command) { shutdown_command = command; };
|
||||
|
||||
auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
|
||||
subcontext_process.MainLoop();
|
||||
return 0;
|
||||
|
@ -254,6 +263,11 @@ Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& sub
|
|||
Restart();
|
||||
return Error() << "Unable to parse message from subcontext";
|
||||
}
|
||||
|
||||
if (subcontext_reply.has_trigger_shutdown()) {
|
||||
trigger_shutdown(subcontext_reply.trigger_shutdown());
|
||||
}
|
||||
|
||||
return subcontext_reply;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,4 +38,6 @@ message SubcontextReply {
|
|||
Failure failure = 2;
|
||||
ExpandArgsReply expand_args_reply = 3;
|
||||
}
|
||||
|
||||
optional string trigger_shutdown = 4;
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
#include <selinux/selinux.h>
|
||||
|
||||
#include "builtin_arguments.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
|
@ -142,6 +143,18 @@ TEST(subcontext, ContextString) {
|
|||
});
|
||||
}
|
||||
|
||||
TEST(subcontext, TriggerShutdown) {
|
||||
static constexpr const char kTestShutdownCommand[] = "reboot,test-shutdown-command";
|
||||
static std::string trigger_shutdown_command;
|
||||
trigger_shutdown = [](const std::string& command) { trigger_shutdown_command = command; };
|
||||
RunTest([](auto& subcontext, auto& context_string) {
|
||||
auto result = subcontext.Execute(
|
||||
std::vector<std::string>{"trigger_shutdown", kTestShutdownCommand});
|
||||
ASSERT_TRUE(result);
|
||||
});
|
||||
EXPECT_EQ(kTestShutdownCommand, trigger_shutdown_command);
|
||||
}
|
||||
|
||||
TEST(subcontext, ExpandArgs) {
|
||||
RunTest([](auto& subcontext, auto& context_string) {
|
||||
auto args = std::vector<std::string>{
|
||||
|
@ -207,6 +220,11 @@ BuiltinFunctionMap BuildTestFunctionMap() {
|
|||
return Error() << args.context;
|
||||
};
|
||||
|
||||
auto do_trigger_shutdown = [](const BuiltinArguments& args) -> Result<void> {
|
||||
trigger_shutdown(args[1]);
|
||||
return {};
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
BuiltinFunctionMap test_function_map = {
|
||||
{"return_pids_as_error", {0, 0, {true, do_return_pids_as_error}}},
|
||||
|
@ -216,6 +234,7 @@ BuiltinFunctionMap BuildTestFunctionMap() {
|
|||
{"cause_log_fatal", {0, 0, {true, do_cause_log_fatal}}},
|
||||
{"generate_sane_error", {0, 0, {true, do_generate_sane_error}}},
|
||||
{"return_context_as_error", {0, 0, {true, do_return_context_as_error}}},
|
||||
{"trigger_shutdown", {1, 1, {true, do_trigger_shutdown}}},
|
||||
};
|
||||
// clang-format on
|
||||
return test_function_map;
|
||||
|
|
|
@ -61,6 +61,8 @@ namespace init {
|
|||
|
||||
const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android/");
|
||||
|
||||
void (*trigger_shutdown)(const std::string& command) = nullptr;
|
||||
|
||||
// DecodeUid() - decodes and returns the given string, which can be either the
|
||||
// numeric or name representation, into the integer uid or gid.
|
||||
Result<uid_t> DecodeUid(const std::string& name) {
|
||||
|
|
|
@ -35,6 +35,8 @@ namespace init {
|
|||
|
||||
static const char kColdBootDoneProp[] = "ro.cold_boot_done";
|
||||
|
||||
extern void (*trigger_shutdown)(const std::string& command);
|
||||
|
||||
Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
|
||||
gid_t gid, const std::string& socketcon);
|
||||
|
||||
|
|
Loading…
Reference in a new issue