Merge changes I0a95f87a,I36b22986

* changes:
  init: Use ScopedCaps for cap_init()
  init: Reland "Terminate gracefully when CAP_SYS_BOOT is absent"
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
index 53832a4..642a364 100644
--- a/init/capabilities.cpp
+++ b/init/capabilities.cpp
@@ -107,17 +107,15 @@
 }
 
 static bool SetProcCaps(const CapSet& to_keep, bool add_setpcap) {
-    cap_t caps = cap_init();
-    auto deleter = [](cap_t* p) { cap_free(*p); };
-    std::unique_ptr<cap_t, decltype(deleter)> ptr_caps(&caps, deleter);
+    ScopedCaps caps(cap_init());
 
-    cap_clear(caps);
+    cap_clear(caps.get());
     cap_value_t value[1];
     for (size_t cap = 0; cap < to_keep.size(); ++cap) {
         if (to_keep.test(cap)) {
             value[0] = cap;
-            if (cap_set_flag(caps, CAP_INHERITABLE, arraysize(value), value, CAP_SET) != 0 ||
-                cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0) {
+            if (cap_set_flag(caps.get(), CAP_INHERITABLE, arraysize(value), value, CAP_SET) != 0 ||
+                cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0) {
                 PLOG(ERROR) << "cap_set_flag(INHERITABLE|PERMITTED, " << cap << ") failed";
                 return false;
             }
@@ -126,14 +124,14 @@
 
     if (add_setpcap) {
         value[0] = CAP_SETPCAP;
-        if (cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0 ||
-            cap_set_flag(caps, CAP_EFFECTIVE, arraysize(value), value, CAP_SET) != 0) {
+        if (cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0 ||
+            cap_set_flag(caps.get(), CAP_EFFECTIVE, arraysize(value), value, CAP_SET) != 0) {
             PLOG(ERROR) << "cap_set_flag(PERMITTED|EFFECTIVE, " << CAP_SETPCAP << ") failed";
             return false;
         }
     }
 
-    if (cap_set_proc(caps) != 0) {
+    if (cap_set_proc(caps.get()) != 0) {
         PLOG(ERROR) << "cap_set_proc(" << to_keep.to_ulong() << ") failed";
         return false;
     }
diff --git a/init/capabilities.h b/init/capabilities.h
index ef507a6..ede85c3 100644
--- a/init/capabilities.h
+++ b/init/capabilities.h
@@ -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();
diff --git a/init/reboot.cpp b/init/reboot.cpp
index df7912f..c8bb98b 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -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 @@
     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);