Skip to main content

driver_manager_node/
add.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, NodePropertyEntry};
6use crate::types::{NodeDictionary, NodeState};
7use driver_manager_types::{Collection, NodeOffer, OfferTransport, to_property2};
8use fidl::endpoints::ServerEnd;
9use futures::channel::oneshot;
10use log::{error, warn};
11use std::cell::RefCell;
12use std::collections::HashSet;
13use std::rc::Rc;
14use {
15    fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_device_fs as fdevfs,
16    fidl_fuchsia_driver_framework as fdf,
17};
18
19impl Node {
20    pub async fn add_child(
21        self: &Rc<Self>,
22        mut args: fdf::NodeAddArgs,
23        controller: Option<ServerEnd<fdf::NodeControllerMarker>>,
24        node: Option<ServerEnd<fdf::NodeMarker>>,
25    ) -> Result<Rc<Node>, fdf::NodeError> {
26        let name = args.name.ok_or(fdf::NodeError::NameMissing)?;
27
28        if args.properties.is_some() && args.properties2.is_some() {
29            return Err(fdf::NodeError::UnsupportedArgs);
30        }
31
32        self.wait_for_child_to_exit(&name).await?;
33
34        let child = Node::new(&name, self.weak_self.clone(), self.node_manager.clone_box());
35
36        let mut properties = if let Some(props) = args.properties2 {
37            props
38        } else if let Some(props) = args.properties {
39            props.into_iter().map(|prop| to_property2(&prop)).collect()
40        } else {
41            vec![]
42        };
43
44        let mut has_dictionary_offer = false;
45
46        if let Some(offers) = args.offers2 {
47            let mut source_node = Some(self.clone());
48            while source_node.is_some()
49                && source_node.as_ref().unwrap().collection() == Collection::None
50            {
51                let current_node = source_node.unwrap();
52                source_node = current_node.get_primary_parent();
53            }
54
55            let (source_name, source_collection) = if let Some(source_node) = source_node {
56                (source_node.make_component_moniker(), source_node.collection())
57            } else {
58                (self.make_component_moniker(), self.collection())
59            };
60
61            child.reserve_offers(offers.len());
62
63            for offer in offers {
64                if matches!(offer, fdf::Offer::DictionaryOffer(_)) {
65                    has_dictionary_offer = true;
66                }
67
68                match Self::process_node_offer_with_transport_property(
69                    &offer,
70                    source_collection,
71                    &source_name,
72                ) {
73                    Ok((processed_offer, property)) => {
74                        child.push_offer(processed_offer);
75                        properties.push(property);
76                    }
77                    Err(e) => return Err(e),
78                }
79            }
80        }
81
82        child.set_non_composite_properties(properties);
83
84        if let Some(driver_host) = args.driver_host {
85            child.set_driver_host_name_for_colocation(&driver_host);
86        }
87
88        if let Some(symbols) = args.symbols {
89            let mut names = HashSet::new();
90            for symbol in &symbols {
91                if symbol.name.is_none() {
92                    return Err(fdf::NodeError::SymbolNameMissing);
93                }
94                if symbol.address.is_none() {
95                    return Err(fdf::NodeError::SymbolAddressMissing);
96                }
97                if !names.insert(symbol.name.as_ref().unwrap()) {
98                    return Err(fdf::NodeError::SymbolAlreadyExists);
99                }
100            }
101            child.set_symbols(symbols);
102        }
103
104        if let Some(bus_info) = args.bus_info {
105            child.set_bus_info(bus_info);
106        }
107
108        // Copy the subtree dictionary of a parent node down to the child.
109        if let NodeDictionary::Subtree(d) = self.dictionary() {
110            if has_dictionary_offer {
111                panic!("Cannot use dictionary offers on node");
112            }
113
114            child.set_dictionary(NodeDictionary::Subtree(d));
115        }
116
117        let devfs_class_path = args.devfs_args.as_ref().and_then(|args| args.class_name.clone());
118
119        let devfs_connector = if let Some(ref mut devfs_args) = args.devfs_args {
120            let allow_controller = match devfs_args.connector_supports {
121                Some(supports) => supports.contains(fdevfs::ConnectionType::CONTROLLER),
122                _ => false,
123            };
124            let class_name = match (allow_controller, &devfs_args.class_name) {
125                (_, Some(class_name)) => class_name.clone(),
126                (true, None) => format!("No_class_name_but_driver_url_is_{}", self.driver_url()),
127                (_, _) => "Unknown_Class_name".to_string(),
128            };
129
130            child.create_devfs_passthrough(
131                devfs_args.connector.take(),
132                devfs_args.controller_connector.take(),
133                allow_controller,
134                class_name,
135            )
136        } else {
137            child.create_devfs_passthrough(None, None, false, "Unknown_Class_name".to_string())
138        };
139
140        let devfs_device = {
141            let device = self.device();
142            let topological = device.topological.as_ref().unwrap_or_else(|| {
143                panic!("Missing topological devfs node: {}", self.make_topological_path(false))
144            });
145
146            topological
147                .add_child(child.name(), devfs_class_path.as_deref(), devfs_connector)
148                .unwrap_or_else(|_| {
149                    panic!("Failed to export {}", child.make_topological_path(false))
150                })
151        };
152        assert!(devfs_device.topological.is_some());
153        child.set_device(devfs_device);
154
155        if let Some(controller) = controller {
156            let control_handle = child.serve_node_controller(controller);
157            child.set_node_controller(control_handle);
158        }
159
160        if has_dictionary_offer && args.offers_dictionary.is_none() {
161            warn!("cannot have dictionary type offers without supplying the offers_dictionary");
162            return Err(fdf::NodeError::UnsupportedArgs);
163        }
164
165        if !has_dictionary_offer && args.offers_dictionary.is_some() {
166            warn!("supplied offers_dictionary but no offers have Dictionary type.");
167            return Err(fdf::NodeError::UnsupportedArgs);
168        }
169
170        if let Some(offers_dictionary) = args.offers_dictionary {
171            let dictionary_util = self.node_manager.get_dictionary_util().map_err(|e| {
172                error!("failed to get dictionary util: {}", e);
173                fdf::NodeError::Internal
174            })?;
175
176            let dictionary_id =
177                dictionary_util.import_dictionary(offers_dictionary).await.map_err(|e| {
178                    error!("failed to import dictionary: {}", e);
179                    fdf::NodeError::Internal
180                })?;
181
182            let dictionary_offer_services = child
183                .offers()
184                .iter()
185                .filter(|offer| matches!(offer.transport, OfferTransport::Dictionary))
186                .map(|offer| offer.service_name.clone())
187                .collect::<Vec<_>>();
188
189            for dictionary_offer_service in dictionary_offer_services {
190                let dir_connector = dictionary_util
191                    .dictionary_dir_connector_route(dictionary_id, &dictionary_offer_service)
192                    .await
193                    .map_err(|e| {
194                        error!("failed to route dictionary: {}", e);
195                        fdf::NodeError::Internal
196                    })?;
197
198                let mut offers = child.offers();
199                offers
200                    .iter_mut()
201                    .find(|offer| {
202                        matches!(offer.transport, OfferTransport::Dictionary)
203                            && offer.service_name == dictionary_offer_service
204                    })
205                    .unwrap()
206                    .dir_connector = Rc::new(RefCell::new(Some(dir_connector)));
207                child.set_offers(offers);
208            }
209        }
210
211        if let Some(node) = node {
212            let node_server_binding = child.serve_node(node);
213            child.set_state(NodeState::OwnedByParent {
214                node_server_binding: Some(node_server_binding),
215            });
216        } else {
217            // Use a silent bind tracker to avoid tracking binds.
218            let tracker = child.create_bind_result_tracker(true);
219            self.node_manager.bind(&child, tracker);
220        }
221
222        child.add_to_parents();
223
224        Ok(child)
225    }
226
227    async fn wait_for_child_to_exit(&self, name: &str) -> Result<(), fdf::NodeError> {
228        let (sender, receiver) = oneshot::channel();
229        {
230            let child = self.children().into_iter().find(|c| c.name() == name);
231            if let Some(child) = child {
232                if !child.node_shutdown_coordinator.borrow().is_shutting_down() {
233                    return Err(fdf::NodeError::NameAlreadyExists);
234                }
235                child.set_remove_complete_callback(sender);
236                child.node_shutdown_coordinator.borrow_mut().check_node_state();
237            } else {
238                return Ok(());
239            }
240        }
241
242        // Wait for channel
243        receiver.await.map_err(|_| fdf::NodeError::Internal)
244    }
245
246    fn process_node_offer_with_transport_property(
247        add_offer: &fdf::Offer,
248        source_collection: Collection,
249        source_name: &str,
250    ) -> Result<(NodeOffer, fdf::NodeProperty2), fdf::NodeError> {
251        let processed_offer = Self::process_node_offer(add_offer, source_collection, source_name)?;
252        let name = &processed_offer.service_name;
253        let transport_str = match processed_offer.transport {
254            OfferTransport::ZirconTransport => "ZirconTransport",
255            OfferTransport::DriverTransport => "DriverTransport",
256            OfferTransport::Dictionary => "ZirconTransport",
257        };
258        let property = fdf::NodeProperty2 {
259            key: name.clone(),
260            value: fdf::NodePropertyValue::StringValue(format!("{}.{}", name, transport_str)),
261        };
262        Ok((processed_offer, property))
263    }
264
265    fn process_node_offer(
266        add_offer: &fdf::Offer,
267        source_collection: Collection,
268        source_name: &str,
269    ) -> Result<NodeOffer, fdf::NodeError> {
270        let (fdecl_offer, transport) = match add_offer {
271            fdf::Offer::ZirconTransport(offer) => (offer, OfferTransport::ZirconTransport),
272            fdf::Offer::DriverTransport(offer) => (offer, OfferTransport::DriverTransport),
273            fdf::Offer::DictionaryOffer(offer) => (offer, OfferTransport::Dictionary),
274            _ => {
275                error!("Unknown offer transport type");
276                return Err(fdf::NodeError::Internal);
277            }
278        };
279
280        let service_offer = match fdecl_offer {
281            fdecl::Offer::Service(service) => service,
282            _ => return Err(fdf::NodeError::UnsupportedArgs),
283        };
284
285        let source_name_from_offer =
286            service_offer.source_name.as_ref().ok_or(fdf::NodeError::OfferSourceNameMissing)?;
287
288        if let Some(target_name) = &service_offer.target_name
289            && target_name != source_name_from_offer
290        {
291            return Err(fdf::NodeError::UnsupportedArgs);
292        }
293
294        if service_offer.source.is_some() || service_offer.target.is_some() {
295            return Err(fdf::NodeError::OfferRefExists);
296        }
297
298        let source_instance_filter = service_offer
299            .source_instance_filter
300            .as_ref()
301            .ok_or(fdf::NodeError::OfferSourceInstanceFilterMissing)?;
302
303        let renamed_instances = service_offer
304            .renamed_instances
305            .as_ref()
306            .ok_or(fdf::NodeError::OfferRenamedInstancesMissing)?;
307
308        // Dictionary based offers don't go to the component framework, but developers can see
309        // these fields in the node list output.
310        let (source_name, source_collection) = match transport {
311            OfferTransport::Dictionary => ("dictionary", Collection::None),
312            _ => (source_name, source_collection),
313        };
314
315        Ok(NodeOffer {
316            source_name: source_name.to_string(),
317            source_collection,
318            transport,
319            service_name: source_name_from_offer.clone(),
320            source_instance_filter: source_instance_filter.clone(),
321            renamed_instances: renamed_instances.clone(),
322            dir_connector: Rc::new(RefCell::new(None)),
323        })
324    }
325
326    fn set_non_composite_properties(&self, properties: Vec<fdf::NodeProperty2>) {
327        self.clear_properties();
328        self.push_property(NodePropertyEntry {
329            name: "default".to_string(),
330            properties: properties.into_iter().map(|p| p.into()).collect(),
331        });
332    }
333}