本疑難排解指南提供偵錯工作流程,可解決 Fuchsia 驅動程式庫開發中的一些常見錯誤。
偵錯工作流程
常見問題的偵錯工作流程:
無法啟動驅動程式
如果驅動程式無法載入、繫結或啟動,就表示無法「啟動」。
如要偵錯這個問題,請嘗試下列步驟:
1. 確認驅動程式庫已成功載入
如果驅動程式庫載入成功,記錄檔中會顯示類似下方的訊息:
Found boot driver: fuchsia-boot:///#meta/ahci.cm
或者,您也可以使用下列指令,轉儲所有驅動程式的清單:
ffx driver list這個指令會輸出類似以下的內容:
fuchsia-boot:///adc#meta/adc.cm
fuchsia-boot:///ahci#meta/ahci.cm
fuchsia-boot:///alc5514#meta/alc5514.cm
fuchsia-boot:///alc5663#meta/alc5663.cm
如果清單中沒有顯示驅動程式庫,表示載入失敗。
可能原因如下:
- 建構套件不含驅動程式。
- 驅動程式庫的元件資訊清單 (
.cml) 檔案有問題。
與元件資訊清單檔案相關的常見錯誤訊息:
Could not load driver: <...>: Failed to open bind fileCould not load driver: <...>: Missing bind pathFailed to start driver, missing 'binary' argument: ZX_ERR_NOT_FOUND
2. 確認驅動程式庫是否嘗試繫結
如果驅動程式庫嘗試繫結至節點,記錄中會顯示類似下列的訊息:
Binding driver fuchsia-boot:///#meta/focaltech.cm
如果沒有看到這則記錄訊息,可能是驅動程式庫繫結規則與節點屬性不符。如要對不相符的問題進行偵錯,請檢查驅動程式庫繫結規則,並與節點屬性進行比較。
如要查看所有節點屬性,請執行下列指令:
ffx driver list-devices -v這個指令會輸出類似以下的結果:
Name : pt
Moniker : acpi._SB_.PCI0.ISA_.RTC_.pt
Driver : unbound
5 Properties
[ 1/ 5] : Key fuchsia.BIND_ACPI_ID Value 0x000004
[ 2/ 5] : Key "fuchsia.acpi.HID" Value "PNP0B00"
[ 3/ 5] : Key fuchsia.BIND_PROTOCOL Value 0x00001e
[ 4/ 5] : Key "fuchsia.Service" Value "fuchsia.driver.compat.Service"
[ 5/ 5] : Key "fuchsia.Service" Value "fuchsia.hardware.acpi.Service"
2 Offers
Service: fuchsia.driver.compat.Service
Source: board
Instances: default
Service: fuchsia.hardware.acpi.Service
Source: board
Instances: default
不過,如果驅動程式庫是複合驅動程式,則必須確認複合節點規格符合複合驅動程式庫繫結規則,以及來自父項節點的節點屬性。
如要查看複合節點規格,請執行下列指令:
ffx driver list-composite-node-specs -v這個指令會輸出類似以下的結果:
Name : COM1-composite-spec
Driver : fuchsia-boot:///uart16550#meta/uart16550.cm
Nodes : 3
Node 0 : "acpi" (Primary)
2 Bind Rules
[ 1/ 2] : Accept "fuchsia.BIND_PROTOCOL" { 0x00001e }
[ 2/ 2] : Accept fuchsia.BIND_ACPI_ID { 0x000007 }
3 Properties
[ 1/ 3] : Key "fuchsia.BIND_PROTOCOL" Value 0x00001e
[ 2/ 3] : Key fuchsia.BIND_ACPI_ID Value 0x000007
[ 3/ 3] : Key "fuchsia.acpi.HID" Value "PNP0501"
Node 1 : "sysmem"
1 Bind Rules
[ 1/ 1] : Accept "fuchsia.Service" { "fuchsia.hardware.sysmem.Service" }
1 Properties
[ 1/ 1] : Key "fuchsia.Service" Value "fuchsia.hardware.sysmem.Service"
Node 2 : "irq000"
3 Bind Rules
[ 1/ 3] : Accept "fuchsia.BIND_ACPI_ID" { 0x000007 }
[ 2/ 3] : Accept "fuchsia.BIND_PLATFORM_DEV_INTERRUPT_ID" { 0x000001 }
[ 3/ 3] : Accept "fuchsia.Service" { "fuchsia.hardware.interrupt.Service" }
3 Properties
[ 1/ 3] : Key "fuchsia.BIND_ACPI_ID" Value 0x000007
[ 2/ 3] : Key "fuchsia.BIND_PLATFORM_DEV_INTERRUPT_ID" Value 0x000001
[ 3/ 3] : Key "fuchsia.Service" Value "fuchsia.hardware.interrupt.Service"
複合驅動程式庫與規格不符,Driver 欄位會顯示 None。
如果繫結規則和節點屬性不一致,請調整至兩者相符。
此外,如果繫結規則使用以 FIDL 為基礎的節點屬性,您必須在子項中新增供應項目,才能納入以 FIDL 為基礎的屬性。
舉例來說,假設繫結規則指定下列條件:
fuchsia.Service == "fuchsia.examples.gizmo.Service";
接著,目標節點的父項驅動程式庫必須將下列供應項目新增至節點:
zx::result child_result =
AddChild("zircon_transport_child", {}, {fdf::MakeOffer2<fuchsia_examples_gizmo::Service>()});
3. 確認驅動程式庫已順利啟動
如果驅動程式庫載入成功,記錄中會顯示類似下方的訊息:
Started driver url=fuchsia-boot:///ramdisk#meta/ramdisk.cm
但如果沒有這則記錄訊息,就表示驅動程式庫無法啟動。
如要偵錯這個問題,請先檢查是否呼叫了驅動程式庫 Start() 函式。
建議您更新 Start() 函式,輸出一些記錄訊息。
如果系統從未呼叫 Start() 函式,可能原因如下:
不過,如果呼叫 Start() 函式後,驅動程式庫仍無法啟動,可能會發生下列任一失敗情況:
- 驅動程式的
Start()函式會回覆或傳回錯誤。 - 驅動程式會覆寫
void Start(StartCompleter completer),且不會回覆完成者。
如果驅動程式庫的 Start() 函式回覆或傳回錯誤,記錄中會顯示類似下列的訊息:
[driver_host,driver] ERROR: [src/devices/bin/driver_host/driver_host.cc(134)] Failed to start driver url=fuchsia-pkg://fuchsia.com/simple_driver#meta/simple.cm status_str=ZX_ERR_INTERNAL
[driver_manager.cm] ERROR: [src/devices/bin/driver_manager/driver_host.cc(152)] Failed to start driver 'driver/simple.so' in driver host: ZX_ERR_INTERNAL
此時,請開始對 Start() 函式進行偵錯,找出錯誤原因。以下是可能的原因:
驅動程式無法與 FIDL 服務通訊 (PEER_CLOSED 錯誤)
如果驅動程式庫中的 FIDL 服務設定不正確,當驅動程式庫嘗試傳送要求至 FIDL 服務時,可能會收到 PEER_CLOSED 錯誤。
如要對 PEER_CLOSED 錯誤進行偵錯,請嘗試下列步驟:
此外,如要查看 DFv2 驅動程式中正確的 FIDL 服務設定,請參閱這些傳輸範例。
1. 驗證傳出目錄
檢查父項驅動程式庫程式將 FIDL 服務新增至傳出目錄的設定,例如:
zx::result result = outgoing()->AddService<fuchsia_examples_gizmo::Service>(std::move(handler));
if (result.is_error()) {
fdf::error("Failed to add service: {}", result);
return result.take_error();
}
2. 檢查執行個體名稱
如果目標驅動程式庫是複合驅動程式,則必須將父項節點的名稱傳遞至 FIDL 服務執行個體。
舉例來說,假設複合式驅動程式庫具有下列繫結規則:
composite mali;
using fuchsia.arm.platform;
using fuchsia.platform;
primary parent "mali" {
fuchsia.Service == "fuchsia.hardware.gpu.mali.Service";
}
parent "pdev" {
fuchsia.BIND_PROTOCOL == fuchsia.platform.BIND_PROTOCOL.DEVICE;
fuchsia.BIND_PLATFORM_DEV_VID == fuchsia.arm.platform.BIND_PLATFORM_DEV_VID.ARM;
fuchsia.BIND_PLATFORM_DEV_PID == fuchsia.platform.BIND_PLATFORM_DEV_PID.GENERIC;
fuchsia.BIND_PLATFORM_DEV_DID == fuchsia.arm.platform.BIND_PLATFORM_DEV_DID.MAGMA_MALI;
}
如要從名為 pdev 的父項節點連線至 fuchsia.hardware.platform.device 服務,驅動程式庫必須包含下列程式碼:
auto platform_device = incoming->Connect<fuchsia_hardware_platform_device::Service::Device>("pdev");
3. 檢查能力轉送問題
請參閱下方的「功能路徑錯誤」一節。
能力轉送錯誤
如要在 Fuchsia 中使用服務,必須在執行階段將服務的功能正確轉送至驅動程式庫。如要將能力轉送至子驅動程式庫,父項驅動程式庫必須公開能力,並提供給子項。
下列指令有助於診斷能力轉送問題:
ffx component doctor <DRIVER_URL>這個指令會輸出類似以下的內容:
$ ffx component doctor fuchsia-pkg://fuchsia.com/driver_transport#meta/driver_transport_child.cm
Moniker: bootstrap/full-drivers:dev.driver_transport_parent.driver_transport_child
Used Capability Result
[✓] fuchsia.logger.LogSink Success
[✗] fuchsia.examples.gizmo.Service `fuchsia.examples.gizmo.Service` was not offered to `bootstrap/full-pkg-
drivers:dev.driver_transport_parent.driver_transport_child`
by parent.
For further diagnosis, try:
$ ffx component route bootstrap/full-drivers:dev.driver_transport_parent.driver_transport_child fuchsia.examples.gizmo.Service
如要解決能力轉送相關問題,請嘗試下列步驟:
此外,如要瞭解功能在 DFv2 驅動程式中的路徑,請參閱這些傳輸範例。
1. 公開能力
如果父項驅動程式庫未正確公開能力,記錄中可能會顯示類似下列的訊息:
[full-drivers:dev.driver_transport_parent.driver_transport_child] WARN: Required service `fuchsia.examples.gizmo.Service` was not available for target component `bootstrap/full-drivers:dev.driver_transport_parent.driver_transport_child`: could not find capability: `fuchsia.examples.gizmo.Service` was not exposed to `bootstrap` from child `#full-drivers:dev.driver_transport_parent`. For more, run `ffx component doctor bootstrap`.
To learn more, see https://fuchsia.dev/go/components/connect-errors
如要修正這個問題,請檢查父項驅動程式庫程式的元件資訊清單 (.cml) 檔案,瞭解能力如何公開,例如:
{
include: [ 'syslog/client.shard.cml' ],
program: {
runner: 'driver',
binary: 'driver/driver_transport_parent.so',
bind: 'meta/bind/parent-driver.bindbc',
},
capabilities: [
{ service: 'fuchsia.examples.gizmo.Service' },
],
expose: [
{
service: 'fuchsia.examples.gizmo.Service',
from: 'self',
},
],
}
2. 提供能力
如要檢查子節點中是否有服務,請執行下列指令 (您也可以使用 ffx component doctor 指令):
ffx driver node list <child_node_name>這個指令會列印每個節點中提供的所有服務詳細資料,例如:
Name: intel-hda-000
Moniker: PCI0.bus.00_01_0.00_01_0.intel-hda-000
Owner: parent
Node State: Bound
Host Koid:
Parent Count: 1
Child Count: 1
Bus Topology: Bus Type Stability Address
Pci Stable 0, 1, 0
Node Properties: Key Value
fuchsia.BIND_PROTOCOL 76
fuchsia.Service fuchsia.driver.compat.Service
Node Offers: Service Source Instances
fuchsia.driver.compat.Service PCI0.bus.00_01_0.00_01_0 default
此外,如果在子節點中找不到優惠,記錄中可能會顯示類似下方的訊息:
[00008.035682][full-drivers:dev.driver_transport_parent.driver_transport_child] WARN: Required service `fuchsia.examples.gizmo.Service` was not available for target component `bootstrap/full-drivers:dev.driver_transport_parent.driver_transport_child`: could not find capability: `fuchsia.examples.gizmo.Service` was not offered to `bootstrap/full-drivers:dev.driver_transport_parent.driver_transport_child` by parent.
To learn more, see https://fuchsia.dev/go/components/connect-errors
如要修正這個問題,請檢查父項驅動程式庫程式包含提供給子項節點的供應項目設定,例如:
// Add a child with a `fuchsia.examples.gizmo.Service` offer.
zx::result child_result =
AddChild("driver_transport_child", {}, {fdf::MakeOffer2<fuchsia_examples_gizmo::Service>()});
if (child_result.is_error()) {
return child_result.take_error();
}
3. 使用能力
如要使用能力,驅動程式庫必須宣告要使用該能力。
如果未正確宣告,記錄中可能會顯示類似下方的訊息:
[00008.631682][full-drivers:dev.driver_transport_parent.driver_transport_child] WARN: No capability available at path /svc/fuchsia.examples.gizmo.Service/default/device for component bootstrap/full-drivers:dev.driver_transport_parent.driver_transport_child, verify the component has the proper `use` declaration.
如要修正這個問題,請檢查驅動程式庫的元件資訊清單 (.cml) 檔案,瞭解該能力的使用方式宣告,例如:
{
include: [ 'syslog/client.shard.cml' ],
program: {
runner: 'driver',
binary: 'driver/driver_transport_child.so',
bind: 'meta/bind/child-driver.bindbc',
colocate: 'true',
},
use: [
{ service: 'fuchsia.examples.gizmo.Service' },
],
}
錯誤訊息
Fuchsia 驅動程式庫開發的常見錯誤訊息:
Failed to load driver <...> driver note not foundRequired service <...> was not available for target componentDriver-Loader: libdriver.so: Not in allowlist__fuchsia_driver_registration__ symbol not availableCould not load driver: <...>: Failed to open bind file (or Missing bind path)no member named 'destroy' in 'fdf_internal::DriverServer<...>Failed to start driver, missing 'binary' argument: ZX_ERR_NOT_FOUND
無法載入驅動程式庫 <...> 找不到驅動程式庫附註
開發驅動程式庫時,記錄中可能會出現下列錯誤訊息:
Failed to load driver <...> driver not found
發生這項錯誤時,請檢查驅動程式庫的元件資訊清單 (.cml) 檔案是否正確。請參閱「駕駛人無法開啟」。
目標元件無法使用必要服務 <...>
如果驅動程式庫未正確公開服務能力,且未從父項驅動程式庫轉送至該功能,就會發生這項錯誤。
如要修正這個問題,請嘗試能力轉送錯誤工作流程。
不過,如果所需服務是 fuchsia.driver.compat,請按照下列操作說明進行:
如果驅動程式庫沒有從父項驅動程式庫轉送的 fuchsia.driver.compat 服務,就會發生錯誤。如要轉送這項服務,父項驅動程式庫必須為每個子項設定相容裝置伺服器。
如要修正這個問題,請從受影響的驅動程式庫開始,逐一檢查每個父項驅動程式庫。舉例來說,如果節點拓撲顯示 A->B->C->D,且 D 是受影響的驅動程式庫,請依序查看 C、B 和 A。請確認鏈結中每個父項驅動程式庫的相容裝置伺服器都已正確設定。
以下是設定相容裝置伺服器時常見的問題:
- 相容裝置伺服器必須使用正確的子節點名稱初始化。
- 必須從相容裝置伺服器新增附帶優惠的子項。
Driver-Loader: libdriver.so: Not in allowlist
如果 libdriver 位於驅動程式庫的其中一個依附元件 (可能是可轉移的),就會發生這項錯誤。
如要修正問題,請搜尋並從依附元件中移除 //src/devices/lib/driver。
如要找出依附元件,請使用下列指令:
fx gn path <out_directory> //path/to/driver //path/to/libdriver無法使用 __fuchsia_driver_registration__ 符號
開發驅動程式庫時,記錄中可能會出現下列錯誤訊息:
[driver_host,driver] ERROR: [src/devices/bin/driver_host/driver.cc(120)] __fuchsia_driver_registration__ symbol not available_.
[driver_host,driver] ERROR: [src/devices/bin/driver_host/driver.cc(316)] Failed to start driver 'fuchsia-pkg://fuchsia.com/fake-battery#meta/fake_battery.cm', could not Load driver: ZX_ERR_NOT_FOUND
如果驅動程式庫未包含 FUCHSIA_DRIVER_EXPORT2 巨集,就會發生這項錯誤。
如要修正這個問題,請參閱「新增驅動程式庫匯出巨集」。
此外,請確認巨集是在 .cc 檔案中定義,而不是在標頭 (.h) 檔案中。
無法載入驅動程式庫:<...>:無法開啟繫結檔案 (或缺少繫結路徑)
開發驅動程式庫時,記錄中可能會出現下列錯誤訊息:
Could not load driver: fuchsia-pkg://fuchsia.com/fake-battery#meta/fake_battery.cm: Failed to open bind file 'meta/bind/fake-battery-driver_2.bindbc'
或
Could not load driver: fuchsia-pkg://fuchsia.com/fake-battery#meta/fake_battery.cm: Missing bind path
如果驅動程式庫的元件資訊清單 (.cml) 檔案缺少 bind 欄位或欄位內容有誤,就會發生這項錯誤,例如:
{
include: [
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/fake_battery.so",
bind: <incorrect bind file path>,
},
}
bind 欄位值必須採用 meta/bind/<bind_output> 格式,其中 bind_output 是建構檔案中 driver_bind_rules 目標內同名的欄位,例如:
driver_bind_rules("fake_battery_bind") {
rules = "meta/fake-battery-driver.bind"
bind_output = "fake-battery-driver.bindbc"
deps = [ "//src/devices/bind/fuchsia.test" ]
deps += [ "//src/devices/bind/fuchsia.platform" ]
}
以這個繫結規則目標範例來說,元件資訊清單檔案中的正確 bind 欄位如下所示:
{
include: [
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/fake_battery.so",
bind: "meta/bind/fake-battery-driver.bindbc",
},
}
不過,如果未在繫結規則目標中明確定義 bind_output,預設值會是目標名稱加上 .bindbc,在上述範例中為 fake_battery_bind.bindbc。
無法啟動驅動程式庫,缺少「binary」引數:ZX_ERR_NOT_FOUND
編寫驅動程式庫時,記錄中可能會出現下列錯誤訊息:
Failed to start driver, missing 'binary' argument: ZX_ERR_NOT_FOUND
binary 欄位值必須採用 driver/<driver_output>.so 格式,其中 driver_output 是建構檔案中 fuchsia_driver 目標內具有相同名稱的欄位,例如:
fuchsia_cc_driver("driver") {
output_name = "simple"
sources = [ "simple_driver.cc" ]
deps = [
"//sdk/fidl/fuchsia.driver.compat:fuchsia.driver.compat_cpp",
"//sdk/lib/driver/compat/cpp",
"//sdk/lib/driver/component/cpp",
"//src/devices/bind/fuchsia.test:fuchsia.test_cpp",
"//src/devices/lib/driver:driver_runtime",
]
}
在這個繫結規則目標範例中,元件資訊清單檔案中正確的 binary 欄位如下所示:
{
include: [
"driver_component/driver.shard.cml",
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
program: {
runner: "driver",
binary: "driver/simple.so",
bind: "meta/bind/simple_driver.bindbc",
},
}
no member named 'destroy' in 'fdf_internal::DriverServer<...>'
如果驅動程式庫實作開放式 FIDL 通訊協定 (即 open protocol <PROTOCOL_NAME>),則驅動程式庫需要覆寫並實作 handle_unknown_method() 函式。
舉例來說,假設驅動程式庫實作了下列通訊協定:
open protocol VirtualController {
...
};
接著,這個驅動程式庫必須包含下列 handle_unknown_method() 函式:
void handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_hardware_bluetooth::VirtualController> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override;
其他資源
- 查看驅動程式庫資訊:參考頁面,包括如何使用
ffx driver進行偵錯。