blob: d3fe4b39f9723707df09f9cb178d0f624fd55ec2 [file] [log] [blame] [edit]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fidl/fuchsia.hardware.fastboot/cpp/wire.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/component/incoming/cpp/service_member_watcher.h>
#include <lib/fastboot/fastboot.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/syscalls.h>
namespace {
class UsbPacketTransport : public fastboot::Transport {
public:
UsbPacketTransport(fidl::WireSyncClient<fuchsia_hardware_fastboot::FastbootImpl> &device,
std::string_view packet)
: device_(&device), packet_(packet) {}
zx::result<size_t> ReceivePacket(void *dst, size_t capacity) override {
if (capacity < PeekPacketSize()) {
return zx::error(ZX_ERR_BUFFER_TOO_SMALL);
}
memcpy(dst, packet_.data(), packet_.size());
return zx::ok(packet_.size());
}
size_t PeekPacketSize() override { return packet_.size(); }
zx::result<> Send(std::string_view packet) override {
fzl::OwnedVmoMapper mapper;
zx_status_t status = mapper.CreateAndMap(packet.size(), "fastboot usb send");
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Failed to create vmo mapper for sending " << zx_status_get_string(status);
return zx::error(status);
}
memcpy(mapper.start(), packet.data(), packet.size());
if (zx_status_t status = mapper.vmo().set_prop_content_size(packet.size()); status != ZX_OK) {
FX_LOGS(ERROR) << "Failed to set content size " << zx_status_get_string(status);
return zx::error(status);
}
auto res = (*device_)->Send(mapper.Release());
if (res->is_error()) {
return res->take_error();
}
return zx::ok();
}
private:
fidl::WireSyncClient<fuchsia_hardware_fastboot::FastbootImpl> *device_ = nullptr;
std::string_view packet_;
};
} // namespace
int main(int argc, const char **argv) {
FX_LOGS(INFO) << "Starting fastboot usb";
auto connect_device =
component::SyncServiceMemberWatcher<fuchsia_hardware_fastboot::Service::Fastboot>()
.GetNextInstance(false);
if (connect_device.is_error()) {
FX_LOGS(ERROR) << "Failed to connect to usb fastboot device" << connect_device.status_string();
return 1;
}
fidl::WireSyncClient<fuchsia_hardware_fastboot::FastbootImpl> device(
std::move(connect_device.value()));
fastboot::Fastboot fastboot;
while (true) {
// Note: fastboot.remaining_download_size() returns 0 in command stage.
size_t request_size =
std::min(fastboot.remaining_download_size(), static_cast<size_t>(512 * 1024));
auto packet_res = device->Receive(request_size);
if (packet_res->is_error()) {
FX_LOGS(ERROR) << "Failed while receiving packet " << packet_res.status_string();
continue;
}
fzl::VmoMapper mapper;
zx_status_t status = mapper.Map(packet_res.value()->data);
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Failed to map packet vmo" << zx_status_get_string(status);
continue;
}
size_t packet_size = 0;
if (zx_status_t status = packet_res.value()->data.get_prop_content_size(&packet_size);
status != ZX_OK) {
FX_LOGS(ERROR) << "Failed to get content size " << zx_status_get_string(status);
continue;
}
UsbPacketTransport transport(
device, std::string_view{reinterpret_cast<const char *>(mapper.start()), packet_size});
auto fastboot_res = fastboot.ProcessPacket(&transport);
if (fastboot_res.is_error()) {
FX_LOGS(ERROR) << "Failed to process fastboot packet " << fastboot_res.status_string();
}
}
return 0;
}