1use crate::{Incoming, Node};
6use fuchsia_component::server::{ServiceFs, ServiceObjTrait};
7use fuchsia_component_config::Config;
8use log::error;
9use namespace::Namespace;
10use zx::Status;
11
12use fdf::DispatcherRef;
13use fidl_fuchsia_driver_framework::DriverStartArgs;
14
15pub struct DriverContext {
17 pub root_dispatcher: DispatcherRef<'static>,
19 pub start_args: DriverStartArgs,
22 pub incoming: Incoming,
25 #[doc(hidden)]
26 _private: (),
27}
28
29impl DriverContext {
30 pub fn take_node(&mut self) -> Result<Node, Status> {
40 let node_client = self.start_args.node.take().ok_or(Status::INVALID_ARGS)?;
41 Ok(Node::from(node_client.into_proxy()))
42 }
43
44 pub fn take_config<C: Config>(&mut self) -> Result<C, Status> {
50 let vmo = self.start_args.config.take().ok_or(Status::INVALID_ARGS)?;
51 Ok(Config::from_vmo(&vmo).expect("Config VMO handle must be valid."))
52 }
53
54 pub fn serve_outgoing<O: ServiceObjTrait>(
61 &mut self,
62 outgoing_fs: &mut ServiceFs<O>,
63 ) -> Result<(), Status> {
64 let Some(outgoing_dir) = self.start_args.outgoing_dir.take() else {
65 error!("Tried to serve on outgoing directory but it wasn't available");
66 return Err(Status::INVALID_ARGS);
67 };
68 outgoing_fs.serve_connection(outgoing_dir).map_err(|err| {
69 error!("Failed to serve outgoing directory: {err}");
70 Status::INTERNAL
71 })?;
72
73 Ok(())
74 }
75
76 pub(crate) fn new(
77 root_dispatcher: DispatcherRef<'static>,
78 mut start_args: DriverStartArgs,
79 ) -> Result<Self, Status> {
80 let incoming_namespace: Namespace = start_args
81 .incoming
82 .take()
83 .unwrap_or_else(|| vec![])
84 .try_into()
85 .map_err(|_| Status::INVALID_ARGS)?;
86 let incoming = incoming_namespace.try_into().map_err(|_| Status::INVALID_ARGS)?;
87 Ok(DriverContext { root_dispatcher, start_args, incoming, _private: () })
88 }
89
90 pub(crate) fn start_logging(&self, driver_name: &str) -> Result<(), Status> {
91 let log_proxy = match self.incoming.connect_protocol() {
92 Ok(log_proxy) => log_proxy,
93 Err(err) => {
94 eprintln!("Error connecting to log sink proxy at driver startup: {err}. Continuing without logging.");
95 return Ok(());
96 }
97 };
98
99 if let Err(e) = diagnostics_log::initialize(
100 diagnostics_log::PublishOptions::default()
101 .use_log_sink(log_proxy)
102 .tags(&["driver", driver_name]),
103 ) {
104 eprintln!("Error initializing logging at driver startup: {e}");
105 }
106 Ok(())
107 }
108}