本指南介绍了如何从父驱动程序导出 FIDL 服务,并在子驱动程序中使用该服务。本指南假定您熟悉以下概念:
如需查看 Fuchsia 源代码树中的完整工作示例,请参阅 Zircon 传输示例。
FIDL 协议定义
以下代码段使用了此 FIDL 定义:
library fidl.examples.echo;
const MAX_STRING_LENGTH uint64 = 32;
@discoverable
closed protocol Echo {
/// Returns the input.
strict EchoString(struct {
value string:<MAX_STRING_LENGTH, optional>;
}) -> (struct {
response string:<MAX_STRING_LENGTH, optional>;
});
};
service EchoService {
echo client_end:Echo;
};
父驱动程序(服务器)
父驱动程序实现了 fidl.examples.echo/Echo 协议,在其传出目录中提供 fidl.examples.echo.EchoService,并在添加子节点时提供该服务。
驱动程序清单
在父驱动程序的清单 (.dml) 中,声明并公开 FIDL 服务功能:
capabilities: [
{ service: "fidl.examples.echo.EchoService" },
],
expose: [
{
service: "fidl.examples.echo.EchoService",
from: "self",
},
],
服务器代码
#include <fidl/fidl.examples.echo/cpp/wire.h>
#include <lib/driver/component/cpp/driver_base2.h>
#include <lib/driver/component/cpp/driver_export2.h>
#include <lib/driver/component/cpp/node_add_args.h>
#include <lib/driver/logging/cpp/logger.h>
// This class implements the fidl.examples.echo/Echo FIDL protocol using the
// C++ Wire bindings.
class ParentDriver : public fdf::DriverBase2,
public fidl::WireServer<fidl_examples_echo::Echo> {
public:
ParentDriver() : fdf::DriverBase2("parent") {}
zx::result<> Start(fdf::DriverContext context) override {
// Add the FIDL service we wish to export to our child to our outgoing
// directory. When a connection is attempted we bind the server end of
// the channel pair to our server implementation using the driver's default
// dispatcher.
fidl_examples_echo::EchoService::InstanceHandler handler({
.echo = bindings_.CreateHandler(this, dispatcher(),
fidl::kIgnoreBindingClosure),
});
zx::result result =
outgoing()->AddService<fidl_examples_echo::EchoService>(std::move(handler));
if (result.is_error()) {
fdf::error("Failed to add EchoService to outgoing directory: {}", result);
return result.take_error();
}
// Declare our outgoing service offer and add the child node. The driver
// framework uses this offer to route the service to the child and
// automatically populate node properties for binding.
std::vector<fuchsia_driver_framework::NodeProperty2> properties = {};
zx::result child_result = AddChild(
"echo_child", properties,
std::array{fdf::MakeOffer2<fidl_examples_echo::EchoService>()});
if (child_result.is_error()) {
fdf::error("Failed to add child node: {}", child_result);
return child_result.take_error();
}
controller_.Bind(std::move(child_result.value()), dispatcher());
return zx::ok();
}
private:
// Implementation of the method required by our FIDL protocol.
void EchoString(EchoStringRequestView request,
EchoStringCompleter::Sync& completer) override {
completer.Reply(request->value);
}
fidl::WireClient<fuchsia_driver_framework::NodeController> controller_;
// Ensures that the FIDL connections do not outlive the driver instance.
fidl::ServerBindingGroup<fidl_examples_echo::Echo> bindings_;
};
FUCHSIA_DRIVER_EXPORT2(ParentDriver);
子驱动程序(客户端)
驱动程序清单
在子驱动程序的清单 (.dml) 中,声明驱动程序使用该服务:
use: [
{ service: "fidl.examples.echo.EchoService" },
],
请注意,子驱动程序的绑定规则是根据其 DML 自动生成的。
客户端代码
以下代码段展示了已绑定到父节点的子驱动程序如何连接到 Echo 协议并调用该协议:
#include <fidl/fidl.examples.echo/cpp/wire.h>
#include <lib/driver/component/cpp/driver_base2.h>
#include <lib/driver/component/cpp/driver_export2.h>
#include <lib/driver/logging/cpp/logger.h>
class ChildDriver : public fdf::DriverBase2 {
public:
ChildDriver() : fdf::DriverBase2("child") {}
zx::result<> Start(fdf::DriverContext context) override {
// Connect to the protocol offered by our parent driver through our incoming
// namespace. We do not need to specify the service or protocol name string
// because Connect is templated on the generated service member type.
zx::result client_end =
context.incoming().Connect<fidl_examples_echo::EchoService::Echo>();
if (client_end.is_error()) {
fdf::error("Failed to connect to Echo protocol: {}", client_end);
return client_end.take_error();
}
// Turn the client side of the endpoint pair into a synchronous client.
fidl::WireSyncClient client{std::move(client_end.value())};
// Utilize our client to make calls.
constexpr std::string_view kInput = "Test String";
fidl::WireResult result =
client->EchoString(fidl::StringView::FromExternal(kInput));
if (!result.ok()) {
fdf::error("Failed to call EchoString: {}", result.error());
return zx::error(result.status());
}
if (result->response.get() != kInput) {
fdf::error("Unexpected response: Actual: \"{}\", Expected: \"{}\"",
result->response.get(), kInput);
return zx::error(ZX_ERR_INTERNAL);
}
return zx::ok();
}
};
FUCHSIA_DRIVER_EXPORT2(ChildDriver);