Merge "Add fastbootd."

This commit is contained in:
Treehugger Robot 2018-08-07 00:08:18 +00:00 committed by Gerrit Code Review
commit c30a75a007
10 changed files with 779 additions and 0 deletions

View file

@ -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",
}

View file

@ -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"

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}
}
}

View file

@ -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_;
};

28
fastboot/device/main.cpp Normal file
View file

@ -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();
}
}

View file

@ -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;
}

View file

@ -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);
};

View file

@ -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;