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