minadbd: Support `adb reboot` under sideload/rescue modes.

Bug: 128415917
Test: Run the following commands under sideload and rescue modes
      respectively.
$ adb reboot
$ adb reboot bootloader
$ adb reboot recovery
$ adb reboot rescue
$ adb reboot invalid
Change-Id: I84daf63e3360b7b4a0af5e055149a4f54e10ba90
Merged-In: I84daf63e3360b7b4a0af5e055149a4f54e10ba90
(cherry picked from commit 10f441a9dbb91be3124f455439631abcf8e96cde)
diff --git a/minadbd/minadbd_services.cpp b/minadbd/minadbd_services.cpp
index f6aff71..9b1999d 100644
--- a/minadbd/minadbd_services.cpp
+++ b/minadbd/minadbd_services.cpp
@@ -64,7 +64,7 @@
   sideload_mount_point = path;
 }
 
-static bool WriteCommandToFd(MinadbdCommands cmd, int fd) {
+static bool WriteCommandToFd(MinadbdCommand cmd, int fd) {
   char message[kMinadbdMessageSize];
   memcpy(message, kMinadbdCommandPrefix, strlen(kMinadbdStatusPrefix));
   android::base::put_unaligned(message + strlen(kMinadbdStatusPrefix), cmd);
@@ -109,7 +109,7 @@
 
   LOG(INFO) << "sideload-host file size " << file_size << ", block size " << block_size;
 
-  if (!WriteCommandToFd(MinadbdCommands::kInstall, minadbd_socket)) {
+  if (!WriteCommandToFd(MinadbdCommand::kInstall, minadbd_socket)) {
     return kMinadbdSocketIOError;
   }
 
@@ -175,7 +175,45 @@
   }
 }
 
+// Reboots into the given target. We don't reboot directly from minadbd, but going through recovery
+// instead. This allows recovery to finish all the pending works (clear BCB, save logs etc) before
+// the reboot.
+static void RebootHostService(unique_fd /* sfd */, const std::string& target) {
+  MinadbdCommand command;
+  if (target == "bootloader") {
+    command = MinadbdCommand::kRebootBootloader;
+  } else if (target == "rescue") {
+    command = MinadbdCommand::kRebootRescue;
+  } else if (target == "recovery") {
+    command = MinadbdCommand::kRebootRecovery;
+  } else if (target == "fastboot") {
+    command = MinadbdCommand::kRebootFastboot;
+  } else {
+    command = MinadbdCommand::kRebootAndroid;
+  }
+  if (!WriteCommandToFd(command, minadbd_socket)) {
+    exit(kMinadbdSocketIOError);
+  }
+  MinadbdCommandStatus status;
+  if (!WaitForCommandStatus(minadbd_socket, &status)) {
+    exit(kMinadbdMessageFormatError);
+  }
+}
+
 unique_fd daemon_service_to_fd(std::string_view name, atransport* /* transport */) {
+  // Common services that are supported both in sideload and rescue modes.
+  if (ConsumePrefix(&name, "reboot:")) {
+    // "reboot:<target>", where target must be one of the following.
+    std::string args(name);
+    if (args.empty() || args == "bootloader" || args == "rescue" || args == "recovery" ||
+        args == "fastboot") {
+      return create_service_thread("reboot",
+                                   std::bind(RebootHostService, std::placeholders::_1, args));
+    }
+    return unique_fd{};
+  }
+
+  // Rescue-specific services.
   if (rescue_mode) {
     if (ConsumePrefix(&name, "rescue-install:")) {
       // rescue-install:<file-size>:<block-size>
@@ -191,6 +229,7 @@
     return unique_fd{};
   }
 
+  // Sideload-specific services.
   if (name.starts_with("sideload:")) {
     // This exit status causes recovery to print a special error message saying to use a newer adb
     // (that supports sideload-host).
diff --git a/minadbd/minadbd_services_test.cpp b/minadbd/minadbd_services_test.cpp
index 413ba0d..593180b 100644
--- a/minadbd/minadbd_services_test.cpp
+++ b/minadbd/minadbd_services_test.cpp
@@ -62,7 +62,7 @@
     signal(SIGPIPE, SIG_DFL);
   }
 
-  void ReadAndCheckCommandMessage(int fd, MinadbdCommands expected_command) {
+  void ReadAndCheckCommandMessage(int fd, MinadbdCommand expected_command) {
     std::vector<uint8_t> received(kMinadbdMessageSize, '\0');
     ASSERT_TRUE(android::base::ReadFully(fd, received.data(), kMinadbdMessageSize));
 
@@ -147,7 +147,7 @@
     unique_fd fd = daemon_service_to_fd(command, nullptr);
     ASSERT_NE(-1, fd);
     WaitForFusePath();
-    ReadAndCheckCommandMessage(recovery_socket_, MinadbdCommands::kInstall);
+    ReadAndCheckCommandMessage(recovery_socket_, MinadbdCommand::kInstall);
 
     struct stat sb;
     ASSERT_EQ(0, stat(exit_flag_.c_str(), &sb));
@@ -188,7 +188,7 @@
 
     unique_fd fd = daemon_service_to_fd("sideload-host:4096:4096", nullptr);
     ASSERT_NE(-1, fd);
-    ReadAndCheckCommandMessage(recovery_socket_, MinadbdCommands::kInstall);
+    ReadAndCheckCommandMessage(recovery_socket_, MinadbdCommand::kInstall);
 
     // Mimic the response from adb host.
     std::string adb_message(8, '\0');
diff --git a/minadbd/minadbd_types.h b/minadbd/minadbd_types.h
index 5fb7803..b370b79 100644
--- a/minadbd/minadbd_types.h
+++ b/minadbd/minadbd_types.h
@@ -43,12 +43,19 @@
   kFailure = 1,
 };
 
-enum class MinadbdCommands : uint32_t {
+enum class MinadbdCommand : uint32_t {
   kInstall = 0,
   kUiPrint = 1,
-  kError = 2,
+  kRebootAndroid = 2,
+  kRebootBootloader = 3,
+  kRebootFastboot = 4,
+  kRebootRecovery = 5,
+  kRebootRescue = 6,
+
+  // Last but invalid command.
+  kError,
 };
 
-static_assert(kMinadbdMessageSize == sizeof(kMinadbdCommandPrefix) - 1 + sizeof(MinadbdCommands));
+static_assert(kMinadbdMessageSize == sizeof(kMinadbdCommandPrefix) - 1 + sizeof(MinadbdCommand));
 static_assert(kMinadbdMessageSize ==
               sizeof(kMinadbdStatusPrefix) - 1 + sizeof(MinadbdCommandStatus));