Skip to main content

driver_manager_development/
driver_development_service.rs

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