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

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

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

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

問題陳述

目前,非驅動程式的驅動程式庫存取權幾乎都由裝置檔案系統 (devfs) 仲介。很抱歉,devfs 有幾個缺點:

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

摘要

我們建議您遷移這類存取權,改用由元件管理員調解的匯總服務,藉此改變非驅動程式存取驅動程式的方式。這項遷移作業將包含拓撲路徑 (/dev/sys/) 和類別路徑 (/dev/class/)。在此程序中,系統也會移除用戶透過 fuchsia.device/Controller 通訊協定對驅動程式的任何剩餘存取權。這份 RFC 將說明遷移至匯總服務時面臨的挑戰,並提出解決方案,確保驅動程式庫作者不會受到不當影響。我們也希望為驅動程式庫存取權提供更多標準化功能,以提升程式碼健康度,並降低編寫驅動程式和用戶端的難度。

利害關係人

協助人員:

審查者:

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

已諮詢:

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

社交:

這項 RFC 已通過 Driver Framework 團隊的設計審查。

背景

直到最近,紫紅色作業系統中的驅動程式都不是元件,非驅動程式與驅動程式庫通訊的唯一方式是透過 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 使用者提供解決方案,因此不得遺失任何功能。此外,驅動程式和用戶端必須能夠執行軟遷移,新增服務並連線至服務,而不必要求提供服務的所有用戶端和驅動程式同時遷移。

設計

驅動程式架構工作

每個用戶端或驅動程式庫從 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) 將 devfs 改為宣傳服務 2) 客戶轉換為服務 3) 司機宣傳服務並移除 devfs

替代方案 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) 驅動程式移除 devfs

實作

您可以針對與特定類別名稱互動的每組驅動程式和用戶,逐步完成這項遷移作業。您需要提供一些工具和程式庫,驅動程式庫程式架構會執行多項遷移作業,確保程式庫符合遷移驅動程式和用戶端的需要。確認遷移程序符合人體工學後,我們會將類別名稱遷移作業新增為開放式工作,供廣大的 Fuchsia 社群參與。系統會找出需要特別注意的特定類別/介面,並採取更協調一致的方法。包括仍使用 fuchsia.device/Controller 介面的任何用戶端,這些用戶端必須先解決問題,才能遷移。所有驅動程式和用戶端都遷移至服務後,即可移除 devfs 的內部實作項目。

遷移機制

如要進一步瞭解如何完成遷移,請參閱下列步驟,將特定類別的驅動程式庫轉換為:

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 介面的主要缺點是需要驅動程式庫提供更多資訊才能填入,因此 devfs 更難自動提供。在這種情況下,驅動程式需要修改 DevfsAddArgs,加入相關資料,而 devfs 會處理該介面的服務。司機必須先完成這項操作,客戶才能轉換為服務。
  • 未來可能會提供選項,讓您在元件中新增標記,指出特定裝置的相關資訊。然後,用戶端可以查詢與每個服務執行個體相關聯的標記。

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

連線至匯總服務時,有許多資訊可協助用戶端找出正確的驅動程式庫。這項資訊可能包括裝置 ID (DID)、產品 ID (PID)、供應商 ID (VID),以及傳遞至驅動程式庫的任何中繼資料量。不過,從拓撲路徑遷移時,用戶端不使用拓撲路徑可能只會遺失三項資訊:司機姓名 (驅動程式庫知道)、巴士類型和巴士 ID/地址。為補償公車資訊的遺失,驅動程式庫架構會新增從匯流排驅動程式將公車類型和地址傳播至所有後代的機制。目前這項資訊會以中繼資料的形式提供給多種匯流排驅動程式 (例如 i2c),因此實作時只要將匯流排類型和位址標記為特定中繼資料項目,並確保這項資訊一律會傳播至子項即可。接著,司機就能使用上述任一選項,向客戶提供公車資訊。

連線至服務供應商

用戶端決定要連線至哪個服務執行個體後,連線方式與連線至類別路徑非常相似。

  • 用戶端必須確保自己有權存取能力,可以將「dev-class」功能替換為預期的服務能力。視用戶端的拓撲位置而定,您可能需要在多個檔案中執行這項操作。另請注意,部分分片包含「dev-class」能力的傳播,因此能力來源可能並不明顯。
  • 開發人員檔案系統和服務的理想連線方法都涉及 DeviceWatcher。這個程式庫會以非同步方式通知用戶端新的服務供應商執行個體。最大的變化應該只是要監控的位置。

3) 驅動程式遷移

如上所述,如果使用服務中的 GetInfo 介面做為驅動程式庫會放送廣告,驅動程式就必須修改 DevfsAddArgs,加入相關資料,而 devfs 會處理該介面的放送作業。客戶必須先完成這項操作,才能轉換為服務。

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

效能

這項遷移作業對成效的影響微乎其微。建立元件的連線通常只會在元件的生命週期中執行一次,且連線類型差異極小。

人體工學

在設計這項遷移作業時,我們將人體工學問題放在首位。主要問題是透過拓撲路徑移除存取權:

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

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

回溯相容性

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

所有驅動程式和用戶端遷移完畢後,系統就會移除 devfs,屆時其他用戶端將無法透過 devfs 存取驅動程式。

安全性考量

這項異動將從幾個方面提升安全性:

  • 用戶端將無法再使用拓撲路徑,這類路徑可無限制存取子樹狀結構中的任何驅動程式庫。
  • 只要有權存取驅動程式庫,用戶就無法再使用 fuchsia.device/Controller 介面
  • 系統會更明確地追蹤每個用戶端可存取的服務和通訊協定,且由於依附元件可明確追蹤,系統和元件關機作業也會變得更加透明。
  • 現在系統會將公車資訊提供給司機,這項資訊先前不會提供給司機。 這項資訊會編碼為列舉,以限制發布 PII 的可能性。雖然驅動程式庫不需要知道家長的公車資訊,但我們認為將這項資訊提供給驅動程式庫不會造成安全風險。

隱私權注意事項

不適用

測試

這項遷移作業的測試主要包括端對端和冒煙測試,以及任何相關主機測試,因為如果任何環節出錯,用戶端就無法連線至服務供應商。這項異動會影響許多主機測試,因此我們建議遷移者手動測試所有受影響的主機測試。我們正藉此機會移除對拓撲路徑的依賴,並全面翻新裝置列舉測試。裝置列舉測試不會檢查特定路徑,而是檢查是否載入所有驅動程式庫套件。

使用 DriverTestRealm 的測試可能會受到遷移作業影響,因此遷移時應與其他用戶端一視同仁。您需要新增路徑,才能配合使用 DriverTestRealm 的任何測試。

說明文件

我們計畫在遷移期間詳細說明如何遷移一類駕駛人和客戶。我們也會在日後提供範例和最佳做法,說明如何以非同步方式連線至服務。由於 devfs 已淘汰,我們會清除文件,移除對 devfs 的參照,並確保所有驅動程式庫文件都說明廣告和連線至服務。預期驅動程式庫作者會增加處理能力轉送的次數,因此我們計畫擴充目前的文件,說明如何確保能力導向正確的元件,以及如何偵錯能力轉送的常見問題。

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

缺點

從 devfs 遷移至服務的主要缺點是,服務連線現在會是強型別,且能力轉送現在必須指定要路由傳送的服務。這兩項變更都會讓系統在設定時較不寬容,但也會提供更多檢查,確保系統正確使用。

遷移至服務的另一個缺點是,元件連線的穩定性可能會降低。匯總服務相對較新,可能會有意想不到的極端情況,透過這項遷移作業顯現出來。此外,這項遷移作業也涉及驅動程式從驅動程式庫程式架構團隊管理的系統遷移至元件架構,而元件架構是由專屬團隊支援。團隊之間始終存在溝通不良的風險,可能導致必要功能失去支援。

替代方案

實作章節會討論幾種替代移轉選項。這項遷移作業的主要替代方案是不執行遷移。雖然新版驅動程式和用戶端仍偏好使用服務,但舊版驅動程式仍可保留 devfs。這樣一來,新增較新的元件會更加困難,關閉程序也會持續複雜化,導致我們出現更多不穩定性。保留 devfs 也會繼續阻礙我們清理驅動程式庫生命週期,並普遍減緩團隊進度,因為我們將被迫使用舊版系統。