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
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index a711340..f6e9676 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -45,6 +45,7 @@
                            const std::string& source_context, const ucred& cr, std::string* error);
 
 // reboot_utils.h
+inline void SetFatalRebootTarget() {}
 inline void __attribute__((noreturn)) InitFatalReboot() {
     abort();
 }
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index 4524f69..d1a712f 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -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 @@
 
     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 @@
     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() {
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
index c4d97d5..3fd969e 100644
--- a/init/reboot_utils.h
+++ b/init/reboot_utils.h
@@ -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();
diff --git a/init/util.cpp b/init/util.cpp
index 790ab92..63d2d44 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -468,6 +468,7 @@
 }
 
 void InitKernelLogging(char** argv) {
+    SetFatalRebootTarget();
     android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
 }