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