RFC-0263:將驅動程式庫通訊遷移至服務

RFC-0263:將驅動程式庫通訊遷移至服務
狀態已接受
領域
  • Driver SDK
說明

將驅動程式和用戶端從連線至 devfs 遷移至使用服務。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2024-08-25
審查日期 (年-月-日)2024-10-28

問題陳述

目前,非驅動程式幾乎都會透過裝置檔案系統 (devfs) 存取驅動程式。不過,開發人員的缺點如下:

  • 很難將 devfs 用戶端限制為特定通訊協定。
  • 這個 API 會讓開發人員難以公開多個通訊協定。
  • 拓樸路徑和硬式編碼的類別路徑會向用戶端揭露內部實作詳細資料,可能導致意外中斷。
  • 由於元件管理員無法辨識開發者連線,因此無法用於追蹤依附元件,但目前任何驅動程式庫和用戶端都可以從開發服務遷移至匯總服務,因此驅動程式庫作者在執行這類遷移作業時,目前面臨了重大的挑戰。

摘要

我們建議改變非驅動程式存取驅動程式的方式,將這類存取權移轉至使用元件管理工具所調解的匯總服務。這項遷移作業將包含拓撲路徑 (/dev/sys/) 和類別路徑 (/dev/class/)。在這個程序中,使用 fuchsia.device/Controller 通訊協定的用戶端,其對驅動程式的任何剩餘存取權也將遭到移除。這份 RFC 將說明遷移至匯總服務時面臨的挑戰,並提出解決方案,確保不對驅動程式庫作者造成不必要的影響。我們也希望為驅動程式庫程式提供更多標準化機制,以改善程式碼健康狀態,並減少編寫驅動程式和用戶端的困難。

利害關係人

協助人員:

審查者:

  • cja@
  • suraj@
  • csuter@
  • jfsulliv@
  • 元件架構團隊

諮詢:

  • 駕駛團隊 / 驅動程式庫作者

社會化:

此 RFC 也與驅動程式架構團隊進行設計審查。

背景

直到最近,Fuchsia 中的驅動程式並非元件,且非驅動程式與驅動程式庫通訊的唯一方式是透過 devfs。驅動程式管理器會維護 devfs,並填入兩個相關的分支:/dev/sys/ 和 /dev/class。

  • /dev/sys/ 會從板卡驅動程式庫做為根目錄開始填入,並代表驅動程式管理器中的父項-子項繫結關係階層。這個分支中的路徑稱為「拓樸路徑」。元件可透過「dev-topological」目錄能力存取拓樸路徑。
  • 新增子裝置時,驅動程式庫會指定類別名稱,並填入 /dev/class/。接著,驅動程式管理員會新增與驅動程式庫相對應的 /dev/class// 項目。這項功能可讓具有類似輸出內容的驅動程式歸為一組,例如所有相機都有一個 /dev/class/camera 中的一個項目。這個分支版本中的路徑稱為「類別路徑」。具有「dev-class」目錄功能存取權的元件可以開啟類別路徑,但通常會進一步限制存取特定類別資料夾。

無論是哪個分支,驅動程式項目都允許兩種驅動程式庫存取權:device_controller 和 device。

  • device_controller 提供 fuchsia.device/Controller 介面,可讓元件查詢、繫結及重新繫結驅動程式庫。
  • 裝置會為驅動程式庫提供特定驅動程式庫介面,實際上會與驅動程式庫新增子裝置時指定的類別名稱相關聯。舉例來說,目前所有新增裝置的驅動程式都會使用類別名稱「camera」,提供 fuchsia.hardware.camera 介面,而連線至 /dev/class/camera/000 (如果存在) 會將連線例項化為該驅動程式庫的 fuchsia.hardware.camera 介面。

過去幾年,我們已盡力隔離並移除 fuchsia.device/Controller 介面的用途,因此移除這些用途將視為超出本 RFC 範圍。我們在此提及這項資訊,是為了完整性,並提醒您,透過匯總服務提供的介面不會有類似的介面。

提振精神

這項遷移作業的主要目標,是移除用於存取驅動程式的 devfs 系統,並以更標準化的服務為基礎的連線模型取代。這種方法有許多優點,其中許多都與 devfs 的缺陷有關:

  • 提高依附元件和連線的可見度。讓用戶端透過服務能力連線,元件管理員就能追蹤連線並維護正確的依附元件圖表。使用 devfs 時無法做到這點,因為其結構對元件管理員來說幾乎不透明。
  • 服務提供更完善的文件和更彈性的方式,可從驅動程式庫匯出功能。使用 devfs 時,每個裝置執行個體只能提供一個通訊協定,且通訊協定類型不會明確定義。匯總服務可提供多個通訊協定,且每個通訊協定都會在服務定義中明確列出。
  • 更明確且嚴密控管的存取權。元件必須指定所要求的服務類型,這與 devfs 中的拓樸路徑不同,後者可讓元件存取任何驅動程式庫。
  • 移除對拓樸路徑的依賴性。拓撲路徑可讓您瞭解每位驅動程式庫如何由驅動程式管理器安裝。因此,硬式編碼拓撲路徑代表對驅動程式庫程式架構內部工作的依附元件,我們希望避免這個情況。

此外,devfs 存取權可透過多種方式完成,包括同步和非同步,以及依據類別路徑和拓樸路徑。我們希望提供單一方法,讓開發人員和非開發人員都能連結相同的服務,這應該有助於改善程式碼健康度,並降低撰寫驅動程式和用戶端的難度。

需求條件

遷移作業必須為所有現有的 devfs 使用者提供解決方案,以免失去任何功能。此外,驅動程式和用戶端必須能夠執行軟遷移作業,新增服務並連線至服務,且不必要求提供服務的所有用戶端和驅動程式同時遷移。

設計

驅動程式架構作業

每次將用戶端或驅動程式庫從開發人員遷移後,都必須個別處理。不過,驅動程式庫架構需要執行一些工作,才能解決上述問題。

類別名稱 <-> 通訊協定 / 服務對應

為輔助轉換,類別名稱、通訊協定名稱和服務名稱之間的對應會套入 c++ 標頭。目前沒有明確的對應項目,只有用戶端和驅動程式之間的隱含協議,也就是每個類別都對應至特定的 fidl 通訊協定。明確建立這項對應關係後,您可以執行下列步驟:

  • 確保 /dev/class/<classname> 的用戶端和伺服器同意使用特定通訊協定
  • 允許用戶端從連線至 /dev/class/<classname> 遷移至 fuchsia.hardware.<protocolname>

這項對應作業需要為每個類別名稱建立服務 (目前約有 200 個可能的類別名稱)。如果目前只能透過拓樸路徑存取的服務,可能需要在這個對應中建立其他項目。這項對應僅適用於遷移期間。每個類別遷移完成後,即可從對應中移除其項目。

公車資訊傳播

移除拓撲路徑後,驅動程式管理器會負責將公車資訊從公車司機傳送給所有子系驅動程式中傳播,以便用於服務執行個體。驅動程式庫程式庫可簡化儲存及擷取這項資訊的流程。

啟用軟體遷移:

當驅動程式和用戶端從 devfs 遷移至服務時,我們必須確保一方能夠處理或提供兩種連線類型,以提供連線的連續性。此外,我們必須確保另一方不會同時提供兩種連線類型,以免出現重複項目。舉例來說,如果驅動程式庫 A 和 B 都為用戶端 C 和 D 提供 Foo 連線,如果驅動程式庫 A 單純切換至服務,用戶端就必須在 devfs 和服務之間做出選擇,且只能看到一項服務。解決方法是遷移多個步驟。如要達成這項遷移作業,有多種做法可以選擇,在兩個面的其中一層進行額外工作。無論採用哪種選項,遷移階段都能依個別類別進行,以便輕鬆推行,也能讓不同類別自訂遷移策略。

建議選項:透過 devfs 自動宣傳服務

修改 devfs,自動為每個 devfs 項目宣傳服務。服務類型會透過類別名稱表示,使用前述的類別名稱 -> 服務對應。在同樣的變更中,devfs 也會將與對應類別名稱相對應的所有服務功能公開給引導程式元件。為類別名稱啟用服務後,用戶端就能改用服務,接著驅動程式就會切換至廣告服務。驅動程式遷移作業只需移除 DevfsAddArgs,並改為呼叫 AddService。最大的缺點是,驅動程式庫轉換作業會在類型轉換的所有用戶端上遭到封鎖。

遷移順序會是: 1) 變更開發人員服務以宣傳服務 2) 用戶端轉換為服務 3) 驅動程式通告服務並移除 devf

替代方法 1:建立用戶端工具:DeviceAndServiceWatcher

建立工具,在收到類別名稱 / 服務名稱時,連結至匯總服務和 /dev/class/ 目錄,並等待項目顯示。新增服務或目錄項目時,無論來源為何,用戶端會收到通知並提供匯總服務執行個體。為了讓這項工具發揮效用,我們要求驅動程式絕對不要同時宣傳服務和 devfs 項目。這個選項較難實作,而且在包裝 fidl 管道方面會有一些困難,以使 devfs 項目的運作方式像服務一樣運作。不過,與偏好的選項一樣,這項選項會限制駕駛人只能進行一次變更,並確保變更有效。另外,驅動程式也必須等到所有類別的用戶端都完成轉換後,才能轉換。不過,當驅動程式切換至服務時,用戶端可能會失敗,因為可能無法正確路由功能。

遷移順序如下: 1) 新增 DeviceAndServiceWatcher 2) 遷移的用戶端以使用 DeviceAndServiceWatcher 3) 驅動程式通告服務,並移除 devfs 4) 完成所有遷移作業後, 從 DeviceAndService Watcher 中移除 devfs 邏輯

替代方法 2:延遲移除 devfs

請驅動程式在宣傳服務後,繼續提供 devfs 項目。在用戶端轉換後,驅動程式可以移除 devfs 程式碼。這樣做的好處是不會阻擋驅動程式庫程式轉換,但之後仍需要對驅動程式庫進行變更。此外,這也有一些缺點:新的 AddService 程式碼不會立即執行,因此當用戶端最終切換為使用服務時,可能還需要對驅動程式庫進行其他變更,除了驅動程式庫必須進行的變更,以移除 devfs 程式碼。

遷移順序會是: 1) 驅動程式新增服務 2) 用戶端轉換為服務 3) 驅動程式移除開發者

實作

您可以針對與特定類別名稱互動的每組驅動程式和用戶端,逐步執行這項遷移作業。您需要提供一些工具和程式庫,驅動程式庫程式架構會執行幾次遷移作業,確保程式庫符合遷移驅動程式和用戶端的需求。在確保遷移程序足夠符合人體工學後,我們會將類別名稱的遷移作業加入開放式工作,讓更多 Fuchsia 社群成員參與。特定類別/介面會視為需要多加留意,因此需要更協調的方法。這包括仍使用 fuchsia.device/Controller 介面的所有用戶端,這些用戶端必須先解決相關問題,才能遷移。一旦所有驅動程式和用戶端都遷移到服務,即可移除 devf 的內部實作。

遷移機制

為進一步說明如何完成遷移作業,以下列出轉換特定類別的驅動程式庫程式步驟:

1) 新增類別名稱 <-> 通訊協定 / 服務對應

  1. 類別與 fidl 通訊協定的對應必須依據目前的使用方式推斷。
  2. 接著,您需要建立服務來包裝通訊協定,並在適當的標頭中記錄類別與服務的對應關係。這樣 devfs 就能開始宣傳這項服務。
  3. 接著,您必須更新 CML 檔案,將服務轉送至用戶端。

2) 用戶端遷移

用戶端遷移作業的複雜度會因用戶端使用拓樸路徑或類別路徑而異。用戶端遷移可分為兩個階段:識別所需的服務供應商,以及連線至服務。第一步可能已由使用類別路徑的用戶端完成。

找出所需的服務供應商

此遷移步驟必須由執行下列任一作業的用戶端實作:

  • 使用拓撲路徑
  • 使用硬式編碼類別路徑 (例如/dev/class/camera/000)
  • 連線至特定 devfs 項目的 device_controller,然後呼叫 GetTopologicalPath()

在上述每種情況中,用戶端都會從以下情況遷移:服務/fidl 介面的供應商 (或似乎) 會同步傳送至匯總服務,在匯總服務中,會以非同步方式新增及移除執行個體,且無法使用執行個體名稱進行識別。

有幾種方法適用於這類客戶:

  • 連線至可用的首個服務執行個體。對於只需要一個服務供應商 (例如電源控制器) 的簡單工具和測試,這通常就足夠了。這也讓用戶端可以維持連線為同步的假設。由於不然系統的非同步性質,因此這並不是一般建議使用的解決方案。
  • 查詢每個服務執行個體的資訊,確認該執行個體是否為正確的執行個體。做法有兩種:
    • 連線至每個服務執行個體的 fidl 介面。許多 fidl 通訊協定都已指定裝置相關資訊 (例如,fuchsia.camera/Control 通訊協定提供 GetInfo 呼叫)。如果目前放送的通訊協定不含識別資訊,可以修改該通訊協定,加入這類裝置專屬資訊。
    • 請在服務中新增額外的 GetInfo 通訊協定,以便包含裝置識別資訊。將識別介面與主要通訊介面分開有幾項優點:
      • 由於此介面提供一組靜態資訊,因此大多由驅動程式庫程式庫處理。
      • 識別介面最好能處理多個同時連線,以利查詢,但大多數驅動程式無法處理多個同時連線至其他介面。
      • 將識別邏輯分開,可讓日後的作業更容易將識別步驟整合至架構。
    • GetInfo 介面的主要缺點在於需要來自驅動程式庫的更多資訊才能填入資料,因此開發人員較難自動提供資訊。在此情況下,驅動程式必須修改 DevfsAddArgs 來新增相關資料,而開發者會負責提供該介面。客戶端必須先由驅動程式執行這項操作,才能轉換為服務。
  • 未來可能會提供的選項,是將標記新增至元件,以便指出特定裝置的相關資訊。接著,用戶端就能查詢與每個服務執行個體相關聯的標記。

裝置特定資訊和匯流排資訊:

當用戶端連線至匯總服務時,有許多資訊可協助他們找出正確的驅動程式庫。這項資訊可能包括裝置 ID (DID)、產品 ID (PID)、供應商 ID (VID),以及傳遞至驅動程式庫的任何中繼資料。不過,從拓樸路徑遷移時,如果不使用拓樸路徑,用戶端可能會遺失的資訊只有三項:驅動程式名稱 (驅動程式庫已知)、匯出器類型和匯出器 ID/地址。為彌補公車資訊遺失的問題,驅動程式庫架構將新增將公車類型與地址從匯流排驅動程式傳遞至所有子系的功能。這項資訊目前會以中繼資料提供給多種公車驅動程式 (例如 i2c),因此實作時只需將公車類型和地址標記為特定中繼資料項目,並確保該項目一律會傳播至子項。接著,駕駛員可以使用上述任一選項,向客戶提供公車資訊。

正在連線至服務供應商

一旦用戶端有策略可決定要連線至哪個服務執行個體,連線本身就會與連線至類別路徑非常相似。

  • 用戶端必須確保自己有權存取該能力,也就是說,用戶端可以將「dev-class」功能替換為預期的服務能力。這項作業可能需要在多個檔案中執行,具體取決於用戶端的拓樸位置。另請注意:部分資料分割包含「dev-class」能力的傳播,因此不一定能看出能力的來源。
  • 不論是開發者還是服務,理想的連線方法都會用到 DeviceWatcher。這個程式庫會以非同步方式通知用戶端新的服務供應器執行個體。最大的變更應該只是監控的位置。

3) 驅動程式遷移

如上所述,如果在服務中使用 GetInfo 介面做為廣告驅動程式庫,驅動程式就必須修改 DevfsAddArgs 以新增相關資料,而 devfs 會負責處理該介面。在用戶端轉換為服務之前,驅動程式必須先執行這項操作。

驅動程式遷移作業涉及呼叫 AddService,並可能在服務中包裝所提供的通訊協定。如果使用 GetInfo 介面,驅動程式庫會提供驅動程式庫程式庫,並提供要提供的靜態資訊,而不是在 DevfsAddArgs 中傳遞。在新增 AddService 呼叫的同時,驅動程式庫會從 NodeAddArgs 項目中移除 devfs_args。這項操作會停用與驅動程式庫相關聯的所有開發項目。

成效

這項遷移作業對效能影響不大。與元件的連線通常只會在元件的循環中完成一次,且連線類型的差異不大。

人體工學

這項遷移作業的設計會優先考量人體工學。主要問題涉及透過拓樸路徑移除存取權:

  • 如未使用拓樸路徑,要區分某些驅動程式會更加困難,因為用戶端必須連線至每項服務,才能判斷是否為所需服務。我們提供用戶端程式庫,讓用戶端提供條件式函式,有助於選取正確的裝置,而無需額外新增固定格式。
  • 驅動程式可能需要新增包含識別資訊的介面或函式。您也可以提供用戶端程式庫,協助驅動程式庫提供任何 GetInfo 通訊協定。
  • 您無法再使用殼層透過 /dev/sys 目錄瀏覽裝置樹狀結構。我們希望其他 ffx 工具能滿足這些需求。此外,您還需要額外的路由,才能將每項服務能力轉送至用戶端。

整體而言,我們認為這項遷移作業帶來的正面效益遠大於額外複雜性。

回溯相容性

我們會為使用 devfs 的驅動程式和用戶端提供軟遷移路徑,但在類別轉換後,我們會停止為該類別提供 devfs 支援。我們的目標是移除所有舊版介面的例項,因此我們不打算在初始遷移期間後提供任何向下相容性支援。

所有驅動程式和用戶端都遷移完成後,devfs 就會移除,這表示任何其他用戶端都無法透過 devfs 存取驅動程式。

安全性考量

這項異動將透過以下幾種方式強化安全性:

  • 用戶端將無法再使用拓樸路徑,因為這類路徑可提供對子樹中任何驅動程式庫的不受限制存取權。
  • 客戶將無法再使用 fuchsia.device/Controller 介面存取驅動程式庫
  • 系統和元件關閉作業將變得更透明,因為可以明確追蹤依附元件。
  • 系統現在會將巴士資訊分享給駕駛人,而這項功能先前並未提供。這項資訊會在列舉中編碼,以限制釋出 PII 的可能性。驅動程式庫不需要知道父項的公車資訊,但我們不認為與驅動程式庫分享這項資訊會帶來安全性風險。

隱私權注意事項

測試

這項遷移作業的測試大多會包含端對端和模擬測試,以及任何相關的主機測試,因為如果有任何錯誤,用戶端就無法連線至服務供應器。由於這項變更會影響許多主機測試,因此我們建議遷移人員手動測試所有受影響的主機測試。我們將把握這個機會,藉由減少對拓樸路徑的依賴,來改善裝置列舉測試。相較於檢查特定路徑,裝置列舉測試會檢查是否已載入所有驅動程式庫套件。

使用 DriverTestRealm 的測試可能會受到遷移作業的影響,因此應與其他用戶端一樣,在遷移作業中受到相同的對待。您必須新增轉送功能,才能配合使用 DriverTestRealm 的所有測試。

說明文件

我們預計在遷移過程中,詳細說明如何遷移特定類別的驅動程式和用戶端。我們也會提供範例和最佳做法,協助您以非同步的方式連線至服務。由於開發者無法使用 devfs,我們會清除說明文件來移除相關的參照,並確保所有驅動程式庫說明文件均描述廣告和連線。為了讓驅動程式庫作者更常處理能力轉送問題,我們打算擴充目前的說明文件,說明如何確保將能力導向正確的元件,以及如何對常見的能力轉送問題進行偵錯。

缺點、替代方案和未知事項

缺點

從 devfs 遷移至服務的主要缺點是,服務連線現在會採用強型別,且能力轉送現在必須指定要路由的服務。這兩項變更可讓系統在設定時更嚴謹,同時提供更多檢查項目,確保系統正確使用。

遷移至服務的另一個缺點,是元件連線的穩定性可能會降低。匯總服務是相對較新的服務,因此可能會在遷移過程中出現意料之外的特殊情況。此外,這項遷移作業涉及將驅動程式從驅動程式庫程式架構團隊管理的系統遷移至元件架構,而元件架構由其團隊提供支援。團隊之間溝通交流的風險一直很高,可能會導致對必要功能失去支援。

替代方案

實作部分會討論幾種替代遷移選項。這項遷移作業的主要替代方法就是不要執行。雖然新駕駛和用戶端仍偏好使用服務,但開發人員可以針對較舊的驅動程式保留使用。這樣做會讓新增較新的元件變得更加困難,並會使關閉程序變得更加複雜,導致 flake 數量增加。維持 devfs 也會繼續阻擋我們清理驅動程式庫生命週期,並普遍減緩團隊進度,因為我們會被迫在舊版系統中工作。