本文件說明如何使用功能將元件串連在一起 和上層元件適用的其他工具
概念
繼續閱讀本指南之前,請先瞭解以下概念:
* 元件架構結合了
命名空間
的
建構元件
元件宣告
並
描述
功能
為此元件
函式。元件公開給他人的功能會組合成
換
公開的目錄
,直接在 Google Cloud 控制台實際操作。
* 每個元件都會收到
Directory
管道,稱為
傳出目錄
,直接在 Google Cloud 控制台實際操作。元件的程式
能夠發掘透過此目錄提供的所有功能。
* 在執行階段,
元件執行個體樹狀結構
描述了父項和子項關係
元件執行個體
,直接在 Google Cloud 控制台實際操作。元件執行個體
樹狀結構,以及該樹狀結構上的能力路徑
作為
元件拓撲
,直接在 Google Cloud 控制台實際操作。
* 父項元件會在
元件資訊清單
或是使用
元件集合
,直接在 Google Cloud 控制台實際操作。集合是一種
動態子項容器,可能會在執行階段建立及刪除
使用 fuchsia.component.Realm
架構通訊協定
透過轉送連接功能
元件會透過功能彼此互動。服務依據
在該元件的資訊清單中,您需要宣告一個元件
可供他人使用,並透過 expose
和 offer
轉送至父項/子項元件
宣告的內容其他使用該能力的元件也需要宣告
並運用在資訊清單中為了讓程式能
必須使用的能力必須轉送至該元件
或由孩子公開提供的資源
功能轉送是指由元件執行的遞迴程序 管理者,可依循個別轉送方式來識別服務元件 所描述的步驟,如資訊清單檔案中所述。在下列情況下,即會開始轉送能力:
- 元件程式會在其程式開啟路徑 命名空間 ,直接在 Google Cloud 控制台實際操作。
- 元件的程式會在另一個元件的 公開的目錄 ,直接在 Google Cloud 控制台實際操作。
- 開發人員叫用
ffx component route
。 - 啟動需要依附於支援器或執行器的元件 解析器或執行元件功能尚未轉送。
轉送作業延後執行:雖然能力可能設定為 由家長或下層提供 (直接或間接透過 時,目標元件可能尚未解決 已啟動轉送作業。這代表完整的路線 傳送至最終供應元件的請求元件 嘗試轉送。
提供能力實作
提供能力的元件必須在其
透過 capabilities
宣告來元件資訊清單。
請參閱宣告 FIDL 的範例 通訊協定元件:
{
include: [
"inspect/client.shard.cml",
"syslog/client.shard.cml",
],
// Information about the program to run.
program: {
// Use the built-in ELF runner.
runner: "elf",
// The binary to run for this component.
binary: "bin/echo_server_rust",
},
// Capabilities provided by this component.
capabilities: [
{ protocol: "fidl.examples.routing.echo.Echo" },
],
expose: [
{
protocol: "fidl.examples.routing.echo.Echo",
from: "self",
},
],
}
在執行階段,伺服器元件會為 使用 fuchsia.io 在傳出目錄中提供該物件 因此效能相當卓越產生的 FIDL 繫結會包裝這個帳號代碼並啟用供應器 開始接收傳入的要求:
荒漠油廠
// Wrap protocol requests being served.
enum IncomingRequest {
Echo(EchoRequestStream),
}
#[fuchsia::main(logging = false)]
async fn main() -> Result<(), anyhow::Error> {
let mut service_fs = ServiceFs::new_local();
// Initialize inspect
component::health().set_starting_up();
let _inspect_server_task = inspect_runtime::publish(
component::inspector(),
inspect_runtime::PublishOptions::default(),
);
// Serve the Echo protocol
service_fs.dir("svc").add_fidl_service(IncomingRequest::Echo);
service_fs.take_and_serve_directory_handle().context("failed to serve outgoing namespace")?;
// Component is serving and ready to handle incoming requests
component::health().set_ok();
// Attach request handler for incoming requests
service_fs
.for_each_concurrent(None, |request: IncomingRequest| async move {
match request {
IncomingRequest::Echo(stream) => handle_echo_request(stream).await,
}
})
.await;
Ok(())
}
// Handler for incoming service requests
async fn handle_echo_request(mut stream: EchoRequestStream) {
while let Some(event) = stream.try_next().await.expect("failed to serve echo service") {
let EchoRequest::EchoString { value, responder } = event;
responder.send(value.as_ref().map(|s| &**s)).expect("failed to send echo response");
}
}
C++
```cpp // 傳入服務要求的處理常式 class EchoImplementation : public fidl::examples::routing::echo::Echo { 公開: void EchoString(fidl::StringPtr value, EchoStringCallback 回呼) 覆寫 { call(value);} fidl::examples::routing::echo::Echo_EventSender* event_sender_; };
int main(int argc, const char** argv) { async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread); 自動內容 = sys::ComponentContext::CreateAndServeOutgoingDirectory(); // 初始化檢查 inspect::ComponentInspector inspector(loop.dispatcher(), inspect::PublishOptions{}); inspector.Health().StartingUp(); // 提供 Echo 通訊協定 Echo 實作 echo_instance; fidl::Binding<fidl::examples::routing::echo::Echo>binding(&echo_instance); echo_instance.event_sender_ = &binding.events(); fidl::InterfaceRequestHandler<fidl::examples::routing::echo::Echo>處理常式 = [&](fidl::InterfaceRequest<fidl::examples::routing::echo::Echo> request) { binding.Bind(std::move(request)); }; context->outgoing()->AddPublicService(std::move(handler)); // 元件正在提供服務,並準備好處理傳入的要求 inspector.Health().Ok(); returnLoop.Run(); } ```
連線至轉送功能
用戶端元件會在元件中宣告可能要求的功能
透過 use
宣告的資訊清單。
請參考以下使用 FIDL 的用戶端元件資訊清單範例 透過先前元件提供的通訊協定
{
include: [
// Enable logging on stdout
"syslog/client.shard.cml",
],
// Information about the program to run.
program: {
// Use the built-in ELF runner.
runner: "elf",
// The binary to run for this component.
binary: "bin/echo_client_rust",
// Program arguments
args: [ "Hello Fuchsia!" ],
},
// Capabilities used by this component.
use: [
{ protocol: "fidl.examples.routing.echo.Echo" },
],
}
在執行階段,用戶端元件會使用 fuchsia.io 通訊協定以取得功能 其他元件提供的元件Fuchsia 元件庫可與 所產生的 FIDL 繫結,提供結構化介面 管道:
荒漠油廠
#[fuchsia::main]
async fn main() -> Result<(), anyhow::Error> {
// Parse arguments, removing binary name
let mut args: Vec<String> = std::env::args().collect();
args.remove(0);
// Connect to FIDL protocol
let echo = connect_to_protocol::<EchoMarker>().expect("error connecting to echo");
// Send messages over FIDL interface
for message in args {
let out = echo.echo_string(Some(&message)).await.expect("echo_string failed");
tracing::info!("Server response: {}", out.as_ref().expect("echo_string got empty result"));
}
Ok(())
}
C++
int main(int argc, const char* argv[], char* envp[]) {
// Set tags for logging.
fuchsia_logging::LogSettingsBuilder builder;
builder.WithTags({"echo_client"}).BuildAndInitialize();
// Connect to FIDL protocol
fidl::examples::routing::echo::EchoSyncPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
// Send messages over FIDL interface for each argument
fidl::StringPtr response = nullptr;
for (int i = 1; i < argc; i++) {
ZX_ASSERT(echo_proxy->EchoString(argv[i], &response) == ZX_OK);
if (!response.has_value()) {
FX_LOG_KV(INFO, "echo_string got empty result");
} else {
FX_LOG_KV(INFO, "Server response", FX_KV("response", response->c_str()));
}
}
return 0;
}
元件的父項必須負責將元件轉送至該元件 即便沒有技術背景,也能因這些工具的功能而受益
將部分功能標示為非必要功能
元件使用的所有功能不一定都能運作 如果元件 而實作能力只會啟用 替代行為
使元件架構瞭解元件功能
需要,以及元件是選用哪些功能,請使用
「availability
」欄位。
use: [
{
// It is ok if this protocol is unavailable
protocol: "fuchsia.examples.Echo1",
availability: "optional",
},
{
// This protocol MUST be provided for the component to function correctly.
protocol: "fuchsia.examples.Echo2",
availability: "required",
},
]
如果元件具有針對能力有 required
使用宣告 (預設值)
但其父項提供的能力為 optional
,那麼
「能力工具」就會產生錯誤
一律會失敗。
使用選用功能
在元件的父項中,offer
設有功能
availability: "optional"
,該能力可能無法在執行階段使用。
元件中的項目
命名空間
會顯示
以及此能力是否可用任何嘗試開放
該能力會產生提供給 Directory.Open()
的控制代碼
用 ZX_ERR_NOT_FOUND
符號打烊的電話。
使用 libc
方法 (例如 open()
或 stat()
) 會傳回 ENOENT
。
路徑功能
元件只能存取轉送到其中的功能。能力 源自元件拓撲中的任何位置,只要具備有效的能力 路徑存在為來自能力中下列宣告的鏈結 提供給任何消費者:
為了將能力供應商與要求這些功能的元件連結, :
將
offer
或expose
宣告新增至能力供應器元件:{ include: [ "inspect/client.shard.cml", "syslog/client.shard.cml", ], // Information about the program to run. program: { // Use the built-in ELF runner. runner: "elf", // The binary to run for this component. binary: "bin/echo_server_rust", }, // Capabilities provided by this component. capabilities: [ { protocol: "fidl.examples.routing.echo.Echo" }, ], expose: [ { protocol: "fidl.examples.routing.echo.Echo", from: "self", }, ], }
對於元件執行個體樹狀結構中的每個中繼元件,請加入 額外的
expose
和offer
宣告,直到觸及 包含use
宣告的元件:{ // Two children: a server and client. children: [ { name: "echo_server", url: "#meta/echo_server.cm", }, { name: "echo_client", url: "#meta/echo_client.cm", }, ], offer: [ // Route Echo protocol from server to client. { protocol: "fidl.examples.routing.echo.Echo", from: "#echo_server", to: "#echo_client", }, // Route diagnostics protocols to both children. { protocol: [ "fuchsia.inspect.InspectSink", "fuchsia.logger.LogSink", ], from: "parent", to: [ "#echo_client", "#echo_server", ], }, ], }
選用的依附元件
如果元件對能力有選用依附元件,則該元件會
該元件的父項來決定該元件是否會接收
不一定。提供能力時,元件可能會設定 availability
欄位
轉換為 optional
、required
或 same_as_target
。每個值都有
下列語意:
optional
:優惠目標必須宣告自身能處理 如果缺少此能力,請將其的use
宣告標示為optional
。 如果目標無法這麼做 (例如,目標的可用性為required
用於這項能力),則轉送能力會造成 錯誤。required
:目標必須接收這項能力。如果優惠來源是parent
和元件的父項 (目標的祖系) 都提供了這個項目 反之,而轉送該能力會導致錯誤 因為父項無法保證能力的可用性。same_as_target
:這項能力是否可用取決於 達到預期的目標如果目標有選用依附元件 能力,這項方案也會是選用項目如果目標為 這項能力所需的依附元件 這通常代表交易 不會十分要求關聯語意
offer: [
{
// child-1 MUST receive the protocol 'fuchsia.logger.LogSink'.
protocol: "fuchsia.logger.LogSink",
to: "#child-1",
from: "#child-2",
availability: "required",
},
{
// child-1 MUST be able to handle the absence of the protocol
// 'fuchsia.tracing.provider.Registry'.
protocol: "fuchsia.tracing.provider.Registry",
to: "#child-1",
from: "parent",
availability: "optional",
},
{
// child-1 decides if it must receive the protocol
// 'fuchsia.posix.socket.Provider', or if it must be able to support its
// absence.
protocol: "fuchsia.posix.socket.Provider",
to: "#child-1",
from: "parent",
availability: "same_as_target",
},
]
與使用宣告相同,您可以省略 availability
欄位,
在這個情況下,預設值為 required
。
轉換型依附元件
元件架構讓元件可在 BERT 環境中 並提供選用與必要功能在 2017 年 可用性標記是使用能力的元件 父項為必要、選用或與驗證錯誤 目標。請注意,雖然有這個欄位是用來啟用軟轉換,但元件 最後應選項為選用或必要項目
如要使用這項功能,子項元件會將其可用性標示為 "過渡期":
use: [
{
// It is ok if this protocol is offered as "required" or "optional"
protocol: "fuchsia.examples.Echo",
availability: "transitional",
},
]
管理子項元件
在元件拓撲中的任何位置,元件都可互相互動 但前提是兩者之間必須有一個有效的能力路徑。 還有其他方法可讓父項元件與 這類行為
下列元件範例宣告了一個名為 lifecycle
的單一靜態子項
以及名為 echo
的集合,可用於建立其他子元件
的廣告:
{
// ...
// Statically declared child components
children: [
{
name: "lifecycle",
url: "lifecycle#meta/default.cm",
},
],
// Collection to hold dynamically created child components
collections: [
{
name: "echo",
durability: "transient",
},
],
// Capabilities required by this component
use: [
{
protocol: "fuchsia.component.Binder",
from: "#lifecycle",
},
{
protocol: "fuchsia.component.Realm",
from: "framework",
},
],
// Capabilities required by child components
offer: [
{
protocol: [
"fuchsia.inspect.InspectSink",
"fuchsia.logger.LogSink",
],
from: "parent",
to: [
"#echo",
"#lifecycle",
],
},
],
}
請注意,集合的運作方式類似於父項中的靜態子項執行個體 設定元件的資訊清單,您可以為元件命名並提供特定功能, 基礎架構集合中的所有子元件可存取一組功能 沒有任何影響
啟動子項元件
元件架構提供 fuchsia.component.Binder
適用於父項元件的通訊協定,明確啟動可能不公開的子項
任何其他功能由於這項能力是由架構提供,
子項元件只需要從元件資訊清單公開:
{
// ...
// Capabilities exposed from this component to parent.
expose: [
{
// Expose this protocol so that parent component can start it
// by binding to this capability.
protocol: "fuchsia.component.Binder",
from: "framework",
},
],
}
建立動態子項
如要在執行階段建立新的子項元件,請使用
使用 fuchsia.component.Realm
通訊協定在內部建立元件
現有的集合呼叫 CreateChild
方法,包含以下參數:
CollectionRef
:說明集合的位置 即可新增元件Child
:元件宣告,包括其名稱和 元件網址
荒漠油廠
use fidl_fuchsia_component::{BinderMarker, CreateChildArgs, RealmMarker};
use fidl_fuchsia_component_decl::{Child, ChildRef, CollectionRef, StartupMode};
// ...
// Use the fuchsia.component.Realm protocol to create a dynamic
// child instance in the collection.
async fn create_dynamic_child() {
let realm = client::connect_to_protocol::<RealmMarker>()
.expect("failed to connect to fuchsia.component.Realm");
let collection_ref = CollectionRef { name: String::from("echo") };
let child_decl = Child {
name: Some(String::from("lifecycle_dynamic")),
url: Some(String::from("echo_server#meta/default.cm")),
startup: Some(StartupMode::Lazy),
..Default::default()
};
realm
.create_child(&collection_ref, &child_decl, CreateChildArgs::default())
.await
.expect("create_child failed")
.expect("failed to create child");
}
C++
#include <fuchsia/component/cpp/fidl.h>
#include <fuchsia/component/decl/cpp/fidl.h>
// ...
// Use the fuchsia.component.Realm protocol to create a dynamic
// child instance in the collection.
void CreateDynamicChild() {
fuchsia::component::decl::CollectionRef collection_ref = {
.name = "echo",
};
fuchsia::component::decl::Child child_decl;
child_decl.set_name("lifecycle_dynamic");
child_decl.set_url("echo_server#meta/default.cm");
child_decl.set_startup(fuchsia::component::decl::StartupMode::LAZY);
realm_proxy_->CreateChild(std::move(collection_ref), std::move(child_decl),
fuchsia::component::CreateChildArgs(),
[&](fuchsia::component::Realm_CreateChild_Result result) {
ZX_ASSERT(!result.is_err());
FX_LOGS(INFO) << "Dynamic child instance created.";
ConnectDynamicChild();
});
}
與孩子交流互動
由於在建構期間無法得知動態元件的父項,因此其 加強版能力路徑中,不得以 元件資訊清單。
如要連線至動態子項執行個體所公開的功能:
使用
fuchsia.component.Realm
通訊協定開啟子項的 公開目錄呼叫OpenExposedDir
方法,其中包含子項元件的名稱和集合名稱:荒漠油廠
use fidl_fuchsia_component::{BinderMarker, CreateChildArgs, RealmMarker}; use fidl_fuchsia_component_decl::{Child, ChildRef, CollectionRef, StartupMode}; // ... // Connect to the fidl.examples.routing.echo capability exposed by the child // instance, and send a request. async fn connect_dynamic_child(message: String) { // Open the child's exposed directory let exposed_dir = client::open_childs_exposed_directory( String::from("lifecycle_dynamic"), Some(String::from("echo")), ) .await .expect("failed to open exposed directory"); // ... }
C++
#include <fuchsia/component/cpp/fidl.h> #include <fuchsia/component/decl/cpp/fidl.h> // ... // Use the fuchsia.component.Realm protocol to open the exposed directory of // the dynamic child instance. void ConnectDynamicChild() { fuchsia::component::decl::ChildRef child_ref = { .name = "lifecycle_dynamic", .collection = "echo", }; fidl::InterfaceHandle<fuchsia::io::Directory> exposed_dir; realm_proxy_->OpenExposedDir( child_ref, exposed_dir.NewRequest(), [this, exposed_dir = std::move(exposed_dir)]( fuchsia::component::Realm_OpenExposedDir_Result result) mutable { ZX_ASSERT(!result.is_err()); std::shared_ptr<sys::ServiceDirectory> svc = std::make_shared<sys::ServiceDirectory>( sys::ServiceDirectory(std::move(exposed_dir))); SendEchoRequest(svc); }); }
使用公開目錄連線至子項公開的功能 作為根:
荒漠油廠
// Access the fidl.examples.routing.echo capability provided there let echo = client::connect_to_protocol_at_dir_root::<EchoMarker>(&exposed_dir) .expect("failed to connect to fidl.examples.routing.echo"); let response = echo .echo_string(Some(&message)) .await .expect("echo_string failed") .expect("echo_string got empty result"); info!("Server response: {}", response);
C++
// Connect to the fidl.examples.routing.echo capability exposed by the child's // service directory. void SendEchoRequest(std::shared_ptr<sys::ServiceDirectory> svc_directory) { // Connect to the protocol inside the child's exposed directory svc_directory->Connect(echo_proxy_.NewRequest()); // Send a protocol request echo_proxy_->EchoString(message_, [&](fidl::StringPtr response) { FX_LOGS(INFO) << "Server response: " << response; DestroyDynamicChild(); }); }
破壞動態子項
不再需要動態子項時,請使用
fuchsia.component.Realm
通訊協定來刪除元件
執行個體。使用下列指令呼叫 DestroyChild
方法:
ChildRef
,代表集合中的子項。
荒漠油廠
use fidl_fuchsia_component::{BinderMarker, CreateChildArgs, RealmMarker};
use fidl_fuchsia_component_decl::{Child, ChildRef, CollectionRef, StartupMode};
// ...
// Use the fuchsia.component.Realm protocol to destroy the dynamic
// child instance running in the collection.
async fn destroy_dynamic_child() {
let realm = client::connect_to_protocol::<RealmMarker>()
.expect("failed to connect to fuchsia.component.Realm");
let child_ref = ChildRef {
name: String::from("lifecycle_dynamic"),
collection: Some(String::from("echo")),
};
realm
.destroy_child(&child_ref)
.await
.expect("destroy_child failed")
.expect("failed to destroy child");
}
C++
#include <fuchsia/component/cpp/fidl.h>
#include <fuchsia/component/decl/cpp/fidl.h>
// ...
// Use the fuchsia.component.Realm protocol to destroy the dynamic
// child instance running in the collection.
void DestroyDynamicChild() {
fuchsia::component::decl::ChildRef child_ref = {
.name = "lifecycle_dynamic",
.collection = "echo",
};
realm_proxy_->DestroyChild(std::move(child_ref),
[&](fuchsia::component::Realm_DestroyChild_Result result) {
ZX_ASSERT(!result.is_err());
FX_LOGS(INFO) << "Dynamic child instance destroyed.";
// Terminate the loop
loop_->Quit();
});
}
這會讓元件在目前正在執行時停止運作。為了處理這種情況 事件中,請參閱監聽停止事件元件。
控制元件生命週期
元件架構提供修改項目以及與各種項目互動的功能 元件部分
如要進一步瞭解生命週期概念,請參閱 元件生命週期。
生命週期通知
ELF 執行元件會使用
fuchsia.process.lifecycle.Lifecycle
通訊協定。
如要監聽子元件中的停止通知:
訂閱元件中的生命週期事件 manifest:
荒漠油廠
// Information about the program to run. program: { // Use the built-in ELF runner. runner: "elf", // The binary to run for this component. binary: "bin/lifecycle_example_rust", // Subscribe to component lifecycle events lifecycle: { stop_event: "notify" }, },
C++
// Information about the program to run. program: { // Use the built-in ELF runner. runner: "elf", // The binary to run for this component. binary: "bin/lifecycle_example_cpp", // Subscribe to component lifecycle events lifecycle: { stop_event: "notify" }, },
使用 執行元件:
荒漠油廠
use fidl_fuchsia_process_lifecycle::{LifecycleRequest, LifecycleRequestStream}; // ... #[fuchsia::main(logging_tags = ["lifecycle", "example"])] async fn main() { // Take the lifecycle handle provided by the runner match fuchsia_runtime::take_startup_handle(HandleInfo::new(HandleType::Lifecycle, 0)) { Some(lifecycle_handle) => { info!("Lifecycle channel received."); // Begin listening for lifecycle requests on this channel let x: fuchsia_zircon::Channel = lifecycle_handle.into(); let async_x = AsyncChannel::from(fuchsia_async::Channel::from_channel(x)); let mut req_stream = LifecycleRequestStream::from_channel(async_x); info!("Awaiting request to close..."); if let Some(request) = req_stream.try_next().await.expect("Failure receiving lifecycle FIDL message") { match request { LifecycleRequest::Stop { control_handle: c } => { info!("Received request to stop. Shutting down."); c.shutdown(); process::exit(0); } } } // We only arrive here if the lifecycle channel closed without // first sending the shutdown event, which is unexpected. process::abort(); } None => { // We did not receive a lifecycle channel, exit abnormally. error!("No lifecycle channel received, exiting."); process::abort(); } } }
C++
#include <fuchsia/process/lifecycle/cpp/fidl.h> // ... // Implementation of the fuchsia.process.lifecycle FIDL protocol class LifecycleHandler : public fuchsia::process::lifecycle::Lifecycle { public: explicit LifecycleHandler(async::Loop* loop) : loop_(loop) { // Get the PA_LIFECYCLE handle, and instantiate the channel with it zx::channel channel = zx::channel(zx_take_startup_handle(PA_LIFECYCLE)); // Bind to the channel and start listening for events bindings_.AddBinding( this, fidl::InterfaceRequest<fuchsia::process::lifecycle::Lifecycle>(std::move(channel)), loop_->dispatcher()); FX_LOGS(INFO) << "Lifecycle channel received."; } // This is the Stop event we must override - see the pure virtual function we // need to override at the declaration of fuchsia::process::lifecycle::Lifecycle void Stop() override { FX_LOGS(INFO) << "Received request to stop. Shutting down."; // Shut down our loop - it's important to call Shutdown() here vs. Quit() loop_->Shutdown(); // Close the binding bindings_.CloseAll(); } private: async::Loop* loop_; fidl::BindingSet<fuchsia::process::lifecycle::Lifecycle> bindings_; };
從父項開始
元件資訊清單可讓您將子項標示為
eager
,這會使元件架構以隱含方式
再由父項開始建立該子項
如果熱銷子項因任何原因無法啟動 (例如缺少元件), 而元件管理工具會顯示下列行為:
- 如果父項不是根元件,父項會啟動,但 和任何繫結至該繫結元件的元件都會觀察到連線中斷 (就像 其他失敗的繫結)。
如果父項為根元件,元件管理員就會停止運作,且 錯誤訊息,例如:
[component_manager] ERROR: protocol `fuchsia.component.CoreBinder` was not available for target `startup`: failed to resolve `fuchsia-pkg://fuchsia.com/your_component#meta/your_component.cm`: package not found: remote resolver responded with PackageNotFound For more, run `ffx component doctor `startup`
標示為 eager
的元件可能導致系統當機,但實際上沒有
如果其祖係也在根元件上標記 eager
,這是
因為許多建構設定會建立包含
可用元件子集如要避免發生這個問題,請宣告這些
使用核心領域資料分割的元件,確保能
將測試版本和產品映像檔安全地排除
eager
元件也應位於同一個套件集中
因為元件會和它的父項同時啟動
父項。一般而言,eager
元件應位於產品的基本套件中
設定。
如要判斷套件是否位於基本套件集中,請執行下列指令 指令:
fx list-packages --verbose my-package
這個指令會輸出符合套件的套件集清單
找到。例如,system-update-checker
位於 base
和 universe
套件集:
$ fx list-packages --verbose system-update-checker
system-update-checker [base universe]
您也可以使用 --base
查看基本套件組合中的所有套件
選項:
fx list-packages --base
終止時重新啟動
元件資訊清單可讓您控管
使用 on_terminate
編輯元件。含有
「終止後重新啟動」政策設定可能導致系統安全重新啟動,
元件因任何原因終止 (包括成功結束時)。
如要啟用這項功能,請按照下列步驟操作:
在父項元件資訊清單中,將子項標示為
on_terminate: reboot
:// core.cml { children: [ ... { name: "system-update-checker", url: "fuchsia-pkg://fuchsia.com/system-update-checker#meta/system-update-checker.cm", startup: "eager", on_terminate: "reboot", }, ], }
將元件的路徑名稱新增至元件管理員的安全性政策許可清單 於
//src/security/policy/component_manager_policy.json5
:// //src/security/policy/component_manager_policy.json5 { security_policy: { ... child_policy: { reboot_on_terminate: [ ... "/core/system-update-checker", ], }, }, }
錯誤
信號機制
當要求用戶端透過執行
Directory.Open()
要求,或
這個
公開的目錄
,它會將伺服器端
zircon 物件控點,該物件會在轉送後提供能力。錯誤數
將導致該帳號代碼的物體被關閉並附帶縮寫。八卦
酬載一律為 Zircon 狀態碼。
轉送作業屬於延遲且非同步作業,因此訊息隨時都會送達 轉送作業啟動後
注意:一旦轉送作業成功,供應元件也可以關閉 帶有自選狀態碼這對客戶來說不可能 判斷物件是否遭到元件管理員關閉 或之後委任的其他方。
類似 libc
的呼叫 (例如 open()
) 也適用相同的錯誤信號機制。
如需實際範例,請參閱「疑難排解」一節。
錯誤狀態碼
元件管理員可能會傳送下列錯誤代碼,表示失敗 轉送作業:
ZX_ERR_NOT_FOUND
:無法將能力轉送至其中一個 。ZX_ERR_ACCESS_DENIED
:無法轉送能力,因為 要求元件無法存取該元件。例如:- 能力存在的政策許可清單,但 不包含要求元件。
- 要求元件的權限大於所提供的值 (也就是要求以唯讀模式提供的目錄讀取/寫入資料)。
ZX_ERR_TIMED_OUT
:其中一個轉送步驟已逾時。ZX_ERR_INTERNAL
:元件管理員本身發生未預期的錯誤, 指出平台發生錯誤。
NOT_FOUND
、ACCESS_DENIED
和 INTERNAL
錯誤都會重現
。軟體更新
甚至可能會變更能力的路徑
並維持該能力的可用性
轉送錯誤語意原則
- 最低度:因為錯誤信號路徑是在元件之間共用 元件管理員和放送元件後,元件管理員會留下 供應元件要使用的錯誤空間
- 用戶端觀點:雖然轉送方式取決於許多人
可能會因為各種原因 (包括錯誤) 而失敗
其他元件作者則會將錯誤語意個人化
要求用戶端和提出要求用戶端的需求例如:
中間元件作者中的使用者錯誤仍會傳回
NOT_FOUND
用於要求用戶端。
疑難排解
本節說明您在嘗試use
與
透過建議的解決方案,從元件應用層面。
無法轉送功能
元件管理員會執行功能轉送,以找出
所指定能力的來源 (一旦元件嘗試存取
技術。如果轉送中的其中一個元件資訊清單,轉送作業可能會失敗
路徑設定不正確例如 offer
或 expose
宣告
路徑中的某些元件 不存在
無法解析鏈結。
請按照下列步驟檢查轉送失敗是否是管道關閉的原因:
使用
ffx component route
檢查元件的轉送方式。這個 可與元件的路徑名稱搭配使用,也可與元件的 網址。例如:# check with the moniker ffx component route /core/ffx-laboratory:echo_realm/echo_client # check with a partial URL ffx component route echo_client.cm
使用
ffx log
檢查元件記錄,找出開頭為Failed to route
的郵件,瞭解轉送鏈結失敗的原因。例如:[echo_client][][W] protocol `fidl.examples.routing.echo.Echo` was not available for target `/core/ffx-laboratory:echo_realm/echo_client`: `fidl.examples.routing.echo.Echo` was not offered to `/core/ffx-laboratory:echo_realm/echo_client` by parent For more, run `ffx component doctor /core/ffx-laboratory:echo_realm/echo_client`
請查看封閉式頻道中的 Epitaph 頻道。八卦 最常見的轉送失敗設定是
ZX_ERR_NOT_FOUND
:[echo_client][][I] Connecting to Echo protocol failed with error "A FIDL client's channel to the service fidl.examples.routing.echo.Echo was closed: NOT_FOUND"
詳情請參閱轉送錯誤。
如需能力轉送失敗的獨立範例,請參閱
//examples/components/routing_failed
。
接收轉送錯誤
當能力轉送失敗時,基礎 FIDL 管道就會關閉。FIDL 通訊協定 如果管道已關閉,繫結會傳回錯誤狀態。假設 範例:
荒漠油廠
let echo = connect_to_protocol::<EchoMarker>()
.context("Failed to connect to echo service")?;
let res = echo.echo_string(Some("Hippos rule!")).await;
match res {
Ok(_) => { info!("Call succeeded!"); }
Err(fidl::Error::ClientChannelClosed { status, service_name } => {
error!("Channel to service {} was closed with status: {}", service_name, status);
}
Err(e) => {
error!("Unexpected error: {}", e);
}
};
C++
fuchsia::examples::EchoPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
// Sets an error handler that will be called if an error causes the underlying
// channel to be closed.
echo_proxy.set_error_handler([&loop](zx_status_t status) {
printf("Channel was closed with status: %d\n", status);
// ...
});
echo_proxy->EchoString("Hippos rule!", [&](std::string response) {
// ...
});
如要判斷管道停用的根本原因,可以查看 可選擇的 epitaph 語言。如果想擷取 請按照以下說明操作:
荒漠油廠
let stream = echo.take_event_stream();
match stream.next().await {
Some(Err(fidl::Error::ClientChannelClosed { status, .. })) => {
info!("Channel was closed with epitaph: {}", status);
}
Some(m) => {
info!("Received message other than epitaph or peer closed: {:?}", m);
}
None => {
info!("Component failed to start or channel was closed by server");
}
}
C++
echo_proxy.set_error_handler([&loop](zx_status_t status) {
// If an Epitaph was present on the channel, its error value will be passed as
// the parameter.
printf("Channel was closed with epitaph: %d\n", status);
});
無法啟動元件
如果能力轉送成功,您可能會遇到錯誤,但發生問題 是否要解析或啟動元件錯誤訊息格式 取決於元件執行器:
如果是 ELF 執行元件,請使用
ffx log --filter component_manager
查看元件管理員記錄。尋找開頭為Failed to start component
的訊息。例如:[component_manager] WARN: Failed to start component `fuchsia-pkg://fuchsia.com/components-routing-failed-example#meta/echo_server_bad.cm`: unable to load component with url "fuchsia-pkg://fuchsia.com/components-routing-failed-example#meta/echo_server_bad.cm": error loading executable: "reading object at \"bin/routing_failed_echo_server_oops\" failed: A FIDL client's channel to the service fuchsia.io.File was closed: PEER_CLOSED"
至於其他執行器,請查看執行元件元件的記錄。個人中心 執行下列指令來進行這項操作:
ffx log --tags runner-name
如要解決這個問題,請確認下列事項:
舉例來說,因設定錯誤而無法啟動的元件示例
請參閱
//examples/components/routing_failed
。
元件已終止或關閉管道
如果您確認轉送成功,並啟動了元件 ,您可能已經遇到來源元件關閉的問題 管道本身這可能會在元件執行期間發生 元件終止的副作用
如果元件因當機而終止,您可以查看當機報告
包含傾印中元件名稱的 ffx log
中:
[33860.645][klog][klog][I] crashsvc: exception received, processing
[33860.645][klog][klog][I] <== fatal : process echo_client.cm[21090] thread initial-thread[21092]
<stack trace follows...>
如果來源元件自行關閉管道,以下提供一些秘訣 疑難排解原因: