init: make fatal reboot target configurable

Currently, if init encounters a fatal issues it reboots to fastboot
but this may be not desirable in all cases, especially the case of
critical services crashing.  Therefore this change adds the ability
for vendors to customize the reboot target via the
androidboot.init_fatal_reboot_target= kernel command line.

This applies to all LOG(FATAL) messages as well as fatal signals in
userdebug/eng builds, except for signals before logging is enabled in
first stage init.

Bug: 121006328
Test: device reboots to configurable target with LOG(FATAL)
Test: device reboots to configurable target after a segfault in the
      various stages of init
Test: device reboots to fastboot without a configured target
Change-Id: I16ea9e32e2fee08dece3d33b697d7a08191d607b
This commit is contained in:
Tom Cherry 2019-05-21 13:53:05 -07:00
parent 59656fb377
commit 75e13baf32
4 changed files with 27 additions and 3 deletions

View File

@ -45,6 +45,7 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
const std::string& source_context, const ucred& cr, std::string* error);
// reboot_utils.h
inline void SetFatalRebootTarget() {}
inline void __attribute__((noreturn)) InitFatalReboot() {
abort();
}

View File

@ -32,6 +32,27 @@
namespace android {
namespace init {
static std::string init_fatal_reboot_target = "bootloader";
void SetFatalRebootTarget() {
std::string cmdline;
android::base::ReadFileToString("/proc/cmdline", &cmdline);
cmdline = android::base::Trim(cmdline);
const char kRebootTargetString[] = "androidboot.init_fatal_reboot_target=";
auto start_pos = cmdline.find(kRebootTargetString);
if (start_pos == std::string::npos) {
return; // We already default to bootloader if no setting is provided.
}
start_pos += sizeof(kRebootTargetString) - 1;
auto end_pos = cmdline.find(' ', start_pos);
// if end_pos isn't found, then we've run off the end, but this is okay as this is the last
// entry, and -1 is a valid size for string::substr();
auto size = end_pos == std::string::npos ? -1 : end_pos - start_pos;
init_fatal_reboot_target = cmdline.substr(start_pos, size);
}
bool IsRebootCapable() {
if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
@ -85,13 +106,13 @@ void __attribute__((noreturn)) InitFatalReboot() {
if (pid == -1) {
// Couldn't fork, don't even try to backtrace, just reboot.
RebootSystem(ANDROID_RB_RESTART2, "bootloader");
RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
} else if (pid == 0) {
// Fork a child for safety, since we always want to shut down if something goes wrong, but
// its worth trying to get the backtrace, even in the signal handler, since typically it
// does work despite not being async-signal-safe.
sleep(5);
RebootSystem(ANDROID_RB_RESTART2, "bootloader");
RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
}
// In the parent, let's try to get a backtrace then shutdown.
@ -103,7 +124,7 @@ void __attribute__((noreturn)) InitFatalReboot() {
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
LOG(ERROR) << backtrace->FormatFrameData(i);
}
RebootSystem(ANDROID_RB_RESTART2, "bootloader");
RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
}
void InstallRebootSignalHandlers() {

View File

@ -21,6 +21,7 @@
namespace android {
namespace init {
void SetFatalRebootTarget();
// Determines whether the system is capable of rebooting. This is conservative,
// so if any of the attempts to determine this fail, it will still return true.
bool IsRebootCapable();

View File

@ -468,6 +468,7 @@ void SetStdioToDevNull(char** argv) {
}
void InitKernelLogging(char** argv) {
SetFatalRebootTarget();
android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
}