將其他服務更新至 DFv2

本頁面提供有關下列主題的操作說明、最佳做法及範例: 更新 DFv1 驅動程式中的各種服務 (DDK 介面除外) 到 DFv2

設定 Compat 裝置伺服器

如果 DFv1 驅動程式庫與其他尚未遷移的 DFv1 驅動程式通訊 您必須使用相容性輔助程式,才能啟用 now-DFv2 驅動程式庫 與系統中的其他 DFv1 驅動程式通訊。如要進一步瞭解 在 DFv2 驅動程式中使用這個相容性輔助程式,請參閱 在 DFv2 驅動程式中設定 Compat 裝置伺服器 指南。

使用 DFv2 服務探索功能

處理驅動程式庫遷移時,您可能會遇到一或多種 在以下三種情況下,兩個驅動程式會建立 FIDL 連線 (child driver -> parent driver 格式):

  • 情境 1:DFv2 驅動程式庫 ->DFv2 驅動程式庫
  • 情境 2:DFv1 驅動程式庫 ->DFv2 驅動程式庫
  • 情境 3:DFv2 驅動程式庫 ->DFv1 驅動程式庫

情境 1 是 DFv2 驅動程式的標準案例 (這個 example 會顯示新的 DFv2 語法)。更新 發生這種狀況,請參閱 DFv2 驅動程式庫到 DFv2 驅動程式一節。

情境 2 和 3 比較複雜,因為 DFv1 驅動程式 包裝在 DFv2 世界中的相容性輔助程式。不過 兩者的差異如下:

  • 情境 2 中,這個「Gerrit 變更」會顯示 向 DFv1 子項公開服務的方法。

  • 情境 3 中,驅動程式庫會連線至 fuchsia_driver_compat::Service::Device 通訊協定 然後驅動程式庫驅動程式庫呼叫 ConnectFidl() 方法,藉此連線至實際的 通訊協定 (如需範例,請參閱 Gerrit 變更)。

如要更新情境 2 或 3 以下的驅動程式,請參閱 DFv1 驅動程式庫到 DFv2 驅動程式庫 (含相容性輔助鍵) 以下章節。

DFv2 驅動程式庫至 DFv2 驅動程式庫

為了讓其他 DFv2 驅動程式找到你的驅動程式庫服務, :

  1. 更新驅動程式的 .fidl 檔案。

    如要使用 DFv2 探索通訊協定,就必須為以下項目新增 service 欄位: 驅動程式庫的通訊協定,例如:

    library fuchsia.example;
    
    @discoverable
    @transport("Driver")
    protocol MyProtocol {
        MyMethod() -> (struct {
            ...
        });
    };
    
    service Service {
        my_protocol client_end:MyProtocol;
    };
    
  2. 更新子項驅動程式庫。

    DFv2 驅動程式能以與 FIDL 服務相同的方式連線至通訊協定, 例如:

    incoming()->Connect<fuchsia_example::Service::MyProtocol>();
    

    您也需要更新元件資訊清單 (.cml) 檔案,才能使用 驅動程式執行階段服務,例如:

    use: [
        { service: "fuchsia.example.Service" },
    ]
    
  3. 更新父項驅動程式庫。

    家長驅動程式庫需要使用 fdf::DriverBaseoutgoing() 函式來取得 fdf::OutgoingDirectory 物件。請注意,您必須使用服務而非通訊協定。 如果驅動程式未使用 fdf::DriverBase,則必須建立並提供 自行fdf::OutgoingDirectory

    接著,您需要將執行階段服務新增至傳出目錄。 以下範例是繼承自 fdf::DriverBase 的驅動程式庫 類別:

    zx::status<> Start() override {
      auto protocol = [this](
          fdf::ServerEnd<fuchsia_example::MyProtocol> server_end) mutable {
        // bindings_ is a class field with type fdf::ServerBindingGroup<fuchsia_example::MyProtocol>
        bindings_.AddBinding(
          dispatcher()->get(), std::move(server_end), this, fidl::kIgnoreBindingClosure);
      };
    
      fuchsia_example::Service::InstanceHandler handler(
           {.my_protocol = std::move(protocol)});
    
      auto status =
            outgoing()->AddService<fuchsia_wlan_phyimpl::Service>(std::move(handler));
      if (status.is_error()) {
        return status.take_error();
      }
    
      return zx::ok();
    }
    

    更新子節點的 NodeAddArgs,加入優惠 定義執行階段服務,例如:

    auto offers =
        std::vector{fdf::MakeOffer2<fuchsia_example::Service>(arena, name)};
    
    fidl::WireSyncClient<fuchsia_driver_framework::Node> node(std::move(node()));
      auto args = fuchsia_driver_framework::wire::NodeAddArgs::Builder(arena)
                        .name(arena, “example_node”)
                        .offers2(offers)
                        .Build();
    
      zx::result controller_endpoints =
           fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
      ZX_ASSERT(controller_endpoints.is_ok());
    
      auto result = node_->AddChild(
          args, std::move(controller_endpoints->server), {});
    

    同樣地,將父項驅動程式庫元件資訊清單 (.cml) 檔案更新為 提供執行階段服務,例如:

    capabilities: [
        { service: "fuchsia.example.Service" },
    ],
    
    expose: [
        {
            service: "fuchsia.example.Service",
            from: "self",
        },
    ],
    

DFv1 驅動程式庫到 DFv2 驅動程式庫 (含相容性輔助程式)

為了讓其他 DFv1 驅動程式找到您的 DFv2 驅動程式庫服務 :

  1. 更新 DFv1 驅動程式。

    您需要更新 DFv1 的元件資訊清單 (.cml) 檔案 這跟 「DFv2 驅動程式庫到 DFv2 驅動程式」一節, 例如:

    • 兒童驅動程式庫:

      {
          include: [
              "//sdk/lib/driver_compat/compat.shard.cml",
              "inspect/client.shard.cml",
              "syslog/client.shard.cml",
          ],
          program: {
              runner: "driver",
              compat: "driver/child-driver-name.so",
              bind: "meta/bind/child-driver-name.bindbc",
              colocate: "true",
          },
          use: [
              { service: "fuchsia.example.Service" },
          ],
      }
      
    • 家長驅動程式庫:

      {
          include: [
              "//sdk/lib/driver_compat/compat.shard.cml",
              "inspect/client.shard.cml",
              "syslog/client.shard.cml",
          ],
          program: {
              runner: "driver",
              compat: "driver/parent-driver-name.so",
              bind: "meta/bind/parent-driver-name.bindbc",
          },
          capabilities: [
              { service: "fuchsia.example.Service" },
          ],
          expose: [
              {
                  service: "fuchsia.example.Service",
                  from: "self",
              },
          ],
      }
      
  2. 更新 DFv2 驅動程式庫。

    以下範例顯示從 DFv2 公開服務的方法 父系 DFv1 子項:

      fit::result<fdf::NodeError> AddChild() {
        fidl::Arena arena;
    
        auto offer = fdf::MakeOffer2<ft::Service>(kChildName);
    
        // Set the properties of the node that a driver will bind to.
        auto property =
            fdf::MakeProperty(1 /*BIND_PROTOCOL */, bind_fuchsia_test::BIND_PROTOCOL_COMPAT_CHILD);
    
        auto args = fdf::NodeAddArgs{
          {
            .name = std::string(kChildName),
            .properties = std::vector{std::move(property)},
            .offers2 = std::vector{std::move(offer)},
          }
        };
    
        // Create endpoints of the `NodeController` for the node.
        auto endpoints = fidl::CreateEndpoints<fdf::NodeController>();
        if (endpoints.is_error()) {
          return fit::error(fdf::NodeError::kInternal);
        }
    
        auto add_result = node_.sync()->AddChild(fidl::ToWire(arena, std::move(args)),
                                                 std::move(endpoints->server), {});
    

    (資料來源:root-driver.cc)

更新其他驅動程式的元件資訊清單

如要完成 DFv1 驅動程式庫遷移至 DFv2 的程序,您不僅 更新目標驅動程式庫的元件資訊清單 (.cml) 檔案, 但您可能也需要更新 和即時 DFv2 驅動程式庫互動的其他驅動程式。

請完成下列步驟:

  1. 更新分葉驅動程式的元件資訊清單 (也就是說, 子項驅動程式) 及下列變更:

    • 從以下位置移除 //sdk/lib/driver/compat/compat.shard.cml: 「include」欄位中的值。
    • program.compat 欄位替換為 program.binary
  2. 對於執行 幾項工作:

    • 存取核心 args
    • 建立複合裝置。
    • 偵測重新啟動、關閉或重新繫結的通話。
    • 使用 Banjo 通訊協定與其他駕駛人交談。
    • 從父母驅動程式庫存取或轉寄中繼資料。
    • 與繫結至驅動程式新增節點的 DFv1 驅動程式庫聯絡。

    請將這些驅動程式的元件資訊清單更新為 如下:

    • 複製下列 use 功能中的部分: compat.shard.cml 新增至元件資訊清單。 例如:

      use: [
          {
              protocol: [
                  "fuchsia.boot.Arguments",
                  "fuchsia.boot.Items",
                  "fuchsia.driver.framework.CompositeNodeManager",
                  "fuchsia.system.state.SystemStateTransition",
              ],
          },
          { service: "fuchsia.driver.compat.Service" },
      ],
      
    • program.runner 欄位設為 driver,例如:

      program: {
          runner: "driver",
          binary: "driver/compat.so",
      },
      

從 DFv2 驅動程式庫公開 devfs 節點

如要從 DFv2 驅動程式庫公開 devfs 節點,您必須新增 NodeAddArgsdevice_args 成員。 具體來說,您需要指定類別名稱 實作連接器,輕鬆使用 Connector 程式庫,例如:

zx::result connector = devfs_connector_.Bind(dispatcher());
if (connector.is_error()) {
  return connector.take_error();
}

auto devfs =
    fuchsia_driver_framework::wire::DevfsAddArgs::Builder(arena).connector(
        std::move(connector.value()));

auto args = fuchsia_driver_framework::wire::NodeAddArgs::Builder(arena)
                    .name(arena, name)
                    .devfs_args(devfs.Build())
                    .Build();

(資料來源:parent-driver.cc)

若需更多資訊,請參閲 公開驅動程式庫: DFv2 驅動程式庫程式碼研究室。您也可以參閱導入 執行本程式碼研究室提及的 ExportToDevfs 方法。

如要進一步瞭解 devfs 設定程序, 請參閱「在 DFv2 驅動程式中設定 devfs」指南。

使用調度工具

管道會從 FIDL 用戶端和伺服器組合根據預設,此管道中的 FIDL 呼叫 非同步匯總資料

如要向 DFv2 中的驅動程式導入非同步作業,請參閱以下內容: 建議:

  • fdf::Dispatcher::GetCurrent() 方法會提供預設值 正在執行驅動程式庫的調度器 (請參閱 aml-ethernet 驅動程式庫範例)。如果可能的話 建議您只使用這個預設的調度工具。

  • 考慮使用多個調度工具的原因如下: (但不限於):

    • 驅動程式需要平行處理才能效能。

    • 驅動程式想要執行封鎖作業 (因為 舊驅動程式庫或非 Fuchsia 驅動程式庫程式 Fuchsia),在遭阻斷時需要處理更多工作。

  • 如果需要多個調度工具,fdf::Dispatcher::Create() 方法即可為您的驅動程式庫建立新的調度工具。不過,您必須 在預設調度工具上呼叫這個方法 (例如呼叫 位於 Start() 掛鉤內),讓驅動程式代管程序知道 司機的其他調度器。

  • 在 DFv2 中,您不需要手動關閉調度工具。他們 將關閉 PrepareStop()Stop() 的呼叫。

如要進一步瞭解如何遷移驅動程式庫以使用多個調度工具, 請參閱 更新 DFv1 驅動程式庫以使用非預設調度工具 一節 (請參閱從 Banjo 遷移至 FIDL) 詞組)。

使用 DFv2 檢查功能

如要在 DFv2 中設定驅動程式庫維護的「檢查」inspect指標, 您可以使用 fdf::DriverBase::inspector() 提供的 ComponentInspector

inspect::Node& root = inspector().root();

如要使用自訂檢查器,請呼叫 fdf::DriverBase::InitInspectorExactlyOnce(inspector) 然後再存取 inspector() 方法

DFv2 檢查不需要將 inspect::Inspector 的 VMO 傳遞至驅動程式庫架構。

DFv2 驅動程式檢查項目會歸因於驅動程式庫 (因為這是「標準」元件)。 然而,DFv2 驅動程式的 Monikers 並不穩定,因此針對以何種方式編寫隱私權選取器時 驅動程式庫應使用萬用字元和名稱篩選器來參照特定驅動程式庫。例如:

bootstrap/*-drivers*:[name=sysmem]root

如要在偵錯期間存取驅動程式庫檢查工具,可以使用所有一般工具,例如

ffx inspect show "bootstrap/*-drivers*:[name=sysmem]root"

ffx inspect show --manifest sysmem.cm

(選用) 實作自己的 load_firmware 方法

如果 DFv1 驅動程式庫呼叫 load_firmware() 函式,則您必須自行實作 這個函式,因為 DFv2 無法使用對等函式。

這個函式的實作方式應該很簡單。您需要取得 手動從路徑載入備份 VMO如需範例,請參閱 生成變更

(選用) 使用 FIDL 服務提供的節點屬性

DFv2 節點包含 FIDL 服務產生的節點屬性 向父母反映

例如,在父項驅動程式 (The Server) 中 舉例來說,父項驅動程式庫新增一個名為 "parent" 的節點並提供服務 「fidl.examples.EchoService」專屬優惠。在 DFv2 中,將繫結至 節點中可以有該 FIDL 服務節點屬性的繫結規則,例如:

using fidl.examples.echo;

fidl.examples.echo.Echo == fidl.examples.echo.Echo.ZirconTransport;

詳情請參閱 FIDL 的產生的繫結程式庫區段 教學課程頁面。

將單元測試更新為 DFv2

mock_ddk 程式庫 (用於單元測試的測試) 驅動程式庫和裝置生命週期) 專屬。新的 DFv2 測試 架構 (請參閱 Gerrit 變更) 對 DFv2 驅動程式可透過 TestEnvironment 使用的模擬 FIDL 伺服器 類別

以下是可用於單元測試 DFv2 驅動程式的程式庫:

  • //sdk/lib/driver/testing/cpp

    • TestNode – 此類別會實作 fuchsia_driver_framework::Node 通訊協定,提供給驅動程式庫以建立子節點。這個 測試也會使用類別來存取驅動程式庫的子項節點

    • TestEnvironment - 針對 OutgoingDirectory 物件套用的包裝函式 可做為傳入網路的備用 VFS (虛擬檔案系統) 測試中驅動程式庫的命名空間。

    • DriverUnderTest - 本課程為 RAII 級 (資源獲取為初始化) 包裝函式 安裝在測試中的驅動程式庫

    • DriverRuntime – 此類別是代管驅動程式庫上的 RAII 包裝函式 執行階段執行緒集區。

  • //sdk/lib/driver/testing/cpp/driver_runtime.h

    • TestSynchronizedDispatcher – 此類別是針對 驅動程式庫調度工具

下列程式庫有助於編寫驅動程式庫單元測試:

最後,下列單元測試範例涵蓋不同設定和 測試案例:

其他資源

部分 DFv2 驅動程式範例:

本節提及的所有「Gerrit 變更」

本節提及的所有原始碼檔案

本節提及的所有說明文件頁面