| // Copyright 2018 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. |
| |
| #ifndef SRC_STORAGE_LIB_PAVER_PAVER_H_ |
| #define SRC_STORAGE_LIB_PAVER_PAVER_H_ |
| |
| #include <fidl/fuchsia.paver/cpp/wire.h> |
| #include <lib/zx/channel.h> |
| #include <zircon/types.h> |
| |
| #include <variant> |
| |
| #include <fbl/mutex.h> |
| #include <fbl/string.h> |
| #include <fbl/unique_fd.h> |
| |
| #include "abr-client.h" |
| #include "device-partitioner.h" |
| #include "lib/async/dispatcher.h" |
| #include "paver-context.h" |
| |
| namespace paver { |
| |
| class Paver : public fidl::WireServer<fuchsia_paver::Paver> { |
| public: |
| void FindDataSink(FindDataSinkRequestView request, |
| FindDataSinkCompleter::Sync& completer) override; |
| |
| void UseBlockDevice(UseBlockDeviceRequestView request, |
| UseBlockDeviceCompleter::Sync& completer) override; |
| |
| void UseBlockDevice(zx::channel block_device, zx::channel dynamic_data_sink); |
| |
| void FindBootManager(FindBootManagerRequestView request, |
| FindBootManagerCompleter::Sync& completer) override; |
| |
| void FindSysconfig(FindSysconfigRequestView request, |
| FindSysconfigCompleter::Sync& completer) override; |
| |
| void FindSysconfig(zx::channel sysconfig); |
| |
| void set_dispatcher(async_dispatcher_t* dispatcher) { dispatcher_ = dispatcher; } |
| void set_devfs_root(fbl::unique_fd devfs_root) { devfs_root_ = std::move(devfs_root); } |
| void set_svc_root(fidl::ClientEnd<fuchsia_io::Directory> svc_root) { |
| svc_root_ = std::move(svc_root); |
| } |
| |
| Paver() : context_(std::make_shared<Context>()) {} |
| |
| private: |
| // Used for test injection. |
| fbl::unique_fd devfs_root_; |
| fidl::ClientEnd<fuchsia_io::Directory> svc_root_; |
| |
| async_dispatcher_t* dispatcher_ = nullptr; |
| |
| // Declared as shared_ptr to avoid life time issues (i.e. Paver exiting before the created device |
| // partitioners). |
| std::shared_ptr<Context> context_; |
| }; |
| |
| // Common shared implementation for DataSink and DynamicDataSink. Necessary to work around lack of |
| // "is-a" relationship in llcpp bindings. |
| class DataSinkImpl { |
| public: |
| DataSinkImpl(fbl::unique_fd devfs_root, std::unique_ptr<DevicePartitioner> partitioner) |
| : devfs_root_(std::move(devfs_root)), partitioner_(std::move(partitioner)) {} |
| |
| zx::status<fuchsia_mem::wire::Buffer> ReadAsset(fuchsia_paver::wire::Configuration configuration, |
| fuchsia_paver::wire::Asset asset); |
| |
| zx::status<> WriteAsset(fuchsia_paver::wire::Configuration configuration, |
| fuchsia_paver::wire::Asset asset, fuchsia_mem::wire::Buffer payload); |
| |
| // FIDL llcpp unions don't currently support memory ownership so we need to |
| // return something that does own the underlying memory. |
| // |
| // Once unions do support owned memory we can just return |
| // WriteBootloaderResult directly here. |
| std::variant<zx_status_t, bool> WriteFirmware(fuchsia_paver::wire::Configuration configuration, |
| fidl::StringView type, |
| fuchsia_mem::wire::Buffer payload); |
| |
| zx::status<> WriteVolumes(zx::channel payload_stream); |
| |
| zx::status<> WriteBootloader(fuchsia_mem::wire::Buffer payload); |
| |
| zx::status<> WriteDataFile(fidl::StringView filename, fuchsia_mem::wire::Buffer payload); |
| |
| zx::status<zx::channel> WipeVolume(); |
| |
| DevicePartitioner* partitioner() { return partitioner_.get(); } |
| |
| private: |
| // Used for test injection. |
| fbl::unique_fd devfs_root_; |
| |
| std::unique_ptr<DevicePartitioner> partitioner_; |
| }; |
| |
| class DataSink : public fidl::WireServer<fuchsia_paver::DataSink> { |
| public: |
| DataSink(fbl::unique_fd devfs_root, std::unique_ptr<DevicePartitioner> partitioner) |
| : sink_(std::move(devfs_root), std::move(partitioner)) {} |
| |
| // Automatically finds block device to use. |
| static void Bind(async_dispatcher_t* dispatcher, fbl::unique_fd devfs_root, |
| fidl::ClientEnd<fuchsia_io::Directory> svc_root, zx::channel server, |
| std::shared_ptr<Context> context); |
| |
| void ReadAsset(ReadAssetRequestView request, ReadAssetCompleter::Sync& completer) override; |
| |
| void WriteAsset(WriteAssetRequestView request, WriteAssetCompleter::Sync& completer) override { |
| completer.Reply( |
| sink_.WriteAsset(request->configuration, request->asset, std::move(request->payload)) |
| .status_value()); |
| } |
| |
| void WriteFirmware(WriteFirmwareRequestView request, |
| WriteFirmwareCompleter::Sync& completer) override; |
| |
| void WriteVolumes(WriteVolumesRequestView request, |
| WriteVolumesCompleter::Sync& completer) override { |
| completer.Reply(sink_.WriteVolumes(request->payload.TakeChannel()).status_value()); |
| } |
| |
| void WriteBootloader(WriteBootloaderRequestView request, |
| WriteBootloaderCompleter::Sync& completer) override { |
| completer.Reply(sink_.WriteBootloader(std::move(request->payload)).status_value()); |
| } |
| |
| void WriteDataFile(WriteDataFileRequestView request, |
| WriteDataFileCompleter::Sync& completer) override { |
| completer.Reply( |
| sink_.WriteDataFile(request->filename, std::move(request->payload)).status_value()); |
| } |
| |
| void WipeVolume(WipeVolumeRequestView request, WipeVolumeCompleter::Sync& completer) override; |
| |
| void Flush(FlushRequestView request, FlushCompleter::Sync& completer) override { |
| completer.Reply(sink_.partitioner()->Flush().status_value()); |
| } |
| |
| private: |
| DataSinkImpl sink_; |
| }; |
| |
| class DynamicDataSink : public fidl::WireServer<fuchsia_paver::DynamicDataSink> { |
| public: |
| DynamicDataSink(fbl::unique_fd devfs_root, std::unique_ptr<DevicePartitioner> partitioner) |
| : sink_(std::move(devfs_root), std::move(partitioner)) {} |
| |
| static void Bind(async_dispatcher_t* dispatcher, fbl::unique_fd devfs_root, |
| fidl::ClientEnd<fuchsia_io::Directory> svc_root, zx::channel block_device, |
| zx::channel server, std::shared_ptr<Context> context); |
| |
| void InitializePartitionTables(InitializePartitionTablesRequestView request, |
| InitializePartitionTablesCompleter::Sync& completer) override; |
| |
| void WipePartitionTables(WipePartitionTablesRequestView request, |
| WipePartitionTablesCompleter::Sync& completer) override; |
| |
| void ReadAsset(ReadAssetRequestView request, ReadAssetCompleter::Sync& completer) override; |
| |
| void WriteAsset(WriteAssetRequestView request, WriteAssetCompleter::Sync& completer) override { |
| completer.Reply( |
| sink_.WriteAsset(request->configuration, request->asset, std::move(request->payload)) |
| .status_value()); |
| } |
| |
| void WriteFirmware(WriteFirmwareRequestView request, |
| WriteFirmwareCompleter::Sync& completer) override; |
| |
| void WriteVolumes(WriteVolumesRequestView request, |
| WriteVolumesCompleter::Sync& completer) override { |
| completer.Reply(sink_.WriteVolumes(request->payload.TakeChannel()).status_value()); |
| } |
| |
| void WriteBootloader(WriteBootloaderRequestView request, |
| WriteBootloaderCompleter::Sync& completer) override { |
| completer.Reply(sink_.WriteBootloader(std::move(request->payload)).status_value()); |
| } |
| |
| void WriteDataFile(WriteDataFileRequestView request, |
| WriteDataFileCompleter::Sync& completer) override { |
| completer.Reply( |
| sink_.WriteDataFile(request->filename, std::move(request->payload)).status_value()); |
| } |
| |
| void WipeVolume(WipeVolumeRequestView request, WipeVolumeCompleter::Sync& completer) override; |
| |
| void Flush(FlushRequestView request, FlushCompleter::Sync& completer) override { |
| completer.Reply(sink_.partitioner()->Flush().status_value()); |
| } |
| |
| private: |
| DataSinkImpl sink_; |
| }; |
| |
| class BootManager : public fidl::WireServer<fuchsia_paver::BootManager> { |
| public: |
| BootManager(std::unique_ptr<abr::Client> abr_client, fbl::unique_fd devfs_root, |
| fidl::ClientEnd<fuchsia_io::Directory> svc_root) |
| : abr_client_(std::move(abr_client)), |
| devfs_root_(std::move(devfs_root)), |
| svc_root_(std::move(svc_root)) {} |
| |
| static void Bind(async_dispatcher_t* dispatcher, fbl::unique_fd devfs_root, |
| fidl::ClientEnd<fuchsia_io::Directory> svc_root, |
| std::shared_ptr<Context> context, zx::channel server); |
| |
| void QueryCurrentConfiguration(QueryCurrentConfigurationRequestView request, |
| QueryCurrentConfigurationCompleter::Sync& completer) override; |
| |
| void QueryActiveConfiguration(QueryActiveConfigurationRequestView request, |
| QueryActiveConfigurationCompleter::Sync& completer) override; |
| |
| void QueryConfigurationLastSetActive( |
| QueryConfigurationLastSetActiveRequestView request, |
| QueryConfigurationLastSetActiveCompleter::Sync& completer) override; |
| |
| void QueryConfigurationStatus(QueryConfigurationStatusRequestView request, |
| QueryConfigurationStatusCompleter::Sync& completer) override; |
| |
| void SetConfigurationActive(SetConfigurationActiveRequestView request, |
| SetConfigurationActiveCompleter::Sync& completer) override; |
| |
| void SetConfigurationUnbootable(SetConfigurationUnbootableRequestView request, |
| SetConfigurationUnbootableCompleter::Sync& completer) override; |
| |
| void SetConfigurationHealthy(SetConfigurationHealthyRequestView request, |
| SetConfigurationHealthyCompleter::Sync& completer) override; |
| |
| void Flush(FlushRequestView request, FlushCompleter::Sync& completer) override { |
| completer.Reply(abr_client_->Flush().status_value()); |
| } |
| |
| private: |
| std::unique_ptr<abr::Client> abr_client_; |
| fbl::unique_fd devfs_root_; |
| fidl::ClientEnd<fuchsia_io::Directory> svc_root_; |
| }; |
| |
| } // namespace paver |
| |
| #endif // SRC_STORAGE_LIB_PAVER_PAVER_H_ |