diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2018-08-07 00:08:18 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2018-08-07 00:08:18 +0000 |
commit | c30a75a00717cefa35de93e0aa50bb48d5f7a5c3 (patch) | |
tree | 32d4c912d52119f02e2e8c8ca62e3b249879078f | |
parent | 0e947189c5a9493e9f2038446d880038024d184b (diff) | |
parent | dea91b4b5354af2f9470845cb05cca1207142c98 (diff) |
Merge "Add fastbootd."
-rw-r--r-- | fastboot/Android.bp | 65 | ||||
-rw-r--r-- | fastboot/constants.h | 2 | ||||
-rw-r--r-- | fastboot/device/commands.cpp | 126 | ||||
-rw-r--r-- | fastboot/device/commands.h | 40 | ||||
-rw-r--r-- | fastboot/device/fastboot_device.cpp | 104 | ||||
-rw-r--r-- | fastboot/device/fastboot_device.h | 52 | ||||
-rw-r--r-- | fastboot/device/main.cpp | 28 | ||||
-rw-r--r-- | fastboot/device/usb_client.cpp | 307 | ||||
-rw-r--r-- | fastboot/device/usb_client.h | 37 | ||||
-rw-r--r-- | fastboot/fastboot.cpp | 18 |
10 files changed, 779 insertions, 0 deletions
diff --git a/fastboot/Android.bp b/fastboot/Android.bp index 2b4a95463..51cc62ade 100644 --- a/fastboot/Android.bp +++ b/fastboot/Android.bp @@ -1,3 +1,17 @@ +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + cc_library_host_static { name: "libfastboot2", @@ -54,3 +68,54 @@ cc_library_host_static { export_include_dirs: ["."], } + +cc_defaults { + name: "fastboot_defaults", + + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-Wvla", + ], + rtti: true, + + clang_cflags: [ + "-Wthread-safety", + ], +} + +cc_binary { + name: "fastbootd", + defaults: ["fastboot_defaults"], + + recovery: true, + + srcs: [ + "device/commands.cpp", + "device/fastboot_device.cpp", + "device/main.cpp", + "device/usb_client.cpp", + ], + + shared_libs: [ + "libasyncio", + "libext4_utils", + "libsparse", + "liblog", + "libbootloader_message", + "libhidltransport", + "libhidlbase", + "libhwbinder", + "libbase", + "libutils", + "libcutils", + "libfs_mgr", + ], + + static_libs: [ + "libadbd", + ], + + cpp_std: "c++17", +} diff --git a/fastboot/constants.h b/fastboot/constants.h index 5e7e95510..7caca3dba 100644 --- a/fastboot/constants.h +++ b/fastboot/constants.h @@ -27,6 +27,8 @@ #define FB_CMD_REBOOT "reboot" #define FB_CMD_SHUTDOWN "shutdown" #define FB_CMD_REBOOT_BOOTLOADER "reboot-bootloader" +#define FB_CMD_REBOOT_RECOVERY "reboot-recovery" +#define FB_CMD_REBOOT_FASTBOOT "reboot-fastboot" #define FB_CMD_POWERDOWN "powerdown" #define RESPONSE_OKAY "OKAY" diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp new file mode 100644 index 000000000..a3cbf9692 --- /dev/null +++ b/fastboot/device/commands.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "commands.h" + +#include <sys/socket.h> +#include <sys/un.h> + +#include <android-base/logging.h> +#include <android-base/parseint.h> +#include <android-base/properties.h> +#include <android-base/stringprintf.h> +#include <android-base/strings.h> +#include <android-base/unique_fd.h> +#include <cutils/android_reboot.h> + +#include "fastboot_device.h" + +bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) { + if (args.size() < 2) { + return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified"); + } + // arg[0] is the command name, arg[1] contains size of data to be downloaded + unsigned int size; + if (!android::base::ParseUint("0x" + args[1], &size, UINT_MAX)) { + return device->WriteStatus(FastbootResult::FAIL, "Invalid size"); + } + device->get_download_data().resize(size); + if (!device->WriteStatus(FastbootResult::DATA, android::base::StringPrintf("%08x", size))) { + return false; + } + + if (device->HandleData(true, &device->get_download_data())) { + return device->WriteStatus(FastbootResult::OKAY, ""); + } + + PLOG(ERROR) << "Couldn't download data"; + return device->WriteStatus(FastbootResult::FAIL, "Couldn't download data"); +} + +bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) { + return device->WriteStatus(FastbootResult::OKAY, ""); +} + +bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) { + auto result = device->WriteStatus(FastbootResult::OKAY, "Shutting down"); + android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,fastboot"); + device->CloseDevice(); + TEMP_FAILURE_RETRY(pause()); + return result; +} + +bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) { + auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting"); + android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,from_fastboot"); + device->CloseDevice(); + TEMP_FAILURE_RETRY(pause()); + return result; +} + +bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) { + auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting bootloader"); + android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader"); + device->CloseDevice(); + TEMP_FAILURE_RETRY(pause()); + return result; +} + +bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) { + auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting fastboot"); + android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,fastboot"); + device->CloseDevice(); + TEMP_FAILURE_RETRY(pause()); + return result; +} + +static bool EnterRecovery() { + const char msg_switch_to_recovery = 'r'; + + android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0)); + if (sock < 0) { + PLOG(ERROR) << "Couldn't create sock"; + return false; + } + + struct sockaddr_un addr = {.sun_family = AF_UNIX}; + strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1); + if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + PLOG(ERROR) << "Couldn't connect to recovery"; + return false; + } + // Switch to recovery will not update the boot reason since it does not + // require a reboot. + auto ret = write(sock, &msg_switch_to_recovery, sizeof(msg_switch_to_recovery)); + if (ret != sizeof(msg_switch_to_recovery)) { + PLOG(ERROR) << "Couldn't write message to switch to recovery"; + return false; + } + + return true; +} + +bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) { + auto status = true; + if (EnterRecovery()) { + status = device->WriteStatus(FastbootResult::OKAY, "Rebooting to recovery"); + } else { + status = device->WriteStatus(FastbootResult::FAIL, "Unable to reboot to recovery"); + } + device->CloseDevice(); + TEMP_FAILURE_RETRY(pause()); + return status; +} diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h new file mode 100644 index 000000000..cd984c854 --- /dev/null +++ b/fastboot/device/commands.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <functional> +#include <string> +#include <vector> + +class FastbootDevice; + +enum class FastbootResult { + OKAY, + FAIL, + INFO, + DATA, +}; + +// Execute a command with the given arguments (possibly empty). +using CommandHandler = std::function<bool(FastbootDevice*, const std::vector<std::string>&)>; + +bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args); +bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& args); +bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& args); +bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& args); +bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& args); +bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& args); +bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& args); diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp new file mode 100644 index 000000000..4c3d23f69 --- /dev/null +++ b/fastboot/device/fastboot_device.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fastboot_device.h" + +#include <android-base/logging.h> +#include <android-base/strings.h> + +#include <algorithm> + +#include "constants.h" +#include "usb_client.h" + +FastbootDevice::FastbootDevice() + : kCommandMap({ + {FB_CMD_SET_ACTIVE, SetActiveHandler}, + {FB_CMD_DOWNLOAD, DownloadHandler}, + {FB_CMD_SHUTDOWN, ShutDownHandler}, + {FB_CMD_REBOOT, RebootHandler}, + {FB_CMD_REBOOT_BOOTLOADER, RebootBootloaderHandler}, + {FB_CMD_REBOOT_FASTBOOT, RebootFastbootHandler}, + {FB_CMD_REBOOT_RECOVERY, RebootRecoveryHandler}, + }), + transport_(std::make_unique<ClientUsbTransport>()) {} + +FastbootDevice::~FastbootDevice() { + CloseDevice(); +} + +void FastbootDevice::CloseDevice() { + transport_->Close(); +} + +bool FastbootDevice::WriteStatus(FastbootResult result, const std::string& message) { + constexpr size_t kResponseReasonSize = 4; + constexpr size_t kNumResponseTypes = 4; // "FAIL", "OKAY", "INFO", "DATA" + char buf[FB_RESPONSE_SZ]; + constexpr size_t kMaxMessageSize = sizeof(buf) - kResponseReasonSize; + size_t msg_len = std::min(kMaxMessageSize, message.size()); + + constexpr const char* kResultStrings[kNumResponseTypes] = {RESPONSE_OKAY, RESPONSE_FAIL, + RESPONSE_INFO, RESPONSE_DATA}; + + if (static_cast<size_t>(result) >= kNumResponseTypes) { + return false; + } + + memcpy(buf, kResultStrings[static_cast<size_t>(result)], kResponseReasonSize); + memcpy(buf + kResponseReasonSize, message.c_str(), msg_len); + + size_t response_len = kResponseReasonSize + msg_len; + auto write_ret = this->get_transport()->Write(buf, response_len); + if (write_ret != static_cast<ssize_t>(response_len)) { + PLOG(ERROR) << "Failed to write " << message; + return false; + } + + return true; +} + +bool FastbootDevice::HandleData(bool read, std::vector<char>* data) { + auto read_write_data_size = read ? this->get_transport()->Read(data->data(), data->size()) + : this->get_transport()->Write(data->data(), data->size()); + if (read_write_data_size == -1 || static_cast<size_t>(read_write_data_size) != data->size()) { + return false; + } + return true; +} + +void FastbootDevice::ExecuteCommands() { + char command[FB_RESPONSE_SZ + 1]; + for (;;) { + auto bytes_read = transport_->Read(command, FB_RESPONSE_SZ); + if (bytes_read == -1) { + PLOG(ERROR) << "Couldn't read command"; + return; + } + command[bytes_read] = '\0'; + + LOG(INFO) << "Fastboot command: " << command; + auto args = android::base::Split(command, ":"); + auto found_command = kCommandMap.find(args[0]); + if (found_command == kCommandMap.end()) { + WriteStatus(FastbootResult::FAIL, "Unrecognized command"); + continue; + } + if (!found_command->second(this, args)) { + return; + } + } +} diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h new file mode 100644 index 000000000..fec42a747 --- /dev/null +++ b/fastboot/device/fastboot_device.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <memory> +#include <string> +#include <unordered_map> +#include <utility> +#include <vector> + +#include "commands.h" +#include "transport.h" + +class FastbootDevice; + +class FastbootDevice { + public: + FastbootDevice(); + ~FastbootDevice(); + + void CloseDevice(); + void ExecuteCommands(); + bool WriteStatus(FastbootResult result, const std::string& message); + bool HandleData(bool read, std::vector<char>* data); + + std::vector<char>& get_download_data() { return download_data_; } + void set_upload_data(const std::vector<char>& data) { upload_data_ = data; } + void set_upload_data(std::vector<char>&& data) { upload_data_ = std::move(data); } + Transport* get_transport() { return transport_.get(); } + + private: + const std::unordered_map<std::string, CommandHandler> kCommandMap; + + std::unique_ptr<Transport> transport_; + + std::vector<char> download_data_; + std::vector<char> upload_data_; +}; diff --git a/fastboot/device/main.cpp b/fastboot/device/main.cpp new file mode 100644 index 000000000..df9c9007d --- /dev/null +++ b/fastboot/device/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/logging.h> + +#include "fastboot_device.h" + +int main(int /*argc*/, char* argv[]) { + android::base::InitLogging(argv, &android::base::KernelLogger); + + while (true) { + FastbootDevice device; + device.ExecuteCommands(); + } +} diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp new file mode 100644 index 000000000..215f99a63 --- /dev/null +++ b/fastboot/device/usb_client.cpp @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "usb_client.h" + +#include <endian.h> +#include <fcntl.h> +#include <linux/usb/ch9.h> +#include <linux/usb/functionfs.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <android-base/logging.h> +#include <android-base/properties.h> + +constexpr int kMaxPacketSizeFs = 64; +constexpr int kMaxPacketSizeHs = 512; +constexpr int kMaxPacketsizeSs = 1024; + +constexpr size_t kFbFfsNumBufs = 16; +constexpr size_t kFbFfsBufSize = 32768; + +constexpr const char* kUsbFfsFastbootEp0 = "/dev/usb-ffs/fastboot/ep0"; +constexpr const char* kUsbFfsFastbootOut = "/dev/usb-ffs/fastboot/ep1"; +constexpr const char* kUsbFfsFastbootIn = "/dev/usb-ffs/fastboot/ep2"; + +struct FuncDesc { + struct usb_interface_descriptor intf; + struct usb_endpoint_descriptor_no_audio source; + struct usb_endpoint_descriptor_no_audio sink; +} __attribute__((packed)); + +struct SsFuncDesc { + struct usb_interface_descriptor intf; + struct usb_endpoint_descriptor_no_audio source; + struct usb_ss_ep_comp_descriptor source_comp; + struct usb_endpoint_descriptor_no_audio sink; + struct usb_ss_ep_comp_descriptor sink_comp; +} __attribute__((packed)); + +struct DescV2 { + struct usb_functionfs_descs_head_v2 header; + // The rest of the structure depends on the flags in the header. + __le32 fs_count; + __le32 hs_count; + __le32 ss_count; + struct FuncDesc fs_descs, hs_descs; + struct SsFuncDesc ss_descs; +} __attribute__((packed)); + +struct usb_interface_descriptor fastboot_interface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 66, + .bInterfaceProtocol = 3, + .iInterface = 1, /* first string from the provided table */ +}; + +static struct FuncDesc fs_descriptors = { + .intf = fastboot_interface, + .source = + { + .bLength = sizeof(fs_descriptors.source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = kMaxPacketSizeFs, + }, + .sink = + { + .bLength = sizeof(fs_descriptors.sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = kMaxPacketSizeFs, + }, +}; + +static struct FuncDesc hs_descriptors = { + .intf = fastboot_interface, + .source = + { + .bLength = sizeof(hs_descriptors.source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = kMaxPacketSizeHs, + }, + .sink = + { + .bLength = sizeof(hs_descriptors.sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = kMaxPacketSizeHs, + }, +}; + +static struct SsFuncDesc ss_descriptors = { + .intf = fastboot_interface, + .source = + { + .bLength = sizeof(ss_descriptors.source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = kMaxPacketsizeSs, + }, + .source_comp = + { + .bLength = sizeof(ss_descriptors.source_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 15, + }, + .sink = + { + .bLength = sizeof(ss_descriptors.sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = kMaxPacketsizeSs, + }, + .sink_comp = + { + .bLength = sizeof(ss_descriptors.sink_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 15, + }, +}; + +#define STR_INTERFACE_ "fastboot" + +static const struct { + struct usb_functionfs_strings_head header; + struct { + __le16 code; + const char str1[sizeof(STR_INTERFACE_)]; + } __attribute__((packed)) lang0; +} __attribute__((packed)) strings = { + .header = + { + .magic = htole32(FUNCTIONFS_STRINGS_MAGIC), + .length = htole32(sizeof(strings)), + .str_count = htole32(1), + .lang_count = htole32(1), + }, + .lang0 = + { + htole16(0x0409), /* en-us */ + STR_INTERFACE_, + }, +}; + +static struct DescV2 v2_descriptor = { + .header = + { + .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2), + .length = htole32(sizeof(v2_descriptor)), + .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC | + FUNCTIONFS_HAS_SS_DESC, + }, + .fs_count = 3, + .hs_count = 3, + .ss_count = 5, + .fs_descs = fs_descriptors, + .hs_descs = hs_descriptors, + .ss_descs = ss_descriptors, +}; + +// Reimplementing since usb_ffs_close() does not close the control FD. +static void CloseFunctionFs(usb_handle* h) { + if (h->bulk_in > 0) { + close(h->bulk_in); + h->bulk_in = -1; + } + if (h->bulk_out > 0) { + close(h->bulk_out); + h->bulk_out = -1; + } + if (h->control > 0) { + close(h->control); + h->control = -1; + } +} + +static bool InitFunctionFs(usb_handle* h) { + LOG(INFO) << "initializing functionfs"; + + if (h->control < 0) { // might have already done this before + LOG(INFO) << "opening control endpoint " << kUsbFfsFastbootEp0; + h->control = open(kUsbFfsFastbootEp0, O_RDWR); + if (h->control < 0) { + PLOG(ERROR) << "cannot open control endpoint " << kUsbFfsFastbootEp0; + goto err; + } + + auto ret = write(h->control, &v2_descriptor, sizeof(v2_descriptor)); + if (ret < 0) { + PLOG(ERROR) << "cannot write descriptors " << kUsbFfsFastbootEp0; + goto err; + } + + ret = write(h->control, &strings, sizeof(strings)); + if (ret < 0) { + PLOG(ERROR) << "cannot write strings " << kUsbFfsFastbootEp0; + goto err; + } + // Signal only when writing the descriptors to ffs + android::base::SetProperty("sys.usb.ffs.ready", "1"); + } + + h->bulk_out = open(kUsbFfsFastbootOut, O_RDONLY); + if (h->bulk_out < 0) { + PLOG(ERROR) << "cannot open bulk-out endpoint " << kUsbFfsFastbootOut; + goto err; + } + + h->bulk_in = open(kUsbFfsFastbootIn, O_WRONLY); + if (h->bulk_in < 0) { + PLOG(ERROR) << "cannot open bulk-in endpoint " << kUsbFfsFastbootIn; + goto err; + } + + h->read_aiob.fd = h->bulk_out; + h->write_aiob.fd = h->bulk_in; + h->reads_zero_packets = false; + return true; + +err: + CloseFunctionFs(h); + return false; +} + +ClientUsbTransport::ClientUsbTransport() + : handle_(std::unique_ptr<usb_handle>(create_usb_handle(kFbFfsNumBufs, kFbFfsBufSize))) { + if (!InitFunctionFs(handle_.get())) { + handle_.reset(nullptr); + } +} + +ssize_t ClientUsbTransport::Read(void* data, size_t len) { + if (handle_ == nullptr || len > SSIZE_MAX) { + return -1; + } + char* char_data = static_cast<char*>(data); + size_t bytes_read_total = 0; + while (bytes_read_total < len) { + auto bytes_to_read = std::min(len - bytes_read_total, kFbFfsNumBufs * kFbFfsBufSize); + auto bytes_read_now = handle_->read(handle_.get(), char_data, bytes_to_read); + if (bytes_read_now < 0) { + return bytes_read_total; + } + bytes_read_total += bytes_read_now; + char_data += bytes_read_now; + if (static_cast<size_t>(bytes_read_now) < bytes_to_read) { + break; + } + } + return bytes_read_total; +} + +ssize_t ClientUsbTransport::Write(const void* data, size_t len) { + if (handle_ == nullptr || len > SSIZE_MAX) { + return -1; + } + const char* char_data = reinterpret_cast<const char*>(data); + size_t bytes_written_total = 0; + while (bytes_written_total < len) { + auto bytes_to_write = std::min(len - bytes_written_total, kFbFfsNumBufs * kFbFfsBufSize); + auto bytes_written_now = handle_->write(handle_.get(), data, bytes_to_write); + if (bytes_written_now < 0) { + return bytes_written_total; + } + bytes_written_total += bytes_written_now; + char_data += bytes_written_now; + if (static_cast<size_t>(bytes_written_now) < bytes_to_write) { + break; + } + } + return bytes_written_total; +} + +int ClientUsbTransport::Close() { + if (handle_ == nullptr) { + return -1; + } + CloseFunctionFs(handle_.get()); + return 0; +} diff --git a/fastboot/device/usb_client.h b/fastboot/device/usb_client.h new file mode 100644 index 000000000..3694f9a20 --- /dev/null +++ b/fastboot/device/usb_client.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <memory> + +#include <adbd/usb.h> + +#include "transport.h" + +class ClientUsbTransport : public Transport { + public: + ClientUsbTransport(); + ~ClientUsbTransport() override = default; + + ssize_t Read(void* data, size_t len) override; + ssize_t Write(const void* data, size_t len) override; + int Close() override; + + private: + std::unique_ptr<usb_handle> handle_; + + DISALLOW_COPY_AND_ASSIGN(ClientUsbTransport); +}; diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 321e6bad7..fb06d19ee 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1333,6 +1333,8 @@ int FastBootTool::Main(int argc, char* argv[]) { bool wants_wipe = false; bool wants_reboot = false; bool wants_reboot_bootloader = false; + bool wants_reboot_recovery = false; + bool wants_reboot_fastboot = false; bool skip_reboot = false; bool wants_set_active = false; bool skip_secondary = false; @@ -1555,6 +1557,12 @@ int FastBootTool::Main(int argc, char* argv[]) { if (what == "bootloader") { wants_reboot = false; wants_reboot_bootloader = true; + } else if (what == "recovery") { + wants_reboot = false; + wants_reboot_recovery = true; + } else if (what == "fastboot") { + wants_reboot = false; + wants_reboot_fastboot = true; } else { syntax_error("unknown reboot target %s", what.c_str()); } @@ -1563,6 +1571,10 @@ int FastBootTool::Main(int argc, char* argv[]) { if (!args.empty()) syntax_error("junk after reboot command"); } else if (command == "reboot-bootloader") { wants_reboot_bootloader = true; + } else if (command == "reboot-recovery") { + wants_reboot_recovery = true; + } else if (command == "reboot-fastboot") { + wants_reboot_fastboot = true; } else if (command == "continue") { fb_queue_command("continue", "resuming boot"); } else if (command == "boot") { @@ -1680,6 +1692,12 @@ int FastBootTool::Main(int argc, char* argv[]) { } else if (wants_reboot_bootloader) { fb_queue_command("reboot-bootloader", "rebooting into bootloader"); fb_queue_wait_for_disconnect(); + } else if (wants_reboot_recovery) { + fb_queue_command("reboot-recovery", "rebooting into recovery"); + fb_queue_wait_for_disconnect(); + } else if (wants_reboot_fastboot) { + fb_queue_command("reboot-fastboot", "rebooting into fastboot"); + fb_queue_wait_for_disconnect(); } int status = fb_execute_queue() ? EXIT_FAILURE : EXIT_SUCCESS; |