1use 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 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 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 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 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}