教學課程:在驅動程式之間傳遞中繼資料

本指南說明如何使用 metadata 程式庫。中繼資料可以是任意資料 由驅動程式庫在繫結至節點時建立,應可存取 繫結至其子節點的驅動程式在一般情況下,駕駛可以自行建立 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 服務。不過,外送命名空間中的 Service 名稱 並非 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" ]
}

中繼資料庫

如要使用 metadata 程式庫,我們需要將 fdf_metadata::ObjectDetails 範本 類別如下:

#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);

元件資訊清單如下: ``` { 包含:[ &quot;inspect/client.shard.cml&quot;, &quot;syslog/client.shard.cml&quot;, ], program: { 執行元件: "驅動程式庫", 二進位檔案:「driver/parent.so」、 繫結: "meta/繫結/parent.bindbc", },您好: }


It's build targets are defined as follows:

fuchsia_driver(&quot;driver&quot;) { testonly = true output_name =「parent」 source = [ &quot;parent.cc&quot;, ] deps = [ &quot;//src/devices/lib/driver:driver_runtime&quot;, ] }

fuchsia_driver_component(&quot;component&quot;) { testonly = true 元件名稱 = 「父項」 資訊清單 =「meta/parent.cml」 deps = [ &quot;:driver&quot;, ":bind", # 個未在本教學課程中指定的繫結規則。 ] info =「parent.json」# 本教學課程未指定資訊。 } ```

傳送程序

此驅動程式庫必須具有 執行個體 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::SetMetadata() 可以多次呼叫 在 fdf_metadata::MetadataServer::Serve() 之前或之後,以及中繼資料伺服器 將提供最新的中繼資料執行個體驅動程式將無法擷取 未呼叫 fdf_metadata::MetadataServer::SetMetadata() 時的中繼資料 然後嘗試擷取中繼資料

需要更新 driver 建構目標: fuchsia_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 並未以「fuchsia.driver.metadata.Service」這個名稱提供這項服務 視為一般 FIDL 服務而是以「名稱」之下提供服務 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_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_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_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_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" },
    ],
}