init: Reland "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: `adb reboot` on bullhead causes no kernel panics Test: `adb reboot` on a system without CAP_SYS_BOOT makes init terminate nicely Change-Id: I36b2298610f5b4a2bf8b05103d04804883df2c88
This commit is contained in:
parent
51b4f48280
commit
519e5f0592
|
@ -15,15 +15,21 @@
|
|||
#ifndef _INIT_CAPABILITIES_H
|
||||
#define _INIT_CAPABILITIES_H
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <sys/capability.h>
|
||||
|
||||
#include <bitset>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
struct CapDeleter {
|
||||
void operator()(cap_t caps) const { cap_free(caps); }
|
||||
};
|
||||
|
||||
using CapSet = std::bitset<CAP_LAST_CAP + 1>;
|
||||
using ScopedCaps = std::unique_ptr<std::remove_pointer<cap_t>::type, CapDeleter>;
|
||||
|
||||
int LookupCap(const std::string& cap_name);
|
||||
bool CapAmbientSupported();
|
||||
|
|
|
@ -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>
|
||||
|
@ -48,6 +49,7 @@
|
|||
#include <logwrap/logwrap.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
|
||||
#include "capabilities.h"
|
||||
#include "property_service.h"
|
||||
#include "service.h"
|
||||
|
||||
|
@ -162,9 +164,38 @@ static void LogShutdownTime(UmountStat stat, Timer* t) {
|
|||
LOG(WARNING) << "powerctl_shutdown_time_ms:" << std::to_string(t->duration_ms()) << ":" << stat;
|
||||
}
|
||||
|
||||
// Determines whether the system is capable of rebooting. This is conservative,
|
||||
// so if any of the attempts to determine this fail, it will still return true.
|
||||
static bool IsRebootCapable() {
|
||||
if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
|
||||
PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
|
||||
return true;
|
||||
}
|
||||
|
||||
ScopedCaps caps(cap_get_proc());
|
||||
if (!caps) {
|
||||
PLOG(WARNING) << "cap_get_proc() failed";
|
||||
return true;
|
||||
}
|
||||
|
||||
cap_flag_value_t value = CAP_SET;
|
||||
if (cap_get_flag(caps.get(), CAP_SYS_BOOT, CAP_EFFECTIVE, &value) != 0) {
|
||||
PLOG(WARNING) << "cap_get_flag(CAP_SYS_BOOT, EFFECTIVE) failed";
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue