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