本頁面提供有關下列主題的操作說明、最佳做法及範例: 更新 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 世界中的相容性輔助程式。不過 兩者的差異如下:
在情境 3 中,驅動程式庫會連線至
fuchsia_driver_compat::Service::Device
通訊協定 然後驅動程式庫驅動程式庫呼叫ConnectFidl()
方法,藉此連線至實際的 通訊協定 (如需範例,請參閱 Gerrit 變更)。
如要更新情境 2 或 3 以下的驅動程式,請參閱 DFv1 驅動程式庫到 DFv2 驅動程式庫 (含相容性輔助鍵) 以下章節。
DFv2 驅動程式庫至 DFv2 驅動程式庫
為了讓其他 DFv2 驅動程式找到你的驅動程式庫服務, :
更新驅動程式的
.fidl
檔案。如要使用 DFv2 探索通訊協定,就必須為以下項目新增
service
欄位: 驅動程式庫的通訊協定,例如:library fuchsia.example; @discoverable @transport("Driver") protocol MyProtocol { MyMethod() -> (struct { ... }); }; service Service { my_protocol client_end:MyProtocol; };
更新子項驅動程式庫。
DFv2 驅動程式能以與 FIDL 服務相同的方式連線至通訊協定, 例如:
incoming()->Connect<fuchsia_example::Service::MyProtocol>();
您也需要更新元件資訊清單 (
.cml
) 檔案,才能使用 驅動程式執行階段服務,例如:use: [ { service: "fuchsia.example.Service" }, ]
更新父項驅動程式庫。
家長驅動程式庫需要使用
fdf::DriverBase
的outgoing()
函式來取得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 驅動程式庫服務 :
更新 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", }, ], }
更新 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 驅動程式庫互動的其他驅動程式。
請完成下列步驟:
更新分葉驅動程式的元件資訊清單 (也就是說, 子項驅動程式) 及下列變更:
- 從以下位置移除
//sdk/lib/driver/compat/compat.shard.cml
: 「include
」欄位中的值。 - 將
program.compat
欄位替換為program.binary
。
- 從以下位置移除
對於執行 幾項工作:
- 存取核心
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
節點,您必須新增
NodeAddArgs
的 device_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 驅動程式的程式庫:
-
TestNode
– 此類別會實作fuchsia_driver_framework::Node
通訊協定,提供給驅動程式庫以建立子節點。這個 測試也會使用類別來存取驅動程式庫的子項節點TestEnvironment
- 針對OutgoingDirectory
物件套用的包裝函式 可做為傳入網路的備用 VFS (虛擬檔案系統) 測試中驅動程式庫的命名空間。DriverUnderTest
- 本課程為 RAII 級 (資源獲取為初始化) 包裝函式 安裝在測試中的驅動程式庫DriverRuntime
– 此類別是代管驅動程式庫上的 RAII 包裝函式 執行階段執行緒集區。
//sdk/lib/driver/testing/cpp/driver_runtime.h
TestSynchronizedDispatcher
– 此類別是針對 驅動程式庫調度工具
下列程式庫有助於編寫驅動程式庫單元測試:
//src/devices/bus/testing/fake-pdev/fake-pdev.h
- 這個 輔助程式庫實作假的pdev
FIDL 通訊協定版本。
最後,下列單元測試範例涵蓋不同設定和 測試案例:
//sdk/lib/driver/component/cpp/tests/driver_base_test.cc
: 這個檔案包含驅動程式的各種執行緒模型範例//sdk/lib/driver/component/cpp/tests/driver_fidl_test.cc
: 這個檔案示範如何使用傳入和傳出的 FIDL 由驅動程式庫運送及 Zircon 運輸服務,以及devfs
。
其他資源
部分 DFv2 驅動程式範例:
本節提及的所有「Gerrit 變更」:
- [iwlwifi] iwlwifi 驅動程式適用的 Dfv2 遷移作業
- [compat-runtime-test] 停止使用 DeviceServer
- [msd-arm-mali] 新增 DFv2 版本
- [sdk][驅動程式庫][testing] 新增測試程式庫
本節提及的所有原始碼檔案:
//examples/drivers/transport/zircon/v2/parent-driver.cc
//sdk/fidl/fuchsia.driver.framework/topology.fidl
//sdk/lib/driver/component/cpp/driver_base.h
//sdk/lib/driver/component/cpp/tests/driver_base_test.cc
//sdk/lib/driver/component/cpp/tests/driver_fidl_test.cc
//sdk/lib/driver/compat/cpp/banjo_server.h
//sdk/lib/driver/compat/cpp/banjo_client.h
//sdk/lib/driver/compat/cpp/device_server.h
//sdk/lib/driver/testing/cpp/driver_runtime.h
//src/connectivity/wlan/testing/wlantap-driver/wlantap-driver.cc
//src/devices/bus/testing/fake-pdev/fake-pdev.h
//src/devices/tests/v2/compat-runtime/root-driver.cc
//src/lib/ddk/include/lib/ddk/device.h
//src/lib/ddk/include/lib/ddk/driver.h
本節提及的所有說明文件頁面:
- 班究琴
- 驅動程式和節點
- 駕駛人溝通
- 驅動程式和節點
- 駕駛員調度程式和執行緒
- 駕駛
- 複合節點
- 公開驅動程式庫
- Fuchsia 元件檢查總覽
- 模擬 DDK 遷移
- 撕下序列示例 (來自驅動程式庫生命週期)
- 父項驅動程式 (伺服器) (來源:FIDL 教學課程)
- 產生的繫結程式庫 (來源:FIDL 教學課程)