Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 683ebc80 authored by Luis Hector Chavez's avatar Luis Hector Chavez
Browse files

init: Terminate gracefully when CAP_SYS_BOOT is absent

This change makes it possible for Android running in a container to
terminate cleanly instead of calling abort() when requested to shut
down.

Bug: 62388055
Test: setprop sys.powerctl reboot makes init terminate nicely

Change-Id: I31c7b475d89d7cbd665e135d9b8951dfd4bca80d
parent 449bfd7a
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/fs.h>
#include <mntent.h>
#include <selinux/selinux.h>
#include <sys/capability.h>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
@@ -39,6 +40,7 @@
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -162,9 +164,30 @@ static void LogShutdownTime(UmountStat stat, Timer* t) {
    LOG(WARNING) << "powerctl_shutdown_time_ms:" << std::to_string(t->duration_ms()) << ":" << stat;
}

static bool IsRebootCapable() {
    cap_t caps = cap_init();
    auto scopeguard = android::base::make_scope_guard([&caps] { cap_free(caps); });

    // Assume we have the capability.
    cap_flag_value_t value = CAP_SET;
    if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT) ||
        cap_get_flag(caps, CAP_SYS_BOOT, CAP_EFFECTIVE, &value) != 0) {
        PLOG(ERROR) << "cap_get_flag(CAP_BOOT, EFFECTIVE) failed";
    }

    return value == CAP_SET;
}

static void __attribute__((noreturn))
RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
    LOG(INFO) << "Reboot ending, jumping to kernel";

    if (!IsRebootCapable()) {
        // On systems where init does not have the capability of rebooting the
        // device, just exit cleanly.
        exit(0);
    }

    switch (cmd) {
        case ANDROID_RB_POWEROFF:
            reboot(RB_POWER_OFF);