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