本文件說明元件嘗試連線至其命名空間中的通訊協定時,會發生的步驟。
大致步驟如下:
- 元件管理員會根據資訊清單中的
use
宣告,建構元件的命名空間。 - 元件開始執行後,會嘗試在其命名空間中開啟通訊協定。
- 元件管理員會收到這項
Open
要求,並執行尋找提供該通訊協定的元件所需的功能路由。 - 元件管理員會繫結至提供通訊協定的元件,並將
Open
要求連結至該元件
建構元件的命名空間
命名空間是一組目錄,會在元件啟動時提供給該元件。每個目錄都會與檔案系統路徑建立關聯,讓元件可透過該路徑存取其他元件提供的檔案和通訊協定。
這些目錄的形式為句柄到管道,元件可透過這些管道使用fuchsia.io.Directory
FIDL 通訊協定。
舉例來說,所有元件都會收到套件內容的句柄,這些元件是在 /pkg
建立。這表示元件可以透過讀取 /pkg/bin
的內容,查看套件中可用的二進位檔。
元件資訊清單中的 use
宣告會決定命名空間的填入方式。使用通訊協定能力時...
use: [
{
protocol: "fuchsia.example.Foo",
},
]
...元件管理員會在通訊協定的父目錄中,為元件的命名空間新增項目。在這個範例中,通訊協定的命名空間路徑為 /svc/fuchsia.example.Foo
(預設路徑指派),表示元件管理員會將 /svc
的句柄新增至命名空間。
/svc
目錄是由元件管理器本身提供,元件管理器會在元件的整個生命週期中,回應對此目錄的通訊協定要求。
命名空間中顯示的確切語意會因能力類型而異。舉例來說,如果使用目錄能力而非通訊協定能力...
use: [
{
directory: "example-data",
rights: [ "r*" ],
path: "/example/data",
},
]
命名空間中會顯示目錄本身的句柄,而不是父目錄的句柄。在這個範例中,這表示 /example/data
的句柄會顯示在命名空間中,但如果這個路徑用於通訊協定能力,/example
就會顯示在命名空間中。
元件開啟通訊協定
當元件想要開啟通訊協定時,會建立新的管道組合,並透過其命名空間中的管道,透過 Open
要求傳送此組合的其中一個端點。舉例來說,如果元件想要開啟與 /svc/fuchsia.example.Foo
的連線,新管道組的其中一端會透過其命名空間中的 /svc
句柄傳送。接著,元件可能會透過管道呼叫 fuchsia.example.Foo
通訊協定。
由於包含通訊協定的目錄 (/svc
) 是由元件管理員提供,因此元件管理員會透過元件傳送的 Open
要求,接收新管道的伺服器端。元件管理員接著必須識別透過此管道提供通訊協定的元件。
Open
會觸發能力轉送
如要判斷透過管道提供通訊協定的元件,元件管理員必須依序檢查 offer
和 expose
宣告,沿著元件樹狀結構尋找能力的來源。這項程序稱為「能力路由」。
元件管理員會從觸發能力轉送的元件父項開始,檢查每個元件的資訊清單,尋找目的地與子項相符的 offer
宣告。方案會指定 parent
、self
或子項名稱的來源。如果優惠來自元件的領域,系統會繼續向上瀏覽樹狀結構,如果優惠來自元件的其中一個子項,系統會向下瀏覽樹狀結構至該子項。
一旦路由開始沿著樹狀結構往下走,就會尋找 expose
宣告,並指定 self
或子項名稱的來源。如果能力來自子項,元件管理員會繼續沿著樹狀結構下移。
一旦找到來源為 self
的 offer
或 expose
宣告,元件管理員就能將管道交給該元件。
如果鏈結的任何步驟無效,元件管理員就會記錄錯誤,並關閉從 Open
呼叫收到的管道。這可能是由多種情況造成,例如:
- 元件
C
提供parent
的能力,但其父項R
並未將該能力提供給C
。 - 元件
C
提供子項D
的能力,但子項D
並未將能力公開給C
。
舉例來說,請考慮下列元件樹狀結構及其資訊清單 (為了簡化說明,省略 program
區塊和執行元件設定):
C
/ \
B D
/
A
A.cml:
{
// ...
capabilities: [
{
protocol: "fuchsia.example.Foo",
},
],
expose: [
{
protocol: "fuchsia.example.Foo",
from: "self",
},
],
}
B.cml:
{
// ...
expose: [
{
protocol: "fuchsia.example.Foo",
from: "#A",
},
],
children: [
{
name: "A",
url: "fuchsia-pkg://fuchsia.com/a#meta/a.cm",
},
]
}
C.cml:
{
// ...
offer: [
{
protocol: "fuchsia.example.Foo",
from: "#B",
to: [ "#D" ],
},
]
children: [
{
name: "B",
url: "fuchsia-pkg://fuchsia.com/b#meta/b.cm",
},
{
name: "D",
url: "fuchsia-pkg://fuchsia.com/d#meta/d.cm",
},
]
}
D.cml:
{
// ...
use: [
{
protocol: "fuchsia.example.Foo",
},
],
}
當 D
在其命名空間中對 /svc/fuchsia.example.Foo
呼叫 Open
時,元件管理員會逐一檢查樹狀結構,找出應提供此通訊協定的元件。它會從 D
的父項 C
開始,然後依序執行以下動作:
- 請找出
fuchsia.example.Foo
到D
的offer
宣告,並確認該宣告來自子項B
。 - 請找出
B
中fuchsia.example.Foo
的expose
宣告,並確認該宣告來自A
。 - 請找出
A
中fuchsia.example.Foo
的expose
宣告,並確認該宣告來自self
。這表示A
是提供D
嘗試使用的能力的元件。
找到提供者元件後,元件管理員可以嘗試透過 Open
要求,將收到的管道交給其他元件。
繫結至元件並傳送通訊協定管道
找到提供者後,用戶端元件現在會繫結至提供者。如果元件目前已停止,這會導致元件開始執行。
每個元件在啟動時都會收到指向某個句柄表的伺服器句柄,元件繫結時,元件管理員會將通訊協定管道的伺服器端轉送至提供元件的傳出目錄,位於提供元件 offer
或 expose
宣告中的來源路徑下。
在上述範例中,元件管理員會透過元件 A
的傳出目錄句柄,將 Open
要求傳送至 /svc/fuchsia.example.Foo
路徑,提供從元件 D
傳送至元件管理員的 Open
呼叫時,所收到的管道句柄。
接著,元件 A
會收到這項要求,並開始透過所提供的管道回應訊息。
由於元件管理員會直接將通訊協定管道的伺服器端轉送至提供者元件的傳出目錄,因此不會參與訊息代理,且在能力轉送完成後,就會完全離開畫面。一旦與其他元件建立連線,它們就會直接互相通訊,中間沒有仲裁者。
注意事項
執行階段的不確定性
由於能力轉送的執行階段特性和提供能力的元件行為,我們無法得知特定元件是否可以在嘗試存取能力之前,成功存取其命名空間中的功能。即使能力有有效的提供/公開鏈結,套件更新也可能會在執行階段中斷鏈結,因此聲稱在其資訊清單中提供能力的元件,在執行時可能無法提供能力。
提供與微光功能
有些功能是由元件架構本身提供,可直接由元件使用 (或會隱含提供給元件),而不需要元件父項提供這些功能。目前有:
/pkg
:建立元件的套件句柄。/svc/fuchsia.component.Realm
:元件可用來管理自身領域的通訊協定。