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