Merge "init: make triggering shutdown from vendor_init better"

This commit is contained in:
Treehugger Robot 2019-11-13 21:59:38 +00:00 committed by Gerrit Code Review
commit b34291bcb6
11 changed files with 50 additions and 24 deletions

View File

@ -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();

View File

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

View File

@ -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!";

View File

@ -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();

View File

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

View File

@ -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_);
}
});

View File

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

View File

@ -38,4 +38,6 @@ message SubcontextReply {
Failure failure = 2;
ExpandArgsReply expand_args_reply = 3;
}
optional string trigger_shutdown = 4;
}

View File

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

View File

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

View File

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