本頁面提供有關下列主題的操作說明、最佳做法及範例: 將 Banjo 通訊協定轉換成 FIDL 通訊協定,做為 DFv1 至 DFv2 的一部分 或用於遷移驅動程式庫
將 DFv1 驅動程式庫從 Banjo 更新為 FIDL
更新驅動程式庫 .fidl
檔案是驅動程式庫很好的起點
但所有項目皆來自 .fidl
檔案。幸運的是
Banjo 和 FIDL 是從相同的 IDL (即 FIDL) 產生程式碼,因此您能
您可能不需要大幅變更現有的 .fidl
檔案。
下方的 .fidl
範例檔案顯示了
Banjo 至 FIDL 遷移作業:
- 變更前 (Banjo):
//sdk/banjo/fuchsia.hardware.wlanphyimpl/wlanphy-impl.fidl
敬上 - 變更後 (FIDL):
//sdk/fidl/fuchsia.wlan.phyimpl/phyimpl.fidl
如要將 DFv1 驅動程式庫從 Banjo 更新為 FIDL,請進行下列變更
(主要位於驅動程式庫 .fidl
檔案中):
1. 在通訊協定定義之前更新屬性
如要使用 Banjo,您必須在 .fidl
中使用 @transport("Banjo")
屬性
檔案。不過,對 FIDL 而言,此屬性並非必要,因為 FIDL 是
)。因此,您可以直接將 @transport("Banjo")
屬性從
驅動程式的 .fidl
檔案,例如:
使用 Banjo:
@transport("Banjo") @banjo_layout("ddk-protocol") protocol MyExampleProtocol { ... }
如何使用 FIDL:
@discoverable @transport("Driver") protocol MyExampleProtocol { ... }
上述範例中,
@discoverable
屬性 是所有 FIDL 通訊協定的必填屬性。這項屬性可讓 用戶端以使用產生的名稱搜尋這個通訊協定。不過,
@transport("Driver")
屬性 (表示 這是驅動程式傳輸通訊協定) 的選填屬性。 並使用驅動程式執行階段 FIDL 的驅動程式。 而且只有在駕駛人交談時,才需要遷移驅動程式庫執行階段 同一位驅動程式代管程序的其他駕駛。如需更多駕駛傳輸通訊協定的範例,請參閱 驅動程式傳輸範例目錄。
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
檔案,新增下列程式碼
不允許:
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. 更新驅動程式庫執行階段的依附元件
更新伺服器和用戶端,加入新的依附元件,以便使用 驅動程式庫執行階段:
在
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
)在原始碼標頭中更新
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。
在用戶端端執行下列操作:
宣告 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
)(僅適用於非同步呼叫) 宣告調度工具物件 裝置類別中 (
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 驅動程式庫以使用非預設調度工具)。
在伺服器端內執行下列操作:
繼承 FIDL 伺服器類別 (
fdf::WireServer<ProtocolName>
)宣告 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。
在用戶端端執行下列操作:
連線至家長裝置驅動程式新增的通訊協定 其傳出目錄,呼叫
DdkConnectRuntimeProtocol()
函式,例如:auto client_end = DdkConnectRuntimeProtocol<fuchsia_wlan_softmac::Service::WlanSoftmac>();
(資料來源:
device.cc
)這個函式會建立一組端點:
- 這個函式會傳回
fdf::ClientEnd<ProtocolName>
物件 。 fdf::ServerEnd<ProtocolName>
物件會在不發出通知的情況下, 家長裝置驅動程式庫。
- 這個函式會傳回
呼叫端取得用戶端端物件時,將物件傳送至
fdf::WireSharedClient<ProtocolName>()
的建構函式 (或fdf::WireSyncClient<ProtocolName>()
),例如:client_ = fdf::WireSharedClient<fuchsia_wlan_phyimpl::WlanPhyImpl>(std::move(client), client_dispatcher_.get());
(資料來源:
device.cc
)
在伺服器端內執行下列操作:
在裝置類別中宣告傳出目錄物件,例如:
#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
)呼叫
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
)將服務新增至傳出目錄並提供服務。
父項驅動程式庫程式的服務通訊協定會提供給這個傳出目錄 讓兒童驅動程式庫連接該裝置
在父項驅動程式的服務回呼函式 (為函式) 子項節點連線至服務時會呼叫的物件)
fdf::ServerEnd<ProtocolName>
使用fdf::BindServer()
函式,例如: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 驅動程式庫以使用非預設調度工具)。此時用戶端和伺服器已準備好互相通訊 來下載該驅動程式庫
4. 提出 FIDL 要求
如要發出 FIDL 呼叫,請使用
在用戶端上建構的 fdf::WireSharedClient<ProtocolName>()
物件
即可。
請參閱以下執行 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
。不過,移動競技物件可能會公開潛在錯誤。 因此,建議您改為傳遞 Area 物件。由於 競技場可重複使用進行下一個層級的 FIDL 呼叫,但 Area 物件不會 已刪除。如果您的驅動程式庫傳送的訊息格式為
.fidl
檔案,FIDL 會根據 定義然而,在這個情況中,建議你使用接線類型,因為 線型是暫時的, HLCPP 的類型。如果 FIDL 偵測到端點交換無效,就會關閉其管道 這就是驗證錯誤:
驗證錯誤範例的其中一個例子,就是傳遞 0 (表示非彈性) 列舉) 只會定義 1 到 5 的值。需要進行驗證時 管道將永久關閉,而後續收到的所有訊息 也會失敗這個行為與 Banjo 不同。( 請參閱嚴格與彈性)。
無效值還包括具有
zx_handle_t
值的核心物件 設為 0。例如zx::vmo(0)
。
(選用) 更新 DFv1 驅動程式庫以使用非預設調度工具
fdf::Dispatcher::GetCurrent()
方法可讓您
執行驅動程式庫的預設調度器。
建議您盡可能只使用這個預設調度工具。不過
如果您需要建立新的非預設調度工具,
不需要瞭解調度器屬於哪個驅動程式庫。這樣一來,
以便設定適當屬性並關閉驅動程式庫程式
正確設定調度器
以下各節說明分配及管理資源的進階用途 您自己的非預設調度工具:
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()
呼叫調度工具的關閉回呼,以確保乾淨關機。
以下程式碼片段範例示範關閉程序 前提:
將
ddk::UnbindTxn
物件儲存在DdkUnbind()
中:void DdkUnbind(ddk::UnbindTxn txn) { // Move the txn here because it’s not copyable. unbind_txn_ = std::move(txn); ... }
做為繫結或
DdkInit()
掛鉤的一部分,建立具有下列權限的調度工具: 叫用ddk::UnbindTxn::Reply()
的關閉回呼:auto dispatcher = fdf::Dispatcher::Create(0, [&](fdf_dispatcher_t*) { if (unbind_txn_) unbind_txn_->Reply(); unbind_txn_.reset(); });
從
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
(可互換),您可以:
- 在 A 的關閉回呼中呼叫 B 的
ShutdownAsync()
。 - 在 B 的關閉回呼中呼叫
ddk::UnbindTxn::Reply()
。
(選用) 更新 DFv1 驅動程式庫以使用雙向通訊
通常只有用戶端上的裝置才需要主動 向伺服器端裝置發出要求但在某些情況下 不必等待整個管道 回應。
如要在 DFv1 驅動程式庫中建立雙向通訊, 下列三種選項:
方法 1:在 FIDL 通訊協定中定義事件 (請參閱「實作 C++ FIDL 伺服器」一節)。
選項 2:反向實作第二個 FIDL 通訊協定 讓兩端的裝置會同時成為伺服器和用戶端
方法 3:使用 FIDL 中的「hanging get」模式 (a FIDL 評分量表建議的流量控制設計模式)。
使用事件的原因 (方法 1) 包括:
簡單 - 一個通訊協定比兩個簡單。
序列化 - 如果您需要兩個通訊協定,事件和回應回覆都是 保證會依照寫入管道的順序進行序列化。
不使用事件的原因 (方法 1) 包括:
您必須在郵件從伺服器傳送到 用戶端。
您需要控制郵件流程。
下列通訊協定實作選項 2,不過兩者的定義是
.fidl
檔案代表兩個不同方向:
在進行 WLAN 驅動程式庫遷移時,團隊選擇了選項 2,因為該選項 將引進其他來自未知網域的 FIDL 語法。但 必須注意的是,WLAN 驅動程式庫是第一個驅動程式庫執行階段 且目前系統不支援驅動程式庫傳輸中的 FIDL 事件 。
視您的需求而定,發送通知通話 (選項 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 通訊協定
此外,下列程式庫也有助於編寫驅動程式庫單元測試:
//src/devices/bus/testing/fake-pdev/fake-pdev.h
- 這個 輔助程式庫實作假的 pdev FIDL 通訊協定版本。
其他資源
本節提及的所有「Gerrit 變更」:
- [iwlwifi][wlanphy] 驅動程式執行階段遷移(wlanphy <--> iwlwifi)
- [iwlwifi][wlansoftmac] 驅動程式執行階段遷移(wlansoftmac <--> iwlwifi)
本節提及的所有原始碼檔案:
//sdk/banjo/fuchsia.hardware.wlanphyimpl/wlanphy-impl.fidl
//sdk/fidl/fuchsia.wlan.phyimpl/phyimpl.fidl
//sdk/fidl/fuchsia.wlan.softmac/softmac.fidl
//sdk/lib/driver/component/cpp/tests/driver_base_test.cc
//sdk/lib/driver/testing/cpp
//src/connectivity/wlan/drivers/third_party/nxp/nxpfmac/device.cc
//src/connectivity/wlan/drivers/wlansoftmac/device.cc
//src/connectivity/wlan/drivers/wlansoftmac/meta/wlansoftmac.cml
//examples/drivers/transport/driver/
本節提及的所有說明文件頁面:
- Banjo
- FIDL
- RFC-0126:驅動程式執行階段
- 新 C++ 繫結教學課程
- 駕駛員調度程式和執行緒
- FIDL 屬性
- 實作 C++ FIDL 伺服器
- HLCPP 教學課程
- 定義驅動程式庫服務通訊協定 (根據「揭露驅動程式庫」一節)
- 嚴格與彈性 (依據 FIDL 語言規格)
- 使用特別銘謝 (來源:FIDL API Rubric)
- 使用等待機制延遲回應 (來源:FIDL API Rubric)