| // Copyright 2020 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.driverhost.test/cpp/wire.h> |
| #include <lib/driver2/record.h> |
| #include <lib/driver2/start_args.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/fidl/epitaph.h> |
| #include <lib/service/llcpp/service.h> |
| #include <lib/sys/component/llcpp/outgoing_directory.h> |
| |
| namespace fdf = fuchsia_driver_framework; |
| namespace ftest = fuchsia_driverhost_test; |
| |
| class TestDriver { |
| public: |
| explicit TestDriver(fdf_dispatcher_t* dispatcher) |
| : dispatcher_(dispatcher), |
| outgoing_( |
| component::OutgoingDirectory::Create(fdf_dispatcher_get_async_dispatcher(dispatcher))) { |
| } |
| |
| zx::status<> Init(fdf::wire::DriverStartArgs* start_args) { |
| auto error = driver::SymbolValue<zx_status_t*>(*start_args, "error"); |
| if (error.is_ok()) { |
| return zx::error(**error); |
| } |
| |
| // Call the "func" driver symbol. |
| auto func = driver::SymbolValue<void (*)()>(*start_args, "func"); |
| if (func.is_ok()) { |
| (*func)(); |
| } |
| |
| // Set the "dispatcher" driver symbol. |
| auto dispatcher = driver::SymbolValue<fdf_dispatcher_t**>(*start_args, "dispatcher"); |
| if (dispatcher.is_ok()) { |
| **dispatcher = dispatcher_; |
| } |
| |
| // Connect to the incoming service. |
| auto svc_dir = driver::NsValue(start_args->ns(), "/svc"); |
| if (svc_dir.is_error()) { |
| return svc_dir.take_error(); |
| } |
| auto client_end = service::ConnectAt<ftest::Incoming>(svc_dir.value()); |
| if (!client_end.is_ok()) { |
| return client_end.take_error(); |
| } |
| |
| // Setup the outgoing service. |
| auto status = |
| outgoing_.AddProtocol<ftest::Outgoing>([](fidl::ServerEnd<ftest::Outgoing> request) { |
| fidl_epitaph_write(request.channel().get(), ZX_ERR_STOP); |
| }); |
| if (status.is_error()) { |
| return status; |
| } |
| |
| return outgoing_.Serve(std::move(start_args->outgoing_dir())); |
| } |
| |
| private: |
| fdf_dispatcher_t* dispatcher_; |
| component::OutgoingDirectory outgoing_; |
| }; |
| |
| zx_status_t test_driver_start(EncodedDriverStartArgs encoded_start_args, |
| fdf_dispatcher_t* dispatcher, void** driver) { |
| // TODO(fxbug.dev/45252): Use FIDL at rest. |
| auto wire_format_metadata = |
| fidl::WireFormatMetadata::FromOpaque(encoded_start_args.wire_format_metadata); |
| fidl::unstable::DecodedMessage<fdf::wire::DriverStartArgs> decoded( |
| wire_format_metadata.wire_format_version(), encoded_start_args.msg); |
| if (!decoded.ok()) { |
| return decoded.status(); |
| } |
| |
| auto test_driver = std::make_unique<TestDriver>(dispatcher); |
| auto init = test_driver->Init(decoded.PrimaryObject()); |
| if (init.is_error()) { |
| return init.error_value(); |
| } |
| |
| *driver = test_driver.release(); |
| return ZX_OK; |
| } |
| |
| zx_status_t test_driver_stop(void* driver) { |
| delete static_cast<TestDriver*>(driver); |
| return ZX_OK; |
| } |
| |
| FUCHSIA_DRIVER_RECORD_V1(.start = test_driver_start, .stop = test_driver_stop); |