From 663fdfc1b2406fd6f88a89b998b300e5de8d5b05 Mon Sep 17 00:00:00 2001 From: Tom Cherry Date: Fri, 10 Mar 2017 14:46:38 -0800 Subject: [PATCH] init: reboot to bootloader on crash for development builds Currently, if init crashes, the kernel panics. During development, we would like to catch this crash before the kernel panics and reboot into bootloader. This will prevent boot looping bad configurations, particularly desired in test labs where manual intervention would otherwise be required to reset the devices. Keep the existing behavior for user builds, as init crashes should be rare for production builds and rebooting the device is the correct behavior for end users. Bug: 34147472 Test: Boot bullhead userdebug, force init to crash, check that the device is in bootloader Test: Boot bullhead user, force init to crash, check that the kernel panics and the device reboots as it did previously Change-Id: Iab3d45ed0d1f82ffaad2a0835d9ca537c0516421 --- init/Android.mk | 10 ++++++++-- init/init.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/init/Android.mk b/init/Android.mk index 2a1ad9cdb..d48f15232 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -5,9 +5,15 @@ LOCAL_PATH:= $(call my-dir) # -- ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) -init_options += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_PERMISSIVE_SELINUX=1 +init_options += \ + -DALLOW_LOCAL_PROP_OVERRIDE=1 \ + -DALLOW_PERMISSIVE_SELINUX=1 \ + -DREBOOT_BOOTLOADER_ON_PANIC=1 else -init_options += -DALLOW_LOCAL_PROP_OVERRIDE=0 -DALLOW_PERMISSIVE_SELINUX=0 +init_options += \ + -DALLOW_LOCAL_PROP_OVERRIDE=0 \ + -DALLOW_PERMISSIVE_SELINUX=0 \ + -DREBOOT_BOOTLOADER_ON_PANIC=0 endif init_options += -DLOG_UEVENTS=0 diff --git a/init/init.cpp b/init/init.cpp index d09568567..0ce1c05d7 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -1099,6 +1099,31 @@ done: return success; } +static void install_reboot_signal_handlers() { + // Instead of panic'ing the kernel as is the default behavior when init crashes, + // we prefer to reboot to bootloader on development builds, as this will prevent + // boot looping bad configurations and allow both developers and test farms to easily + // recover. + struct sigaction action; + memset(&action, 0, sizeof(action)); + sigfillset(&action.sa_mask); + action.sa_handler = [](int) { + // panic() reboots to bootloader + panic(); + }; + action.sa_flags = SA_RESTART; + sigaction(SIGABRT, &action, nullptr); + sigaction(SIGBUS, &action, nullptr); + sigaction(SIGFPE, &action, nullptr); + sigaction(SIGILL, &action, nullptr); + sigaction(SIGSEGV, &action, nullptr); +#if defined(SIGSTKFLT) + sigaction(SIGSTKFLT, &action, nullptr); +#endif + sigaction(SIGSYS, &action, nullptr); + sigaction(SIGTRAP, &action, nullptr); +} + int main(int argc, char** argv) { if (!strcmp(basename(argv[0]), "ueventd")) { return ueventd_main(argc, argv); @@ -1108,6 +1133,10 @@ int main(int argc, char** argv) { return watchdogd_main(argc, argv); } + if (REBOOT_BOOTLOADER_ON_PANIC) { + install_reboot_signal_handlers(); + } + add_environment("PATH", _PATH_DEFPATH); bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);