Merge "Add fastbootd."
This commit is contained in:
commit
c30a75a007
10 changed files with 779 additions and 0 deletions
|
|
@ -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",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
126
fastboot/device/commands.cpp
Normal file
126
fastboot/device/commands.cpp
Normal 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;
|
||||
}
|
||||
40
fastboot/device/commands.h
Normal file
40
fastboot/device/commands.h
Normal 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);
|
||||
104
fastboot/device/fastboot_device.cpp
Normal file
104
fastboot/device/fastboot_device.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
52
fastboot/device/fastboot_device.h
Normal file
52
fastboot/device/fastboot_device.h
Normal 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
28
fastboot/device/main.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
307
fastboot/device/usb_client.cpp
Normal file
307
fastboot/device/usb_client.cpp
Normal 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;
|
||||
}
|
||||
37
fastboot/device/usb_client.h
Normal file
37
fastboot/device/usb_client.h
Normal 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);
|
||||
};
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue