From 20c81b308d834f84f3decf795575dc7a0baeb69d Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Fri, 27 Jul 2018 22:09:12 -0700 Subject: Add fastboot mode to recovery Add a fastboot mode to recovery that can be entered with command line args or with the ui. Add usb property triggers to switch between fastboot and adb configurations. Allow switching between fastboot and adb through usb commands by opening a unix socket. adbd/fastbootd writes to this socket, which interrupts the ui and switches to the new mode. Test: Use fastboot mode Bug: 78793464 Change-Id: I7891bb84427ec734a21a872036629b95ab3fb13c --- recovery_main.cpp | 124 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 103 insertions(+), 21 deletions(-) (limited to 'recovery_main.cpp') diff --git a/recovery_main.cpp b/recovery_main.cpp index 9a9890de0..99f965098 100644 --- a/recovery_main.cpp +++ b/recovery_main.cpp @@ -30,15 +30,19 @@ #include #include +#include #include +#include #include #include #include #include #include +#include #include #include +#include #include /* private pmsg functions */ #include #include @@ -46,6 +50,7 @@ #include "common.h" #include "device.h" +#include "fastboot/fastboot.h" #include "logging.h" #include "minadbd/minadbd.h" #include "otautil/paths.h" @@ -162,6 +167,44 @@ static std::string load_locale_from_cache() { return android::base::Trim(content); } +static void ListenRecoverySocket(RecoveryUI* ui, std::atomic& action) { + android::base::unique_fd sock_fd(android_get_control_socket("recovery")); + if (sock_fd < 0) { + PLOG(ERROR) << "Failed to open recovery socket"; + return; + } + listen(sock_fd, 4); + + while (true) { + android::base::unique_fd connection_fd; + connection_fd.reset(accept(sock_fd, nullptr, nullptr)); + if (connection_fd < 0) { + PLOG(ERROR) << "Failed to accept socket connection"; + continue; + } + char msg; + constexpr char kSwitchToFastboot = 'f'; + constexpr char kSwitchToRecovery = 'r'; + ssize_t ret = TEMP_FAILURE_RETRY(read(connection_fd, &msg, sizeof(msg))); + if (ret != sizeof(msg)) { + PLOG(ERROR) << "Couldn't read from socket"; + continue; + } + switch (msg) { + case kSwitchToRecovery: + action = Device::BuiltinAction::ENTER_RECOVERY; + break; + case kSwitchToFastboot: + action = Device::BuiltinAction::ENTER_FASTBOOT; + break; + default: + LOG(ERROR) << "Unrecognized char from socket " << msg; + continue; + } + ui->InterruptKey(); + } +} + static void redirect_stdio(const char* filename) { int pipefd[2]; if (pipe(pipefd) == -1) { @@ -251,6 +294,11 @@ static void redirect_stdio(const char* filename) { } } +static bool SetUsbConfig(const std::string& state) { + android::base::SetProperty("sys.usb.config", state); + return android::base::WaitForProperty("sys.usb.state", state); +} + int main(int argc, char** argv) { // We don't have logcat yet under recovery; so we'll print error on screen and log to stdout // (which is redirected to recovery.log) as we used to do. @@ -281,8 +329,6 @@ int main(int argc, char** argv) { // instances with different timestamps. redirect_stdio(Paths::Get().temporary_log_file().c_str()); - printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start)); - load_volume_table(); has_cache = volume_for_mount_point(CACHE_ROOT) != nullptr; @@ -290,12 +336,14 @@ int main(int argc, char** argv) { auto args_to_parse = StringVectorToNullTerminatedArray(args); static constexpr struct option OPTIONS[] = { + { "fastboot", no_argument, nullptr, 0 }, { "locale", required_argument, nullptr, 0 }, { "show_text", no_argument, nullptr, 't' }, { nullptr, 0, nullptr, 0 }, }; bool show_text = false; + bool fastboot = false; std::string locale; int arg; @@ -310,6 +358,8 @@ int main(int argc, char** argv) { std::string option = OPTIONS[option_index].name; if (option == "locale") { locale = optarg; + } else if (option == "fastboot") { + fastboot = true; } break; } @@ -328,8 +378,6 @@ int main(int argc, char** argv) { } } - printf("locale is [%s]\n", locale.c_str()); - static constexpr const char* kDefaultLibRecoveryUIExt = "librecovery_ui_ext.so"; // Intentionally not calling dlclose(3) to avoid potential gotchas (e.g. `make_device` may have // handed out pointers to code or static [or thread-local] data and doesn't collect them all back @@ -374,33 +422,67 @@ int main(int argc, char** argv) { ui->SetBackground(RecoveryUI::NONE); if (show_text) ui->ShowText(true); + LOG(INFO) << "Starting recovery (pid " << getpid() << ") on " << ctime(&start); + LOG(INFO) << "locale is [" << locale << "]"; + sehandle = selinux_android_file_context_handle(); selinux_android_set_sehandle(sehandle); if (!sehandle) { ui->Print("Warning: No file_contexts\n"); } - Device::BuiltinAction after = start_recovery(device, args); + std::atomic action; + std::thread listener_thread(ListenRecoverySocket, ui, std::ref(action)); + listener_thread.detach(); + + while (true) { + std::string usb_config = fastboot ? "fastboot" : is_ro_debuggable() ? "adb" : "none"; + std::string usb_state = android::base::GetProperty("sys.usb.state", "none"); + if (usb_config != usb_state) { + if (!SetUsbConfig("none")) { + LOG(ERROR) << "Failed to clear USB config"; + } + if (!SetUsbConfig(usb_config)) { + LOG(ERROR) << "Failed to set USB config to " << usb_config; + } + } - switch (after) { - case Device::SHUTDOWN: - ui->Print("Shutting down...\n"); - android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,"); - break; + auto ret = fastboot ? StartFastboot(device, args) : start_recovery(device, args); - case Device::REBOOT_BOOTLOADER: - ui->Print("Rebooting to bootloader...\n"); - android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader"); - break; + if (ret == Device::KEY_INTERRUPTED) { + ret = action.exchange(ret); + if (ret == Device::NO_ACTION) { + continue; + } + } + switch (ret) { + case Device::SHUTDOWN: + ui->Print("Shutting down...\n"); + android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,"); + break; - default: - ui->Print("Rebooting...\n"); - reboot("reboot,"); - break; - } - while (true) { - pause(); + case Device::REBOOT_BOOTLOADER: + ui->Print("Rebooting to bootloader...\n"); + android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader"); + break; + + case Device::ENTER_FASTBOOT: + LOG(INFO) << "Entering fastboot"; + fastboot = true; + break; + + case Device::ENTER_RECOVERY: + LOG(INFO) << "Entering recovery"; + fastboot = false; + break; + + default: + ui->Print("Rebooting...\n"); + reboot("reboot,"); + break; + } } + // Should be unreachable. return EXIT_SUCCESS; } -- cgit v1.2.3