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