1use crate::info_iterator::{CompositeInfoIterator, DeviceInfoIterator, DriverHostInfoIterator};
6use driver_manager_core::DriverRunner;
7use driver_manager_node::Node;
8use driver_manager_shutdown::RemovalSet;
9use driver_manager_types::to_deprecated_property;
10use fdd::ManagerRequest::*;
11use fidl::endpoints::{ControlHandle, DiscoverableProtocolMarker, Responder, ServerEnd};
12use fuchsia_component::client::connect_to_protocol;
13use fuchsia_component::server::{ServiceFs, ServiceObjLocal};
14use futures::prelude::*;
15use log::{error, warn};
16use std::cell::RefCell;
17use std::collections::{HashMap, HashSet, VecDeque};
18use std::rc::{Rc, Weak};
19use {
20 fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_driver_development as fdd,
21 fidl_fuchsia_driver_framework as fdf, fidl_fuchsia_driver_index as fdi,
22 fuchsia_async as fasync,
23};
24
25pub struct DriverDevelopmentService {
26 driver_runner: Rc<DriverRunner>,
27 test_nodes: RefCell<HashMap<String, Weak<Node>>>,
28 scope: fasync::Scope,
29}
30
31impl DriverDevelopmentService {
32 pub fn new(driver_runner: Rc<DriverRunner>) -> Self {
33 let scope = fasync::Scope::new_with_name("driver_development_service");
34 Self { driver_runner, test_nodes: RefCell::new(HashMap::new()), scope }
35 }
36
37 pub fn publish(self: &Rc<Self>, fs: &mut ServiceFs<ServiceObjLocal<'_, ()>>) {
38 let this = self.clone();
39 fs.dir("svc").add_fidl_service(move |stream: fdd::ManagerRequestStream| {
40 let this_clone = this.clone();
41 this.scope.spawn_local(async move {
42 if let Err(e) = this_clone.serve(stream).await {
43 warn!("Failed to serve DriverDevelopmentService: {}", e);
44 }
45 });
46 });
47 }
48
49 pub async fn serve(
50 self: Rc<Self>,
51 mut stream: fdd::ManagerRequestStream,
52 ) -> Result<(), fidl::Error> {
53 while let Some(request) = stream.try_next().await? {
54 match request {
55 GetNodeInfo { node_filter, exact_match, iterator, .. } => {
56 self.get_node_info(node_filter, exact_match, iterator).await;
57 }
58 GetCompositeInfo { iterator, .. } => {
59 self.get_composite_info(iterator);
60 }
61 GetDriverInfo { driver_filter, iterator, .. } => {
62 self.get_driver_info(driver_filter, iterator);
63 }
64 GetCompositeNodeSpecs { name_filter, iterator, .. } => {
65 self.get_composite_node_specs(name_filter, iterator);
66 }
67 AddTestNode { args, responder } => {
68 self.add_test_node(args, responder).await;
69 }
70 RemoveTestNode { name, responder } => {
71 self.remove_test_node(name, responder);
72 }
73 BindAllUnboundNodes { responder } => {
74 self.bind_all_unbound_nodes(responder).await;
75 }
76 BindAllUnboundNodes2 { responder } => {
77 self.bind_all_unbound_nodes2(responder).await;
78 }
79 WaitForBootup { responder } => {
80 self.wait_for_bootup(responder).await;
81 }
82 GetDriverHostInfo { iterator, .. } => {
83 self.get_driver_host_info(iterator).await;
84 }
85 RestartDriverHosts { driver_url, rematch_flags, responder } => {
86 self.restart_driver_hosts(driver_url, rematch_flags, responder).await;
87 }
88 DisableDriver { driver_url, package_hash, responder } => {
89 self.disable_driver(driver_url, package_hash, responder).await;
90 }
91 EnableDriver { driver_url, package_hash, responder } => {
92 self.enable_driver(driver_url, package_hash, responder).await;
93 }
94 RebindCompositesWithDriver { driver_url, responder } => {
95 self.rebind_composites_with_driver(driver_url, responder).await;
96 }
97 RestartWithDictionary { moniker, dictionary, responder } => {
98 self.restart_with_dictionary(moniker, dictionary, responder).await;
99 }
100 _ => {}
101 }
102 }
103 Ok(())
104 }
105
106 async fn get_node_info(
107 &self,
108 node_filter: Vec<String>,
109 exact_match: bool,
110 iterator: ServerEnd<fdd::NodeInfoIteratorMarker>,
111 ) {
112 let mut device_infos = vec![];
113 let mut unique_nodes = HashSet::new();
114 let mut remaining_nodes = VecDeque::new();
115 remaining_nodes.push_back(self.driver_runner.root_node());
116
117 while let Some(node) = remaining_nodes.pop_front() {
118 let node_ptr: *const _ = Rc::as_ptr(&node);
119 if !unique_nodes.insert(node_ptr) {
120 continue;
121 }
122
123 for child in node.children() {
124 remaining_nodes.push_back(child);
125 }
126
127 let moniker = node.make_component_moniker();
128 if !node_filter.is_empty() {
129 let found = node_filter.iter().any(|filter| {
130 if exact_match { &moniker == filter } else { moniker.contains(filter) }
131 });
132 if !found {
133 continue;
134 }
135 }
136
137 match create_device_info(&node).await {
138 Ok(info) => device_infos.push(info),
139 Err(_) => return, }
141 }
142
143 let iterator_stream = iterator.into_stream();
144 let device_info_iterator = DeviceInfoIterator::new(device_infos);
145 self.scope.spawn_local(async move {
146 if let Err(e) = device_info_iterator.serve(iterator_stream).await {
147 warn!("DeviceInfoIterator server failed: {}", e);
148 }
149 });
150 }
151
152 fn get_composite_info(&self, iterator: ServerEnd<fdd::CompositeInfoIteratorMarker>) {
153 let list = self.driver_runner.get_composite_list_info();
154 let iterator_stream = iterator.into_stream();
155 let composite_info_iterator = CompositeInfoIterator::new(list);
156 self.scope.spawn_local(async move {
157 if let Err(e) = composite_info_iterator.serve(iterator_stream).await {
158 warn!("CompositeInfoIterator server failed: {}", e);
159 }
160 });
161 }
162
163 fn get_driver_info(
164 &self,
165 driver_filter: Vec<String>,
166 iterator: ServerEnd<fdd::DriverInfoIteratorMarker>,
167 ) {
168 let driver_index_client = match connect_to_protocol::<fdi::DevelopmentManagerMarker>() {
169 Ok(proxy) => proxy,
170 Err(e) => {
171 error!(
172 "Failed to connect to service '{}': {}",
173 fdi::DevelopmentManagerMarker::PROTOCOL_NAME,
174 e
175 );
176 iterator.close_with_epitaph(zx::Status::UNAVAILABLE).ok();
177 return;
178 }
179 };
180
181 if let Err(e) = driver_index_client.get_driver_info(&driver_filter, iterator) {
182 error!("Failed to call DriverIndex::GetDriverInfo: {}", e);
183 }
184 }
185
186 fn get_composite_node_specs(
187 &self,
188 name_filter: Option<String>,
189 iterator: ServerEnd<fdd::CompositeNodeSpecIteratorMarker>,
190 ) {
191 let driver_index_client = match connect_to_protocol::<fdi::DevelopmentManagerMarker>() {
192 Ok(proxy) => proxy,
193 Err(e) => {
194 error!(
195 "Failed to connect to service '{}': {}",
196 fdi::DevelopmentManagerMarker::PROTOCOL_NAME,
197 e
198 );
199 iterator.close_with_epitaph(zx::Status::UNAVAILABLE).ok();
200 return;
201 }
202 };
203
204 if let Err(e) =
205 driver_index_client.get_composite_node_specs(name_filter.as_deref(), iterator)
206 {
207 error!("Failed to call DriverIndex::GetCompositeNodeSpecs: {}", e);
208 }
209 }
210
211 async fn add_test_node(
212 &self,
213 args: fdd::TestNodeAddArgs,
214 responder: fdd::ManagerAddTestNodeResponder,
215 ) {
216 let name = if let Some(name) = args.name {
217 name
218 } else {
219 let _ = responder.send(Err(fdf::NodeError::NameMissing));
220 return;
221 };
222
223 let add_args = fdf::NodeAddArgs {
224 name: Some(name.clone()),
225 properties: args.properties,
226 ..Default::default()
227 };
228
229 let result = self.driver_runner.root_node().add_child(add_args, None, None).await;
230
231 match result {
232 Ok(node) => {
233 self.test_nodes.borrow_mut().insert(name, Rc::downgrade(&node));
234 let _ = responder.send(Ok(()));
235 }
236 Err(e) => {
237 let _ = responder.send(Err(e));
238 }
239 }
240 }
241
242 fn remove_test_node(&self, name: String, responder: fdd::ManagerRemoveTestNodeResponder) {
243 let mut test_nodes = self.test_nodes.borrow_mut();
244 if !test_nodes.contains_key(&name) {
245 let _ = responder.send(Err(zx::Status::NOT_FOUND.into_raw()));
246 return;
247 }
248
249 if let Some(node_weak) = test_nodes.get(&name)
250 && let Some(node) = node_weak.upgrade()
251 {
252 node.remove(RemovalSet::All, None);
253 }
254
255 test_nodes.remove(&name);
256 let _ = responder.send(Ok(()));
257 }
258
259 async fn bind_all_unbound_nodes(&self, responder: fdd::ManagerBindAllUnboundNodesResponder) {
260 let result = self.driver_runner.bind_manager.try_bind_all_available().await;
261 let _ = responder.send(Ok(&result));
262 }
263
264 async fn bind_all_unbound_nodes2(&self, responder: fdd::ManagerBindAllUnboundNodes2Responder) {
265 let result = self.driver_runner.bind_manager.try_bind_all_available().await;
266 let _ = responder.send(Ok(&result));
267 }
268
269 async fn wait_for_bootup(&self, responder: fdd::ManagerWaitForBootupResponder) {
270 self.driver_runner.bootup_tracker.wait_for_bootup().await;
271 let _ = responder.send();
272 }
273
274 async fn get_driver_host_info(&self, iterator: ServerEnd<fdd::DriverHostInfoIteratorMarker>) {
275 let mut driver_host_to_drivers: HashMap<zx::Koid, HashSet<String>> = HashMap::new();
276 let mut unique_nodes = HashSet::new();
277 let mut remaining_nodes = VecDeque::new();
278 remaining_nodes.push_back(self.driver_runner.root_node());
279
280 while let Some(node) = remaining_nodes.pop_front() {
281 let node_ptr: *const _ = Rc::as_ptr(&node);
282 if !unique_nodes.insert(node_ptr) {
283 continue;
284 }
285
286 for child in node.children() {
287 remaining_nodes.push_back(child);
288 }
289
290 if node.is_bound()
291 && let Some(host) = node.driver_host()
292 && let Ok(koid) = host.get_process_koid().await
293 {
294 driver_host_to_drivers.entry(koid).or_default().insert(node.driver_url());
295 }
296 }
297
298 let mut infos = vec![];
299 for host in self.driver_runner.driver_hosts() {
300 let process_info = match host.get_process_info_internal().await {
301 Ok(info) => info,
302 Err(_) => continue,
303 };
304
305 let threads = process_info
306 .threads
307 .into_iter()
308 .map(|t| fdd::ThreadInfo {
309 koid: Some(t.koid),
310 name: Some(t.name),
311 scheduler_role: Some(t.scheduler_role),
312 ..Default::default()
313 })
314 .collect();
315
316 let dispatchers = process_info
317 .dispatchers
318 .into_iter()
319 .map(|d| fdd::DispatcherInfo {
320 driver: Some(d.driver),
321 name: Some(d.name),
322 options: Some(d.options),
323 scheduler_role: Some(d.scheduler_role),
324 ..Default::default()
325 })
326 .collect();
327
328 let mut drivers = vec![];
329 if let Some(d) = driver_host_to_drivers.get(&process_info.process_koid) {
330 drivers = d.iter().cloned().collect();
331 drivers.sort();
332 }
333
334 infos.push(fdd::DriverHostInfo {
335 process_koid: Some(process_info.process_koid.raw_koid()),
336 name: Some(host.name_for_colocation().to_string()),
337 threads: Some(threads),
338 dispatchers: Some(dispatchers),
339 drivers: Some(drivers),
340 ..Default::default()
341 });
342 }
343
344 let iterator_stream = iterator.into_stream();
345 let driver_host_info_iterator = DriverHostInfoIterator::new(infos);
346 self.scope.spawn_local(async move {
347 if let Err(e) = driver_host_info_iterator.serve(iterator_stream).await {
348 warn!("DriverHostInfoIterator server failed: {}", e);
349 }
350 });
351 }
352
353 async fn restart_driver_hosts(
354 &self,
355 driver_url: String,
356 rematch_flags: fdd::RestartRematchFlags,
357 responder: fdd::ManagerRestartDriverHostsResponder,
358 ) {
359 let result = self
360 .driver_runner
361 .restart_nodes_colocated_with_driver_url(&driver_url, rematch_flags)
362 .await;
363 match result {
364 Ok(count) => {
365 let _ = responder.send(Ok(count));
366 }
367 Err(status) => {
368 let _ = responder.send(Err(status.into_raw()));
369 }
370 }
371 }
372
373 async fn disable_driver(
374 &self,
375 driver_url: String,
376 package_hash: Option<String>,
377 responder: fdd::ManagerDisableDriverResponder,
378 ) {
379 let driver_index_client = match connect_to_protocol::<fdi::DevelopmentManagerMarker>() {
380 Ok(proxy) => proxy,
381 Err(e) => {
382 error!(
383 "Failed to connect to service '{}': {}",
384 fdi::DevelopmentManagerMarker::PROTOCOL_NAME,
385 e
386 );
387 responder.control_handle().shutdown_with_epitaph(zx::Status::UNAVAILABLE);
388 return;
389 }
390 };
391
392 match driver_index_client.disable_driver(&driver_url, package_hash.as_deref()).await {
393 Ok(result) => {
394 let _ = responder.send(result);
395 }
396 Err(e) => {
397 error!("Failed to call DriverIndex::DisableDriver: {}", e);
398 let status = match e {
399 fidl::Error::ClientChannelClosed { status, .. } => status,
400 _ => zx::Status::INTERNAL,
401 };
402 responder.control_handle().shutdown_with_epitaph(status);
403 }
404 }
405 }
406
407 async fn enable_driver(
408 &self,
409 driver_url: String,
410 package_hash: Option<String>,
411 responder: fdd::ManagerEnableDriverResponder,
412 ) {
413 let driver_index_client = match connect_to_protocol::<fdi::DevelopmentManagerMarker>() {
414 Ok(proxy) => proxy,
415 Err(e) => {
416 error!(
417 "Failed to connect to service '{}': {}",
418 fdi::DevelopmentManagerMarker::PROTOCOL_NAME,
419 e
420 );
421 responder.control_handle().shutdown_with_epitaph(zx::Status::UNAVAILABLE);
422 return;
423 }
424 };
425
426 match driver_index_client.enable_driver(&driver_url, package_hash.as_deref()).await {
427 Ok(result) => {
428 let _ = responder.send(result);
429 }
430 Err(e) => {
431 error!("Failed to call DriverIndex::EnableDriver: {}", e);
432 let status = match e {
433 fidl::Error::ClientChannelClosed { status, .. } => status,
434 _ => zx::Status::INTERNAL,
435 };
436 responder.control_handle().shutdown_with_epitaph(status);
437 }
438 }
439 }
440
441 async fn rebind_composites_with_driver(
442 &self,
443 driver_url: String,
444 responder: fdd::ManagerRebindCompositesWithDriverResponder,
445 ) {
446 let driver_index_client = match connect_to_protocol::<fdi::DevelopmentManagerMarker>() {
447 Ok(proxy) => proxy,
448 Err(e) => {
449 error!(
450 "Failed to connect to service '{}': {}",
451 fdi::DevelopmentManagerMarker::PROTOCOL_NAME,
452 e
453 );
454 responder.control_handle().shutdown_with_epitaph(zx::Status::UNAVAILABLE);
455 return;
456 }
457 };
458
459 match driver_index_client.rebind_composites_with_driver(&driver_url).await {
460 Ok(Ok(())) => {
461 let count = self.driver_runner.rebind_composites_with_driver(&driver_url).await;
463 let _ = responder.send(Ok(count));
464 }
465 Ok(Err(status)) => {
466 error!(
467 "DriverIndex::RebindCompositesWithDriver failed: {}",
468 zx::Status::from_raw(status)
469 );
470 let _ = responder.send(Err(status));
471 }
472 Err(e) => {
473 error!("Failed to call DriverIndex::RebindCompositesWithDriver: {}", e);
474 let status = match e {
475 fidl::Error::ClientChannelClosed { status, .. } => status,
476 _ => zx::Status::INTERNAL,
477 };
478 let _ = responder.send(Err(status.into_raw()));
479 }
480 }
481 }
482
483 async fn restart_with_dictionary(
484 &self,
485 moniker: String,
486 dictionary: fidl_fuchsia_component_sandbox::DictionaryRef,
487 responder: fdd::ManagerRestartWithDictionaryResponder,
488 ) {
489 let (endpoint0, endpoint1) = zx::EventPair::create();
490 self.driver_runner.restart_with_dictionary(moniker, dictionary, endpoint1).await;
491 let _ = responder.send(Ok(endpoint0));
492 }
493}
494
495async fn create_device_info(node: &Rc<Node>) -> Result<fdd::NodeInfo, zx::Status> {
496 let children = node.children();
497 let child_ids: Vec<u64> = children.iter().map(|child| Rc::as_ptr(child) as u64).collect();
498
499 let parents = node.parents();
500 let parent_ids: Vec<u64> = parents
501 .iter()
502 .filter_map(|parent| parent.upgrade())
503 .map(|parent| Rc::as_ptr(&parent) as u64)
504 .collect();
505
506 let driver_host_koid = if node.as_ref().is_bound() {
507 match node.driver_host().as_ref() {
508 Some(dh) => Some(dh.get_process_koid().await.unwrap().raw_koid()),
509 None => None,
510 }
511 } else {
512 None
513 };
514
515 let offers = node.offers();
516 let offer_list: Vec<fdecl::Offer> = offers
517 .iter()
518 .map(|o| o.into())
519 .filter_map(|offer| match offer {
520 fdf::Offer::DriverTransport(d) => Some(d),
521 fdf::Offer::ZirconTransport(z) => Some(z),
522 fdf::Offer::DictionaryOffer(d) => Some(d),
523 _ => None,
524 })
525 .collect();
526
527 let node_property_list = if node.is_composite() {
528 None
529 } else {
530 node.get_node_properties(None).and_then(|properties| {
531 if properties.is_empty() {
532 None
533 } else {
534 Some(properties.iter().map(to_deprecated_property).collect())
535 }
536 })
537 };
538
539 Ok(fdd::NodeInfo {
540 id: Some(Rc::as_ptr(node) as u64),
541 moniker: Some(node.make_component_moniker()),
542 bound_driver_url: Some(node.driver_url()),
543 quarantined: Some(node.is_quarantined()),
544 child_ids: if child_ids.is_empty() { None } else { Some(child_ids) },
545 parent_ids: if parent_ids.is_empty() { None } else { Some(parent_ids) },
546 driver_host_koid,
547 offer_list: if offer_list.is_empty() { None } else { Some(offer_list) },
548 node_property_list,
549 bus_topology: Some(node.get_bus_topology()),
550 ..Default::default()
551 })
552}