first_stage_init: add console

Start and wait on a console if androidboot.first_stage_console=1 is
present on the kernel command line. This only works on eng and
userdebug builds.

Change-Id: I978e9390a89509431b399ea58b284736b27eeb1b
This commit is contained in:
Steve Muckle 2019-05-21 15:50:39 -07:00
parent c538656d7d
commit d75f30a4f0
3 changed files with 58 additions and 4 deletions

View file

@ -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",

View file

@ -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 \

View file

@ -24,10 +24,12 @@
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <filesystem>
#include <string>
#include <thread>
#include <vector>
#include <android-base/chrono_utils.h>
@ -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<char**>(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.