diff --git a/init/Android.bp b/init/Android.bp index 6bc581d9d..86dcb4ca7 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -26,6 +26,7 @@ cc_defaults { "-Wextra", "-Wno-unused-parameter", "-Werror", + "-DALLOW_FIRST_STAGE_CONSOLE=0", "-DALLOW_LOCAL_PROP_OVERRIDE=0", "-DALLOW_PERMISSIVE_SELINUX=0", "-DREBOOT_BOOTLOADER_ON_PANIC=0", @@ -36,6 +37,8 @@ cc_defaults { product_variables: { debuggable: { cppflags: [ + "-UALLOW_FIRST_STAGE_CONSOLE", + "-DALLOW_FIRST_STAGE_CONSOLE=1", "-UALLOW_LOCAL_PROP_OVERRIDE", "-DALLOW_LOCAL_PROP_OVERRIDE=1", "-UALLOW_PERMISSIVE_SELINUX", diff --git a/init/Android.mk b/init/Android.mk index b24f7577b..901777293 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -8,6 +8,7 @@ LOCAL_PATH:= $(call my-dir) ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) init_options += \ + -DALLOW_FIRST_STAGE_CONSOLE=1 \ -DALLOW_LOCAL_PROP_OVERRIDE=1 \ -DALLOW_PERMISSIVE_SELINUX=1 \ -DREBOOT_BOOTLOADER_ON_PANIC=1 \ @@ -15,6 +16,7 @@ init_options += \ -DDUMP_ON_UMOUNT_FAILURE=1 else init_options += \ + -DALLOW_FIRST_STAGE_CONSOLE=0 \ -DALLOW_LOCAL_PROP_OVERRIDE=0 \ -DALLOW_PERMISSIVE_SELINUX=0 \ -DREBOOT_BOOTLOADER_ON_PANIC=0 \ diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index 17387e200..36eece8d2 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -24,10 +24,12 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -92,9 +94,50 @@ void FreeRamdisk(DIR* dir, dev_t dev) { } } -bool ForceNormalBoot() { - std::string cmdline; - android::base::ReadFileToString("/proc/cmdline", &cmdline); +void StartConsole() { + if (mknod("/dev/console", S_IFCHR | 0600, makedev(5, 1))) { + PLOG(ERROR) << "unable to create /dev/console"; + return; + } + pid_t pid = fork(); + if (pid != 0) { + int status; + waitpid(pid, &status, 0); + LOG(ERROR) << "console shell exited with status " << status; + return; + } + int fd = -1; + int tries = 10; + // The device driver for console may not be ready yet so retry for a while in case of failure. + while (tries--) { + fd = open("/dev/console", O_RDWR); + if (fd != -1) { + break; + } + std::this_thread::sleep_for(100ms); + } + if (fd == -1) { + LOG(ERROR) << "Could not open /dev/console, errno = " << errno; + _exit(127); + } + ioctl(fd, TIOCSCTTY, 0); + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + close(fd); + + const char* path = "/system/bin/sh"; + const char* args[] = {path, nullptr}; + int rv = execv(path, const_cast(args)); + LOG(ERROR) << "unable to execv, returned " << rv << " errno " << errno; + _exit(127); +} + +bool FirstStageConsole(const std::string& cmdline) { + return cmdline.find("androidboot.first_stage_console=1") != std::string::npos; +} + +bool ForceNormalBoot(const std::string& cmdline) { return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos; } @@ -127,6 +170,8 @@ int FirstStageMain(int argc, char** argv) { #undef MAKE_STR // Don't expose the raw commandline to unprivileged processes. CHECKCALL(chmod("/proc/cmdline", 0440)); + std::string cmdline; + android::base::ReadFileToString("/proc/cmdline", &cmdline); gid_t groups[] = {AID_READPROC}; CHECKCALL(setgroups(arraysize(groups), groups)); CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL)); @@ -198,7 +243,11 @@ int FirstStageMain(int argc, char** argv) { LOG(FATAL) << "Failed to load kernel modules"; } - if (ForceNormalBoot()) { + if (ALLOW_FIRST_STAGE_CONSOLE && FirstStageConsole(cmdline)) { + StartConsole(); + } + + if (ForceNormalBoot(cmdline)) { mkdir("/first_stage_ramdisk", 0755); // SwitchRoot() must be called with a mount point as the target, so we bind mount the // target directory to itself here.