Merge change 20039

* changes:
  adb: add "adb reboot" command.
diff --git a/adb/adb.c b/adb/adb.c
index 956df54..e8d2c8f 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -30,6 +30,8 @@
 
 #if !ADB_HOST
 #include <private/android_filesystem_config.h>
+#include <linux/capability.h>
+#include <linux/prctl.h>
 #else
 #include "usb_vendors.h"
 #endif
@@ -879,6 +881,11 @@
     /* don't listen on port 5037 if we are running in secure mode */
     /* don't run as root if we are running in secure mode */
     if (secure) {
+        struct __user_cap_header_struct header;
+        struct __user_cap_data_struct cap;
+
+        prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
         /* add extra groups:
         ** AID_ADB to access the USB driver
         ** AID_LOG to read system logs (adb logcat)
@@ -896,6 +903,13 @@
         setgid(AID_SHELL);
         setuid(AID_SHELL);
 
+        /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
+        header.version = _LINUX_CAPABILITY_VERSION;
+        header.pid = 0;
+        cap.effective = cap.permitted = (1 << CAP_SYS_BOOT);
+        cap.inheritable = 0;
+        capset(&header, &cap);
+
         D("Local port 5037 disabled\n");
     } else {
         if(install_listener("tcp:5037", "*smartsocket*", NULL)) {
diff --git a/adb/adb.h b/adb/adb.h
index 95610a7..8d57bf2 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -33,7 +33,7 @@
 #define ADB_VERSION_MAJOR 1         // Used for help/version information
 #define ADB_VERSION_MINOR 0         // Used for help/version information
 
-#define ADB_SERVER_VERSION    21    // Increment this when we want to force users to start a new adb server
+#define ADB_SERVER_VERSION    22    // Increment this when we want to force users to start a new adb server
 
 typedef struct amessage amessage;
 typedef struct apacket apacket;
diff --git a/adb/commandline.c b/adb/commandline.c
index ad1021c..4ec5c8b 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -148,6 +148,7 @@
         "  adb get-serialno             - prints: <serial-number>\n"
         "  adb status-window            - continuously print device status for a specified device\n"
         "  adb remount                  - remounts the /system partition on the device read-write\n"
+        "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
         "  adb root                     - restarts adb with root permissions\n"
         "\n"
         "networking:\n"
@@ -918,6 +919,22 @@
         return 1;
     }
 
+    if(!strcmp(argv[0], "reboot")) {
+        int fd;
+        if (argc > 1)
+            snprintf(buf, sizeof(buf), "reboot:%s", argv[1]);
+        else
+            snprintf(buf, sizeof(buf), "reboot:");
+        fd = adb_connect(buf);
+        if(fd >= 0) {
+            read_and_dump(fd);
+            adb_close(fd);
+            return 0;
+        }
+        fprintf(stderr,"error: %s\n", adb_error());
+        return 1;
+    }
+
     if(!strcmp(argv[0], "root")) {
         int fd = adb_connect("root:");
         if(fd >= 0) {
diff --git a/adb/services.c b/adb/services.c
index 78d092b..517da55 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -33,6 +33,7 @@
 #  endif
 #else
 #include <sys/poll.h>
+#include <sys/reboot.h>
 #endif
 
 typedef struct stinfo stinfo;
@@ -133,6 +134,20 @@
     }
 }
 
+void reboot_service(int fd, char *arg)
+{
+    char buf[100];
+    int ret;
+
+    sync();
+    ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, arg);
+    if (ret < 0) {
+        snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
+        writex(fd, buf, strlen(buf));
+    }
+    adb_close(fd);
+}
+
 #endif
 
 #if 0
@@ -399,6 +414,11 @@
         ret = create_service_thread(file_sync_service, NULL);
     } else if(!strncmp(name, "remount:", 8)) {
         ret = create_service_thread(remount_service, NULL);
+    } else if(!strncmp(name, "reboot:", 7)) {
+        char* arg = name + 7;
+        if (*name == 0)
+            arg = NULL;
+        ret = create_service_thread(reboot_service, arg);
     } else if(!strncmp(name, "root:", 5)) {
         ret = create_service_thread(restart_root_service, NULL);
 #endif