字典可將多項功能歸類為 將單一單位轉送為單一能力
字典的格式是鍵/值儲存庫,其中鍵是 capability name 字串,而其值是能力。 值本身也可以是另一項字典能力,可用來 或類似巢狀結構的巢狀結構
定義字典功能
如要定義新的字典,請為該字典新增 capability
宣告,如下所示:
capabilities: [
{
dictionary: "bundle",
},
],
請參閱匯總一節,瞭解如何新增功能 然後提供給字典
從一開始,這個平台有一項重要區別
元件中的字典功能和大多數其他能力類型
例如通訊協定和
目錄。通訊協定能力最終是由
由元件相關聯的程式進行protocol
能力
宣告只是讓元件架構知道
以及通訊協定是否存在另一方面,dictionary
能力
由元件架構執行階段代管實際上,元件並不需要
具有 program
可宣告 dictionary
能力。
轉送字典功能
字典屬於集合類型,因此支援更多元的轉送方式 與其他能力類型相比
基本操作會公開字典給父項或 提供與其他功能類似。但 字典也支援以下額外的轉送作業:
字典建立後即無法修改。轉送字典授權 僅供讀取。可變動性說明瞭 字典的可變動性
如需更多有關能力轉送的一般資訊,請參閱 頂層網頁。
公開
公開字典能力會授予元件的父項存取權:
{
expose: [
{
dictionary: "bundle",
from: "self",
},
],
}
如同其他功能,您可以使用
as
關鍵字:
{
expose: [
{
dictionary: "local-bundle",
from: "self",
as: "bundle",
},
],
}
提供
提供字典能力可讓子項元件存取:
{
offer: [
{
dictionary: "bundle",
from: "parent",
to: [ "#child-a", "#child-b" ],
},
],
}
如同其他功能,您可以使用 as
變更子項顯示的名稱
關鍵字:
{
offer: [
{
dictionary: "local-bundle",
from: "self",
to: [ "#child-a", "#child-b" ],
as: "bundle",
},
],
}
使用
這個架構目前不支援 use
將 dictionary
能力設為
此類內容。不過,您可從多種位置擷取個別功能
並用來形容詞
匯總
如要在您定義的字典中新增功能,請使用 offer
並在 to
中指定目標字典。這項作業稱為
匯總。字典必須以
包含 offer
。
如要表示您想將能力新增至目標字典,請使用
以下是 to
中的語法:
to: "self/<dictionary-name>",
其中有 dictionary:
"<dictionary-name>"
的 capabilities
宣告。self/
前置字串反映了字典的事實
就是這個元件的局部(這是字典路徑語法的其中一個案例)
相關說明請參閱擷取中所述)。
如同其他 offer
種類,在
您可以使用 as
關鍵字將字典從原始名稱變更為其他名稱。
以下是工作匯總的範例:
capabilities: [
{
dictionary: "bundle",
},
{
directory: "fonts",
rights: [ "r*" ],
path: "/fonts",
},
],
offer: [
{
protocol: "fuchsia.examples.Echo",
from: "#echo-server",
to: "self/bundle",
},
{
directory: "fonts",
from: "self",
to: "self/bundle",
as: "custom-fonts",
},
],
建立巢狀結構
capabilities: [
{
dictionary: "bundle",
},
],
offer: [
{
dictionary: "gfx",
from: "parent",
to: "self/bundle",
},
],
如此一來,就可以將功能嵌入在更深層的字典中 第二,自訂角色只能 套用至專案或機構請參閱下一節,瞭解這項資訊。
擷取
從字典存取能力再獨立轉送功能, 稱為「擷取」
擷取作業有兩個輸入內容:用來擷取 能力,以及該字典中能力鍵的關鍵CML 代表 如下所示:
- 字典路徑會在
from
屬性中提供。- 語法為
"<source>/<path>/<to>/<dictionary>"
。 <source>
可以是轉送作業的任一常見來源 支援。舉例來說,offer
支援self
、#<child>
或parent
, 且expose
支援self
或#<child>
。- 其餘路徑區段可識別 (可能為巢狀結構) 字典
已由
<source>
轉送至這個元件。 - 將一般概念化為一般性
非巢狀
from
語法 (如範例所示 這裡)。從概念上說,您可以把<source>
做為特殊的「頂層」字典提供的字典適用對象 例如,parent
是字典名稱,這個字典包含所有 父項提供的功能,#<child>
是字典 包含<child>
公開的所有功能。如果您將 路徑包含額外線段,只是代表字典 巢狀結構中的上層帳戶
- 語法為
- 能力命名的鍵將做為能力的值
關鍵字 (
protocol
、directory
等)。這是 這與命名能力時,無法在 字典中。
這個語法最容易透過範例說明:
expose: [
{
protocol: "fuchsia.examples.Echo",
from: "#echo-realm/bundle",
to: "parent",
},
],
在這個範例中,此元件預期名為 bundle
的字典為
由 #echo-realm
公開。from
包含這個字典的路徑:
#echo-realm/bundle
。bundle
字典中的功能
要擷取及轉送的元件是具有索引鍵的 protocol
fuchsia.examples.Echo
。最後,這項通訊協定會向
元件的父項為 fuchsia.examples.Echo
(做為個別能力,而非
附加至任何含有字典的一部分)。
類似的語法與 use
相容:
use: [
{
protocol: "fuchsia.examples.Echo",
from: "parent/bundle",
},
],
在這個例子中,元件預期父項會提供字典
bundle
,包含通訊協定 fuchsia.examples.Echo
。不是path
因此程式傳入命名空間中的通訊協定路徑
設為預設值:/svc/fuchsia.examples.Echo
。
請注意,一般而言,使用宣告中的 from
預設值是
"parent"
,但因為我們是從提供的字典中擷取通訊協定
我們需要將父項明確指定為來源。
由於字典可「建立巢狀結構」,因此可擷取字典本身 並從字典中轉送:
offer: [
{
dictionary: "gfx",
from: "parent/bundle",
to: "#echo-child",
},
],
在這個範例中,元件會假設父項為該元件提供字典
名為 bundle
,這個 bundle
包含名為 gfx
的字典,
提供給「#echo-child
」使用。
from
支援任意層級的巢狀結構。這是前一頁的變化
範例:
offer: [
{
protocol: "fuchsia.ui.Compositor",
from: "parent/bundle/gfx",
to: "#echo-child",
},
],
如同最後一個範例,元件會假設父項提供字典
名為 bundle
,而這個 bundle
包含名為 gfx
的字典。
最後,gfx
包含名為 fuchsia.ui.Compositor
的通訊協定能力。
是獨立提供給 #echo-child
使用。
最後,甚至可以結合 「匯總」,可將能力從一個字典轉送至 其他:
capabilities: [
{
dictionary: "my-bundle",
},
],
offer: [
{
protocol: "fuchsia.examples.Echo",
from: "parent/bundle",
to: "self/my-bundle",
},
],
擴充功能
在某些情況下,您可能會想建立一個涵蓋功能的字典 由多個元件新增無法以匯總的方式執行這項操作 一個字典,因為一個元件 可以在定義的字典中新增功能。
不過,您也可以透過擴充功能執行類似操作。擴充功能 作業可讓您宣告 複製自另一個字典 (稱為「來源字典」)。如此一來 可以建立新的字典,逐步使用先前的字典 而不必個別轉送所有功能
通常當您擴充字典時,還需要 擴充字典功能額外用於 功能不得與來源字典中的任何鍵衝突。如果他們 否則,當使用者嘗試擷取 來自擴充字典的能力
您可以新增 extends
,將字典宣告為另一個字典
將關鍵字加入字典的 capability
宣告中,以識別來源
字典中。extends
的語法與先前提過的 from
語法相同
擷取:
例如:
capabilities: [
{
dictionary: "my-bundle",
extends: "parent/bundle",
},
],
offer: [
{
protocol: "fuchsia.examples.Echo",
from: "#echo-server",
to: "self/my-bundle",
},
{
dictionary: "my-bundle",
from: "self",
to: "#echo-client",
as: "bundle",
},
],
與 from
相同,extends
中的路徑可參照巢狀字典:
capabilities: [
{
dictionary: "my-gfx",
extends: "parent/bundle/gfx",
},
],
動態字典
在「擴充功能」的特殊情況下,來源字典可以是
元件程式在執行階段動態提供的字典。
這樣就能在執行階段佈建的字典與
宣告式 dictionary
功能。語法如下:
extends: "program/<outgoing-dir-path>",
<outgoing-dir-path>
是元件中的路徑
傳出目錄至處理常式
fuchsia.component.sandbox/Router
通訊協定
應傳回 Dictionary
能力。
讓我們透過範例說明這項功能。這個範例包含 分屬兩個元件
dynamic-dictionary-provider
:建立執行階段Dictionary
搭配三個Echo
通訊協定 執行個體。這會透過Router
公開Dictionary
並在其 CML 中定義可擴充Router
的dictionary
。dynamic-dictionary
:宣告 CML 以擷取三個 來自dictionary
的Echo
通訊協定,並執行程式碼來使用這些 通訊協定
供應商
dynamic-dictionary-provider
的元件資訊清單如下所示。在這裡
請參閱擴充 Router
的 bundle
的 dictionary
定義。
capabilities: [
{
dictionary: "bundle",
path: "/svc/fuchsia.component.sandbox.Router",
},
],
use: [
{
protocol: [
"fuchsia.component.sandbox.CapabilityStore",
"fuchsia.component.sandbox.Factory",
],
from: "framework",
},
],
expose: [
{
dictionary: "bundle",
from: "self",
},
],
}
在初始化時,dynamic-dictionary-provider
會使用
CapabilityStore
sandbox API 建立新項目
Dictionary
,然後新增三個 Connector
。每項
Connector
代表 Echo
通訊協定執行個體的其中一個。
let store = client::connect_to_protocol::<fsandbox::CapabilityStoreMarker>().unwrap();
let id_gen = sandbox::CapabilityIdGenerator::new();
// Create a dictionary
let dict_id = id_gen.next();
store.dictionary_create(dict_id).await.unwrap().unwrap();
// Add 3 Echo servers to the dictionary
let mut receiver_tasks = fasync::TaskGroup::new();
for i in 1..=3 {
let (receiver, receiver_stream) =
endpoints::create_request_stream::<fsandbox::ReceiverMarker>().unwrap();
let connector_id = id_gen.next();
store.connector_create(connector_id, receiver).await.unwrap().unwrap();
store
.dictionary_insert(
dict_id,
&fsandbox::DictionaryItem {
key: format!("fidl.examples.routing.echo.Echo-{i}"),
value: connector_id,
},
)
.await
.unwrap()
.unwrap();
receiver_tasks.spawn(async move { handle_echo_receiver(i, receiver_stream).await });
}
每個 Connector
都會繫結至 Receiver
,
Echo
的傳入要求。Receiver
處理常式的實作方式為
與 ServiceFs
處理常式非常相似,差別在於前者是
ServiceFs
,Receiver
會繫結至 Connector
,而不是
元件的傳出目錄
async fn handle_echo_receiver(index: u64, mut receiver_stream: fsandbox::ReceiverRequestStream) {
let mut task_group = fasync::TaskGroup::new();
while let Some(request) = receiver_stream.try_next().await.unwrap() {
match request {
fsandbox::ReceiverRequest::Receive { channel, control_handle: _ } => {
task_group.spawn(async move {
let server_end = endpoints::ServerEnd::<EchoMarker>::new(channel.into());
run_echo_server(index, server_end.into_stream().unwrap()).await;
});
}
fsandbox::ReceiverRequest::_UnknownMethod { ordinal, .. } => {
warn!(%ordinal, "Unknown Receiver request");
}
}
}
}
async fn run_echo_server(index: u64, mut stream: EchoRequestStream) {
while let Ok(Some(event)) = stream.try_next().await {
let EchoRequest::EchoString { value, responder } = event;
let res = match value {
Some(s) => responder.send(Some(&format!("{s} {index}"))),
None => responder.send(None),
};
if let Err(err) = res {
warn!(%err, "Failed to send echo response");
}
}
}
最後,我們需要公開先前建立的字典,
Router
。
let mut fs = ServiceFs::new_local();
fs.dir("svc").add_fidl_service(IncomingRequest::Router);
fs.take_and_serve_directory_handle().unwrap();
fs.for_each_concurrent(None, move |request: IncomingRequest| {
let store = store.clone();
let id_gen = id_gen.clone();
async move {
match request {
IncomingRequest::Router(mut stream) => {
while let Ok(Some(request)) = stream.try_next().await {
match request {
fsandbox::RouterRequest::Route { payload: _, responder } => {
let dup_dict_id = id_gen.next();
store.duplicate(dict_id, dup_dict_id).await.unwrap().unwrap();
let capability = store.export(dup_dict_id).await.unwrap().unwrap();
let _ = responder.send(Ok(capability));
}
fsandbox::RouterRequest::_UnknownMethod { ordinal, .. } => {
warn!(%ordinal, "Unknown Router request");
}
}
}
}
}
}
})
.await;
Router
要求處理常式會匯出字典,
傳回。請注意
字典的 CapabilityStore/Duplicate
因為架構可能會多次呼叫 Router/Route
這個引數包含
複製字典把手的效果,不複製內部
內容。
fsandbox::RouterRequest::Route { payload: _, responder } => {
let dup_dict_id = id_gen.next();
store.duplicate(dict_id, dup_dict_id).await.unwrap().unwrap();
let capability = store.export(dup_dict_id).await.unwrap().unwrap();
let _ = responder.send(Ok(capability));
}
用戶端
用戶端很簡單。首先,元件資訊清單會擷取
來自 bundle
字典的通訊協定 (使用一般擷取)
語法。
use: [
{
protocol: [
"fidl.examples.routing.echo.Echo-1",
"fidl.examples.routing.echo.Echo-2",
"fidl.examples.routing.echo.Echo-3",
],
from: "#provider/bundle",
},
],
程式會依序連線到每個通訊協定並嘗試使用:
for i in 1..=3 {
info!("Connecting to Echo protocol {i} of 3");
let echo = client::connect_to_protocol_at_path::<EchoMarker>(&format!(
"/svc/fidl.examples.routing.echo.Echo-{i}"
))
.unwrap();
let res = echo.echo_string(Some(&format!("hello"))).await;
assert_matches!(res, Ok(Some(s)) if s == format!("hello {i}"));
}
可變動性
dictionary
功能遵循下列可變動規則:
- 只有定義字典的元件允許
匯總或擴充資料。此外,這是
將功能新增至
dictionary
的方式,而且無法 而且在執行階段修改檔案 - 轉送字典的元件皆可擷取 所有 AI 功能
- 如果元件發出兩個連續的轉送要求,
從相同的
dictionary
擷取,則每個要求可能會 會傳回不同的結果。舉例來說,雖然在 其他失敗。這是能力要求性質的副作用 轉送。在兩項要求之間,可能 上游重新解決,並將 字典