1use crate::{Incoming, Node};
6use fuchsia_async::ScopeHandle;
7use fuchsia_component::server::{ServiceFs, ServiceObjTrait};
8use fuchsia_component_config::Config;
9use fuchsia_inspect::Inspector;
10use inspect_runtime::PublishOptions;
11use log::error;
12use namespace::Namespace;
13use zx::Status;
14
15use fdf::DispatcherRef;
16use fidl_fuchsia_driver_framework::DriverStartArgs;
17
18pub use fuchsia_inspect_contrib::content_publisher as inspect_publisher;
19
20#[non_exhaustive]
22pub struct DriverContext {
23 pub root_dispatcher: DispatcherRef<'static>,
25 pub start_args: DriverStartArgs,
28 pub incoming: Incoming,
31}
32
33impl DriverContext {
34 pub fn take_node(&mut self) -> Result<Node, Status> {
44 let node_client = self.start_args.node.take().ok_or(Status::INVALID_ARGS)?;
45 Ok(Node::from(node_client.into_proxy()))
46 }
47
48 pub fn take_config<C: Config>(&mut self) -> Result<C, Status> {
54 let vmo = self.start_args.config.take().ok_or(Status::INVALID_ARGS)?;
55 Ok(Config::from_vmo(&vmo).expect("Config VMO handle must be valid."))
56 }
57
58 pub fn serve_outgoing<O: ServiceObjTrait>(
65 &mut self,
66 outgoing_fs: &mut ServiceFs<O>,
67 ) -> Result<(), Status> {
68 let Some(outgoing_dir) = self.start_args.outgoing_dir.take() else {
69 error!("Tried to serve on outgoing directory but it wasn't available");
70 return Err(Status::INVALID_ARGS);
71 };
72 outgoing_fs.serve_connection(outgoing_dir).map_err(|err| {
73 error!("Failed to serve outgoing directory: {err}");
74 Status::INTERNAL
75 })?;
76
77 Ok(())
78 }
79
80 pub fn publish_inspect(&self, inspector: &Inspector, scope: ScopeHandle) -> Result<(), Status> {
85 let client = self.incoming.connect_protocol().map_err(|err| {
86 error!("Error connecting to inspect : {err}");
87 Status::INTERNAL
88 })?;
89
90 let task = inspect_runtime::publish(
91 inspector,
92 PublishOptions::default().on_inspect_sink_client(client),
93 )
94 .ok_or(Status::INTERNAL)?;
95
96 scope.spawn_local(task);
97
98 Ok(())
99 }
100
101 pub fn inspect_content_publisher(&self) -> Result<inspect_publisher::ContentPublisher, Status> {
103 let inspect_sink_client = self.incoming.connect_protocol().map_err(|err| {
104 error!("Error connecting to inspect : {err}");
105 Status::INTERNAL
106 })?;
107
108 let options = inspect_publisher::PublishOptions { inspect_sink_client };
109 inspect_publisher::content_publisher(options).map_err(|err| {
110 error!("Error creating inspect content publisher: {err}");
111 Status::INTERNAL
112 })
113 }
114
115 pub fn vmar(&self) -> zx::Unowned<'_, zx::Vmar> {
120 if let Some(vmar) = self.start_args.vmar.as_ref().map(zx::Unowned::new) {
123 vmar
124 } else {
125 fuchsia_runtime::vmar_root_self()
126 }
127 }
128
129 pub(crate) fn new(
130 root_dispatcher: DispatcherRef<'static>,
131 mut start_args: DriverStartArgs,
132 ) -> Result<Self, Status> {
133 let incoming_namespace: Namespace = start_args
134 .incoming
135 .take()
136 .unwrap_or_default()
137 .try_into()
138 .map_err(|_| Status::INVALID_ARGS)?;
139 let incoming = Incoming::from(incoming_namespace);
140 Ok(DriverContext { root_dispatcher, start_args, incoming })
141 }
142
143 pub(crate) fn start_logging(&self, driver_name: &str) -> Result<(), Status> {
144 let log_client = match self.incoming.connect_protocol() {
145 Ok(log_client) => log_client,
146 Err(err) => {
147 eprintln!(
148 "Error connecting to log sink proxy at driver startup: {err}. Continuing without logging."
149 );
150 return Ok(());
151 }
152 };
153
154 if let Err(e) = driver_diagnostics_log::initialize(
155 driver_diagnostics_log::PublishOptions::default()
156 .use_log_sink(log_client)
157 .tags(&["driver", driver_name]),
158 ) {
159 eprintln!("Error initializing logging at driver startup: {e}");
160 }
161 Ok(())
162 }
163}