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

本頁會在 DFv1 至 DFv2 驅動程式庫的遷移作業中,將 Banjo 通訊協定轉換為 FIDL 通訊協定的相關操作說明、最佳做法和範例。

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

更新驅動程式庫程式的 .fidl 檔案是個不錯的起點,因為一切都源自於 .fidl 檔案。幸運的是,Banjo 和 FIDL 會透過相同的 IDL (即 FIDL) 產生程式碼,因此您不必對現有的 .fidl 檔案進行重大變更。

以下 .fidl 檔案範例顯示了 Banjo-to-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") 屬性 (表示這是驅動程式傳輸通訊協定) 為選用屬性。只有當駕駛人與相同驅動程式代管程序中的其他驅動程式通訊時,才需要遷移驅動程式庫執行階段。

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

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 目標

編輯此 .fidl 檔案的 BUILD.gn 檔案,在 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 檔案。在這種情況下,您可以在 sdk/banjo 目錄中保留這個 .fidl 檔案的副本。

(選用) 更新 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
    

    使用您的 FIDL 程式庫名稱取代 YOUR_FIDL_LIB,例如:

    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 的形式傳遞。然而,移動舞台物件可能會公開潛在的錯誤。因此,建議您傳送 Iaa 物件。由於該區域可重複用於下一個層 FIDL 呼叫,因此傳遞之後不會刪除運動場物件。

  • 如果驅動程式傳送 .fidl 檔案中自行定義類型的訊息,FIDL 會根據定義產生性質類型和傳輸類型。不過,本案例建議使用線路類型,因為線路類型較為穩定,而性質類型則是 HLCPP 的臨時類型。

  • 如果 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. ddk::UnbindTxn 物件儲存在 DdkUnbind() 中:

    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 中的「Hhanging get」模式 (FIDL 評分量表建議的流量控制設計模式)。

使用事件的原因 (方法 1) 包括:

  • 簡單 - 單個通訊協定比兩個簡單。

  • 序列化 - 如果您需要兩個通訊協定,事件和對要求的回覆保證會依照寫入管道的順序序列化。

不使用事件的原因 (方法 1) 包括:

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

  • 您必須控制訊息流。

下列通訊協定會實作選項 2,在相同 .fidl 檔案中定義兩種不同方向:

進行 WLAN 驅動程式庫遷移時,團隊選擇了選項 2,因為該團隊不會從不明網域導入額外的 FIDL 語法。但請注意,WLAN 驅動程式庫是驅動程式庫執行階段遷移作業的第一個執行個體,且在遷移時不支援驅動程式庫傳輸中的 FIDL 事件。

視您的需求而定,「等待中」呼叫 (選項 3) 通常是比事件更好的選項,因為前者可讓用戶端指定其已可處理事件,同時也提供流量控制。(但如有需要,您也可以透過 FIDL Rubric 的「使用確認事件節流事件」一節中說明,透過其他方式為事件新增流量控管機制。)

更新 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 變更

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

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