Merge "init: replace panic() with LOG(FATAL)"
diff --git a/init/init.cpp b/init/init.cpp
index c65d846..d0afac1 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -34,6 +34,7 @@
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/strings.h>
+#include <cutils/android_reboot.h>
 #include <keyutils.h>
 #include <libavb/libavb.h>
 #include <private/android_filesystem_config.h>
@@ -252,8 +253,7 @@
     // because any build that slow isn't likely to boot at all, and we'd
     // rather any test lab devices fail back to the bootloader.
     if (wait_for_file(COLDBOOT_DONE, 60s) < 0) {
-        LOG(ERROR) << "Timed out waiting for " COLDBOOT_DONE;
-        panic();
+        LOG(FATAL) << "Timed out waiting for " COLDBOOT_DONE;
     }
 
     property_set("ro.boottime.init.cold_boot_wait", std::to_string(t.duration().count()));
@@ -367,8 +367,7 @@
 static void global_seccomp() {
     import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
         if (key == "androidboot.seccomp" && value == "global" && !set_global_seccomp_filter()) {
-            LOG(ERROR) << "Failed to globally enable seccomp!";
-            panic();
+            LOG(FATAL) << "Failed to globally enable seccomp!";
         }
     });
 }
@@ -398,8 +397,11 @@
     memset(&action, 0, sizeof(action));
     sigfillset(&action.sa_mask);
     action.sa_handler = [](int) {
-        // panic() reboots to bootloader
-        panic();
+        // Calling DoReboot() or LOG(FATAL) is not a good option as this is a signal handler.
+        // RebootSystem uses syscall() which isn't actually async-signal-safe, but our only option
+        // and probably good enough given this is already an error case and only enabled for
+        // development builds.
+        RebootSystem(ANDROID_RB_RESTART2, "bootloader");
     };
     action.sa_flags = SA_RESTART;
     sigaction(SIGABRT, &action, nullptr);
@@ -468,8 +470,7 @@
         LOG(INFO) << "init first stage started!";
 
         if (!DoFirstStageMount()) {
-            LOG(ERROR) << "Failed to mount required partitions early ...";
-            panic();
+            LOG(FATAL) << "Failed to mount required partitions early ...";
         }
 
         SetInitAvbVersionInRecovery();
@@ -484,8 +485,7 @@
         // We're in the kernel domain, so re-exec init to transition to the init domain now
         // that the SELinux policy has been loaded.
         if (selinux_android_restorecon("/init", 0) == -1) {
-            PLOG(ERROR) << "restorecon failed of /init failed";
-            panic();
+            PLOG(FATAL) << "restorecon failed of /init failed";
         }
 
         setenv("INIT_SECOND_STAGE", "true", 1);
@@ -500,8 +500,7 @@
 
         // execv() only returns if an error happened, in which case we
         // panic and never fall through this conditional.
-        PLOG(ERROR) << "execv(\"" << path << "\") failed";
-        panic();
+        PLOG(FATAL) << "execv(\"" << path << "\") failed";
     }
 
     // At this point we're in the second stage of init.
diff --git a/init/log.cpp b/init/log.cpp
index 1830077..391bc1f 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -21,17 +21,35 @@
 #include <string.h>
 
 #include <android-base/logging.h>
+#include <cutils/android_reboot.h>
 #include <selinux/selinux.h>
 
+#include "reboot.h"
+
 namespace android {
 namespace init {
 
+static void RebootAborter(const char* abort_message) {
+    // DoReboot() does a lot to try to shutdown the system cleanly.  If something happens to call
+    // LOG(FATAL) in the shutdown path, we want to catch this and immediately use the syscall to
+    // reboot instead of recursing here.
+    static bool has_aborted = false;
+    if (!has_aborted) {
+        has_aborted = true;
+        // Do not queue "shutdown" trigger since we want to shutdown immediately and it's not likely
+        // that we can even run the ActionQueue at this point.
+        DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
+    } else {
+        RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+    }
+}
+
 void InitKernelLogging(char* argv[]) {
     // Make stdin/stdout/stderr all point to /dev/null.
     int fd = open("/sys/fs/selinux/null", O_RDWR);
     if (fd == -1) {
         int saved_errno = errno;
-        android::base::InitLogging(argv, &android::base::KernelLogger);
+        android::base::InitLogging(argv, &android::base::KernelLogger, RebootAborter);
         errno = saved_errno;
         PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
     }
@@ -40,7 +58,7 @@
     dup2(fd, 2);
     if (fd > 2) close(fd);
 
-    android::base::InitLogging(argv, &android::base::KernelLogger);
+    android::base::InitLogging(argv, &android::base::KernelLogger, RebootAborter);
 }
 
 int selinux_klog_callback(int type, const char *fmt, ...) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 4d580f2..5bae4bc 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -191,8 +191,7 @@
     return value == CAP_SET;
 }
 
-static void __attribute__((noreturn))
-RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
+void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
     LOG(INFO) << "Reboot ending, jumping to kernel";
 
     if (!IsRebootCapable()) {
@@ -216,7 +215,7 @@
             break;
     }
     // In normal case, reboot should not return.
-    PLOG(FATAL) << "reboot call returned";
+    PLOG(ERROR) << "reboot call returned";
     abort();
 }
 
diff --git a/init/reboot.h b/init/reboot.h
index e559540..8586556 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -22,6 +22,9 @@
 namespace android {
 namespace init {
 
+// This is a wrapper around the actual reboot calls.  DoReboot() should be preferred in most cases.
+void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget);
+
 /* Reboot / shutdown the system.
  * cmd ANDROID_RB_* as defined in android_reboot.h
  * reason Reason string like "reboot", "userrequested"
diff --git a/init/security.cpp b/init/security.cpp
index f8976de..aac8f2e 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -25,8 +25,6 @@
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
-#include "util.h"
-
 using android::base::unique_fd;
 
 namespace android {
@@ -178,8 +176,7 @@
     LOG(ERROR) << "Unknown architecture";
 #endif
 
-    LOG(ERROR) << "Unable to set adequate mmap entropy value!";
-    panic();
+    LOG(FATAL) << "Unable to set adequate mmap entropy value!";
     return Error();
 }
 
@@ -194,8 +191,7 @@
     std::string path = KPTR_RESTRICT_PATH;
 
     if (!SetHighestAvailableOptionValue(path, KPTR_RESTRICT_MINVALUE, KPTR_RESTRICT_MAXVALUE)) {
-        LOG(ERROR) << "Unable to set adequate kptr_restrict value!";
-        panic();
+        LOG(FATAL) << "Unable to set adequate kptr_restrict value!";
         return Error();
     }
     return Success();
diff --git a/init/selinux.cpp b/init/selinux.cpp
index dd49f84..1104fb3 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -327,21 +327,19 @@
 
     LOG(INFO) << "Loading SELinux policy";
     if (!LoadPolicy()) {
-        panic();
+        LOG(FATAL) << "Unable to load SELinux policy";
     }
 
     bool kernel_enforcing = (security_getenforce() == 1);
     bool is_enforcing = IsEnforcing();
     if (kernel_enforcing != is_enforcing) {
         if (security_setenforce(is_enforcing)) {
-            PLOG(ERROR) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
-            panic();
+            PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
         }
     }
 
     if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result) {
-        LOG(ERROR) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
-        panic();
+        LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
     }
 
     // init's first stage can't set properties, so pass the time to the second stage.
diff --git a/init/service.cpp b/init/service.cpp
index 1b5cc19..c201ec9 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -306,8 +306,7 @@
     if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) {
         if (now < time_crashed_ + 4min) {
             if (++crash_count_ > 4) {
-                LOG(ERROR) << "critical process '" << name_ << "' exited 4 times in 4 minutes";
-                panic();
+                LOG(FATAL) << "critical process '" << name_ << "' exited 4 times in 4 minutes";
             }
         } else {
             time_crashed_ = now;
diff --git a/init/util.cpp b/init/util.cpp
index fcf7ca8..9112c3f 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -345,12 +345,6 @@
     return true;
 }
 
-void panic() {
-    LOG(ERROR) << "panic: rebooting to bootloader";
-    // Do not queue "shutdown" trigger since we want to shutdown immediately
-    DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
-}
-
 static std::string init_android_dt_dir() {
     // Use the standard procfs-based path by default
     std::string android_dt_dir = kDefaultAndroidDtDir;
diff --git a/init/util.h b/init/util.h
index 298aa1c..2cfcf6c 100644
--- a/init/util.h
+++ b/init/util.h
@@ -55,8 +55,6 @@
 bool is_dir(const char* pathname);
 bool expand_props(const std::string& src, std::string* dst);
 
-void panic() __attribute__((__noreturn__));
-
 // Returns the platform's Android DT directory as specified in the kernel cmdline.
 // If the platform does not configure a custom DT path, returns the standard one (based in procfs).
 const std::string& get_android_dt_dir();