From f66b74f820c9ecfb09dc45b88dae1fc3b73b61ea Mon Sep 17 00:00:00 2001 From: Tom Cherry Date: Wed, 4 Sep 2019 15:26:52 -0700 Subject: [PATCH] init: add exec_reboot_on_failure builtin Add exec_reboot_on_failure builtin and refactor the VDC commands that had similar functionality. These will now also reboot in the case that the program cannot be found or run for any reason. Test: boots normally, reboots if command is not found or if command returns status '1' Change-Id: I1c99498c2b741512a50188e1a325c25e9ec8fba0 (cherry picked from commit 7896e7adccbd272533ee2250f4a9c65cd4ca66d0) --- init/builtins.cpp | 69 +++++++++++++++++++++++++++-------------- init/check_builtins.cpp | 9 ++++++ init/check_builtins.h | 1 + 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/init/builtins.cpp b/init/builtins.cpp index 7c66de5f8..d2c73cb69 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -80,6 +80,7 @@ using namespace std::literals::string_literals; using android::base::Basename; +using android::base::StringPrintf; using android::base::unique_fd; using android::fs_mgr::Fstab; using android::fs_mgr::ReadFstabFromFile; @@ -1062,34 +1063,59 @@ static bool is_file_crypto() { return android::base::GetProperty("ro.crypto.type", "") == "file"; } -static Result ExecWithRebootOnFailure(const std::string& reboot_reason, - const BuiltinArguments& args) { - auto service = Service::MakeTemporaryOneshotService(args.args); +static Result ExecWithFunctionOnFailure(const std::vector& args, + std::function function) { + auto service = Service::MakeTemporaryOneshotService(args); if (!service) { - return Error() << "Could not create exec service: " << service.error(); + function("MakeTemporaryOneshotService failed: " + service.error().message()); } - (*service)->AddReapCallback([reboot_reason](const siginfo_t& siginfo) { + (*service)->AddReapCallback([function](const siginfo_t& siginfo) { if (siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) { - // TODO (b/122850122): support this in gsi - if (fscrypt_is_native() && !android::gsi::IsGsiRunning()) { - LOG(ERROR) << "Rebooting into recovery, reason: " << reboot_reason; - if (auto result = reboot_into_recovery( - {"--prompt_and_wipe_data", "--reason="s + reboot_reason}); - !result) { - LOG(FATAL) << "Could not reboot into recovery: " << result.error(); - } - } else { - LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason; - } + function(StringPrintf("Exec service failed, status %d", siginfo.si_status)); } }); if (auto result = (*service)->ExecStart(); !result) { - return Error() << "Could not start exec service: " << result.error(); + function("ExecStart failed: " + result.error().message()); } ServiceList::GetInstance().AddService(std::move(*service)); return {}; } +static Result do_exec_reboot_on_failure(const BuiltinArguments& args) { + auto reboot_reason = args[1]; + auto reboot = [reboot_reason](const std::string& message) { + property_set(LAST_REBOOT_REASON_PROPERTY, reboot_reason); + sync(); + LOG(FATAL) << message << ": rebooting into bootloader, reason: " << reboot_reason; + }; + + std::vector remaining_args(args.begin() + 1, args.end()); + remaining_args[0] = args[0]; + + return ExecWithFunctionOnFailure(remaining_args, reboot); +} + +static Result ExecVdcRebootOnFailure(const std::string& vdc_arg) { + auto reboot_reason = vdc_arg + "_failed"; + + auto reboot = [reboot_reason](const std::string& message) { + // TODO (b/122850122): support this in gsi + if (fscrypt_is_native() && !android::gsi::IsGsiRunning()) { + LOG(ERROR) << message << ": Rebooting into recovery, reason: " << reboot_reason; + if (auto result = reboot_into_recovery( + {"--prompt_and_wipe_data", "--reason="s + reboot_reason}); + !result) { + LOG(FATAL) << "Could not reboot into recovery: " << result.error(); + } + } else { + LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason; + } + }; + + std::vector args = {"exec", "/system/bin/vdc", "--wait", "cryptfs", vdc_arg}; + return ExecWithFunctionOnFailure(args, reboot); +} + static Result do_installkey(const BuiltinArguments& args) { if (!is_file_crypto()) return {}; @@ -1097,15 +1123,11 @@ static Result do_installkey(const BuiltinArguments& args) { if (!make_dir(unencrypted_dir, 0700) && errno != EEXIST) { return ErrnoError() << "Failed to create " << unencrypted_dir; } - return ExecWithRebootOnFailure( - "enablefilecrypto_failed", - {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "enablefilecrypto"}, args.context}); + return ExecVdcRebootOnFailure("enablefilecrypto"); } static Result do_init_user0(const BuiltinArguments& args) { - return ExecWithRebootOnFailure( - "init_user0_failed", - {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}, args.context}); + return ExecVdcRebootOnFailure("init_user0"); } static Result do_mark_post_data(const BuiltinArguments& args) { @@ -1180,6 +1202,7 @@ const BuiltinFunctionMap& GetBuiltinFunctionMap() { {"enable", {1, 1, {false, do_enable}}}, {"exec", {1, kMax, {false, do_exec}}}, {"exec_background", {1, kMax, {false, do_exec_background}}}, + {"exec_reboot_on_failure", {2, kMax, {false, do_exec_reboot_on_failure}}}, {"exec_start", {1, 1, {false, do_exec_start}}}, {"export", {2, 2, {false, do_export}}}, {"hostname", {1, 1, {true, do_hostname}}}, diff --git a/init/check_builtins.cpp b/init/check_builtins.cpp index 771f1d773..2efaeeafa 100644 --- a/init/check_builtins.cpp +++ b/init/check_builtins.cpp @@ -81,6 +81,15 @@ Result check_exec_background(const BuiltinArguments& args) { return check_exec(std::move(args)); } +Result check_exec_reboot_on_failure(const BuiltinArguments& args) { + BuiltinArguments remaining_args(args.context); + + remaining_args.args = std::vector(args.begin() + 1, args.end()); + remaining_args.args[0] = args[0]; + + return check_exec(remaining_args); +} + Result check_interface_restart(const BuiltinArguments& args) { if (auto result = IsKnownInterface(args[1]); !result) { return result.error(); diff --git a/init/check_builtins.h b/init/check_builtins.h index 4ff0d0c3b..fb345560a 100644 --- a/init/check_builtins.h +++ b/init/check_builtins.h @@ -25,6 +25,7 @@ namespace init { Result check_chown(const BuiltinArguments& args); Result check_exec(const BuiltinArguments& args); Result check_exec_background(const BuiltinArguments& args); +Result check_exec_reboot_on_failure(const BuiltinArguments& args); Result check_interface_restart(const BuiltinArguments& args); Result check_interface_start(const BuiltinArguments& args); Result check_interface_stop(const BuiltinArguments& args);