本指南介绍了如何使用 元数据库将元数据从一个驱动程序传递给另一个驱动程序。元数据是驱动程序创建的任何任意数据,应可供绑定到其子节点的驱动程序访问。通常,驱动程序可以创建自己的 FIDL 协议来传递 元数据,但 元数据 库提供了一些 功能,可用于在驱动程序之间传递元数据,而无需编写太多代码。
您可以在此处找到驱动程序发送、检索和转发元数据的示例 here。
元数据定义
首先,必须将元数据的类型定义为 FIDL 类型,并使用 @serializable 进行注释:
library fuchsia.examples.metadata;
// Type of the metadata to be passed.
// Make sure to annotate it with `@serializable`.
@serializable
type Metadata = table {
1: test_property string:MAX;
};
此元数据将使用
fuchsia.driver.metadata/Service
FIDL 服务在驱动程序的传出命名空间中提供。驱动程序的传出命名空间中的 FIDL 服务的名称不会是 fuchsia.driver.metadata.Service。相反,它将是 FIDL 类型的可序列化名称。只有在 FIDL 类型使用 @serializable 进行注释时,才会创建可序列化名称。
FIDL 库的 build 目标将定义如下:
fidl("fuchsia.examples.metadata") {
sources = [ "fuchsia.examples.metadata.fidl" ]
}
发送元数据
初始设置
假设我们有一个驱动程序想要向其子驱动程序发送元数据:
#include <lib/driver/component/cpp/driver_export2.h>
class Sender : public fdf::DriverBase2 {
public:
Sender() : fdf::DriverBase2("sender") {}
};
FUCHSIA_DRIVER_EXPORT2(Sender);
其组件清单如下:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/sender.so",
bind: "meta/bind/sender.bindbc",
},
}
其 build 目标定义如下:
fuchsia_cc_driver("driver") {
testonly = true
output_name = "sender"
sources = [
"sender.cc",
]
deps = [
"//src/devices/lib/driver:driver_runtime",
]
}
fuchsia_driver_component("component") {
testonly = true
component_name = "sender"
manifest = "meta/sender.cml"
deps = [
":driver",
":bind", # Bind rules not specified in this tutorial.
]
info = "sender.json" # Info not specified in this tutorial.
}
发送过程
为了让此驱动程序向其子驱动程序发送元数据,它需要
创建
fdf_metadata::MetadataServer
类的一个实例,调用 fdf_metadata::MetadataServer::Serve() 以提供
元数据,并将
fdf_metadata::MetadataServer::CreateOffer()创建的元数据服务器的 offer 传递给子节点:
// Defines the fuchsia.examples.metadata types in C++.
#include <fidl/fuchsia.examples.metadata/cpp/fidl.h>
// Defines fdf::MetadataServer.
#include <lib/driver/metadata/cpp/metadata_server.h>
class Sender : public fdf::DriverBase2 {
public:
zx::result<> Start(fdf::DriverContext context) override {
// Serve the metadata to the driver's outgoing directory.
fuchsia_examples_metadata::Metadata metadata({.test_property = "test value"});
ZX_ASSERT(metadata_server_.Serve(*outgoing(), dispatcher(), metadata).is_ok());
std::vector<fuchsia_driver_framework::Offer> offers;
std::optional<fuchsia_driver_framework::Offer> metadata_offer =
metadata_server_.CreateOffer();
// The metadata server should create an offer because it is serving
// metadata.
ZX_ASSERT(metadata_offer.has_value());
// The metadata server's offer must be provided to the child node.
offers.push_back(*metadata_offer);
zx::result child = AddChild("child", {}, offers);
if (child.is_error()) {
return child.take_error();
}
return zx::ok();
}
private:
// Responsible for serving metadata.
fdf_metadata::MetadataServer<fuchsia_examples_metadata::Metadata> metadata_server_;
};
可以多次调用 fdf_metadata::MetadataServer::Serve(),元数据服务器将提供最新的元数据实例。
需要更新 driver build 目标,以包含元数据库和定义元数据类型的 FIDL 库:
fuchsia_cc_driver("driver") {
testonly = true
output_name = "sender"
sources = [
"sender.cc",
]
deps = [
"//src/devices/lib/driver:driver_runtime",
# This should be the fuchsia.examples.metadata FIDL library's C++ target.
":fuchsia.examples.metadata_cpp",
# This library contains `fdf::MetadataServer`.
"//sdk/lib/driver/metadata/cpp",
]
}
公开元数据服务
最后,驱动程序需要在其组件清单中声明并公开 fuchsia.examples.metadata.Metadata FIDL 服务:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/sender.so",
bind: "meta/bind/sender.bindbc",
},
capabilities: [
{ service: "fuchsia.examples.metadata.Metadata" },
],
expose: [
{
service: "fuchsia.examples.metadata.Metadata",
from: "self",
},
],
}
从技术上讲,没有 fuchsia.examples.metadata.Metadata FIDL 服务。
在底层,
fdf_metadata::MetadataServer
提供
fuchsia.driver.metadata/Service
FIDL 服务以发送元数据。但是,
fdf_metadata::MetadataServer
不会像普通的 FIDL 服务那样以名称 fuchsia.driver.metadata.Service
提供此服务。相反,该服务以元数据类型的可序列化名称提供。在本例中,该名称为 fuchsia.examples.metadata.Metadata。您可以在 C++ 字段 fuchsia_examples_metadata::Metadata::kSerializableName 中找到此名称。这样,接收驱动程序就可以识别正在传递的元数据类型。这意味着,即使 fuchsia.examples.metadata.Metadata FIDL 服务不存在,驱动程序也需要声明并公开该服务。
检索元数据
初始设置
假设我们有一个驱动程序想要从其父驱动程序检索元数据:
#include <lib/driver/component/cpp/driver_export2.h>
class Retriever : public fdf::DriverBase2 {
public:
Retriever() : fdf::DriverBase2("retriever") {}
};
FUCHSIA_DRIVER_EXPORT2(Retriever);
其组件清单如下:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/retriever.so",
bind: "meta/bind/retriever.bindbc",
},
}
其 build 目标定义如下:
fuchsia_cc_driver("driver") {
testonly = true
output_name = "retriever"
sources = [
"retriever.cc",
]
deps = [
"//src/devices/lib/driver:driver_runtime",
]
}
fuchsia_driver_component("component") {
testonly = true
component_name = "retriever"
manifest = "meta/retriever.cml"
deps = [
":driver",
":bind", # Bind rules not specified in this tutorial.
]
info = "retriever.json" # Info not specified in this tutorial.
}
检索过程
为了让驱动程序从其父驱动程序检索元数据,驱动程序需要调用 fdf_metadata::GetMetadata():
// Defines the fuchsia.examples.metadata types in C++.
#include <fidl/fuchsia.examples.metadata/cpp/fidl.h>
// Defines fdf::GetMetadata().
#include <lib/driver/metadata/cpp/metadata.h>
class Retriever : public fdf::DriverBase2 {
public:
zx::result<> Start(fdf::DriverContext context) override {
zx::result<fuchsia_examples_metadata::Metadata> metadata =
fdf_metadata::GetMetadata<fuchsia_examples_metadata::Metadata>(context.incoming());
ZX_ASSERT(!metadata.is_error());
return zx::ok();
}
};
需要更新 driver build 目标,以依赖于元数据库和定义元数据类型的 FIDL 库:
fuchsia_cc_driver("driver") {
testonly = true
output_name = "retriever"
sources = [
"retriever.cc",
]
deps = [
"//src/devices/lib/driver:driver_runtime",
# This should be the fuchsia.examples.metadata FIDL library's C++ target.
":fuchsia.examples.metadata_cpp",
# This library contains `fdf::GetMetadata()`.
"//sdk/lib/driver/metadata/cpp",
]
}
使用元数据服务
最后,驱动程序需要在其组件清单中声明其对 fuchsia.examples.metadata.Metadata FIDL 服务的用法:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/retriever.so",
bind: "meta/bind/retriever.bindbc",
},
use: [
{ service: "fuchsia.examples.metadata.Metadata" },
],
}
转发元数据
初始设置
假设我们有一个驱动程序想要从其父驱动程序检索元数据,并将该元数据转发给其子驱动程序:
#include <lib/driver/component/cpp/driver_export2.h>
class Forwarder : public fdf::DriverBase2 {
public:
Forwarder() : fdf::DriverBase2("forwarder") {}
};
FUCHSIA_DRIVER_EXPORT2(Forwarder);
其组件清单如下:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/forwarder.so",
bind: "meta/bind/forwarder.bindbc",
},
}
其 build 目标定义如下:
fuchsia_cc_driver("driver") {
testonly = true
output_name = "forwarder"
sources = [
"forwarder.cc",
]
deps = [
"//src/devices/lib/driver:driver_runtime",
]
}
fuchsia_driver_component("component") {
testonly = true
component_name = "forward"
manifest = "meta/forward.cml"
deps = [
":driver",
":bind", # Bind rules not specified in this tutorial.
]
info = "forward.json" # Info not specified in this tutorial.
}
转发过程
为了让驱动程序将其父驱动程序的元数据转发给其子
驱动程序,它需要创建
fdf_metadata::MetadataServer
类的一个实例,调用 fdf_metadata::MetadataServer::ForwardAndServe() 以从其父驱动程序检索元数据并将其提供给驱动程序的传出
目录,并将
fdf_metadata::MetadataServer::CreateOffer()创建的元数据服务器的 offer 传递给子节点。
如果 fdf_metadata::MetadataServer::ForwardAndServe() 无法从其父驱动程序检索元数据,则不会返回错误。相反,它会返回
zx::ok(false),并且不会提供任何内容。
```cpp
// Defines the fuchsia.examples.metadata types in C++.
include
// Defines fdf::MetadataServer.
include
class Forwarder : public fdf::DriverBase2 { public: zx::result<> Start(fdf::DriverContext context) override { // Retrieve the metadata from the driver's parent and serve it to the // driver's outgoing directory. zx::result is_serving = metadataserver.ForwardAndServe( *outgoing(), dispatcher(), context.incoming()).is_ok(); ZX_ASSERT(is_serving.is_ok());
std::vector<fuchsia_driver_framework::Offer> offers;
std::optional<fuchsia_driver_framework::Offer> metadata_offer =
metadata_server_.CreateOffer();
// The metadata server may not be serving metadata if the driver failed to
// retrieve it from the driver's parent. In that case, the metadata server
// will not have an offer.
if (metadata_offer.has_value()) {
// The metadata server's offer must be provided to the child node.
offers.push_back(metadata_offer.value());
}
zx::result child = AddChild("child", {}, offers);
if (child.is_error()) {
return child.take_error();
}
return zx::ok();
}
private:
// Responsible for serving metadata.
fdf_metadata::MetadataServer
请注意,fdf_metadata::MetadataServer::ForwardAndServe() 不会检查父驱动程序在调用
fdf_metadata::MetadataServer::ForwardAndServe() 后是否更改了其提供的元数据。驱动程序必须再次调用
fdf_metadata::MetadataServer::ForwardAndServe() 才能纳入更改。
需要更新 driver build 目标,以依赖于元数据库和定义元数据类型的 FIDL 库:
fuchsia_cc_driver("driver") {
testonly = true
output_name = "forwarder"
sources = [
"forwarder.cc",
]
deps = [
"//src/devices/lib/driver:driver_runtime",
# This should be the fuchsia.examples.metadata FIDL library's C++ target.
":fuchsia.examples.metadata_cpp",
# This library contains `fdf::MetadataServer`.
"//sdk/lib/driver/metadata/cpp",
]
}
公开和使用元数据服务
最后,驱动程序需要在其组件清单中声明、使用和公开 fuchsia.examples.metadata.Metadata FIDL 服务:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/forwarder.so",
bind: "meta/bind/forwarder.bindbc",
},
capabilities: [
{ service: "fuchsia.examples.metadata.Metadata" },
],
expose: [
{
service: "fuchsia.examples.metadata.Metadata",
from: "self",
},
],
use: [
{ service: "fuchsia.examples.metadata.Metadata" },
],
}