1use crate::bootup_tracker::BootupTracker;
6use crate::driver_host_runner::DriverHostRunner;
7use crate::memory_attribution::MemoryAttributor;
8use crate::offer_injection::OfferInjector;
9use crate::runner::Runner;
10use crate::{DriverRunnerBridge, LoaderServiceFactory, perform_bfs, to_collection};
11use driver_manager_bind::BindManagerHandle;
12use driver_manager_composite::{CompositeNodeSpec, CompositeNodeSpecManager};
13use driver_manager_devfs::Devfs;
14use driver_manager_driver_host::{DriverHost, DriverHostComponent};
15use driver_manager_node::Node;
16use driver_manager_shutdown::NodeRemovalTracker;
17use driver_manager_types::{Collection, to_bind_rule2, to_property2};
18use driver_manager_utils::DictionaryUtil;
19use fidl::endpoints::{ServerEnd, create_endpoints};
20use fidl_fuchsia_component as fcomponent;
21use fidl_fuchsia_component_decl as fdecl;
22use fidl_fuchsia_component_sandbox as fsandbox;
23use fidl_fuchsia_driver_crash as fcrash;
24use fidl_fuchsia_driver_development as fdd;
25use fidl_fuchsia_driver_framework as fdf;
26use fidl_fuchsia_driver_host as fdh;
27use fidl_fuchsia_driver_index as fdi;
28use fidl_fuchsia_driver_token as fdt;
29use fidl_fuchsia_io as fio;
30use fuchsia_async as fasync;
31use fuchsia_component::client::connect_to_protocol_at_dir_root;
32use fuchsia_component::server::{ServiceFs, ServiceObjLocal};
33use fuchsia_inspect as inspect;
34use fuchsia_inspect::ArrayProperty;
35use futures::StreamExt;
36use futures::channel::oneshot;
37use log::{debug, error, info, warn};
38use rand::rngs::StdRng;
39use std::cell::RefCell;
40use std::collections::HashSet;
41use std::rc::{Rc, Weak};
42use std::sync::Arc;
43use vfs::execution_scope::ExecutionScope;
44
45pub struct DriverRunner {
46 pub(crate) driver_index: fdi::DriverIndexProxy,
47 pub(crate) dictionary_util: Rc<DictionaryUtil>,
48 loader_service_factory: LoaderServiceFactory,
49 pub(crate) root_node: Rc<Node>,
50 pub bind_manager: BindManagerHandle,
51 pub(crate) composite_node_spec_manager: CompositeNodeSpecManager,
52 runner: Runner,
53 driver_host_runner: Rc<DriverHostRunner>,
54 pub(crate) removal_tracker: Rc<RefCell<NodeRemovalTracker>>,
55 pub bootup_tracker: Rc<BootupTracker>,
56 driver_hosts: RefCell<Vec<Weak<dyn DriverHost>>>,
57 pub devfs: Arc<Devfs>,
58 pub(crate) memory_attributor: Rc<MemoryAttributor>,
59 launcher: Option<fidl_fuchsia_driver_loader::DriverHostLauncherProxy>,
60 pub(crate) enable_test_shutdown_delays: bool,
61 pub(crate) shutdown_test_rng: Rc<RefCell<StdRng>>,
62 pub(crate) scope: fasync::Scope,
63}
64
65impl DriverRunner {
66 #[allow(clippy::too_many_arguments)]
67 pub fn new(
68 realm: fcomponent::RealmProxy,
69 introspector: fcomponent::IntrospectorProxy,
70 dictionary_util: DictionaryUtil,
71 driver_index: fdi::DriverIndexProxy,
72 loader_service_factory: LoaderServiceFactory,
73 enable_test_shutdown_delays: bool,
74 offer_injector: OfferInjector,
75 devfs: Arc<Devfs>,
76 ) -> Rc<Self> {
77 Rc::new_cyclic(|weak_driver_runner| {
78 let bind_manager_bridge = Box::new(DriverRunnerBridge(weak_driver_runner.clone()));
79 let bind_manager = BindManagerHandle::new(bind_manager_bridge);
80
81 let composite_manager_bridge = Box::new(DriverRunnerBridge(weak_driver_runner.clone()));
82 let composite_node_spec_manager =
83 CompositeNodeSpecManager::new(composite_manager_bridge);
84
85 let bootup_tracker = BootupTracker::new(bind_manager.clone());
86
87 let root_node = Node::new(
88 "dev",
89 Weak::new(),
90 Box::new(DriverRunnerBridge(weak_driver_runner.clone())),
91 );
92 root_node.setup_devfs_for_root_node(devfs.root_node());
93
94 let runner = Runner::new(realm.clone(), introspector, offer_injector);
95 let driver_host_runner = DriverHostRunner::new(realm);
96 let removal_tracker = NodeRemovalTracker::new();
97 let memory_attributor = Rc::new(MemoryAttributor::new());
98
99 Self {
100 driver_index,
101 dictionary_util: Rc::new(dictionary_util),
102 loader_service_factory,
103 root_node,
104 bind_manager,
105 composite_node_spec_manager,
106 runner,
107 driver_host_runner,
108 removal_tracker,
109 bootup_tracker,
110 driver_hosts: RefCell::new(Vec::new()),
111 devfs,
112 memory_attributor,
113 launcher: None,
114 enable_test_shutdown_delays,
115 shutdown_test_rng: Rc::new(RefCell::new(rand::make_rng())),
116 scope: fasync::Scope::new_with_name("driver_runner"),
117 }
118 })
119 }
120
121 pub fn register_notifier(self: &Rc<Self>) -> Result<(), anyhow::Error> {
122 let (client, server) = create_endpoints();
123 self.driver_index.set_notifier(client)?;
124 let weak_self = Rc::downgrade(self);
125 self.scope.spawn_local(async move {
126 let mut stream = server.into_stream();
127 while let Some(Ok(msg)) = stream.next().await {
128 match msg {
129 fdi::DriverNotifierRequest::NewDriverAvailable { .. } => {
130 let Some(this) = weak_self.upgrade() else {
131 return;
132 };
133 let _ = this.bind_manager.try_bind_all_available().await;
134 }
135 }
136 }
137 });
138 Ok(())
139 }
140
141 pub fn root_node(&self) -> Rc<Node> {
142 self.root_node.clone()
143 }
144
145 pub fn get_composite_list_info(&self) -> Vec<fdd::CompositeNodeInfo> {
146 self.composite_node_spec_manager.get_composite_info()
147 }
148
149 pub fn driver_hosts(&self) -> Vec<Rc<dyn DriverHost>> {
150 self.driver_hosts.borrow().iter().filter_map(|w| w.upgrade()).collect()
151 }
152
153 pub fn get_driver_host(
154 &self,
155 driver_host_name_for_colocation: &str,
156 ) -> Option<Rc<dyn DriverHost>> {
157 if driver_host_name_for_colocation.is_empty() {
158 return None;
159 }
160 for host_weak in self.driver_hosts.borrow().iter() {
161 if let Some(host) = host_weak.upgrade()
162 && host.name_for_colocation() == driver_host_name_for_colocation
163 {
164 return Some(host);
165 }
166 }
167 None
168 }
169
170 pub async fn start_root_driver(self: &Rc<Self>, url: String) -> Result<(), zx::Status> {
171 self.bootup_tracker.start();
172 let package_type = if url.starts_with("fuchsia-boot://") {
173 fdf::DriverPackageType::Boot
174 } else {
175 fdf::DriverPackageType::Base
176 };
177
178 let (sender, receiver) = oneshot::channel();
179 self.root_node.set_driver_host_name_for_colocation("root");
180 let self_clone = self.clone();
181 self.scope.spawn_local(async move {
182 if let Err(e) = self_clone.start_driver(&self_clone.root_node, &url, package_type).await
183 {
184 error!("Failed to start root driver: {}", e);
185 sender.send(Err(e)).unwrap();
186 } else {
187 sender.send(Ok(())).unwrap();
188 }
189 });
190 receiver.await.map_err(|_| zx::Status::CANCELED)?
191 }
192
193 pub fn start_devfs_driver(self: &Rc<Self>) {
194 let self_clone = self.clone();
195 self.scope.spawn_local(async move {
196 let (client, server) = fidl::endpoints::create_proxy::<fcomponent::ControllerMarker>();
197 let result = self_clone
198 .runner
199 .create_driver_component(
200 "devfs_driver",
201 "fuchsia-boot:///devfs-driver#meta/devfs-driver.cm",
202 &Collection::Boot.to_string(),
203 &[],
204 None,
205 true,
206 server,
207 )
208 .await;
209 if let Ok((handle, receiver)) = result {
210 self_clone.devfs.set_component_controller_proxy(client);
211 if let Err(e) = self_clone.devfs.attach_component(handle, receiver).await {
212 error!("Failed to attach devfs component: {}", e);
213 }
214 } else {
215 error!("Starting the devfs component failed");
216 }
217 });
218 }
219
220 pub async fn start_driver(
221 self: &Rc<Self>,
222 node: &Rc<Node>,
223 url: &str,
224 package_type: fdf::DriverPackageType,
225 ) -> Result<(), zx::Status> {
226 node.set_collection(to_collection(node, package_type));
235 node.set_driver_package_type(package_type);
236
237 let moniker = node.make_component_moniker();
238 self.bootup_tracker.notify_new_start_request(
239 moniker.clone(),
240 url.to_string(),
241 node.weak_from_this(),
242 );
243
244 match self.start_driver_internal(node, url, &moniker).await {
245 Ok(_) => {
246 node.complete_bind(Ok(())).await;
247 self.bootup_tracker.notify_start_complete(&moniker);
248 Ok(())
249 }
250 Err(err) => {
251 node.on_start_error(err);
252 node.complete_bind(Err(err)).await;
253 self.bootup_tracker.notify_start_complete(&moniker);
254 Err(err)
255 }
256 }
257 }
258
259 async fn start_driver_internal(
260 self: &Rc<Self>,
261 node: &Rc<Node>,
262 url: &str,
263 moniker: &str,
264 ) -> Result<(), zx::Status> {
265 let dictionary = node.prepare_dictionary().await;
266
267 if !node.has_component_controller_proxy() {
268 let (client, server) = fidl::endpoints::create_proxy::<fcomponent::ControllerMarker>();
269
270 let offers = node.offers().clone();
271 let create_result = self
272 .runner
273 .create_driver_component(
274 moniker,
275 url,
276 &node.collection().to_string(),
277 &offers,
278 dictionary,
279 node.skip_injected_offers(),
280 server,
281 )
282 .await;
283
284 match create_result {
285 Ok((handle_info, receiver)) => {
286 node.set_created_info(client, handle_info, receiver).await;
287 }
288 Err(err) => {
289 return Err(err);
290 }
291 }
292 }
293
294 node.send_start_request().await?;
295 let (start_info, controller) = node.get_next_start_request().await?;
296 node.start_driver(start_info, controller).await
297 }
298
299 pub async fn create_driver_host(
300 &self,
301 use_next_vdso: bool,
302 driver_host_name_for_colocation: String,
303 ) -> Result<Rc<dyn DriverHost>, zx::Status> {
304 let (exposed_dir_client, exposed_dir_server) = create_endpoints::<fio::DirectoryMarker>();
305 let name = if !driver_host_name_for_colocation.is_empty() {
306 format!("driver-host-{}", driver_host_name_for_colocation.trim_start_matches('#'))
307 } else {
308 format!("driver-host-{}", self.driver_hosts.borrow().len())
309 };
310
311 self.create_driver_host_component(&name, exposed_dir_server, use_next_vdso)?;
312
313 let driver_host_proxy =
314 connect_to_protocol_at_dir_root::<fdh::DriverHostMarker>(&exposed_dir_client)
315 .map_err(|_| zx::Status::INTERNAL)?;
316
317 let (tx, rx) = oneshot::channel();
318 let _ = self.loader_service_factory.unbounded_send(tx);
319 let loader_service_client = rx.await.map_err(|e| {
320 error!("Failed to connect to loader service: {}", e);
321 zx::Status::INTERNAL
322 })??;
323
324 let driver_host: Rc<dyn DriverHost> = Rc::new(DriverHostComponent::new(
325 driver_host_proxy,
326 None,
327 ExecutionScope::new(),
328 driver_host_name_for_colocation,
329 ));
330 driver_host.install_loader(loader_service_client)?;
331
332 self.driver_hosts.borrow_mut().push(Rc::downgrade(&driver_host));
333
334 Ok(driver_host)
335 }
336
337 pub async fn create_driver_host_dynamic_linker(
338 self: &Rc<Self>,
339 driver_host_name_for_colocation: String,
340 ) -> Result<Rc<dyn DriverHost>, zx::Status> {
341 let driver_host_runner = self.driver_host_runner.clone();
342 let launcher = self.launcher.clone().unwrap();
343 let (exposed_dir_client, exposed_dir_server) = create_endpoints::<fio::DirectoryMarker>();
344 let loader_client = driver_host_runner
345 .start_driver_host(launcher, exposed_dir_server)
346 .await
347 .map_err(|e| {
348 error!("Failed to start driver host: {e:?}");
349 zx::Status::INTERNAL
350 })?;
351
352 let driver_host_client =
353 connect_to_protocol_at_dir_root::<fdh::DriverHostMarker>(&exposed_dir_client)
354 .map_err(|_| zx::Status::INTERNAL)?;
355 let driver_host: Rc<dyn DriverHost> = Rc::new(DriverHostComponent::new(
356 driver_host_client,
357 Some(loader_client.into_proxy()),
358 ExecutionScope::new(),
359 driver_host_name_for_colocation,
360 ));
361 self.driver_hosts.borrow_mut().push(Rc::downgrade(&driver_host));
362 Ok(driver_host)
363 }
364
365 fn create_driver_host_component(
366 &self,
367 moniker: &str,
368 exposed_dir: ServerEnd<fio::DirectoryMarker>,
369 use_next_vdso: bool,
370 ) -> Result<(), zx::Status> {
371 let url = if use_next_vdso {
372 "fuchsia-boot:///driver_host#meta/driver_host_next.cm"
373 } else {
374 "fuchsia-boot:///driver_host#meta/driver_host.cm"
375 };
376
377 let child_decl = fdecl::Child {
378 name: Some(moniker.to_string()),
379 url: Some(url.to_string()),
380 startup: Some(fdecl::StartupMode::Lazy),
381 ..Default::default()
382 };
383
384 let create_child_args = fcomponent::CreateChildArgs::default();
385
386 let realm = self.runner.realm.clone();
387 let child_moniker = moniker.to_string();
388 self.scope.spawn_local(async move {
389 let result = realm
390 .create_child(
391 &fdecl::CollectionRef { name: "driver-hosts".to_string() },
392 &child_decl,
393 create_child_args,
394 )
395 .await;
396
397 if let Err(e) = result {
398 error!("Failed to create driver host '{}': {}", child_moniker, e);
399 return;
400 }
401
402 let child_ref = fdecl::ChildRef {
403 name: child_moniker.clone(),
404 collection: Some("driver-hosts".to_string()),
405 };
406 let open_result = realm.open_exposed_dir(&child_ref, exposed_dir).await;
407 if let Err(e) = open_result {
408 error!(
409 "Failed to open exposed directory for driver host: '{}': {}",
410 child_moniker, e
411 );
412 }
413 });
414
415 Ok(())
416 }
417
418 pub async fn destroy_driver_host(
419 &self,
420 driver_host_name_for_colocation: String,
421 ) -> Result<(), zx::Status> {
422 let name = if !driver_host_name_for_colocation.is_empty() {
423 let suffix = driver_host_name_for_colocation.trim_start_matches('#');
424 format!("driver-host-{}", suffix)
425 } else {
426 return Err(zx::Status::INVALID_ARGS);
427 };
428
429 let child_ref =
430 fdecl::ChildRef { name: name.clone(), collection: Some("driver-hosts".to_string()) };
431
432 let result = self.runner.realm.destroy_child(&child_ref).await;
433 match result {
434 Ok(Ok(())) => Ok(()),
435 Ok(Err(fcomponent::Error::InstanceNotFound)) => Ok(()),
436 Ok(Err(fcomponent::Error::InstanceDied)) => Ok(()),
437 Ok(Err(e)) => {
438 error!("Failed to destroy driver host '{}': {:?}", name, e);
439 Err(zx::Status::INTERNAL)
440 }
441 Err(e) => {
442 error!("Failed to destroy driver host '{}': {}", name, e);
443 Err(zx::Status::INTERNAL)
444 }
445 }
446 }
447
448 pub fn publish(self: &Rc<Self>, fs: &mut ServiceFs<ServiceObjLocal<'_, ()>>) {
449 self.runner.publish(fs);
450 self.driver_host_runner.publish(fs);
451 self.memory_attributor.publish(fs);
452
453 let this = self.clone();
454 fs.dir("svc").add_fidl_service(move |stream: fdf::CompositeNodeManagerRequestStream| {
455 this.serve_composite_node_manager(stream);
456 });
457
458 let this = self.clone();
459 fs.dir("svc").add_fidl_service(move |stream: fdt::NodeBusTopologyRequestStream| {
460 this.serve_node_bus_topology(stream);
461 });
462
463 let this = self.clone();
464 fs.dir("svc").add_fidl_service(move |stream: fcrash::CrashIntrospectRequestStream| {
465 this.serve_crash_introspect(stream);
466 });
467
468 let this = self.clone();
469 fs.dir("svc").add_fidl_service(move |stream: fdt::DebugRequestStream| {
470 this.serve_debug(stream);
471 });
472 }
473
474 pub fn serve_debug(self: &Rc<Self>, mut stream: fdt::DebugRequestStream) {
475 let this = self.clone();
476 self.scope.spawn_local(async move {
477 while let Some(Ok(request)) = stream.next().await {
478 match request {
479 fdt::DebugRequest::LogStackTrace { node_token, responder } => {
480 let result = this.log_stack_trace(node_token).await;
481 let _ = match result {
482 Ok(()) => responder.send(Ok(())),
483 Err(status) => responder.send(Err(status.into_raw())),
484 };
485 }
486 fdt::DebugRequest::GetHostKoid { node_token, responder } => {
487 let result = this.get_host_koid(node_token).await;
488 let _ = match result {
489 Ok(host_koid) => responder.send(Ok(host_koid.raw_koid())),
490 Err(status) => responder.send(Err(status.into_raw())),
491 };
492 }
493 fdt::DebugRequest::_UnknownMethod { ordinal, .. } => {
494 warn!("Unknown Debug request: {}", ordinal);
495 }
496 }
497 }
498 });
499 }
500
501 async fn log_stack_trace(&self, node_token: zx::Event) -> Result<(), zx::Status> {
502 let token_koid = node_token.basic_info()?.koid;
503 let node = self.find_node_by_token_koid(token_koid).await;
504 if let Some(node) = node {
505 if let Some(host) = node.driver_host() {
506 host.trigger_stack_trace();
507 Ok(())
508 } else {
509 Err(zx::Status::NOT_FOUND)
510 }
511 } else {
512 Err(zx::Status::NOT_FOUND)
513 }
514 }
515
516 async fn get_host_koid(&self, node_token: zx::Event) -> Result<zx::Koid, zx::Status> {
517 let token_koid = node_token.basic_info()?.koid;
518 let node = self.find_node_by_token_koid(token_koid).await;
519 if let Some(node) = node {
520 if let Some(host) = node.driver_host() {
521 host.get_process_koid().await
522 } else {
523 Err(zx::Status::NOT_FOUND)
524 }
525 } else {
526 Err(zx::Status::NOT_FOUND)
527 }
528 }
529
530 pub fn serve_composite_node_manager(
531 self: &Rc<Self>,
532 mut stream: fdf::CompositeNodeManagerRequestStream,
533 ) {
534 let this = self.clone();
535 self.scope.spawn_local(async move {
536 while let Some(Ok(request)) = stream.next().await {
537 this.handle_composite_node_manager_request(request).await;
538 }
539 });
540 }
541
542 async fn handle_composite_node_manager_request(
543 self: &Rc<Self>,
544 request: fdf::CompositeNodeManagerRequest,
545 ) {
546 match request {
547 fdf::CompositeNodeManagerRequest::AddSpec { payload, responder } => {
548 let result = self.add_spec(payload).await;
549 let _ = responder.send(result);
550 }
551 fdf::CompositeNodeManagerRequest::_UnknownMethod { .. } => (),
552 }
553 }
554
555 async fn add_spec(
556 self: &Rc<Self>,
557 spec: fdf::CompositeNodeSpec,
558 ) -> Result<(), fdf::CompositeNodeSpecError> {
559 let name = spec.name.clone().ok_or(fdf::CompositeNodeSpecError::MissingArgs)?;
560
561 let parents_present = spec.parents.is_some();
562 let parents2_present = spec.parents2.is_some();
563
564 if !parents_present && !parents2_present {
565 return Err(fdf::CompositeNodeSpecError::MissingArgs);
566 }
567
568 if parents_present && parents2_present {
569 return Err(fdf::CompositeNodeSpecError::DuplicateParents);
570 }
571
572 let parents2 = if let Some(ref parents) = spec.parents {
573 if parents.is_empty() {
574 return Err(fdf::CompositeNodeSpecError::EmptyNodes);
575 }
576 parents
577 .iter()
578 .map(|parent| {
579 let bind_rules = parent.bind_rules.iter().map(to_bind_rule2).collect();
580 let properties = parent.properties.iter().map(to_property2).collect();
581 fdf::ParentSpec2 { bind_rules, properties }
582 })
583 .collect()
584 } else if let Some(ref parents2) = spec.parents2 {
585 if parents2.is_empty() {
586 return Err(fdf::CompositeNodeSpecError::EmptyNodes);
587 }
588 parents2.clone()
589 } else {
590 unreachable!();
591 };
592
593 let driver_host_name_for_colocation = spec.driver_host.clone().unwrap_or_default();
594
595 let spec_for_manager = CompositeNodeSpec::new(
596 name,
597 parents2,
598 Box::new(DriverRunnerBridge(Rc::downgrade(self))),
599 driver_host_name_for_colocation,
600 );
601
602 self.composite_node_spec_manager.add_spec(spec, spec_for_manager).await
603 }
604
605 pub fn serve_node_bus_topology(self: &Rc<Self>, mut stream: fdt::NodeBusTopologyRequestStream) {
606 let this = self.clone();
607 self.scope.spawn_local(async move {
608 while let Some(Ok(request)) = stream.next().await {
609 match request {
610 fdt::NodeBusTopologyRequest::Get { token, responder } => {
611 let result = this.get_bus_topology(token).await;
612 let _ = match result {
613 Ok(topology) => responder.send(Ok(&topology)),
614 Err(status) => responder.send(Err(status.into_raw())),
615 };
616 }
617 fdt::NodeBusTopologyRequest::_UnknownMethod { .. } => (),
618 }
619 }
620 });
621 }
622
623 async fn get_bus_topology(&self, token: zx::Event) -> Result<Vec<fdf::BusInfo>, zx::Status> {
624 let token_koid = token.basic_info()?.koid;
625
626 let node = self.find_node_by_token_koid(token_koid).await;
627
628 if let Some(node) = node { Ok(node.get_bus_topology()) } else { Err(zx::Status::NOT_FOUND) }
629 }
630
631 pub fn serve_crash_introspect(
632 self: &Rc<Self>,
633 mut stream: fcrash::CrashIntrospectRequestStream,
634 ) {
635 let this = self.clone();
636 self.scope.spawn_local(async move {
637 while let Some(Ok(request)) = stream.next().await {
638 match request {
639 fcrash::CrashIntrospectRequest::FindDriverCrash {
640 process_koid,
641 thread_koid,
642 responder,
643 } => {
644 let result = this
645 .find_driver_crash(
646 zx::Koid::from_raw(process_koid),
647 zx::Koid::from_raw(thread_koid),
648 )
649 .await;
650 let _ = match result {
651 Ok(info) => responder.send(Ok(&info)),
652 Err(status) => responder.send(Err(status.into_raw())),
653 };
654 }
655 }
656 }
657 });
658 }
659
660 async fn find_driver_crash(
661 &self,
662 process_koid: zx::Koid,
663 thread_koid: zx::Koid,
664 ) -> Result<fcrash::DriverCrashInfo, zx::Status> {
665 let hosts = self.driver_hosts.borrow().clone();
666 for host in hosts {
667 if let Some(host) = host.upgrade()
668 && let Ok(koid) = host.get_process_koid().await
669 && koid == process_koid
670 {
671 let crash_info = host.get_crash_info(thread_koid).await?;
672 let token = crash_info.node_token.ok_or(zx::Status::INTERNAL)?;
673 let token_koid = token.into_handle().basic_info()?.koid;
674
675 let node = self.find_node_by_token_koid(token_koid).await;
676
677 if let Some(node) = node {
678 return Ok(fcrash::DriverCrashInfo {
679 node_moniker: Some(node.make_component_moniker()),
680 url: crash_info.url,
681 ..Default::default()
682 });
683 } else {
684 return Err(zx::Status::NOT_FOUND);
685 }
686 }
687 }
688 Err(zx::Status::NOT_FOUND)
689 }
690
691 async fn find_node_by_token_koid(&self, token_koid: zx::Koid) -> Option<Rc<Node>> {
692 let mut result: Option<Rc<Node>> = None;
693 perform_bfs(self.root_node(), async |current| {
694 if result.is_some() {
695 return false; }
697 if let Some(current_koid) = current.token_koid()
698 && current_koid == token_koid
699 {
700 result = Some(current.clone());
701 return false;
702 }
703 true
704 })
705 .await;
706 result
707 }
708
709 pub async fn rebind_composites_with_driver(&self, driver_url: &str) -> u32 {
710 let mut names = HashSet::new();
711 perform_bfs(self.root_node(), async |node| {
712 if node.is_composite() && node.driver_url() == driver_url {
713 names.insert(node.name().to_string());
714 return false; }
716 true })
718 .await;
719
720 let count = names.len() as u32;
721 for name in names {
722 let _ = self.composite_node_spec_manager.rebind(name, None).await;
723 }
724
725 count
726 }
727
728 pub async fn restart_nodes_colocated_with_driver_url(
729 self: &Rc<Self>,
730 url: &str,
731 rematch_flags: fdd::RestartRematchFlags,
732 ) -> Result<u32, zx::Status> {
733 let mut driver_hosts = HashSet::new();
735 perform_bfs(self.root_node(), async |node| {
736 if node.driver_url() == url
737 && let Some(host) = node.driver_host()
738 {
739 driver_hosts.insert(Rc::as_ptr(&host) as *const ());
742 }
743 true })
745 .await;
746
747 if driver_hosts.is_empty() {
748 warn!(
749 "restart_nodes_colocated_with_driver_url: no driver hosts found with url {}",
750 url
751 );
752 return Ok(0);
753 }
754
755 let driver_host_count = driver_hosts.len() as u32;
756
757 let this = self.clone();
759 perform_bfs(self.root_node(), async |node| {
760 let host_ptr = node.driver_host().map(|host| Rc::as_ptr(&host) as *const ());
761 if host_ptr.is_none() || !driver_hosts.contains(&host_ptr.unwrap()) {
762 return true;
764 }
765
766 if node.evaluate_rematch_flags(rematch_flags, url) {
768 if node.is_composite() {
769 debug!(
770 "RestartNodesColocatedWithDriverUrl rebinding composite {}",
771 node.make_component_moniker()
772 );
773 let _ = this
774 .composite_node_spec_manager
775 .rebind(node.name().to_string(), None)
776 .await;
777 } else {
778 debug!(
779 "RestartNodesColocatedWithDriverUrl restarting node with rematch {}",
780 node.make_component_moniker()
781 );
782 let (tx, _rx) = oneshot::channel();
783 node.restart_node_with_rematch(Some("".to_string()), tx);
784 }
785 } else {
786 info!(
787 "RestartNodesColocatedWithDriverUrl restarting node {}",
788 node.make_component_moniker()
789 );
790 node.restart_node();
791 }
792
793 false })
795 .await;
796
797 Ok(driver_host_count)
798 }
799
800 pub async fn restart_with_dictionary(
801 self: &Rc<Self>,
802 moniker: String,
803 dictionary: fsandbox::DictionaryRef,
804 reset_eventpair: zx::EventPair,
805 ) {
806 let imported = self.dictionary_util.import_dictionary(dictionary).await;
807 let imported = match imported {
808 Ok(imported) => imported,
809 Err(e) => {
810 error!("Failed to import dictionary: {}", e);
811 return;
812 }
813 };
814
815 let mut restarted_node: Option<Rc<Node>> = None;
816 perform_bfs(self.root_node(), async |node| {
817 if restarted_node.is_some() {
818 return false; }
820
821 if node.make_component_moniker() == moniker {
822 if node.has_subtree_dictionary() {
823 error!(concat!(
824 "RestartWithDictionary requested node id already contains a ",
825 "dictionary_ref from another RestartWithDictionary operation."
826 ));
827 return false; }
829 assert!(restarted_node.is_none(), "Multiple nodes with same moniker not possible.");
830 restarted_node = Some(node.clone());
831 node.set_subtree_dictionary(imported);
832 node.restart_node();
833 return false; }
835
836 true })
838 .await;
839
840 if let Some(restarted_node) = restarted_node {
841 self.scope.spawn_local(async move {
842 let signals = zx::Signals::EVENTPAIR_PEER_CLOSED | zx::Signals::EVENTPAIR_SIGNALED;
843 let on_signals = fasync::OnSignals::new(&reset_eventpair, signals);
844 on_signals.await.expect("failed to wait on eventpair");
845
846 info!("RestartWithDictionary operation released.");
847 restarted_node.remove_subtree_dictionary();
848 restarted_node.restart_node();
849 });
850 }
851 }
852
853 pub fn inspect(&self) -> inspect::Inspector {
854 let inspector =
855 inspect::Inspector::new(inspect::InspectorConfig::default().size(2 * 256 * 1024));
856
857 let mut roots = Vec::new();
858 let mut unique_nodes = HashSet::new();
859
860 let device_tree = inspector.root().create_child("node_topology");
861 let mut root_node_inspect = device_tree.create_child(self.root_node.name());
862
863 self.inspect_node_recursive(
864 &self.root_node,
865 &mut root_node_inspect,
866 &mut roots,
867 &mut unique_nodes,
868 );
869
870 device_tree.record(root_node_inspect);
871 inspector.root().record(device_tree);
872
873 for root in roots {
874 inspector.root().record(root);
875 }
876
877 self.bind_manager.record_inspect(inspector.root());
878
879 inspector
880 }
881
882 fn inspect_node_recursive(
883 &self,
884 node: &Rc<Node>,
885 inspect_node: &mut inspect::Node,
886 roots: &mut Vec<inspect::Node>,
887 unique_nodes: &mut HashSet<*const Node>,
888 ) {
889 let node_ptr = Rc::as_ptr(node);
890 if !unique_nodes.insert(node_ptr) {
891 return;
892 }
893
894 let offers = node.offers();
895 if !offers.is_empty() {
896 let array = inspect_node.create_string_array("offers", offers.len());
897 for (i, offer) in offers.iter().enumerate() {
898 array.set(i, &offer.service_name);
899 }
900 inspect_node.record(array);
901 }
902
903 let symbols = node.symbols();
904 if !symbols.is_empty() {
905 let array = inspect_node.create_string_array("symbols", symbols.len());
906 for (i, symbol) in symbols.iter().enumerate() {
907 if let Some(name) = &symbol.name {
908 array.set(i, name);
909 }
910 }
911 inspect_node.record(array);
912 }
913
914 if let Some(properties) = node.get_node_properties(None)
915 && !properties.is_empty()
916 {
917 inspect_node.record_child("properties", |properties_node| {
918 for (i, property) in properties.iter().enumerate() {
919 properties_node.record_child(i.to_string(), |inspect_property| {
920 inspect_property.record_string("key", &property.key);
921 match &property.value {
922 fdf::NodePropertyValue::StringValue(s) => {
923 inspect_property.record_string("value", s)
924 }
925 fdf::NodePropertyValue::IntValue(i) => {
926 inspect_property.record_uint("value", *i as u64)
927 }
928 fdf::NodePropertyValue::EnumValue(e) => {
929 inspect_property.record_string("value", e)
930 }
931 fdf::NodePropertyValue::BoolValue(b) => {
932 inspect_property.record_bool("value", *b)
933 }
934 _ => inspect_property.record_string("value", "UNKNOWN VALUE TYPE"),
935 }
936 });
937 }
938 });
939 }
940
941 inspect_node
942 .record_string("type", if node.is_composite() { "Composite Device" } else { "Device" });
943 inspect_node.record_string("topological_path", node.make_topological_path(false));
944 inspect_node.record_string("driver", node.driver_url());
945
946 for child in node.children() {
947 let mut child_inspect_node = inspect_node.create_child(child.name());
948 self.inspect_node_recursive(&child, &mut child_inspect_node, roots, unique_nodes);
949 roots.push(child_inspect_node);
950 }
951 }
952}
953
954#[cfg(test)]
955mod tests {
956 use super::*;
957 use crate::testing::{MockDriverHost, MockNodeManager};
958 use futures::channel::mpsc;
959 use std::sync::atomic::Ordering;
960
961 use fidl_fuchsia_driver_index as fdi;
962
963 #[fuchsia::test]
964 async fn test_log_stack_trace() {
965 let (realm, _) = fidl::endpoints::create_proxy::<fcomponent::RealmMarker>();
966 let (introspector, _) = fidl::endpoints::create_proxy::<fcomponent::IntrospectorMarker>();
967 let (driver_index, _) = fidl::endpoints::create_proxy::<fdi::DriverIndexMarker>();
968 let (capability_store, _) =
969 fidl::endpoints::create_proxy::<fsandbox::CapabilityStoreMarker>();
970 let (loader_service_factory, _) = mpsc::unbounded();
971
972 let driver_runner = DriverRunner::new(
973 realm,
974 introspector,
975 DictionaryUtil::new(capability_store),
976 driver_index,
977 loader_service_factory,
978 false,
979 OfferInjector::new(crate::offer_injection::PowerOffersConfig {
980 power_inject_offer: false,
981 power_suspend_enabled: false,
982 }),
983 Devfs::new(mpsc::unbounded().0),
984 );
985
986 let node_manager = Box::new(MockNodeManager);
987 let node = Node::new("test_node", Rc::downgrade(&driver_runner.root_node), node_manager);
988 let host = Rc::new(MockDriverHost::new());
989 node.set_host(host.clone());
990
991 let token = zx::Event::create();
994 let token_remote = token.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
995 let koid = token.koid().unwrap();
996
997 node.set_state_for_testing(driver_manager_node::types::NodeState::DriverComponent(
998 driver_manager_node::types::DriverComponent::new(
999 "url".to_string(),
1000 token_remote,
1001 koid,
1002 None,
1003 None,
1004 None,
1005 driver_manager_node::types::DriverState::Running,
1006 ),
1007 ));
1008
1009 driver_runner.root_node.add_child_to_children_for_testing(node);
1011
1012 let result = driver_runner.log_stack_trace(token).await;
1014 assert!(result.is_ok());
1015 assert_eq!(host.stack_trace_count.load(Ordering::SeqCst), 1);
1016
1017 let random_token = zx::Event::create();
1019 let result = driver_runner.log_stack_trace(random_token).await;
1020 assert_eq!(result, Err(zx::Status::NOT_FOUND));
1021 }
1022
1023 #[fuchsia::test]
1024 async fn test_get_host_koid() {
1025 let (realm, _) = fidl::endpoints::create_proxy::<fcomponent::RealmMarker>();
1026 let (introspector, _) = fidl::endpoints::create_proxy::<fcomponent::IntrospectorMarker>();
1027 let (driver_index, _) = fidl::endpoints::create_proxy::<fdi::DriverIndexMarker>();
1028 let (capability_store, _) =
1029 fidl::endpoints::create_proxy::<fsandbox::CapabilityStoreMarker>();
1030 let (loader_service_factory, _) = mpsc::unbounded();
1031
1032 let driver_runner = DriverRunner::new(
1033 realm,
1034 introspector,
1035 DictionaryUtil::new(capability_store),
1036 driver_index,
1037 loader_service_factory,
1038 false,
1039 OfferInjector::new(crate::offer_injection::PowerOffersConfig {
1040 power_inject_offer: false,
1041 power_suspend_enabled: false,
1042 }),
1043 Devfs::new(mpsc::unbounded().0),
1044 );
1045
1046 let node_manager = Box::new(MockNodeManager);
1047 let node = Node::new("test_node", Rc::downgrade(&driver_runner.root_node), node_manager);
1048 let host = Rc::new(MockDriverHost::new());
1049 node.set_host(host.clone());
1050
1051 let token = zx::Event::create();
1052 let token_remote = token.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
1053 let koid = token.koid().unwrap();
1054
1055 node.set_state_for_testing(driver_manager_node::types::NodeState::DriverComponent(
1056 driver_manager_node::types::DriverComponent::new(
1057 "url".to_string(),
1058 token_remote,
1059 koid,
1060 None,
1061 None,
1062 None,
1063 driver_manager_node::types::DriverState::Running,
1064 ),
1065 ));
1066
1067 driver_runner.root_node.add_child_to_children_for_testing(node);
1068
1069 let result = driver_runner.get_host_koid(token).await;
1070 assert_eq!(result, Ok(zx::Koid::from_raw(0)));
1071
1072 let random_token = zx::Event::create();
1073 let result = driver_runner.get_host_koid(random_token).await;
1074 assert_eq!(result, Err(zx::Status::NOT_FOUND));
1075 }
1076}