blob: 2893b20281282915a827b3d81866955ebb5b67c3 [file] [log] [blame]
// 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 "fake-paver.h"
#include <lib/fzl/vmo-mapper.h>
namespace paver_test {
zx_status_t FakePaver::Connect(async_dispatcher_t* dispatcher,
fidl::ServerEnd<fuchsia_paver::Paver> request) {
dispatcher_ = dispatcher;
return fidl::BindSingleInFlightOnly<fidl::WireServer<fuchsia_paver::Paver>>(
dispatcher, std::move(request), this);
}
void FakePaver::FindDataSink(FindDataSinkRequestView request,
FindDataSinkCompleter::Sync& _completer) {
fidl::BindSingleInFlightOnly<fidl::WireServer<fuchsia_paver::DynamicDataSink>>(
dispatcher_,
fidl::ServerEnd<fuchsia_paver::DynamicDataSink>(request->data_sink.TakeChannel()), this);
}
void FakePaver::UseBlockDevice(UseBlockDeviceRequestView request,
UseBlockDeviceCompleter::Sync& _completer) {
auto result = fidl::WireCall(fidl::UnownedClientEnd<fuchsia_device::Controller>(
request->block_device.borrow().channel()))
->GetTopologicalPath();
if (!result.ok() || result->is_error()) {
return;
}
const auto& path = result->value()->path;
{
fbl::AutoLock al(&lock_);
if (std::string(path.data(), path.size()) != expected_block_device_) {
return;
}
}
fidl::BindSingleInFlightOnly<fidl::WireServer<fuchsia_paver::DynamicDataSink>>(
dispatcher_, std::move(request->data_sink), this);
}
void FakePaver::FindBootManager(FindBootManagerRequestView request,
FindBootManagerCompleter::Sync& _completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kInitializeAbr);
if (abr_supported_) {
fidl::BindSingleInFlightOnly<fidl::WireServer<fuchsia_paver::BootManager>>(
dispatcher_, std::move(request->boot_manager), this);
}
}
void FakePaver::QueryCurrentConfiguration(QueryCurrentConfigurationRequestView request,
QueryCurrentConfigurationCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kQueryCurrentConfiguration);
completer.ReplySuccess(fuchsia_paver::wire::Configuration::kA);
}
void FakePaver::FindSysconfig(FindSysconfigRequestView request,
FindSysconfigCompleter::Sync& _completer) {}
void FakePaver::QueryActiveConfiguration(QueryActiveConfigurationRequestView request,
QueryActiveConfigurationCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kQueryActiveConfiguration);
completer.ReplySuccess(fuchsia_paver::wire::Configuration::kA);
}
void FakePaver::QueryConfigurationLastSetActive(
QueryConfigurationLastSetActiveRequestView request,
QueryConfigurationLastSetActiveCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kQueryConfigurationLastSetActive);
completer.ReplySuccess(fuchsia_paver::wire::Configuration::kA);
}
void FakePaver::QueryConfigurationStatus(QueryConfigurationStatusRequestView request,
QueryConfigurationStatusCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kQueryConfigurationStatus);
completer.ReplySuccess(fuchsia_paver::wire::ConfigurationStatus::kHealthy);
}
void FakePaver::SetConfigurationActive(SetConfigurationActiveRequestView request,
SetConfigurationActiveCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kSetConfigurationActive);
zx_status_t status;
switch (request->configuration) {
case fuchsia_paver::wire::Configuration::kA:
abr_data_.slot_a.active = true;
abr_data_.slot_a.unbootable = false;
status = ZX_OK;
break;
case fuchsia_paver::wire::Configuration::kB:
abr_data_.slot_b.active = true;
abr_data_.slot_b.unbootable = false;
status = ZX_OK;
break;
case fuchsia_paver::wire::Configuration::kRecovery:
status = ZX_ERR_INVALID_ARGS;
break;
}
completer.Reply(status);
}
void FakePaver::SetConfigurationUnbootable(SetConfigurationUnbootableRequestView request,
SetConfigurationUnbootableCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kSetConfigurationUnbootable);
zx_status_t status;
switch (request->configuration) {
case fuchsia_paver::wire::Configuration::kA:
abr_data_.slot_a.unbootable = true;
status = ZX_OK;
break;
case fuchsia_paver::wire::Configuration::kB:
abr_data_.slot_b.unbootable = true;
status = ZX_OK;
break;
case fuchsia_paver::wire::Configuration::kRecovery:
status = ZX_ERR_INVALID_ARGS;
break;
}
completer.Reply(status);
}
void FakePaver::SetConfigurationHealthy(SetConfigurationHealthyRequestView request,
SetConfigurationHealthyCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kSetConfigurationHealthy);
completer.Reply(ZX_OK);
}
void FakePaver::Flush(
fidl::WireServer<fuchsia_paver::DynamicDataSink>::FlushRequestView request,
fidl::WireServer<fuchsia_paver::DynamicDataSink>::FlushCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kDataSinkFlush);
completer.Reply(ZX_OK);
}
void FakePaver::Flush(
fidl::WireServer<fuchsia_paver::BootManager>::FlushRequestView request,
fidl::WireServer<fuchsia_paver::BootManager>::FlushCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kBootManagerFlush);
completer.Reply(ZX_OK);
}
void FakePaver::ReadAsset(ReadAssetRequestView request, ReadAssetCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kReadAsset);
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void FakePaver::WriteAsset(WriteAssetRequestView request, WriteAssetCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kWriteAsset);
auto status = request->payload.size == expected_payload_size_ ? ZX_OK : ZX_ERR_INVALID_ARGS;
last_asset_ = request->asset;
last_asset_config_ = request->configuration;
completer.Reply(status);
}
void FakePaver::WriteOpaqueVolume(WriteOpaqueVolumeRequestView request,
WriteOpaqueVolumeCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
if (request->payload.size == expected_payload_size_) {
completer.ReplySuccess();
} else {
completer.ReplyError(ZX_ERR_INVALID_ARGS);
}
}
void FakePaver::WriteFirmware(WriteFirmwareRequestView request,
WriteFirmwareCompleter::Sync& completer) {
using fuchsia_paver::wire::WriteFirmwareResult;
fbl::AutoLock al(&lock_);
AppendCommand(Command::kWriteFirmware);
last_firmware_type_ = std::string(request->type.data(), request->type.size());
last_firmware_config_ = request->configuration;
// Reply varies depending on whether we support |type| or not.
if (supported_firmware_type_ == std::string_view(request->type.data(), request->type.size())) {
auto status = request->payload.size == expected_payload_size_ ? ZX_OK : ZX_ERR_INVALID_ARGS;
completer.Reply(WriteFirmwareResult::WithStatus(status));
} else {
completer.Reply(WriteFirmwareResult::WithUnsupported(true));
}
}
void FakePaver::ReadFirmware(ReadFirmwareRequestView request,
ReadFirmwareCompleter::Sync& completer) {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void FakePaver::WriteVolumes(WriteVolumesRequestView request,
WriteVolumesCompleter::Sync& completer) {
{
fbl::AutoLock al(&lock_);
AppendCommand(Command::kWriteVolumes);
}
// Register VMO.
zx::vmo vmo;
auto status = zx::vmo::create(1024, 0, &vmo);
if (status != ZX_OK) {
completer.Reply(status);
return;
}
fidl::WireSyncClient stream = fidl::BindSyncClient(std::move(request->payload));
auto result = stream->RegisterVmo(std::move(vmo));
status = result.ok() ? result.value().status : result.status();
if (status != ZX_OK) {
completer.Reply(status);
return;
}
// Stream until EOF.
status = [&]() {
size_t data_transferred = 0;
for (;;) {
{
fbl::AutoLock al(&lock_);
if (wait_for_start_signal_) {
al.release();
sync_completion_wait(&start_signal_, ZX_TIME_INFINITE);
sync_completion_reset(&start_signal_);
} else {
signal_size_ = expected_payload_size_ + 1;
}
}
while (data_transferred < signal_size_) {
auto result = stream->ReadData();
if (!result.ok()) {
return result.status();
}
const auto& response = result.value();
switch (response.result.Which()) {
case fuchsia_paver::wire::ReadResult::Tag::kErr:
return response.result.err();
case fuchsia_paver::wire::ReadResult::Tag::kEof:
return data_transferred == expected_payload_size_ ? ZX_OK : ZX_ERR_INVALID_ARGS;
case fuchsia_paver::wire::ReadResult::Tag::kInfo:
data_transferred += response.result.info().size;
continue;
default:
return ZX_ERR_INTERNAL;
}
}
sync_completion_signal(&done_signal_);
}
}();
sync_completion_signal(&done_signal_);
completer.Reply(status);
}
void FakePaver::WriteBootloader(WriteBootloaderRequestView request,
WriteBootloaderCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kWriteBootloader);
auto status = request->payload.size == expected_payload_size_ ? ZX_OK : ZX_ERR_INVALID_ARGS;
completer.Reply(status);
}
void FakePaver::WriteDataFile(WriteDataFileRequestView request,
WriteDataFileCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kWriteDataFile);
data_file_path_ = std::string(request->filename.data(), request->filename.size());
auto status = request->payload.size == expected_payload_size_ ? ZX_OK : ZX_ERR_INVALID_ARGS;
completer.Reply(status);
}
void FakePaver::WipeVolume(WipeVolumeRequestView request, WipeVolumeCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kWipeVolume);
completer.ReplySuccess({});
}
void FakePaver::InitializePartitionTables(InitializePartitionTablesRequestView request,
InitializePartitionTablesCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kInitPartitionTables);
completer.Reply(ZX_OK);
}
void FakePaver::WipePartitionTables(WipePartitionTablesRequestView request,
WipePartitionTablesCompleter::Sync& completer) {
fbl::AutoLock al(&lock_);
AppendCommand(Command::kWipePartitionTables);
completer.Reply(ZX_OK);
}
void FakePaver::WaitForWritten(size_t size) {
signal_size_ = size;
sync_completion_signal(&start_signal_);
sync_completion_wait(&done_signal_, ZX_TIME_INFINITE);
sync_completion_reset(&done_signal_);
}
const std::vector<Command> FakePaver::GetCommandTrace() {
fbl::AutoLock al(&lock_);
return command_trace_;
}
std::string FakePaver::last_firmware_type() const {
fbl::AutoLock al(&lock_);
return last_firmware_type_;
}
fuchsia_paver::wire::Configuration FakePaver::last_firmware_config() const {
fbl::AutoLock al(&lock_);
return last_firmware_config_;
}
fuchsia_paver::wire::Configuration FakePaver::last_asset_config() const {
fbl::AutoLock al(&lock_);
return last_asset_config_;
}
fuchsia_paver::wire::Asset FakePaver::last_asset() const {
fbl::AutoLock al(&lock_);
return last_asset_;
}
const std::string& FakePaver::data_file_path() const {
fbl::AutoLock al(&lock_);
return data_file_path_;
}
void FakePaver::set_supported_firmware_type(std::string type) {
fbl::AutoLock al(&lock_);
supported_firmware_type_ = type;
}
void FakePaver::set_expected_device(std::string expected) {
fbl::AutoLock al(&lock_);
expected_block_device_ = expected;
}
const AbrData FakePaver::abr_data() {
fbl::AutoLock al(&lock_);
return abr_data_;
}
} // namespace paver_test