| // 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 |