通訊協定的效期

本文說明元件嘗試連線至命名空間中的通訊協定時會執行的步驟。

大致步驟如下:

建構元件的命名空間

「命名空間」是元件啟動時,提供給元件的一組目錄。每個目錄都與檔案系統路徑相關聯,元件可透過該路徑存取其他元件提供的檔案和通訊協定。

這些目錄會採用「處理管道」的形式,通過管道,因此元件可以使用 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 會觸發能力轉送

如要判斷透過管道提供通訊協定的元件,元件管理員必須遵循 offerexpose 宣告中的元件樹狀結構,才能找到能力的來源。這項程序稱為「功能轉送」

從觸發能力轉送的元件父項開始,元件管理員會檢查每個元件的資訊清單,尋找目的地與子項相符的 offer 宣告。優惠會指定 parentself 或子項名稱的來源。如果優惠是來自元件的運作範圍,領域會繼續往樹狀結構前進,如果優惠來自元件的其中一個子項,則會向下走至樹狀結構的子項。

轉送開始往下行到樹狀結構時,會尋找 expose 宣告,這會指定 self 或子項名稱的來源。如果能力來自子項,元件管理員會繼續往下到樹狀結構。

找到含有 self 來源的 offerexpose 宣告後,元件管理員就能將管道交給該元件。

如果鏈結的任一步驟無效,元件管理員就會記錄錯誤,並關閉從 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.FooDoffer 宣告,您會發現它來自子項 B
  • B 尋找 fuchsia.example.Fooexpose 宣告,可以看到來自 A
  • A 尋找 fuchsia.example.Fooexpose 宣告,可以看到來自 self。也就是說,A 是提供 D 嘗試使用能力的元件。

現在已找到供應商元件,元件管理員就能嘗試透過 Open 要求處理收到的管道。

繫結至元件並傳送通訊協定管道

供應商找到用戶端元件後,現在已和供應商繫結。如果元件目前停止,這會導致元件開始執行。

元件繫結時,元件管理員會將通訊協定管道的伺服器端,轉送至提供元件的傳出目錄,位於提供元件 offerexpose 宣告的來源路徑底下。

在上述範例元件管理員中,元件管理員會透過元件 A 的傳出目錄控點傳送 Open 要求至 /svc/fuchsia.example.Foo 路徑,提供在元件 D 呼叫 Open 給元件管理員時,從元件 D 收到的管道控制代碼。

接著,元件 A 就能接收這項要求,並開始透過指定的管道回應訊息。

由於元件管理員會將通訊協定管道的伺服器端直接轉送到供應器元件的傳出目錄,因此它不會涉及訊息 Proxy,而是在能力轉送完成後完全消失。連線至其他元件後,這些元件會直接彼此通訊,中間不具有仲裁者。

注意事項

執行階段無法預測

由於能力轉送的執行階段性質和提供功能的元件行為的關係,無法得知特定元件能否在嘗試執行該功能前成功存取其命名空間。即使該項能力存在有效的優惠/公開鏈結,套件更新仍可能會在執行階段中斷這個鏈,因此宣告在資訊清單中提供某項能力的元件將無法執行此操作。

提供的功能與環境功能

某些功能是由元件架構本身提供,可在沒有父項提供這些功能的情況下,直接 (或以隱含方式) 元件使用。目前: