From 10f441a9dbb91be3124f455439631abcf8e96cde Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 19 Apr 2019 15:22:15 -0700 Subject: 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 --- install/adb_install.cpp | 98 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 26 deletions(-) (limited to 'install/adb_install.cpp') diff --git a/install/adb_install.cpp b/install/adb_install.cpp index f430920a4..d79f6f4b0 100644 --- a/install/adb_install.cpp +++ b/install/adb_install.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -44,30 +45,34 @@ #include "install/install.h" #include "minadbd_types.h" #include "otautil/sysutil.h" +#include "recovery_ui/device.h" #include "recovery_ui/ui.h" -using CommandFunction = std::function; +// A CommandFunction returns a pair of (result, should_continue), which indicates the command +// execution result and whether it should proceed to the next iteration. The execution result will +// always be sent to the minadbd side. +using CommandFunction = std::function()>; static bool SetUsbConfig(const std::string& state) { android::base::SetProperty("sys.usb.config", state); return android::base::WaitForProperty("sys.usb.state", state); } -// Parses the minadbd command in |message|; returns MinadbdCommands::kError upon errors. -static MinadbdCommands ParseMinadbdCommands(const std::string& message) { +// Parses the minadbd command in |message|; returns MinadbdCommand::kError upon errors. +static MinadbdCommand ParseMinadbdCommand(const std::string& message) { if (!android::base::StartsWith(message, kMinadbdCommandPrefix)) { LOG(ERROR) << "Failed to parse command in message " << message; - return MinadbdCommands::kError; + return MinadbdCommand::kError; } auto cmd_code_string = message.substr(strlen(kMinadbdCommandPrefix)); auto cmd_code = android::base::get_unaligned(cmd_code_string.c_str()); - if (cmd_code >= static_cast(MinadbdCommands::kError)) { + if (cmd_code >= static_cast(MinadbdCommand::kError)) { LOG(ERROR) << "Unsupported command code: " << cmd_code; - return MinadbdCommands::kError; + return MinadbdCommand::kError; } - return static_cast(cmd_code); + return static_cast(cmd_code); } static bool WriteStatusToFd(MinadbdCommandStatus status, int fd) { @@ -82,13 +87,15 @@ static bool WriteStatusToFd(MinadbdCommandStatus status, int fd) { return true; } -// Installs the package from FUSE. Returns true if the installation succeeds, and false otherwise. -static bool AdbInstallPackageHandler(RecoveryUI* ui, int* result) { +// Installs the package from FUSE. Returns the installation result and whether it should continue +// waiting for new commands. +static auto AdbInstallPackageHandler(RecoveryUI* ui, int* result) { // How long (in seconds) we wait for the package path to be ready. It doesn't need to be too long // because the minadbd service has already issued an install command. FUSE_SIDELOAD_HOST_PATHNAME // will start to exist once the host connects and starts serving a package. Poll for its // appearance. (Note that inotify doesn't work with FUSE.) constexpr int ADB_INSTALL_TIMEOUT = 15; + bool should_continue = true; *result = INSTALL_ERROR; for (int i = 0; i < ADB_INSTALL_TIMEOUT; ++i) { struct stat st; @@ -97,6 +104,7 @@ static bool AdbInstallPackageHandler(RecoveryUI* ui, int* result) { sleep(1); continue; } else { + should_continue = false; ui->Print("\nTimed out waiting for fuse to be ready.\n\n"); break; } @@ -108,13 +116,39 @@ static bool AdbInstallPackageHandler(RecoveryUI* ui, int* result) { // Calling stat() on this magic filename signals the FUSE to exit. struct stat st; stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st); - return *result == INSTALL_SUCCESS; + return std::make_pair(*result == INSTALL_SUCCESS, should_continue); } -// Parses and executes the command from minadbd. Returns false if we enter an invalid state so that -// the caller can kill the minadbd service properly. -static bool HandleMessageFromMinadbd( - int socket_fd, const std::map& command_map) { +static auto AdbRebootHandler(MinadbdCommand command, int* result, + Device::BuiltinAction* reboot_action) { + switch (command) { + case MinadbdCommand::kRebootBootloader: + *reboot_action = Device::REBOOT_BOOTLOADER; + break; + case MinadbdCommand::kRebootFastboot: + *reboot_action = Device::ENTER_FASTBOOT; + break; + case MinadbdCommand::kRebootRecovery: + *reboot_action = Device::ENTER_RECOVERY; + break; + case MinadbdCommand::kRebootRescue: + // Use Device::REBOOT_RESCUE instead of Device::ENTER_RESCUE. This allows rebooting back into + // rescue mode (potentially using a newly installed recovery image). + *reboot_action = Device::REBOOT_RESCUE; + break; + case MinadbdCommand::kRebootAndroid: + default: + *reboot_action = Device::REBOOT; + break; + } + *result = INSTALL_REBOOT; + return std::make_pair(true, false); +} + +// Parses and executes the command from minadbd. Returns whether the caller should keep waiting for +// next command. +static bool HandleMessageFromMinadbd(int socket_fd, + const std::map& command_map) { char buffer[kMinadbdMessageSize]; if (!android::base::ReadFully(socket_fd, buffer, kMinadbdMessageSize)) { PLOG(ERROR) << "Failed to read message from minadbd"; @@ -122,8 +156,8 @@ static bool HandleMessageFromMinadbd( } std::string message(buffer, buffer + kMinadbdMessageSize); - auto command_type = ParseMinadbdCommands(message); - if (command_type == MinadbdCommands::kError) { + auto command_type = ParseMinadbdCommand(message); + if (command_type == MinadbdCommand::kError) { return false; } if (command_map.find(command_type) == command_map.end()) { @@ -135,17 +169,19 @@ static bool HandleMessageFromMinadbd( // We have received a valid command, execute the corresponding function. const auto& command_func = command_map.at(command_type); - if (!command_func()) { - LOG(ERROR) << "Failed to execute command " << static_cast(command_type); - return WriteStatusToFd(MinadbdCommandStatus::kFailure, socket_fd); + const auto [result, should_continue] = command_func(); + LOG(INFO) << "Command " << static_cast(command_type) << " finished with " << result; + if (!WriteStatusToFd(result ? MinadbdCommandStatus::kSuccess : MinadbdCommandStatus::kFailure, + socket_fd)) { + return false; } - return WriteStatusToFd(MinadbdCommandStatus::kSuccess, socket_fd); + return should_continue; } // TODO(xunchang) add a wrapper function and kill the minadbd service there. static void ListenAndExecuteMinadbdCommands( pid_t minadbd_pid, android::base::unique_fd&& socket_fd, - const std::map& command_map) { + const std::map& command_map) { android::base::unique_fd epoll_fd(epoll_create1(O_CLOEXEC)); if (epoll_fd == -1) { PLOG(ERROR) << "Failed to create epoll"; @@ -230,7 +266,7 @@ static void ListenAndExecuteMinadbdCommands( // b11. exit the listening loop // static void CreateMinadbdServiceAndExecuteCommands( - const std::map& command_map, bool rescue_mode) { + const std::map& command_map, bool rescue_mode) { signal(SIGPIPE, SIG_IGN); android::base::unique_fd recovery_socket; @@ -271,7 +307,6 @@ static void CreateMinadbdServiceAndExecuteCommands( std::thread listener_thread(ListenAndExecuteMinadbdCommands, child, std::move(recovery_socket), std::ref(command_map)); - if (listener_thread.joinable()) { listener_thread.join(); } @@ -289,7 +324,7 @@ static void CreateMinadbdServiceAndExecuteCommands( signal(SIGPIPE, SIG_DFL); } -int ApplyFromAdb(RecoveryUI* ui, bool rescue_mode) { +int ApplyFromAdb(RecoveryUI* ui, bool rescue_mode, Device::BuiltinAction* reboot_action) { // Save the usb state to restore after the sideload operation. std::string usb_state = android::base::GetProperty("sys.usb.state", "none"); // Clean up state and stop adbd. @@ -307,8 +342,19 @@ int ApplyFromAdb(RecoveryUI* ui, bool rescue_mode) { } int install_result = INSTALL_ERROR; - std::map command_map{ - { MinadbdCommands::kInstall, std::bind(&AdbInstallPackageHandler, ui, &install_result) }, + std::map command_map{ + { MinadbdCommand::kInstall, std::bind(&AdbInstallPackageHandler, ui, &install_result) }, + { MinadbdCommand::kRebootAndroid, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootAndroid, + &install_result, reboot_action) }, + { MinadbdCommand::kRebootBootloader, + std::bind(&AdbRebootHandler, MinadbdCommand::kRebootBootloader, &install_result, + reboot_action) }, + { MinadbdCommand::kRebootFastboot, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootFastboot, + &install_result, reboot_action) }, + { MinadbdCommand::kRebootRecovery, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootRecovery, + &install_result, reboot_action) }, + { MinadbdCommand::kRebootRescue, + std::bind(&AdbRebootHandler, MinadbdCommand::kRebootRescue, &install_result, reboot_action) }, }; CreateMinadbdServiceAndExecuteCommands(command_map, rescue_mode); -- cgit v1.2.3