Merge "init: make triggering shutdown from vendor_init better"
am: b34291bcb6
Change-Id: I2f08e6abb496d089a7b795c6dff44d5e4391bf15
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 5ee928e..a55514b 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -140,14 +140,7 @@
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 @@
// 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 @@
// 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 @@
}
// 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();
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index 9b33a1c..30d3129 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -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;
diff --git a/init/init.cpp b/init/init.cpp
index ff86f8d..8e2da59 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -180,7 +180,7 @@
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 @@
boot_clock::time_point start_time = boot_clock::now();
+ trigger_shutdown = TriggerShutdown;
+
SetStdioToDevNull(argv);
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
diff --git a/init/init.h b/init/init.h
index d884a94..0805940 100644
--- a/init/init.h
+++ b/init/init.h
@@ -31,8 +31,6 @@
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();
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 4a16969..64ec1fb 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -731,7 +731,7 @@
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
diff --git a/init/service.cpp b/init/service.cpp
index f8e98a2..574ff52 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -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 @@
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 @@
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::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_);
}
});
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 79fc372..e55265b 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -51,6 +51,8 @@
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 @@
<< 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 @@
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 @@
Restart();
return Error() << "Unable to parse message from subcontext";
}
+
+ if (subcontext_reply.has_trigger_shutdown()) {
+ trigger_shutdown(subcontext_reply.trigger_shutdown());
+ }
+
return subcontext_reply;
}
diff --git a/init/subcontext.proto b/init/subcontext.proto
index e68115e..068c7ce 100644
--- a/init/subcontext.proto
+++ b/init/subcontext.proto
@@ -38,4 +38,6 @@
Failure failure = 2;
ExpandArgsReply expand_args_reply = 3;
}
+
+ optional string trigger_shutdown = 4;
}
\ No newline at end of file
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp
index 9cac35e..9c1a788 100644
--- a/init/subcontext_test.cpp
+++ b/init/subcontext_test.cpp
@@ -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, 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 @@
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 @@
{"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;
diff --git a/init/util.cpp b/init/util.cpp
index ada9e78..e5254dd 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -61,6 +61,8 @@
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) {
diff --git a/init/util.h b/init/util.h
index 3d81d72..9d89ed7 100644
--- a/init/util.h
+++ b/init/util.h
@@ -35,6 +35,8 @@
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);