blob: 68c98596193119c3ae9a53d7186bf337b6fe8898 [file] [log] [blame]
// 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.driver.framework/cpp/driver/fidl.h>
#include <fidl/fuchsia.driverhost.test/cpp/wire.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/component/outgoing/cpp/outgoing_directory.h>
#include <lib/driver/component/cpp/internal/start_args.h>
#include <lib/driver/component/cpp/internal/symbols.h>
#include <lib/driver/symbols/symbols.h>
#include <lib/fdio/directory.h>
#include <lib/fidl/epitaph.h>
namespace fdf {
using namespace fuchsia_driver_framework;
} // namespace fdf
namespace ftest = fuchsia_driverhost_test;
class TestDriver : public fdf::Server<fuchsia_driver_framework::Driver> {
public:
explicit TestDriver(fdf_dispatcher_t* dispatcher, fdf_handle_t server_handle)
: dispatcher_(dispatcher), outgoing_(fdf_dispatcher_get_async_dispatcher(dispatcher)) {
driver_binding_.emplace(
dispatcher, fdf::ServerEnd<fuchsia_driver_framework::Driver>(fdf::Channel(server_handle)),
this, fidl::kIgnoreBindingClosure);
}
void Start(StartRequest& request, StartCompleter::Sync& completer) override {
auto& start_args = request.start_args();
auto error = fdf_internal::SymbolValue<zx_status_t*>(start_args.symbols(), "error");
if (error.is_ok()) {
completer.Reply(zx::error(**error));
return;
}
// Call the "func" driver symbol.
auto func = fdf_internal::SymbolValue<void (*)()>(start_args.symbols(), "func");
if (func.is_ok()) {
(*func)();
}
// Set the "dispatcher" driver symbol.
auto dispatcher =
fdf_internal::SymbolValue<fdf_dispatcher_t**>(start_args.symbols(), "dispatcher");
if (dispatcher.is_ok()) {
**dispatcher = dispatcher_;
}
// Connect to the incoming service.
auto svc_dir = fdf_internal::NsValue(start_args.incoming().value(), "/svc");
if (svc_dir.is_error()) {
completer.Reply(svc_dir.take_error());
return;
}
auto client_end = component::ConnectAt<ftest::Incoming>(svc_dir.value());
if (!client_end.is_ok()) {
completer.Reply(client_end.take_error());
return;
}
// Setup the outgoing service.
auto status = outgoing_.AddUnmanagedProtocol<ftest::Outgoing>(
[](fidl::ServerEnd<ftest::Outgoing> request) {
fidl_epitaph_write(request.channel().get(), ZX_ERR_STOP);
});
if (status.is_error()) {
completer.Reply(status);
return;
}
completer.Reply(outgoing_.Serve(std::move(start_args.outgoing_dir().value())));
}
void Stop(StopCompleter::Sync& completer) override { driver_binding_.reset(); }
void handle_unknown_method(fidl::UnknownMethodMetadata<fuchsia_driver_framework::Driver> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override {}
private:
fdf_dispatcher_t* dispatcher_;
component::OutgoingDirectory outgoing_;
std::optional<fdf::ServerBinding<fuchsia_driver_framework::Driver>> driver_binding_;
};
void* init(fdf_handle_t server_handle) {
fdf_dispatcher_t* dispatcher = fdf_dispatcher_get_current_dispatcher();
auto test_driver = std::make_unique<TestDriver>(dispatcher, server_handle);
return test_driver.release();
}
void destroy(void* token) {
if (token != nullptr) {
delete static_cast<TestDriver*>(token);
}
}
EXPORT_FUCHSIA_DRIVER_REGISTRATION_V1(.initialize = init, .destroy = destroy);