RFC-0235:元件字典 | |
---|---|
狀態 | 已接受 |
領域 |
|
說明 | 提案:將字典類型導入元件架構,以便整合能力。 |
問題 | |
更小鳥 | |
作者 | |
審查人員 | |
提交日期 (年月分) | 2023-10-16 |
摘要
這個 RFC 提議建立執行階段和宣告式 API,用於建立及轉送功能套裝組合,稱為字典。
提振精神
目前,元件架構僅支援所定義功能的「點至點」轉送功能:如要將能力 C 從元件 A 轉送至元件 B,每個中繼元件中都必須有路徑片段,才能在相鄰元件之間轉送 C。
提供多個功能組合做為單一邏輯單元的能力,且有助於大幅受益。如果沒有這項功能,這些客戶必須設法解決費用高昂、缺乏彈性和靈活的問題。以下列舉這些應用實例:
LogSink
、InspectSink
和追蹤記錄供應器等診斷功能幾乎每個元件都會使用,如果我們可以將其視為組合路徑,就能大幅簡化轉送拓撲。fuchsia.debugdata.Publisher
等分析器功能與診斷功能相似,差別只在於某些版本時才啟用。對於設定新增需要跨整個拓撲的能力,我們目前沒有良好的建構方法。因此,分析器今天只能在測試領域中啟用。- 測試領域 Proxy 會向測試案例公開介面,讓測試用來執行測試中的元件。目前這是自訂介面,與元件連線 API 非常類似。這個介面可以替換為由測試領域 Proxy 轉移至測試的各項功能組合。如此一來,測試領域 Proxy 就不必定義自己的抽象層,並且可讓任何元件架構功能供測試使用。
- 任何位置的功能都是透過多個層轉送,路徑則可透過選項整合來簡化:
session_manager
:所有從core
轉送至session_manager
的功能都必須由session_manager.cml
重新轉送。由於這是大量的功能,因此很難維護,也表示部分非平台功能會外洩至session_manager.cml
。chromium
:Chromium cml 檔案含有大量重複項目。如果系統能使用單一名稱將功能分組及轉送,則也會大幅簡化。https://fxbug.dev/42072339)
- 元件架構「環境」是執行器和解析器的功能,可設為可供整個子樹狀結構使用,並以隱含轉送的方式轉送。如果我們應該改用通用的套裝組合 API 完成這項作業,會比較其他元件架構轉送 API,並透過以環境為基礎的隱式轉送減輕最低權限問題。
下列項目也是能力組合功能的動機使用案例,但它們有特別的考量,需要在本 RFC 中規劃之外進行後續設計工作。
- 有些主面板專用驅動程式想公開未針對平台定義的自訂服務。這些服務應由
bootstrap
領域公開,因為所有驅動程式庫元件都位於該處,但在平台拓撲中明確命名這些元件並不合理。如果 cml 將這些服務整合在一起,我們就可以處理這種情況。 - 使用
driver_test_realm
的測試也會發生類似問題。這些測試希望將不同服務從驅動程式庫轉送至測試。在這些測試中,驅動程式庫測試領域元件位於驅動程式和測試之間,而我們希望可以在不修改這些測試的情況下,在這些測試中重複使用驅動程式庫測試領域。
最後,目前已有數個現有元件架構 API 涉及分組功能。但這些函式各自獨立,且僅適用於特定情況。以下是一些例子:
事實上,我們擁有許多 API 提示,使用者可透過一般抽象化,定義自己的字典並轉送這些摘要,因此使用者可以受益。
相關人員
根據上述用途,下列團隊已識別為利害關係人:
- 架構
- 診斷
- 測試
- 工具鏈
- 驅動程式架構
- 安全性
講師:hjfreyer@
審查者:
- abarth@ (架構)
- crjohns@ (測試中)
- Markdittmer@ (安全性)
- miguelfrde@ (診斷)
- surajmalhotra@ (駕駛人員)
- ypomortsev@ (元件架構)
諮詢時間:
- phosek@
- kjharland@
- Anmittal@
- Wittrock@
- novinc@
社會化:
前面有兩份的內部文件:用途與需求文件,以及核心設計文件。這些文件已獲得相關人員的非正式核准。
這些文件中的資訊已納入相關的 RFC 中。
相關規定
以下是必須支援的作業字典,我們藉由分析用途和從現有分組 API 一般化所衍生而來:
- 一流:字典是 CF API 中的一流概念,會以能力表示。
- 匯總:這是「匯總」作業,可從一組功能建構字典。
- 擷取:有一種「擷取」作業,可從字典中擷取個別能力,並可像任何能力一樣轉送和使用。這與匯總作業大致相反。
- 委派:字典可傳遞到元件之間。
- 巢狀結構:由於字典是一項能力,因此字典中可以包含其他字典。
- 結構:字典會標記中繼資料,指出字典中包含的功能。
- 擴充功能:這種做法可建構新的字典
B'
,繼承B
的內容並新增其他功能。 - 可操作性:字典內容可能會隨時間變動。不過,較高的層級政策可能存在限制特定字典的可變動性。
設計
定義
「字典」定義為一組鍵/值組合,其中鍵是「功能名稱」 (例如fuchsia.example.Echo
) 且值為 CF 能力。
「功能名稱」是指 [A-Za-z0-9_-.]
集合中一或多個字元的序列,大小為 1 到 N (目前 N = 100,但日後可能會擴充)。
執行階段的字典
我們會推出公開 FIDL 通訊協定,為字典提供介面。如 FIDL-虛擬程式碼:
library fuchsia.component;
type DictionaryEntry = resource struct {
key DictionaryKey;
value Capability;
};
protocol Dictionary {
Insert(DictionaryEntry) -> ();
Remove(DictionaryKey) -> (Capability);
Lookup(DictionaryKey) -> (Capability);
Enumerate() -> Iterator<DictionaryKey>;
Clone();
};
我們也會推出可探索的公開 FIDL 通訊協定,讓呼叫端建立空白的字典。
後續設計工作將決定 Capability
的精確類型定義。
元件宣告中的字典
首先,我們來簡單介紹一些有助於定義作業的正規化。我們會定義與每個元件相關聯的四個特殊字典:元件輸入字典、元件輸出字典、程式輸入字典,以及程式輸出字典。這些就是根字典。
「元件輸入字典」這個字典包含父項設為元件的所有功能,offer
換句話說,元件可轉送 from parent
的所有功能。
「元件輸出字典」這個字典包含元件由元件 expose
的所有功能,換句話說,就是父項可轉送 from #component
的所有功能。
程式輸入字典是包含元件 use
所有功能的字典。
程式輸出字典是包含元件所有 capability
宣告的字典。
我們可以根據下列定義,表示能力轉送作業:
use
、offer
、expose
和capabilities
屬於「轉送作業」,這類作業會在字典之間轉送功能。use
會將能力從根字典轉送至程式輸入字典。expose
會將能力從根字典轉送至元件輸出字典。offer
會將能力從根字典轉送至子項的元件輸入字典。capabilities
提供程式輸出字典中的能力,可用於轉送。
透過這項設計,我們會對作業進行一般化,讓轉送作業使用任意字典做為來源,而不只是根字典:
use
會將能力從字典轉送至程式輸入字典。expose
會將能力從字典轉送至元件輸出字典。offer
會將能力從字典轉送至子項的元件輸入字典 或其他字典。
宣告
如何定義全新的空白字典:
capabilities: [
{
dictionary: "diagnostics-bundle",
},
],
如要定義繼承自現有字典的字典,請以 extends
提供該字典的路徑 (請參閱「擴充功能」一節):
{
dictionary: "diagnostics-bundle",
extends: "parent/logging-bundle/sys",
},
匯總
如要將功能匯總成字典,請使用 offer
中的 to
關鍵字將功能轉送至字典。由於字典是由這個元件定義,因此包含該字典的根字典為 self
。所有相同關鍵字都可做為一般 offer
提供支援。舉例來說,您可以使用 as
關鍵字來變更目標字典中的能力名稱。
capabilities: [
{
dictionary: "diagnostics-bundle",
},
],
offer: [
{
protocol: "fuchsia.logger.LogSink",
from: "#archivist",
to: "self/diagnostics-bundle",
},
{
protocol: "fuchsia.inspect.InspectSink",
from: "#archivist",
to: "self/diagnostics-bundle",
},
{
directory: "publisher",
from: "#debugdata",
to: "self/diagnostics-bundle",
rights: [ "r*" ],
as: "coverage",
},
],
委派
委派代表轉送字典:
offer: [
{
dictionary: "diagnostics-bundle",
from: "parent",
to: "#session",
},
],
與其他能力路徑一樣,您可以使用 as
關鍵字變更目標名稱。
offer: [
{
dictionary: "logging-bundle",
from: "parent",
to: "#session",
as: "diagnostics-bundle",
},
],
對等的執行階段 API 將適用於動態優惠。
巢狀結構
您可以使用「匯總」語法,將字典納入其他字典,以包含其他字典:
capabilities: [
{
dictionary: "session-bundle",
},
],
offer: [
{
dictionary: "driver-services-bundle",
from: "parent",
to: "self/session-bundle",
},
],
擷取
按照正規化後,我們將擴充 from
關鍵字,並納入根字典,同時支援在根字典中巢狀結構的字典。
如要從字典中擷取能力,請在 from
中為字典命名。這個字典是相對於根字典 (parent
、#child
等)
offer: [
{
protocol: "fuchsia.ui.composition.Flatland",
from: "parent/session-bundle",
to: "#window_manager",
},
],
這也適用於 use
:
use: [
{
protocol: "fuchsia.ui.composition.Flatland",
from: "parent/session-bundle",
},
],
當字典內嵌在其他字典中時,擷取功能也適用:
use: [
{
protocol: "fuchsia.ui.composition.Flatland",
from: "parent/session-bundle/gfx",
},
],
擴充功能
在字典定義中使用 extends
選項,以便繼承其他字典:
capabilities: [
{
dictionary: "session-bundle",
// `session-bundle` is initialized with the dictionary the parent
// offered to this component, also called `session-bundle`.
extends: "parent/session-bundle",
},
],
offer: [
{
dictionary: "session-bundle",
from: "self",
to: "#session-manager",
},
{
protocol: "fuchsia.ui.composition.Flatland",
from: "#ui",
to: "self/session-bundle",
},
],
可變動性
以宣告方式建構的字典不可變更,這是一種實用的安全性屬性。必須在執行階段建立字典,才能設為可變動的字典。
字典功能的中繼資料
功能進入字典時,系統會保留所有類型資訊和中繼資料,這些類型資訊和中繼資料不會與字典本身相關聯的任何中繼資料分開。
舉例來說,如果元件 A
將具有 optional
可用性的能力加入字典,而 B
元件擷取了該能力,則擷取時就會具備 optional
可用性,即使字典本身的可用性為 required
也一樣。
在匯總期間,我們可能會對可用性設下特定限制。例如,禁止將 required
能力放入 optional
字典中是合理的做法,因為這違反一般不變性,在從目標轉送至來源時,可用性永遠不會變低。
執行階段和宣告式字典之間的互通性
在執行階段建立的字典必須與元件宣告中的字典互通。如果如果不是,則會強迫使用者選擇其中一種方式,並是證據表明,套裝組合的概念基礎不足以類似方式解決這兩種用途。
後續提案的主旨將納入可互通性的設計細節。
這項功能的主要用途是驅動程式庫架構,用於轉送在執行階段填入的服務套裝組合。
實作
Cml 中的到達網頁字典將遵循一般管道導入新的 Cml 功能。首先,我們會將字典新增至 cml 和 Component.decl 結構定義。接著,我們會更新 cmc
、cm_fidl_validator
、cm_rust
和 realm_builder
,以便編譯、驗證及代表字典。Scruti 也會更新,以便識別字典,並能夠驗證字典路徑。
目前仍在進行將字典 (做為 Rust 類型) 整合至元件模型和轉送引擎的作業。字典 API 的實作應以這項工作為基礎,以便使用這些字典做為公開字典 API 的後端,並做為轉送字典功能的傳輸機制。
效能
我們不會有特殊的效能考量。轉送字典應和個別轉送組成功能的速度更快或更快。
人體工學
改善建構元件拓撲是一種人體工學,是這個設計的主要動機。
雖然導入新功能會自然增加 API 的複雜性,但我們相信將字典納入拓撲後,將增加的複雜度減緩,還應會降低成本。
回溯相容性
cmc 尚不支援元件資訊清單功能的版本管理,因此必須謹慎,以免與預建資訊清單破壞相容性。幸運的是,新引入字典的新語法都能與舊的語法相容,以便您更輕鬆地執行工作。舉例來說,from
中的目前名稱語法會成為新路徑語法的特殊情況。
如果部分能力路徑通過字典,則與該能力相關的任何安全性政策仍必須套用。
安全性考量
在字典中轉送功能時,會失去部分透明度,因為字典內的功能身分不會顯示在路徑的中繼元件中。不過,系統仍可根據路徑向後至供應商,藉此推進這些供應商。這是為了實現字典解鎖的靈活性和能力。這個謹慎的入侵手段。
以宣告方式建構的字典不可變更。對於這些字典,您可以執行深入優先搜尋從目標到其來源的字典匯總路徑,以獲得其內容的完整說明。
如果字典替換環境,那麼當字典替換環境時,系統就能提升系統的安全性狀態,因為字典 (與環境不同) 會以明確方式轉送,而且採用與其他功能相同的方式。
隱私權注意事項
這項提案對隱私權沒有任何影響。
測試
我們會像大多數元件管理員功能一樣對其進行測試,在 component_manager
和 cmc
中使用單元測試,以及在 component_manager/tests
中進行整合測試。我們也將加入整合測試來仔細審查,針對採用字典的路徑執行字典和政策。
說明文件
我們會在 //tools/lib/cml
中更新 rustdoc。
新增頁面至 //docs/concepts/components
以說明字典。
在 //examples/components
中新增範例。
缺點、替代項目和未知
替代方法 1:「in
」和「into
」用於字典的關鍵字
宣告
「字典功能」是一種可授予字典存取權的 cml/component.decl 能力類型,
您可以宣告字典,就像宣告任何其他元件架構能力一樣。這是字典建立的兩個變體,取決於 extends
關鍵字是否存在。
首先,您可以定義全新的空白字典:
capabilities: [
{
dictionary: "diagnostics-bundle",
},
],
或者,您可以在 extends
中指定字典路徑,並在 from
中指定來源,藉此定義內容沿用自現有字典的字典 (請參閱「擴充功能」一節):
{
dictionary: "diagnostics-bundle",
extends: "logging-bundle/sys",
from: "parent",
},
匯總
如要將功能匯總成字典,請使用 into
關鍵字將能力轉送至字典:
capabilities: [
{
dictionary: "diagnostics-bundle",
},
],
offer: [
{
protocol: "fuchsia.logger.LogSink",
from: "#archivist",
into: "diagnostics-bundle",
},
{
protocol: "fuchsia.inspect.InspectSink",
from: "#archivist",
into: "diagnostics-bundle",
},
{
protocol: "fuchsia.debugdata.Publisher",
from: "#debugdata",
into: "diagnostics-bundle",
},
],
委派
與主要設計相同。
巢狀結構
字典可以包含其他字典,只要使用匯總語法將字典轉送至字典即可。
capabilities: [
{
dictionary: "session-bundle",
},
],
offer: [
{
dictionary: "driver-services-bundle",
from: "parent",
into: "session-bundle",
},
],
擷取
我們推出新的 in
關鍵字,用於指定用於擷取能力的字典。
當 in
存在時,能力關鍵字 (protocol
等) 是指這個字典中的能力,而非 from
中所命名元件直接提供的能力。
in
可以是名稱或路徑 (其中名稱可視為解碼大小寫)。如果是名稱,則會參照由 from
提供的字典。如果是路徑,路徑的第一個區段會指定由 from
提供的字典,而路徑的其餘部分則指定一條路徑至巢狀結構的字典。
in
由 use
、offer
和 expose
支援。您可以自行決定是否採用。
offer: [
{
protocol: "fuchsia.ui.composition.Flatland",
from: "parent",
in: "session-bundle/gfx",
to: "#window_manager",
},
],
expose: [
{
protocol: "fuchsia.ui.composition.Flatland",
from: "#scenic",
in: "gfx-bundle",
},
],
use: [
{
protocol: "fuchsia.ui.composition.Flatland",
in: "session-bundle/gfx",
},
],
擴充功能
在字典定義中使用 extends
關鍵字,以便繼承其他字典:
capabilities: [
{
dictionary: "diagnostics-bundle",
extends: "parent/logging-bundle/sys",
},
],
offer: [
{
dictionary: "diagnostics-bundle",
from: "self",
to: "#session-manager",
},
{
protocol: "fuchsia.tracing.provider.Registry",
from: "#trace_manager",
into: "diagnostics-bundle",
},
],
替代做法 2:能力 ID 的路徑
路徑可以是能力 ID (protocol
、directory
等) 的一部分,而不是在 from
中指定字典的路徑。
匯總
與主要設計相同。
委派
與主要設計相同。
巢狀結構
與主要設計相同。
擷取
如要從字典中擷取能力,請在能力 ID (protocol
、directory
等) 中指定字典內的能力路徑。
offer: [
{
protocol: "session-bundle/fuchsia.ui.composition.Flatland",
from: "parent",
to: "#window_manager",
},
],
目標中的名稱將是最後一個路徑元素或「目錄名稱」(fuchsia.ui.composition.Flatland
)。或者,您也可以使用 as
重新命名:
offer: [
{
protocol: "session-bundle/fuchsia.ui.composition.Flatland",
from: "parent",
to: "#window_manager",
as: "fuchsia.ui.composition.Flatland-windows",
},
],
這也適用於 use
,也就是讓程式可以使用字典中的能力。和其他 use
宣告一樣,預設目標路徑會在 /svc
時重新定義名稱 (最後一個路徑元素):
use: [
{
protocol: "session-bundle/fuchsia.ui.composition.Flatland",
path: "/svc/fuchsia.ui.composition.Flatland", // default
},
],
路徑語法也適用於巢狀字典中的其他字典:
use: [
{ protocol: "session-bundle/gfx/fuchsia.ui.composition.Flatland" },
],
擴充功能
在字典定義中使用 origin: #...
選項,以便繼承其他字典:
capabilities: [
{
dictionary: "session-bundle",
// Source of the dictionary to extend (in this case, the one named
// "session-bundle" from the parent)
origin: "#session",
from: "parent",
},
],
offer: [
{
dictionary: "session-bundle",
from: "self",
to: "#session-manager",
},
{
protocol: "fuchsia.ui.composition.Flatland",
from: "#ui",
into: "session-bundle",
},
],
替代方法 3:功能 ID 成為路徑
[Names] (名稱) -> [Paths] (路徑)
事實上,cml 中的能力 ID 是名稱,沒有內建巢狀結構。例如:
offer: [
{
protocol: "fuchsia.fonts.Provider",
from: "#font_provider",
to: "#session-manager",
},
],
但功能 ID 會對應至 capabilities
和 use
區段中的路徑。以通訊協定來說,這通常為隱含值:如未提供路徑,cmc 會在預設路徑 /svc/${capability-name}
中填入。例如:
use: [
{
protocol: "fuchsia.fonts.Provider",
// path in namespace
path: "/svc/fuchsia.fonts.Provider",
},
],
capabilities: [
{
protocol: "fuchsia.fonts.Provider",
// path in outgoing directory
path: "/svc/fuchsia.fonts.Provider",
},
],
這個替代做法會能力中的路徑。更正式:
- 「功能 ID」是來自字元集
[A-Za-z0-9_-.]
的一或多個「名稱」序列,其中包含 1 至 100 個字元,並以/
字元分隔。且開頭不是/
。- 或者,在規則運算式語法中:
[A-Za-z0-9_-]{1,100}(/[A-Za-z0-9_-]{1,100})*
- 現有能力 ID 與新語法具有前瞻相容性。
- 或者,在規則運算式語法中:
以下將說明這個語法自然如何奠定組合基礎。
匯總
如要將功能匯總成字典,請使用相同的路徑前置字串轉送功能:
offer: [
{
protocol: "fuchsia.logger.LogSink",
from: "#archivist",
to: "all",
as: "diagnostics/fuchsia.logger.LogSink",
},
{
protocol: "fuchsia.inspect.InspectSink",
from: "#archivist",
to: "all",
as: "diagnostics/fuchsia.inspect.InspectSink",
},
{
protocol: "fuchsia.debugdata.Publisher",
from: "#debugdata",
to: "all",
as: "diagnostics/fuchsia.debugdata.Publisher",
},
],
委派
委派單純只是轉送字典,如下所示:
offer: [
{
dictionary: "diagnostics",
from: "parent",
to: "#session",
},
],
巢狀結構
只要將巢狀字典的路徑設為巢狀字典的前置字串,即可讓字典包含其他字典:
offer: [
{
dictionary: "driver-services-bundle",
from: "parent",
to: "#session-manager",
as: "session/driver-services",
},
],
擷取
只要為您想擷取的字典中的能力命名,即可:
offer: [
{
protocol: "session-bundle/fuchsia.ui.composition.Flatland",
from: "parent",
to: "#window_manager",
as: "fuchsia.ui.composition.Flatland",
},
],
這也適用於 use
:
use: [
{
protocol: "session-bundle/fuchsia.ui.composition.Flatland",
path: "/svc/fuchsia.ui.composition.Flatland",
},
],
當字典在其他字典中嵌套時 (TODO: 範例) 時,擷取功能也適用
擴充功能
重新命名功能,讓路徑前置字元與字典相同:
offer: [
{
protocol: "session-bundle",
from: "parent",
to: "#session-manager",
},
{
protocol: "fuchsia.ui.composition.Flatland",
as: "session-bundle/fuchsia.ui.composition.Flatland",
from: "#ui",
to: "#session-manager",
},
],
為何選擇字典而非目錄?
我們不必導入字典,而是使用 fuchsia.io
目錄做為套件的基礎類型。從一個方面來說,這是很有吸引力的:目錄已經存在,並提供自己的階層式組合模式。但是,使用目錄時有許多引數:
- VFS 類型系統沿用的資訊與 CF 類型系統不同;例如,服務、目錄和儲存空間全都會對應至 VFS 中的子目錄,即使它們在 CF 中為不同的類型。
- 目錄的介面遠比支援能力繫結所需的介面更加複雜。NODE_REFERENCE、連結、旗標、屬性、資料檔案等功能與套裝組合用途無關。
- VFS 程式庫對於部分應用程式而言 (尤其是驅動程式) 過大。因此,
//sdk/lib/component/outgoing
程式庫連結位於共用程式庫填充碼 (//sdk/lib/svc
) 中,而非直接連結 VFS 程式庫,但須支付功能和透明度。 - 這個 VFS 無法實作,而是兩個獨立的 C++ 實作和一個 Rust 實作。這些實作方式有細微的差異和功能漏洞。字典則不構成問題,因為元件執行階段中會實作字典的單一實作。
- 目錄會提高編寫程式碼產生繫結的難度,這類繫結會將程式提供或使用的每項能力做為離散語言元素。
- 目錄自然不支援「匯總」或「擴充功能」作業。您必須透過提供新的目錄來模擬,其中有些節點會將他們重新導向至舊目錄,整個實作既簡單又容易出錯。
未來工作
系統會另外提出隨附設計以鎖定驅動程式庫程式用途,而這類設計無法僅透過本提案中的功能完全解決。
此設計為能力轉送作業開啟了更經濟實惠的語法。與其將能力名稱和 from
分開,不如將其合併為單一路徑,在概念上是包含所有根字典的字典。例如:
offer: [
{
protocol: "#ui/fuchsia.ui.composition.Flatland",
to: "#session-manager",
},
],
這個語法有不錯的屬性:一般來說,是允許單一根字典轉送整個根字典:
offer: [
{
// Plumb all capabilities from parent to child #session-manager
dictionary: "parent",
to: "#session-manager",
},
],
值得一提的是,較通用的版本能夠統一語法:
route: [
{
// Path to source capability in dictionary
src: "#ui/fuchsia.ui.composition.Flatland",
// Path of target capability in dictionary
dst: "#session-manager/fuchsia.ui.composition.Flatland",
},
],
route: [
{
src: "parent",
dst: "#session-manager/parent",
},
],
優先藝術與參考資料
功能組合是很舊的想法。有很多內部的前身文件可以提出類似的想法