將 Banjo 通訊協定轉換為 FIDL 通訊協定

本頁面提供操作說明、最佳做法和範例,說明如何將 Banjo 通訊協定轉換為 FIDL 通訊協定,以便將 DFv1 驅動程式庫遷移至 DFv2。

將 DFv1 驅動程式庫從 Banjo 更新為 FIDL

更新驅動程式庫 .fidl 檔案是驅動程式庫遷移作業的良好起點,因為所有內容都源自 .fidl 檔案。幸運的是,Banjo 和 FIDL 會從相同的 IDL (即 FIDL) 產生程式碼,因此您可能不需要對現有的 .fidl 檔案進行重大變更。

以下範例 .fidl 檔案顯示 Banjo 到 FIDL 遷移前後的變更:

如要將 DFv1 驅動程式庫從 Banjo 更新為 FIDL,請進行下列變更 (大多是在驅動程式庫的 .fidl 檔案中):

  1. 先更新通訊協定定義前的屬性
  2. 更新函式定義,以便使用 FIDL 錯誤語法
  3. 更新 BUILD.gn 中的 FIDL 目標
  4. 將 FIDL 檔案移至 SDK/FIDL 目錄

1. 更新通訊協定定義前的屬性

如要使用 Banjo,.fidl 檔案中必須包含 @transport("Banjo") 屬性。不過,FIDL 不需要這個屬性 (因為 FIDL 是預設值)。因此,您只需從驅動程式的 .fidl 檔案中刪除 @transport("Banjo") 屬性,例如:

  • 使用 Banjo:

    @transport("Banjo")
    @banjo_layout("ddk-protocol")
    protocol MyExampleProtocol {
     ...
    }
    
  • 如何使用 FIDL:

    @discoverable
    @transport("Driver")
    protocol MyExampleProtocol {
     ...
    }
    

    在上述範例中,所有 FIDL 通訊協定都必須提供 @discoverable 屬性。這個屬性可讓用戶端使用產生的名稱搜尋此通訊協定。

    不過,對於使用驅動程式執行階段 FIDL 的驅動程式,@transport("Driver") 屬性 (表示這是驅動程式傳輸通訊協定) 是選用的。只有在驅動驅動程式庫與位於相同驅動程式代管程序的其他驅動程式通訊時,才需要進行驅動程式庫程式執行階段遷移。

    如需更多 Driver 傳輸通訊協定的範例,請參閱這個 Driver 傳輸範例目錄。

2. 更新函式定義,以便使用 FIDL 錯誤語法

如果 .fidl 檔案中的部分函式定義包含傳回狀態,您必須更新這些定義,以便使用 FIDL 錯誤語法,而非在傳回結構中新增狀態,例如:

  • 使用傳回結構:

    protocol MyExampleProtocol {
       MyExampleFunction() -> (struct {
           Error zx.status;
       });
    };
    

    (來源:wlanphy-impl.fidl)

  • 如要傳回 FIDL 錯誤語法:

    protocol MyExampleProtocol {
       BMyExampleFunction() -> () error zx.status;
    };
    

    (來源:phyimpl.fidl)

使用 FIDL 錯誤語法有以下優點:

  • 傳回結構體現在可以專注於需要傳送至伺服器端的資料。

  • 伺服器端的錯誤處理會更簡潔,因為擷取狀態不需要讀取傳回結構。

3. 更新 BUILD.gn 中的 FIDL 目標

編輯 BUILD.gn 檔案 (這個 .fidl 檔案),在 FIDL 目標中新增下列行:

contains_drivers = true

以下範例顯示 FIDL 目標中的 contains_drivers = true 行:

import("//build/fidl/fidl.gni")

fidl("fuchsia.wlan.phyimpl") {
 sdk_category = "partner"
 sources = [ "phyimpl.fidl" ]
 public_deps = [
   "//sdk/fidl/fuchsia.wlan.common",
   "//sdk/fidl/fuchsia.wlan.ieee80211",
   "//zircon/vdso/zx",
 ]
 contains_drivers = true
 enable_banjo = true
}

(來源:BUILD.gn)

如果沒有 contains_drivers = true 行,具有 @transport("Driver") 屬性的通訊協定就不會正確產生至 FIDL 程式庫。

4. 將 FIDL 檔案移至 SDK/FIDL 目錄

將更新後的 .fidl 檔案從 sdk/banjo 目錄移至 sdk/fidl 目錄。

sdk/fidl 目錄是儲存所有產生 FIDL 程式碼的檔案的預設位置。不過,如果 Banjo 結構或函式仍用於其他位置 (也就是驅動程式庫通訊之外),則不允許移動這個 .fidl 檔案。在這種情況下,您可以將此 .fidl 檔案的副本保留在 sdk/banjo 目錄中。

(選用) 更新 DFv1 驅動程式庫,以便使用驅動程式庫執行階段

本節要求上一節更新的 .fidl 檔案能夠成功產生 FIDL 程式碼。這個 FIDL 程式碼可用於在驅動程式之間建立驅動程式庫執行階段 FIDL 通訊。

如要更新 DFv1 驅動程式庫,以便使用驅動程式庫執行階段,請按照下列步驟操作:

  1. 更新驅動程式庫執行階段的依附元件
  2. 為驅動程式庫執行階段 FIDL 設定用戶端和伺服器物件
  3. 更新驅動程式庫,以便使用驅動程式庫執行階段 FIDL
  4. 發出 FIDL 要求

1. 更新驅動程式庫執行階段的依附元件

更新伺服器和用戶端端,納入使用驅動程式庫執行階段的新依附元件:

  1. BUILD.gn 檔案中,更新依附元件欄位,納入下列行:

    //sdk/fidl/<YOUR_FIDL_LIB>_cpp_wire
    //sdk/fidl/<YOUR_FIDL_LIB>_cpp_driver
    //src/devices/lib/driver:driver_runtime
    

    YOUR_FIDL_LIB 替換為 FIDL 程式庫的名稱,例如:

    public_deps = [
      ...
      "//sdk/fidl/fuchsia.factory.wlan:fuchsia.factory.wlan_cpp_wire",
      "//sdk/fidl/fuchsia.wlan.fullmac:fuchsia.wlan.fullmac_cpp_driver",
      "//sdk/fidl/fuchsia.wlan.phyimpl:fuchsia.wlan.phyimpl_cpp_driver",
      ...
      "//src/devices/lib/driver:driver_runtime",
      ...
    ]
    

    (來源:BUILD.gn)

  2. 在原始碼的標頭中更新 include 行,例如:

    #include <fidl/<YOUR_FIDL_LIB>/cpp/driver/wire.h>
    #include <lib/fdf/cpp/arena.h>
    #include <lib/fdf/cpp/channel.h>
    #include <lib/fdf/cpp/channel_read.h>
    #include <lib/fdf/cpp/dispatcher.h>
    #include <lib/fidl/cpp/wire/connect_service.h>
    #include <lib/fidl/cpp/wire/vector_view.h>
    ...
    

    (來源:wlanphy-impl-device.h)

2. 為驅動程式庫執行階段 FIDL 設定用戶端和伺服器物件

更新伺服器和用戶端端點,以便使用驅動程式庫執行階段 FIDL。

在用戶端端執行下列操作:

  1. 在裝置類別中宣告 FIDL 用戶端物件 (fdf::WireSharedClient<ProtocolName>fdf::WireSyncClient<ProtocolName>)。

    這個 FIDL 用戶端物件可讓您發出 FIDL 呼叫,將要求傳送至伺服器端。

    以下程式碼範例顯示裝置類別中的 FIDL 用戶端物件:

    class Device : public fidl::WireServer<fuchsia_wlan_device::Phy>,
                   public ::ddk::Device<Device, ::ddk::MessageableManual, ::ddk::Unbindable> {
     ...
     private:
      // Dispatcher for being a FIDL server listening MLME requests.
      async_dispatcher_t* server_dispatcher_;
    
      // The FIDL client to communicate with iwlwifi
      fdf::WireSharedClient<fuchsia_wlan_wlanphyimpl::WlanphyImpl> client_;
     ...
    

    (來源:device_dfv2.h)

  2. (僅限非同步呼叫) 在裝置類別中宣告調度器物件 (fdf::Dispatcher)。

    您需要使用調度器,才能將步驟 1 中的 FIDL 用戶端物件繫結。

    以下程式碼範例顯示裝置類別中的 FIDL 用戶端和調度器物件:

    class Device : public fidl::WireServer<fuchsia_wlan_device::Phy>,
                   public ::ddk::Device<Device, ::ddk::MessageableManual, ::ddk::Unbindable> {
     ...
     private:
      // Dispatcher for being a FIDL server listening MLME requests.
      async_dispatcher_t* server_dispatcher_;
    
      // The FIDL client to communicate with iwlwifi
      fdf::WireSharedClient<fuchsia_wlan_wlanphyimpl::WlanphyImpl> client_;
    
      // Dispatcher for being a FIDL client firing requests to WlanphyImpl device.
      fdf::Dispatcher client_dispatcher_;
     ...
    

    (來源:device_dfv2.h)

    您可以使用 fdf::Dispatcher::GetCurrent() 方法擷取驅動程式的預設調度器,或建立新的非預設調度器 (請參閱「更新 DFv1 驅動程式庫以使用非預設調度器」)。

在伺服器端執行下列操作:

  1. 從裝置類別繼承 FIDL 伺服器類別 (fdf::WireServer<ProtocolName>)。

  2. 宣告 FIDL 伺服器繫結到的調度器物件 (fdf::Dispatcher)。

    與用戶端端不同,伺服器端一律需要調度器,才能繫結 FIDL 伺服器物件。

    以下程式碼範例顯示裝置類別中的 FIDL 伺服器和調度器物件:

    class Device : public fidl::WireServer<fuchsia_wlan_device::Phy>,
                   public ::ddk::Device<Device, ::ddk::MessageableManual, ::ddk::Unbindable> {
     ...
     private:
      // Dispatcher for being a FIDL server listening MLME requests.
      async_dispatcher_t* server_dispatcher_;
     ...
    

    (來源:device_dfv2.h)

    您可以使用 fdf::Dispatcher::GetCurrent() 方法擷取驅動程式的預設調度器,或建立新的非預設調度器 (請參閱「更新 DFv1 驅動程式庫以使用非預設調度器」)。

.fidl 檔案中,執行下列操作:

  • 為用戶端和伺服器端定義驅動程式服務通訊協定

    以下程式碼範例顯示在 .fidl 檔案中定義的驅動程式庫服務通訊協定:

    service Service {
        wlan_phy_impl client_end:WlanPhyImpl;
    };
    

    (來源:phyimpl.fidl)

3. 更新驅動程式庫,以便使用驅動程式庫執行階段 FIDL

上一個步驟中進行變更後,您就可以開始更新驅動程式庫實作項目,以便使用驅動程式庫執行階段 FIDL。

在用戶端執行下列操作:

  1. 如要連線至父項裝置驅動程式庫程式新增至其傳出目錄的通訊協定,請呼叫 DdkConnectRuntimeProtocol() 函式,例如:

    auto client_end = DdkConnectRuntimeProtocol<fuchsia_wlan_softmac::Service::WlanSoftmac>();
    

    (來源:device.cc)

    這個函式會建立一組端點:

    • 函式會將 fdf::ClientEnd<ProtocolName> 物件傳回給呼叫端。
    • fdf::ServerEnd<ProtocolName> 物件會靜默傳送至父項裝置驅動程式庫。
  2. 當呼叫端取得用戶端端物件時,請將物件傳遞至 fdf::WireSharedClient<ProtocolName>() (或 fdf::WireSyncClient<ProtocolName>()) 的建構函式,例如:

    client_ = fdf::WireSharedClient<fuchsia_wlan_phyimpl::WlanPhyImpl>(std::move(client), client_dispatcher_.get());
    

    (來源:device.cc)

在伺服器端執行下列操作:

  1. 在裝置類別中宣告傳出目錄物件,例如:

    #include <lib/driver/outgoing/cpp/outgoing_directory.h>
    
    class Device : public DeviceType,
                   public fdf::WireServer<fuchsia_wlan_phyimpl::WlanPhyImpl>,
                   public DataPlaneIfc {
    ...
    
       fdf::OutgoingDirectory outgoing_dir_;
    

    (來源:device.h)

  2. 呼叫 fdf::OutgoingDirectory::Create() 函式,讓父項驅動程式庫建立傳出目錄物件,例如:

    #include <lib/driver/outgoing/cpp/outgoing_directory.h>
    
    ...
    
    Device::Device(zx_device_t *parent)
        : DeviceType(parent),
          outgoing_dir_(
              fdf::OutgoingDirectory::Create(
                 fdf::Dispatcher::GetCurrent()->get()))
    

    (來源:wlan_interface.cc)

  3. 將服務新增至傳出目錄並提供服務。

    父項驅動程式庫的服務通訊協定會提供至這個傳出目錄,以便子項驅動程式庫連線。

    在父項驅動程式庫程式的服務回呼函式 (這是在子節點連線至服務時呼叫的函式) 中,使用 fdf::BindServer() 函式將 fdf::ServerEnd<ProtocolName> 物件繫結至自身,例如:

    zx_status_t Device::ServeWlanPhyImplProtocol(
            fidl::ServerEnd<fuchsia_io::Directory> server_end) {
      // This callback will be invoked when this service is being connected.
      auto protocol = [this](
          fdf::ServerEnd<fuchsia_wlan_phyimpl::WlanPhyImpl> server_end) mutable {
        fdf::BindServer(fidl_dispatcher_.get(), std::move(server_end), this);
        protocol_connected_.Signal();
      };
    
      // Register the callback to handler.
      fuchsia_wlan_phyimpl::Service::InstanceHandler handler(
           {.wlan_phy_impl = std::move(protocol)});
    
      // Add this service to the outgoing directory so that the child driver can
      // connect to by calling DdkConnectRuntimeProtocol().
      auto status =
           outgoing_dir_.AddService<fuchsia_wlan_phyimpl::Service>(
                std::move(handler));
      if (status.is_error()) {
        NXPF_ERR("%s(): Failed to add service to outgoing directory: %s\n",
             status.status_string());
        return status.error_value();
      }
    
      // Serve the outgoing directory to the entity that intends to open it, which
      // is DFv1 in this case.
      auto result = outgoing_dir_.Serve(std::move(server_end));
      if (result.is_error()) {
        NXPF_ERR("%s(): Failed to serve outgoing directory: %s\n",
             result.status_string());
        return result.error_value();
      }
    
      return ZX_OK;
    }
    

    (來源:device.cc)

    請注意,fdf::BindServer() 函式需要調度器做為輸入內容。您可以使用驅動程式代管程序 (fdf::Dispatcher::GetCurrent()->get()) 提供的預設驅動程式庫調度器,也可以建立新的非預設調度器,分別處理 FIDL 要求 (請參閱「更新 DFv1 驅動程式庫以使用非預設調度器」)。

    此時,用戶端和伺服器端已準備好使用驅動程式庫執行階段 FIDL 互相通訊。

4. 提出 FIDL 要求

如要發出 FIDL 呼叫,請使用上一個步驟在用戶端端建立的 fdf::WireSharedClient<ProtocolName>() 物件 Proxy。

請參閱下列語法,瞭解如何發出 FIDL 呼叫 (其中 CLIENT_ 是執行個體名稱):

  • 非同步 FIDL 呼叫:

    CLIENT_.buffer(*std::move(arena))->MyExampleFunction().ThenExactlyOnce([](fdf::WireUnownedResult<FidlFunctionName>& result) mutable {
      // Your result handler.
    });
    

    (來源:device.cc)

  • 同步 FIDL 呼叫:

    auto result = CLIENT_.sync().buffer(*std::move(arena))->MyExampleFunction();
    // Your result handler.
    

    (來源:device.cc)

以下做法或許有助於您發出 FIDL 呼叫:

  • 您可以使用 FIDL 錯誤語法呼叫 result.is_error(),檢查呼叫是否傳回網域錯誤。同樣地,result.error_value() 呼叫會傳回確切的錯誤值。

  • 在進行非同步雙向用戶端 FIDL 呼叫時,您可以使用 .Then(callback).ThenExactlyOnce(callback) 指定待處理回呼的所需取消語意,而非傳遞回呼。

  • 同步 FIDL 呼叫會等待伺服器端的回呼。因此,您必須在 .fidl 檔案中為此呼叫定義回呼。否則,呼叫就會執行「發射並遺忘」並立即傳回。

    如需回呼定義,請參閱 .fidl 檔案中的以下範例:

    protocol MyExampleProtocol {
    // You can only make async calls based on this function.
      FunctionWithoutCallback();
    
      // You can make both sync and async calls based on this function.
      FunctionWithCallback() -> ();
    }
    

    建立回呼定義後,就必須在伺服器端實作函式 (在上述範例中,這會在同步和非同步回呼中一併叫用) (請參閱下方的 MyExampleFunction())。

    當伺服器端裝置類別繼承 fdf::WireServer<ProtocolName> 物件時,系統會產生根據您的通訊協定定義所建立的虛擬函式,類似於 fidl::WireServer<ProtocolName>。以下是這個函式的格式:

    void MyExampleFunction(MyExampleFunctionRequestView request, fdf::Arena& arena, MyExampleFunctionCompleter::Sync& completer);
    

    這個函式採用三個參數:

    • MyExampleFunctionRequestView:由 FIDL 產生,包含您要從用戶端傳送至伺服器的要求結構。

    • fdf::Arena:這是此 FIDL 訊息的緩衝區。這個緩衝區會從用戶端傳遞或移出。您可以將其用作緩衝區,透過 completer 物件傳回訊息或錯誤語法。您也可以重複使用此方法,對下一個層級的驅動程式發出 FIDL 呼叫。

    • MyExampleFunctionCompleter:由 FIDL 產生,用於叫用回呼,並將此 FIDL 呼叫的結果傳回至用戶端。如果定義了 FIDL 錯誤語法,您可以使用 completer.ReplySuccess()completer.ReplyError() 傳回訊息和錯誤狀態;如果未定義 FIDL 錯誤語法,則只能使用 completer.Reply() 傳回訊息。

  • 您可以將競技場物件移至 FIDL 呼叫,也可以直接將其傳遞為 *arena。不過,移動競技場物件可能會公開潛在錯誤。因此,建議您改為傳遞 arena 物件。由於競技場可能會用於下一個層級的 FIDL 呼叫,因此競技場物件不會在傳遞後遭到銷毀。

  • 如果驅動程式會傳送以 .fidl 檔案中自訂類型格式化訊息,FIDL 會根據定義產生自然類型和線路類型。不過,在這種情況下,建議使用線路類型,因為線路類型是更穩定的選擇。

  • 如果 FIDL 發現端點交換了無效值 (稱為驗證錯誤),就會關閉管道:

    • 驗證錯誤的最佳範例是傳遞 0 (針對非彈性列舉),但列舉只定義 1 到 5 的值。如果發生驗證錯誤,管道就會永久關閉,且所有後續訊息都會失敗。這與 Banjo 的行為不同。(詳情請參閱「嚴格與彈性」)。

    • 無效的值也包括 zx_handle_t 值設為 0 的核心物件。例如 zx::vmo(0)

(選用) 更新 DFv1 驅動程式庫,以便使用非預設調度器

fdf::Dispatcher::GetCurrent() 方法會提供驅動程式庫執行的預設調度器。建議您盡可能單獨使用這個預設調度器。不過,如果您需要建立新的非預設調度工具,驅動程式庫執行階段必須瞭解調度工具屬於哪個驅動程式庫。這可讓驅動程式庫架構設定適當的屬性,並正確關閉調度器。

以下各節將說明如何分配及管理自訂的非預設調度器,以便您進一步瞭解相關用途:

  1. 分配調度器
  2. 關閉調度器

1. 分配調度器

為確保調度器是在由驅動程式庫程式架構管理的執行緒中建立及執行,您必須在由驅動程式庫程式架構叫用的函式 (例如 DdkInit()) 中分配調度器,例如:

void Device::DdkInit(ddk::InitTxn txn) {
  bool fw_init_pending = false;
  const zx_status_t status = [&]() -> zx_status_t {
    auto dispatcher = fdf::SynchronizedDispatcher::Create(
        {}, "nxpfmac-sdio-wlanphy",
        [&](fdf_dispatcher_t *) { sync_completion_signal(&fidl_dispatcher_completion_); });
    if (dispatcher.is_error()) {
      NXPF_ERR("Failed to create fdf dispatcher: %s", dispatcher.status_string());
      return dispatcher.status_value();
    }
    fidl_dispatcher_ = std::move(*dispatcher);
  ...

(來源:device.cc)

2. 關閉調度器

同樣地,為了避免發生相同問題,調度器關閉作業也必須在驅動程式庫程式架構所叫用的函式中執行。DdkUnbind()device_unbind() 方法是這項作業的理想選擇。

請注意,調度器關閉作業是非同步的,因此需要妥善處理。舉例來說,如果調度器在 DdkUnbind() 呼叫中關閉,我們需要使用 ddk::UnbindTxn 物件 (先前從 Unbind() 呼叫傳遞),在調度器的關閉回呼中叫用 ddk::UnbindTxn::Reply() 呼叫,以確保能順利關閉。

以下程式碼片段示例說明上述關閉程序:

  1. DdkUnbind() 中儲存 ddk::UnbindTxn 物件:

    void DdkUnbind(ddk::UnbindTxn txn) {
      // Move the txn here because it’s not copyable.
      unbind_txn_ = std::move(txn);
      ...
    }
    
  2. 在繫結或 DdkInit() 鉤子的部分,請使用可叫用 ddk::UnbindTxn::Reply() 的關閉回呼建立調度器:

      auto dispatcher = fdf::Dispatcher::Create(0, [&](fdf_dispatcher_t*) {
        if (unbind_txn_)
          unbind_txn_->Reply();
        unbind_txn_.reset();
      });
    
  3. DdkUnbind() 結尾從調度器呼叫 ShutdownAsync()

    void DdkUnbind(ddk::UnbindTxn txn) {
      // Move the txn here because it’s not copyable.
      unbind_txn_ = std::move(txn);
      ...
      dispatcher.ShutDownAsync();
    }
    

不過,如果驅動程式庫中分配了多個調度器,因為 ddk::UnbindTxn::Reply() 只會呼叫一次,您就需要實作關閉作業的鏈結。舉例來說,假設您有 A 和 B 兩個可互換的調度器,您可以:

  1. 在 A 的關閉回呼中呼叫 B 的 ShutdownAsync()
  2. 在 B 的關閉回呼中呼叫 ddk::UnbindTxn::Reply()

(選用) 更新 DFv1 驅動程式庫,以便使用雙向通訊

通常只有用戶端端的裝置需要主動向伺服器端裝置提出要求。但在某些情況下,兩部裝置都需要透過管道傳送訊息,而不需要等待另一端回應。

如要在 DFv1 驅動程式庫中建立雙向通訊,您有以下三個選項:

  • 選項 1:在 FIDL 通訊協定中定義事件 (請參閱「實作 C++ FIDL 伺服器」)。

  • 選項 2:在相反方向實作第二個 FIDL 通訊協定,讓兩端裝置同時是伺服器和用戶端。

  • 選項 3:在 FIDL 中使用「hanging get」模式 (這是 FIDL 評分標準建議的流程控管設計模式)。

使用事件的理由 (選項 1) 包括:

  • 簡單:單一通訊協定比兩個通訊協定更簡單。

  • 序列化:如果您需要兩個通訊協定,則系統會保證事件和要求回覆會按照寫入管道的順序進行序列化。

不使用事件的理由 (選項 1) 包括:

  • 您需要在訊息從伺服器傳送到用戶端時回應訊息。

  • 您需要控制訊息流程。

以下通訊協定實作「選項 2」,在同一個 .fidl 檔案中定義兩個不同方向:

針對 WLAN 驅動程式庫遷移作業,團隊選取了「選項 2」,因為不會從不明網域引入其他 FIDL 語法。但請注意,WLAN 驅動程式庫是驅動程式庫執行階段遷移作業的第一個例項,且在遷移期間,系統不支援驅動程式庫傳輸中的 FIDL 事件。

視您的需求而定,「懸掛式 get」呼叫 (選項 3) 通常比事件更適合,因為它可讓用戶端指定是否已準備好處理事件,同時也提供流程控制。(不過,如有需要,您可以透過其他方式為事件加入資料流控制,詳情請參閱 FIDL 規範的「使用確認訊息來降低事件頻率」一節)。

更新 DFv1 驅動程式的單元測試,以便使用 FIDL

如果驅動程式有以 Banjo API 為基礎的單元測試,您需要遷移測試,以便提供模擬 FIDL 伺服器,而非 Banjo 伺服器 (或模擬 FIDL 用戶端)。

在 DFv1 中,如要模擬 FIDL 伺服器或用戶端,您可以使用 MockDevice::FakeRootParent() 方法,例如:

std::shared_ptr<MockDevice> fake_parent_ = MockDevice::FakeRootParent();

(來源:ft_device_test.cc)

MockDevice::FakeRootParent() 方法已與 DriverRuntime 測試程式庫整合 (這是 DFv1 唯一支援的測試程式庫)。MockDevice::FakeRootParent() 方法會為使用者建立 fdf_testing::DriverRuntime 例項。接著,執行個體會啟動驅動程式庫執行階段,並為使用者建立前景驅動程式庫調度器。不過,您也可以透過這個物件建立背景調度器。您可以使用 fdf_testing::DriverRuntime::GetInstance() 方法擷取例項。

例如,請參閱這個單元測試,模擬 DFv1 驅動程式庫程式的 PWM 和 vreg FIDL 通訊協定。

此外,下列程式庫可能有助於編寫驅動程式庫單元測試:

其他資源

本節提及的所有 Gerrit 變更

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

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