Merge "Add sideload, fastboot as reboot targets in init" am: 3231be66ce am: daf8cda934
am: f19d462740

Change-Id: I09dcb207c67d9ef93d26d2258437b2e592569da7
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index dfcc52d..8417690 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -26,6 +26,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 #include <unistd.h>
 
 #include <thread>
@@ -96,41 +98,44 @@
 
 void reboot_service(unique_fd fd, const std::string& arg) {
     std::string reboot_arg = arg;
-    bool auto_reboot = false;
-
-    if (reboot_arg == "sideload-auto-reboot") {
-        auto_reboot = true;
-        reboot_arg = "sideload";
-    }
-
-    // It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot"
-    // in the command file.
-    if (reboot_arg == "sideload") {
-        if (getuid() != 0) {
-            WriteFdExactly(fd.get(), "'adb root' is required for 'adb reboot sideload'.\n");
-            return;
-        }
-
-        const std::vector<std::string> options = {auto_reboot ? "--sideload_auto_reboot"
-                                                              : "--sideload"};
-        std::string err;
-        if (!write_bootloader_message(options, &err)) {
-            D("Failed to set bootloader message: %s", err.c_str());
-            return;
-        }
-
-        reboot_arg = "recovery";
-    }
-
     sync();
 
     if (reboot_arg.empty()) reboot_arg = "adb";
     std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
-    if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
-        WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str());
-        return;
-    }
 
+    if (reboot_arg == "fastboot" && access("/dev/socket/recovery", F_OK) == 0) {
+        LOG(INFO) << "Recovery specific reboot fastboot";
+        /*
+         * The socket is created to allow switching between recovery and
+         * fastboot.
+         */
+        android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
+        if (sock < 0) {
+            WriteFdFmt(fd, "reboot (%s) create\n", strerror(errno));
+            PLOG(ERROR) << "Creating recovery socket failed";
+            return;
+        }
+
+        sockaddr_un addr = {.sun_family = AF_UNIX};
+        strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
+        if (connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
+            WriteFdFmt(fd, "reboot (%s) connect\n", strerror(errno));
+            PLOG(ERROR) << "Couldn't connect to recovery socket";
+            return;
+        }
+        const char msg_switch_to_fastboot = 'f';
+        auto ret = adb_write(sock, &msg_switch_to_fastboot, sizeof(msg_switch_to_fastboot));
+        if (ret != sizeof(msg_switch_to_fastboot)) {
+            WriteFdFmt(fd, "reboot (%s) write\n", strerror(errno));
+            PLOG(ERROR) << "Couldn't write message to recovery socket to switch to fastboot";
+            return;
+        }
+    } else {
+        if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
+            WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str());
+            return;
+        }
+    }
     // Don't return early. Give the reboot command time to take effect
     // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
     while (true) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 7401857..2f88121 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -473,7 +473,21 @@
                                   "bootloader_message: "
                                << err;
                 }
+            } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
+                       reboot_target == "fastboot") {
+                std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
+                                                                          : reboot_target;
+                const std::vector<std::string> options = {
+                        "--" + arg,
+                };
+                std::string err;
+                if (!write_bootloader_message(options, &err)) {
+                    LOG(ERROR) << "Failed to set bootloader message: " << err;
+                    return false;
+                }
+                reboot_target = "recovery";
             }
+
             // If there is an additional parameter, pass it along
             if ((cmd_params.size() == 3) && cmd_params[2].size()) {
                 reboot_target += "," + cmd_params[2];