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::{ControlHandle, DiscoverableProtocolMarker, Responder, ServerEnd};
12use fuchsia_component::client::connect_to_protocol;
13use fuchsia_component::server::{ServiceFs, ServiceObjLocal};
14use futures::prelude::*;
15use log::{error, warn};
16use std::cell::RefCell;
17use std::collections::{HashMap, HashSet, VecDeque};
18use std::rc::{Rc, Weak};
19use {
20    fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_driver_development as fdd,
21    fidl_fuchsia_driver_framework as fdf, fidl_fuchsia_driver_index as fdi,
22    fuchsia_async as fasync,
23};
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            properties: 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: Some(t.scheduler_role),
312                    ..Default::default()
313                })
314                .collect();
315
316            let dispatchers = process_info
317                .dispatchers
318                .into_iter()
319                .map(|d| fdd::DispatcherInfo {
320                    driver: Some(d.driver),
321                    name: Some(d.name),
322                    options: Some(d.options),
323                    scheduler_role: Some(d.scheduler_role),
324                    ..Default::default()
325                })
326                .collect();
327
328            let mut drivers = vec![];
329            if let Some(d) = driver_host_to_drivers.get(&process_info.process_koid) {
330                drivers = d.iter().cloned().collect();
331                drivers.sort();
332            }
333
334            infos.push(fdd::DriverHostInfo {
335                process_koid: Some(process_info.process_koid.raw_koid()),
336                name: Some(host.name_for_colocation().to_string()),
337                threads: Some(threads),
338                dispatchers: Some(dispatchers),
339                drivers: Some(drivers),
340                ..Default::default()
341            });
342        }
343
344        let iterator_stream = iterator.into_stream();
345        let driver_host_info_iterator = DriverHostInfoIterator::new(infos);
346        self.scope.spawn_local(async move {
347            if let Err(e) = driver_host_info_iterator.serve(iterator_stream).await {
348                warn!("DriverHostInfoIterator server failed: {}", e);
349            }
350        });
351    }
352
353    async fn restart_driver_hosts(
354        &self,
355        driver_url: String,
356        rematch_flags: fdd::RestartRematchFlags,
357        responder: fdd::ManagerRestartDriverHostsResponder,
358    ) {
359        let result = self
360            .driver_runner
361            .restart_nodes_colocated_with_driver_url(&driver_url, rematch_flags)
362            .await;
363        match result {
364            Ok(count) => {
365                let _ = responder.send(Ok(count));
366            }
367            Err(status) => {
368                let _ = responder.send(Err(status.into_raw()));
369            }
370        }
371    }
372
373    async fn disable_driver(
374        &self,
375        driver_url: String,
376        package_hash: Option<String>,
377        responder: fdd::ManagerDisableDriverResponder,
378    ) {
379        let driver_index_client = match connect_to_protocol::<fdi::DevelopmentManagerMarker>() {
380            Ok(proxy) => proxy,
381            Err(e) => {
382                error!(
383                    "Failed to connect to service '{}': {}",
384                    fdi::DevelopmentManagerMarker::PROTOCOL_NAME,
385                    e
386                );
387                responder.control_handle().shutdown_with_epitaph(zx::Status::UNAVAILABLE);
388                return;
389            }
390        };
391
392        match driver_index_client.disable_driver(&driver_url, package_hash.as_deref()).await {
393            Ok(result) => {
394                let _ = responder.send(result);
395            }
396            Err(e) => {
397                error!("Failed to call DriverIndex::DisableDriver: {}", e);
398                let status = match e {
399                    fidl::Error::ClientChannelClosed { status, .. } => status,
400                    _ => zx::Status::INTERNAL,
401                };
402                responder.control_handle().shutdown_with_epitaph(status);
403            }
404        }
405    }
406
407    async fn enable_driver(
408        &self,
409        driver_url: String,
410        package_hash: Option<String>,
411        responder: fdd::ManagerEnableDriverResponder,
412    ) {
413        let driver_index_client = match connect_to_protocol::<fdi::DevelopmentManagerMarker>() {
414            Ok(proxy) => proxy,
415            Err(e) => {
416                error!(
417                    "Failed to connect to service '{}': {}",
418                    fdi::DevelopmentManagerMarker::PROTOCOL_NAME,
419                    e
420                );
421                responder.control_handle().shutdown_with_epitaph(zx::Status::UNAVAILABLE);
422                return;
423            }
424        };
425
426        match driver_index_client.enable_driver(&driver_url, package_hash.as_deref()).await {
427            Ok(result) => {
428                let _ = responder.send(result);
429            }
430            Err(e) => {
431                error!("Failed to call DriverIndex::EnableDriver: {}", e);
432                let status = match e {
433                    fidl::Error::ClientChannelClosed { status, .. } => status,
434                    _ => zx::Status::INTERNAL,
435                };
436                responder.control_handle().shutdown_with_epitaph(status);
437            }
438        }
439    }
440
441    async fn rebind_composites_with_driver(
442        &self,
443        driver_url: String,
444        responder: fdd::ManagerRebindCompositesWithDriverResponder,
445    ) {
446        let driver_index_client = match connect_to_protocol::<fdi::DevelopmentManagerMarker>() {
447            Ok(proxy) => proxy,
448            Err(e) => {
449                error!(
450                    "Failed to connect to service '{}': {}",
451                    fdi::DevelopmentManagerMarker::PROTOCOL_NAME,
452                    e
453                );
454                responder.control_handle().shutdown_with_epitaph(zx::Status::UNAVAILABLE);
455                return;
456            }
457        };
458
459        match driver_index_client.rebind_composites_with_driver(&driver_url).await {
460            Ok(Ok(())) => {
461                // success from driver_index, now rebind in driver_runner
462                let count = self.driver_runner.rebind_composites_with_driver(&driver_url).await;
463                let _ = responder.send(Ok(count));
464            }
465            Ok(Err(status)) => {
466                error!(
467                    "DriverIndex::RebindCompositesWithDriver failed: {}",
468                    zx::Status::from_raw(status)
469                );
470                let _ = responder.send(Err(status));
471            }
472            Err(e) => {
473                error!("Failed to call DriverIndex::RebindCompositesWithDriver: {}", e);
474                let status = match e {
475                    fidl::Error::ClientChannelClosed { status, .. } => status,
476                    _ => zx::Status::INTERNAL,
477                };
478                let _ = responder.send(Err(status.into_raw()));
479            }
480        }
481    }
482
483    async fn restart_with_dictionary(
484        &self,
485        moniker: String,
486        dictionary: fidl_fuchsia_component_sandbox::DictionaryRef,
487        responder: fdd::ManagerRestartWithDictionaryResponder,
488    ) {
489        let (endpoint0, endpoint1) = zx::EventPair::create();
490        self.driver_runner.restart_with_dictionary(moniker, dictionary, endpoint1).await;
491        let _ = responder.send(Ok(endpoint0));
492    }
493}
494
495async fn create_device_info(node: &Rc<Node>) -> Result<fdd::NodeInfo, zx::Status> {
496    let children = node.children();
497    let child_ids: Vec<u64> = children.iter().map(|child| Rc::as_ptr(child) as u64).collect();
498
499    let parents = node.parents();
500    let parent_ids: Vec<u64> = parents
501        .iter()
502        .filter_map(|parent| parent.upgrade())
503        .map(|parent| Rc::as_ptr(&parent) as u64)
504        .collect();
505
506    let driver_host_koid = if node.as_ref().is_bound() {
507        match node.driver_host().as_ref() {
508            Some(dh) => Some(dh.get_process_koid().await.unwrap().raw_koid()),
509            None => None,
510        }
511    } else {
512        None
513    };
514
515    let offers = node.offers();
516    let offer_list: Vec<fdecl::Offer> = offers
517        .iter()
518        .map(|o| o.into())
519        .filter_map(|offer| match offer {
520            fdf::Offer::DriverTransport(d) => Some(d),
521            fdf::Offer::ZirconTransport(z) => Some(z),
522            fdf::Offer::DictionaryOffer(d) => Some(d),
523            _ => None,
524        })
525        .collect();
526
527    let node_property_list = if node.is_composite() {
528        None
529    } else {
530        node.get_node_properties(None).and_then(|properties| {
531            if properties.is_empty() {
532                None
533            } else {
534                Some(properties.iter().map(to_deprecated_property).collect())
535            }
536        })
537    };
538
539    Ok(fdd::NodeInfo {
540        id: Some(Rc::as_ptr(node) as u64),
541        moniker: Some(node.make_component_moniker()),
542        bound_driver_url: Some(node.driver_url()),
543        quarantined: Some(node.is_quarantined()),
544        child_ids: if child_ids.is_empty() { None } else { Some(child_ids) },
545        parent_ids: if parent_ids.is_empty() { None } else { Some(parent_ids) },
546        driver_host_koid,
547        offer_list: if offer_list.is_empty() { None } else { Some(offer_list) },
548        node_property_list,
549        bus_topology: Some(node.get_bus_topology()),
550        ..Default::default()
551    })
552}