本指南說明如何使用中繼資料程式庫,將中繼資料從某個驅動程式傳送至另一個驅動程式。中繼資料是指驅動程式繫結至節點時所建立的任意資料,且該節點應可供繫結至其子節點的驅動程式存取。通常,驅動程式可以建立自己的 FIDL 通訊協定來傳遞中繼資料,但 metadata 程式庫提供在程式碼較少的驅動程式之間傳遞中繼資料的功能。
如需駕駛人傳送、擷取及轉寄中繼資料的範例,請參閱這篇文章。
中繼資料定義
首先,中繼資料類型必須定義為 FIDL 類型:
library fuchsia.examples.metadata;
// Type of the metadata to be passed.
type Metadata = table {
1: test_property string:MAX;
};
這項中繼資料會透過 fuchsia.driver.metadata/Service FIDL 服務,在驅動程式的傳出命名空間中提供。不過,外送命名空間中的服務名稱不會是 fuchsia.driver.metadata.Service
。而是我們提供的關聯中繼資料類型自訂字串。在本教學課程中,我們會在上述相同的 FIDL 程式庫中定義該字串:
library fuchsia.examples.metadata;
const SERVICE string = "fuchsia.examples.metadata.Metadata";
FIDL 程式庫的建構目標將定義如下:
fidl("fuchsia.examples.metadata") {
sources = [ "fuchsia.examples.metadata.fidl" ]
}
中繼資料資料庫
為了使用中繼資料程式庫傳送及接收中繼資料,我們需要將 fdf_metadata::ObjectDetails 範本類別專門化,如下所示:
// Defines `fdf_metadata::ObjectDetails`.
#include <lib/driver/metadata/cpp/metadata.h>
// Defines the fuchsia.examples.metadata types in C++.
#include <fidl/fuchsia.examples.metadata/cpp/fidl.h>
// `ObjectDetails` must be specialized within the `fdf_metadata` namespace.
namespace fdf_metadata {
template <>
// Pass the metadata type as the template argument.
struct ObjectDetails<fuchsia_examples_metadata::Metadata> {
// Specify the name of the service used to serve the metadata.
inline static const char* Name = fuchsia_examples_metadata::kService;
};
} // namespace fdf_metadata
由於傳送和接收驅動程式都需要執行這項操作,我們可以將這段程式碼插入兩個驅動程式都會納入的新程式庫:
source_set("examples_metadata") {
# This header file should contain the above code.
sources = [ "examples_metadata.h" ]
public_deps = [
# This should be the fuchsia.examples.metadata FIDL library's C++ target.
":fuchsia.examples.metadata_cpp",
]
}
傳送中繼資料
初始設定
假設我們有一個驅動程式,想要將中繼資料傳送至子項:
#include <lib/driver/component/cpp/driver_export.h>
class Sender : public fdf::DriverBase {
public:
Sender(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher driver_dispatcher)
: DriverBase("parent", std::move(start_args), std::move(driver_dispatcher)) {}
};
FUCHSIA_DRIVER_EXPORT(Sender);
元件資訊清單如下所示:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/parent.so",
bind: "meta/bind/parent.bindbc",
},
}
其建構目標的定義如下:
fuchsia_cc_driver("driver") {
testonly = true
output_name = "parent"
sources = [
"parent.cc",
]
deps = [
"//src/devices/lib/driver:driver_runtime",
]
}
fuchsia_driver_component("component") {
testonly = true
component_name = "parent"
manifest = "meta/parent.cml"
deps = [
":driver",
":bind", # Bind rules not specified in this tutorial.
]
info = "parent.json" # Info not specified in this tutorial.
}
傳送程序
為了讓這個驅動程式將中繼資料傳送至子驅動程式,它需要 fdf_metadata::MetadataServer 類別的例項,透過呼叫其 fdf_metadata::MetadataServer::SetMetadata()
方法設定中繼資料,然後透過呼叫其 fdf_metadata::MetadataServer::Serve()
方法,將中繼資料提供至驅動程式的傳出目錄:
// Make sure to include the metadata library that specializes the
// `fdf_metadata::ObjectDetails` class. It is needed by
// `fdf_metadata::MetadataServer`.
#include "examples_metadata.h"
#include <lib/driver/metadata/cpp/metadata_server.h>
class Sender : public fdf::DriverBase {
public:
zx::result<> Start() override {
// Set the metadata to be served.
fuchsia_examples_metadata::Metadata metadata{{.test_property = "test value"}};
ZX_ASSERT(metadata_server_.SetMetadata(std::move(metadata)) == ZX_OK);
// Serve the metadata to the driver's outgoing directory.
ZX_ASSERT(metadata_server_.Serve(*outgoing(), dispatcher()) == ZX_OK);
return zx::ok();
}
private:
// Responsible for serving metadata.
fdf_metadata::MetadataServer<fuchsia_examples_metadata::Metadata> metadata_server_;
};
您可在 fdf_metadata::MetadataServer::Serve()
之前或之後多次呼叫 fdf_metadata::MetadataServer::SetMetadata()
,中繼資料伺服器將提供最新的中繼資料執行個體。如果在嘗試擷取中繼資料之前未呼叫 fdf_metadata::MetadataServer::SetMetadata()
,驅動程式就無法擷取中繼資料。
需要更新 driver
建構目標:fuchsia_cc_driver("driver") {
testonly = true
output_name = "parent"
sources = [
"parent.cc",
]
deps = [
"//src/devices/lib/driver:driver_runtime",
":examples_metadata",
]
}
公開中繼資料服務
最後,驅動程式庫必須在元件資訊清單中宣告並公開 fuchsia.examples.metadata.Metadata
FIDL 服務:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/parent.so",
bind: "meta/bind/parent.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
名稱提供服務。這可讓接收驅動程式識別要傳遞的中繼資料類型。這表示即使 fuchsia.examples.metadata.Metadata
服務不存在,我們也需要宣告並公開該服務。
擷取中繼資料
初始設定
假設某個驅動程式庫想接收來自父項驅動程式庫的中繼資料:
#include <lib/driver/component/cpp/driver_export.h>
class Retriever : public fdf::DriverBase {
public:
Retriever(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher driver_dispatcher)
: DriverBase("child", std::move(start_args), std::move(driver_dispatcher)) {}
};
FUCHSIA_DRIVER_EXPORT(Retriever);
元件資訊清單如下所示:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/child.so",
bind: "meta/bind/child.bindbc",
},
}
其建構目標的定義如下:
fuchsia_cc_driver("driver") {
testonly = true
output_name = "child"
sources = [
"child.cc",
]
deps = [
"//src/devices/lib/driver:driver_runtime",
]
}
fuchsia_driver_component("component") {
testonly = true
component_name = "child"
manifest = "meta/child.cml"
deps = [
":driver",
":bind", # Bind rules not specified in this tutorial.
]
info = "child.json" # Info not specified in this tutorial.
}
擷取程序
為從驅動程式庫的父項驅動程式庫擷取中繼資料,驅動程式庫會呼叫 fdf_metadata::GetMetadata()
:
#include <lib/driver/metadata/cpp/metadata.h>
// Make sure to include the metadata library that specializes the
// `fdf_metadata::ObjectDetails` class. It is needed by
// `fdf_metadata::GetMetadata()`.
#include "examples_metadata.h"
class Retriever : public fdf::DriverBase {
public:
zx::result<> Start() override {
zx::result<fuchsia_examples_metadata::Metadata> metadata =
fdf_metadata::GetMetadata<fuchsia_examples_metadata::Metadata>(incoming());
ZX_ASSERT(!metadata.is_error());
return zx::ok();
}
};
需要更新 driver
建構目標:
fuchsia_cc_driver("driver") {
testonly = true
output_name = "child"
sources = [
"child.cc",
]
deps = [
"//src/devices/lib/driver:driver_runtime",
":examples_metadata",
]
}
使用中繼資料服務
最後,驅動程式需要在元件資訊清單中宣告 fuchsia.examples.metadata.Metadata
FIDL 服務的用法:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/child.so",
bind: "meta/bind/child.bindbc",
},
use: [
{ service: "fuchsia.examples.metadata.Metadata" },
],
}
轉送中繼資料
初始設定
假設有個驅動程式想要從父項驅動程式擷取中繼資料,並將該中繼資料轉送至子項驅動程式:
#include <lib/driver/component/cpp/driver_export.h>
class Forwarder : public fdf::DriverBase {
public:
Forwarder(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher driver_dispatcher)
: DriverBase("forward", std::move(start_args), std::move(driver_dispatcher)) {}
};
FUCHSIA_DRIVER_EXPORT(Forwarder);
元件資訊清單如下所示:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/forward_driver.so",
bind: "meta/bind/forward.bindbc",
},
}
其建構目標的定義如下:
fuchsia_cc_driver("driver") {
testonly = true
output_name = "forward_driver"
sources = [
"forward_driver.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::ForwardMetadata()
方法設定中繼資料,然後透過呼叫其 fdf_metadata::MetadataServer::Serve()
方法,將中繼資料提供至驅動程式的傳出目錄:
// Make sure to include the metadata library that specializes the
// `fdf_metadata::ObjectDetails` class. It is needed by
// `fdf_metadata::MetadataServer`.
#include "examples_metadata.h"
#include <lib/driver/metadata/cpp/metadata_server.h>
class Forwarder : public fdf::DriverBase {
public:
zx::result<> Start() override {
// Set metadata using the driver's parent driver metadata.
ZX_ASSERT(metadata_server_.ForwardMetadata(incoming()) == ZX_OK);
// Serve the metadata to the driver's outgoing directory.
ZX_ASSERT(metadata_server_.Serve(*outgoing(), dispatcher()) == ZX_OK);
return zx::ok();
}
private:
// Responsible for serving metadata.
fdf_metadata::MetadataServer<fuchsia_examples_metadata::Metadata> metadata_server_;
};
請注意,fdf_metadata::MetadataServer::ForwardMetadata()
不會在 fdf_metadata::MetadataServer::ForwardMetadata()
呼叫後,檢查父項驅動程式是否變更所提供的中繼資料。驅動程式必須再次呼叫 fdf_metadata::MetadataServer::ForwardMetadata()
,才能納入變更。
您需要更新 driver
建構目標:
fuchsia_cc_driver("driver") {
testonly = true
output_name = "forward_driver"
sources = [
"forward_driver.cc",
]
deps = [
"//src/devices/lib/driver:driver_runtime",
":examples_metadata",
]
}
公開及使用中繼資料服務
最後,驅動程式需要在其元件資訊清單中宣告、使用及公開 fuchsia.examples.metadata.Metadata
FIDL 服務:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/forward_driver.so",
bind: "meta/bind/forward.bindbc",
},
capabilities: [
{ service: "fuchsia.examples.metadata.Metadata" },
],
expose: [
{
service: "fuchsia.examples.metadata.Metadata",
from: "self",
},
],
use: [
{ service: "fuchsia.examples.metadata.Metadata" },
],
}