Skip to main content

driver_manager_node/
start.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::node::Node;
6use crate::types::{DriverComponent, DriverState, NodeState};
7use driver_manager_driver_host::{DriverLoadArgs, DriverStartArgs};
8use driver_manager_types::{ShutdownState, StartRequestReceiver};
9use fidl::endpoints::{ServerEnd, create_endpoints};
10use futures::StreamExt;
11use log::{debug, error, warn};
12use std::rc::Rc;
13use zx::HandleBased;
14use {
15    fidl_fuchsia_component as fcomponent, fidl_fuchsia_component_runner as frunner,
16    fidl_fuchsia_data as fdata, fidl_fuchsia_driver_framework as fdf,
17    fidl_fuchsia_driver_host as fdh,
18};
19
20impl Node {
21    pub async fn send_start_request(&self) -> Result<(), zx::Status> {
22        let (handles, proxy) = {
23            let handles = self.take_start_handles_for_start();
24            let proxy = self.component_controller_proxy().expect("component");
25            (handles, proxy)
26        };
27
28        let start_child_args =
29            fcomponent::StartChildArgs { numbered_handles: Some(handles), ..Default::default() };
30        let (_, server_end) = fidl::endpoints::create_endpoints();
31
32        proxy
33            .start(start_child_args, server_end)
34            .await
35            .map_err(|e| {
36                error!("Failed to start driver for node {}: {}", self.name(), e);
37                zx::Status::INTERNAL
38            })?
39            .map_err(|e: fcomponent::Error| {
40                error!("Failed to start driver for node {}: {:?}", self.name(), e);
41                zx::Status::INTERNAL
42            })?;
43        Ok(())
44    }
45
46    pub async fn get_next_start_request(
47        &self,
48    ) -> Result<
49        (frunner::ComponentStartInfo, ServerEnd<frunner::ComponentControllerMarker>),
50        zx::Status,
51    > {
52        struct ReleaseStartRequestReceiverGuard<'a> {
53            receiver: Option<StartRequestReceiver>,
54            node: &'a Node,
55        }
56
57        impl<'a> Drop for ReleaseStartRequestReceiverGuard<'a> {
58            fn drop(&mut self) {
59                if let Some(rx) = self.receiver.take() {
60                    self.node.set_start_request_receiver(rx);
61                }
62            }
63        }
64
65        let receiver = self.take_start_request_receiver().ok_or(zx::Status::BAD_STATE)?;
66
67        let mut guard = ReleaseStartRequestReceiverGuard { receiver: Some(receiver), node: self };
68
69        let start_request =
70            guard.receiver.as_mut().unwrap().next().await.ok_or(zx::Status::TIMED_OUT)??;
71        let start_info = start_request.info;
72        let controller = start_request.controller;
73        Ok((start_info, controller))
74    }
75
76    pub async fn start_driver(
77        self: &Rc<Self>,
78        mut start_info: frunner::ComponentStartInfo,
79        controller: ServerEnd<frunner::ComponentControllerMarker>,
80    ) -> Result<(), zx::Status> {
81        if self.shutdown_state() == ShutdownState::Stopped {
82            self.node_shutdown_coordinator.borrow_mut().reset_shutdown();
83        }
84        let url = start_info.resolved_url.clone().ok_or(zx::Status::INVALID_ARGS)?;
85        self.set_state(NodeState::Starting { driver_url: url.clone() });
86
87        let program = start_info.program.as_ref();
88        let get_prog_val = |key: &str| -> Option<String> {
89            program.and_then(|p| p.entries.as_ref()).and_then(|e| {
90                e.iter().find(|entry| entry.key == key).and_then(|entry| {
91                    if let Some(fdata::DictionaryValue::Str(s)) =
92                        entry.value.as_ref().map(|v| v.as_ref())
93                    {
94                        Some(s.clone())
95                    } else {
96                        None
97                    }
98                })
99            })
100        };
101
102        let colocate = get_prog_val("colocate").as_deref() == Some("true");
103        let use_next_vdso = get_prog_val("use_next_vdso").as_deref() == Some("true");
104        let host_restart_on_crash =
105            get_prog_val("host_restart_on_crash").as_deref() == Some("true");
106        let use_dynamic_linker = get_prog_val("use_dynamic_linker").as_deref() == Some("true");
107
108        if host_restart_on_crash && colocate {
109            error!(
110                "Failed to start driver '{}'. Both host_restart_on_crash and colocate cannot be true.",
111                url
112            );
113            return Err(zx::Status::INVALID_ARGS);
114        }
115        self.set_restart_on_crash(host_restart_on_crash);
116
117        let driver_host = self.host();
118        let mut found_driver_host = colocate;
119        let driver_host = if found_driver_host {
120            match driver_host {
121                Some(dh) => dh,
122                None => {
123                    error!(
124                        "Failed to start driver '{}', driver is colocated but does not have a parent with a driver host",
125                        url
126                    );
127                    return Err(zx::Status::INVALID_ARGS);
128                }
129            }
130        } else {
131            let driver_host_name = self.driver_host_name_for_colocation();
132            match self.node_manager.get_driver_host(&driver_host_name) {
133                Some(dh) => {
134                    found_driver_host = true;
135                    self.set_host(dh.clone());
136                    dh
137                }
138                None => {
139                    if use_dynamic_linker {
140                        let driver_host = self
141                            .node_manager
142                            .create_driver_host_dynamic_linker(driver_host_name)
143                            .await?;
144                        self.set_host(driver_host.clone());
145                        driver_host
146                    } else {
147                        debug!(
148                            "Creating driver host for node '{}' driver url '{}'",
149                            self.name(),
150                            url
151                        );
152                        let driver_host = self
153                            .node_manager
154                            .create_driver_host(use_next_vdso, driver_host_name)
155                            .await
156                            .map_err(|e| {
157                                error!("Failed to start driver '{url}': {e:?}");
158                                zx::Status::INTERNAL
159                            })?;
160                        self.set_host(driver_host.clone());
161                        driver_host
162                    }
163                }
164            }
165        };
166
167        if found_driver_host {
168            // Whether dynamic linking is enabled for a driver host is determined by the first driver in the
169            // host. Otherwise for colocated drivers, we need to match what has been set for the driver
170            // host.
171            if use_dynamic_linker != driver_host.is_dynamic_linking_enabled() {
172                error!(
173                    concat!(
174                        "Failed to start driver '{}', driver is colocated and set",
175                        "use_dynamic_linker={} but its driver host is not configured for this"
176                    ),
177                    url,
178                    if use_dynamic_linker { "true" } else { "false" }
179                );
180                return Err(zx::Status::INVALID_ARGS);
181            }
182        }
183
184        let (node_client, node_server) = create_endpoints::<fdf::NodeMarker>();
185        let (driver_client, driver_server) = create_endpoints::<fdh::DriverMarker>();
186
187        let node_token = start_info.component_instance.take().unwrap_or_else(|| {
188            warn!("Component instance not provided in start request");
189            zx::Event::create()
190        });
191
192        let node_token_dup = node_token.duplicate_handle(zx::Rights::SAME_RIGHTS)?;
193
194        let runner_component_controller = self.serve_runner_component_controller(controller);
195        let node_server_binding = self.serve_node(node_server);
196
197        let driver = driver_client.into_proxy();
198        let driver_client_binding = self.serve_driver_host_client(driver);
199
200        self.set_state(NodeState::DriverComponent(DriverComponent::new(
201            url.clone(),
202            node_token_dup,
203            node_token.koid().unwrap(),
204            Some(runner_component_controller),
205            Some(node_server_binding),
206            Some(driver_client_binding),
207            DriverState::Binding,
208        )));
209
210        let symbols = if colocate { Some(self.symbols()) } else { None };
211        let offers: Vec<fdf::Offer> = self.offers().iter().map(|f| f.into()).collect();
212        let properties = self.get_node_property_dict();
213
214        let load_args = if use_dynamic_linker {
215            Some(DriverLoadArgs::new(&mut start_info).await?)
216        } else {
217            None
218        };
219
220        let start_args = DriverStartArgs {
221            node: node_client,
222            node_name: self.name.clone(),
223            properties,
224            symbols,
225            offers,
226            start_info,
227            component_instance: node_token,
228        };
229
230        log::info!("Binding {} to {}", url, self.name);
231
232        if use_dynamic_linker {
233            driver_host
234                .start_with_dynamic_linker(load_args.unwrap(), start_args, driver_server)
235                .await
236        } else {
237            driver_host.start(start_args, driver_server).await
238        }
239        .inspect_err(|_| {
240            error!("Failed to start driver host for {}", self.make_component_moniker())
241        })?;
242
243        Ok(())
244    }
245}