Skip to main content

driver_manager_bind/
bind_manager.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::bind_node_set::BindNodeSet;
6use async_trait::async_trait;
7use driver_manager_node::Node;
8use driver_manager_types::{BindResult, BindResultTracker, NodeType};
9use futures::StreamExt;
10use futures::channel::{mpsc, oneshot};
11use log::{error, warn};
12use std::cell::RefCell;
13use std::rc::{Rc, Weak};
14use {
15    fidl_fuchsia_driver_development as fdd, fidl_fuchsia_driver_framework as fdf,
16    fidl_fuchsia_driver_index as fdi, fuchsia_async as fasync,
17};
18
19pub type NodeBindingInfoResultCompleter = oneshot::Sender<Vec<fdd::NodeBindingInfo>>;
20
21pub struct CompositeNodeAndDriver {
22    pub driver: fdf::CompositeDriverInfo,
23    pub node: Weak<Node>,
24}
25
26pub struct BindSpecResult {
27    pub bound_composite_parents: Vec<fdf::CompositeParent>,
28    pub completed_node_and_drivers: Vec<CompositeNodeAndDriver>,
29}
30
31#[derive(Debug)]
32pub struct BindRequest {
33    node_moniker: String,
34    node: Weak<Node>,
35    driver_url_suffix: String,
36    tracker: Rc<RefCell<BindResultTracker>>,
37    composite_only: bool,
38}
39
40#[async_trait(?Send)]
41pub trait BindManagerBridge {
42    fn box_clone(&self) -> Box<dyn BindManagerBridge>;
43    fn on_binding_state_changed(&self);
44    async fn request_match_from_driver_index(
45        &self,
46        args: fdi::MatchDriverArgs,
47    ) -> fidl::Result<fdi::MatchDriverResult>;
48    async fn start_driver(
49        &self,
50        node: &Rc<Node>,
51        driver_info: fdf::DriverInfo,
52    ) -> Result<String, zx::Status>;
53    fn bind_to_parent_spec(
54        &self,
55        parents: &[fdf::CompositeParent],
56        node: Weak<Node>,
57        enable_multibind: bool,
58    ) -> Result<BindSpecResult, zx::Status>;
59}
60
61pub struct BindManager {
62    bridge: Box<dyn BindManagerBridge>,
63    bind_node_set: RefCell<BindNodeSet>,
64    pending_bind_requests: RefCell<Vec<BindRequest>>,
65    pending_orphan_rebind_completers: RefCell<Vec<NodeBindingInfoResultCompleter>>,
66    weak_self: Weak<Self>,
67    scope: fasync::Scope,
68}
69
70// This handle is what other parts of the driver manager will use to interact with the
71// BindManager. It's a separate struct so that we can wrap the BindManager in a Mutex
72// and control access.
73#[derive(Clone)]
74pub struct BindManagerHandle(Rc<BindManager>);
75
76impl BindManager {
77    pub fn new(bridge: Box<dyn BindManagerBridge>) -> Rc<Self> {
78        Rc::new_cyclic(|weak_self| {
79            let mut bind_node_set = BindNodeSet::new();
80            let (sender, mut receiver) = mpsc::unbounded();
81            bind_node_set.set_on_bind_state_changed(sender);
82
83            let scope = fasync::Scope::new_with_name("bind_manager");
84            let bridge_clone = bridge.box_clone();
85            scope.spawn_local(async move {
86                while let Some(()) = receiver.next().await {
87                    bridge_clone.on_binding_state_changed();
88                }
89            });
90
91            Self {
92                bridge,
93                bind_node_set: RefCell::new(bind_node_set),
94                pending_bind_requests: RefCell::new(Vec::new()),
95                pending_orphan_rebind_completers: RefCell::new(Vec::new()),
96                weak_self: weak_self.clone(),
97                scope,
98            }
99        })
100    }
101
102    pub fn bind(
103        &self,
104        node: &Rc<Node>,
105        driver_url_suffix: &str,
106        tracker: Rc<RefCell<BindResultTracker>>,
107    ) {
108        let request = BindRequest {
109            node_moniker: node.make_component_moniker(),
110            node: Rc::downgrade(node),
111            driver_url_suffix: driver_url_suffix.to_string(),
112            tracker,
113            composite_only: false,
114        };
115
116        if self.bind_node_set.borrow().is_bind_ongoing() {
117            self.pending_bind_requests.borrow_mut().push(request);
118            return;
119        }
120
121        self.bind_node_set.borrow_mut().remove_orphaned_node(&node.make_component_moniker());
122        self.bind_node_set.borrow_mut().start_next_bind_process();
123
124        let weak_self = self.weak_self.clone();
125        self.scope.spawn_local(async move {
126            if let Some(this) = weak_self.upgrade() {
127                this.bind_internal(request).await;
128                this.process_pending_bind_requests();
129            }
130        });
131    }
132
133    pub async fn try_bind_all_available(&self) -> Vec<fdd::NodeBindingInfo> {
134        if self.bind_node_set.borrow().is_bind_ongoing() {
135            let (tx, rx) = oneshot::channel();
136            self.pending_orphan_rebind_completers.borrow_mut().push(tx);
137            return rx.await.unwrap_or_default();
138        }
139
140        if self.bind_node_set.borrow().num_of_available_nodes() == 0 {
141            return vec![];
142        }
143
144        self.bind_node_set.borrow_mut().start_next_bind_process();
145
146        let (tx, rx) = oneshot::channel();
147        let tracker = Rc::new(RefCell::new(BindResultTracker::new(
148            self.bind_node_set.borrow().num_of_available_nodes(),
149            tx,
150        )));
151
152        self.try_bind_all_available_internal(tracker).await;
153        let results = rx.await.unwrap_or_default();
154        self.process_pending_bind_requests();
155        results
156    }
157
158    async fn bind_internal(&self, request: BindRequest) {
159        assert!(self.bind_node_set.borrow().is_bind_ongoing());
160        let node = match request.node.upgrade() {
161            Some(node) => node,
162            None => {
163                warn!("Node was freed before bind request is processed. {}", request.node_moniker);
164                request.tracker.borrow_mut().report_no_bind();
165                return;
166            }
167        };
168
169        let mut args =
170            fdi::MatchDriverArgs { name: Some(node.name().to_string()), ..Default::default() };
171
172        if *node.node_type() == NodeType::Normal
173            && let Some(props) = node.get_node_properties(None)
174        {
175            args.properties = Some(props);
176        }
177
178        if !request.driver_url_suffix.is_empty() {
179            args.driver_url_suffix = Some(request.driver_url_suffix.clone());
180        }
181
182        let result = self.bridge.request_match_from_driver_index(args).await;
183
184        let node = match request.node.upgrade() {
185            Some(node) => node,
186            None => {
187                warn!("Node was freed before it could be bound");
188                request.tracker.borrow_mut().report_no_bind();
189                return;
190            }
191        };
192
193        let bind_result =
194            self.bind_node_to_result(&node, request.composite_only, result, true).await;
195
196        let node_moniker = node.make_component_moniker();
197
198        if !bind_result.is_bound()
199            && !request.composite_only
200            && !self.bind_node_set.borrow().multibind_contains(&node_moniker)
201        {
202            self.bind_node_set.borrow_mut().add_orphaned_node(&node);
203        } else {
204            self.bind_node_set.borrow_mut().remove_orphaned_node(&node_moniker);
205        }
206
207        if bind_result.is_bound() {
208            if let Some(url) = bind_result.driver_url() {
209                request.tracker.borrow_mut().report_successful_bind_driver(&node_moniker, url);
210            } else if let Some(parents) = bind_result.composite_parents() {
211                request
212                    .tracker
213                    .borrow_mut()
214                    .report_successful_bind_composite(&node_moniker, parents);
215            } else {
216                error!("Unknown bind result type for {}.", node_moniker);
217                request.tracker.borrow_mut().report_no_bind();
218            }
219        } else {
220            request.tracker.borrow_mut().report_no_bind();
221        }
222    }
223
224    async fn bind_node_to_result(
225        &self,
226        node: &Rc<Node>,
227        composite_only: bool,
228        result: fidl::Result<fdi::MatchDriverResult>,
229        has_tracker: bool,
230    ) -> BindResult {
231        let matched_driver = match result {
232            Ok(res) => res,
233            Err(e) => {
234                if let fidl::Error::ClientChannelClosed { status, .. } = e {
235                    if status != zx::Status::NOT_FOUND || !has_tracker {
236                        warn!(
237                            "Failed to match Node '{}': {}",
238                            node.make_component_moniker(),
239                            status
240                        );
241                    }
242                } else {
243                    error!("Failed to call match Node '{}': {}", node.name(), e);
244                }
245                return BindResult::NotBound;
246            }
247        };
248
249        match matched_driver {
250            fdi::MatchDriverResult::Driver(driver_info) => {
251                if composite_only
252                    || self
253                        .bind_node_set
254                        .borrow()
255                        .multibind_contains(&node.make_component_moniker())
256                {
257                    return BindResult::NotBound;
258                }
259                match self.bridge.start_driver(node, driver_info).await {
260                    Ok(url) => BindResult::Driver(url),
261                    Err(e) => {
262                        error!("Failed to start driver '{}': {}", node.name(), e);
263                        BindResult::NotBound
264                    }
265                }
266            }
267            fdi::MatchDriverResult::CompositeParents(parents) => {
268                match self.bind_node_to_spec(node, &parents).await {
269                    Ok(bound_parents) => BindResult::Composite(bound_parents),
270                    Err(_) => BindResult::NotBound,
271                }
272            }
273            _ => {
274                warn!("Unknown MatchDriverResult variant");
275                BindResult::NotBound
276            }
277        }
278    }
279
280    async fn bind_node_to_spec(
281        &self,
282        node: &Rc<Node>,
283        parents: &[fdf::CompositeParent],
284    ) -> Result<Vec<fdf::CompositeParent>, zx::Status> {
285        if node.can_multibind_composites {
286            self.bind_node_set.borrow_mut().add_or_move_multibind_node(node);
287        }
288
289        let result = self.bridge.bind_to_parent_spec(
290            parents,
291            Rc::downgrade(node),
292            node.can_multibind_composites,
293        );
294        if let Err(e) = &result {
295            if *e != zx::Status::NOT_FOUND {
296                error!("Failed to bind node '{}' to any of the matched parent specs.", node.name());
297            }
298            node.on_match_error(*e);
299            return result.map(|_| vec![]);
300        }
301        let result = result?;
302
303        for composite in result.completed_node_and_drivers {
304            let composite_node = composite.node.upgrade().expect("Composite node freed before use");
305            if let Err(e) = self
306                .bridge
307                .start_driver(&composite_node, composite.driver.driver_info.unwrap())
308                .await
309            {
310                error!("Failed to start driver '{}': {}", node.name(), e);
311            }
312        }
313
314        Ok(result.bound_composite_parents)
315    }
316
317    async fn try_bind_all_available_internal(&self, tracker: Rc<RefCell<BindResultTracker>>) {
318        assert!(self.bind_node_set.borrow().is_bind_ongoing());
319        if self.bind_node_set.borrow().num_of_available_nodes() == 0 {
320            return;
321        }
322
323        let multibind_nodes: Vec<_> =
324            self.bind_node_set.borrow().current_multibind_nodes().into_values().collect();
325        for node_weak in multibind_nodes {
326            let request = BindRequest {
327                node_moniker: node_weak.upgrade().unwrap().make_component_moniker(),
328                node: node_weak.clone(),
329                driver_url_suffix: "".to_string(),
330                tracker: tracker.clone(),
331                composite_only: true,
332            };
333            self.bind_internal(request).await;
334        }
335
336        let orphaned_nodes: Vec<_> =
337            self.bind_node_set.borrow().current_orphaned_nodes().into_values().collect();
338        for node_weak in orphaned_nodes {
339            let request = BindRequest {
340                node_moniker: node_weak.upgrade().unwrap().make_component_moniker(),
341                node: node_weak.clone(),
342                driver_url_suffix: "".to_string(),
343                tracker: tracker.clone(),
344                composite_only: false,
345            };
346            self.bind_internal(request).await;
347        }
348    }
349
350    pub fn record_inspect(&self, root: &fuchsia_inspect::Node) {
351        root.record_child("orphan_nodes", |orphans| {
352            let mut i = 0;
353            for (moniker, node_weak) in self.bind_node_set.borrow().current_orphaned_nodes() {
354                if node_weak.upgrade().is_some() {
355                    orphans.record_child(format!("orphan-{}", i), |orphan| {
356                        orphan.record_string("moniker", moniker);
357                    });
358                    i += 1;
359                }
360            }
361
362            orphans.record_bool("bind_all_ongoing", self.bind_node_set.borrow().is_bind_ongoing());
363            orphans.record_uint(
364                "pending_bind_requests",
365                self.pending_bind_requests.borrow().len() as u64,
366            );
367            orphans.record_uint(
368                "pending_orphan_rebind_callbacks",
369                self.pending_orphan_rebind_completers.borrow().len() as u64,
370            );
371        });
372    }
373
374    pub fn process_pending_bind_requests(&self) {
375        assert!(self.bind_node_set.borrow().is_bind_ongoing());
376        if self.pending_bind_requests.borrow().is_empty()
377            && self.pending_orphan_rebind_completers.borrow().is_empty()
378        {
379            self.bind_node_set.borrow_mut().end_bind_process();
380            return;
381        }
382
383        for request in self.pending_bind_requests.borrow().iter() {
384            if let Some(node) = request.node.upgrade() {
385                self.bind_node_set
386                    .borrow_mut()
387                    .remove_orphaned_node(&node.make_component_moniker());
388            }
389        }
390
391        self.bind_node_set.borrow_mut().start_next_bind_process();
392
393        let have_bind_all_orphans_request =
394            !self.pending_orphan_rebind_completers.borrow().is_empty();
395        let bind_tracker_size = if have_bind_all_orphans_request {
396            self.pending_bind_requests.borrow().len()
397                + self.bind_node_set.borrow().num_of_available_nodes()
398        } else {
399            self.pending_bind_requests.borrow().len()
400        };
401
402        if have_bind_all_orphans_request && bind_tracker_size == 0 {
403            for sender in std::mem::take(&mut *self.pending_orphan_rebind_completers.borrow_mut()) {
404                let _ = sender.send(vec![]);
405            }
406            self.bind_node_set.borrow_mut().end_bind_process();
407            return;
408        }
409
410        let (tx, rx) = oneshot::channel::<Vec<fdd::NodeBindingInfo>>();
411        let weak_self = self.weak_self.clone();
412        let completers = std::mem::take(&mut *self.pending_orphan_rebind_completers.borrow_mut());
413        self.scope.spawn_local(async move {
414            let results = rx.await.unwrap_or_default();
415            for completer in completers {
416                let _ = completer.send(results.clone());
417            }
418            if let Some(this) = weak_self.upgrade() {
419                this.process_pending_bind_requests();
420            }
421        });
422
423        let tracker = Rc::new(RefCell::new(BindResultTracker::new(bind_tracker_size, tx)));
424
425        let pending_bind = std::mem::take(&mut *self.pending_bind_requests.borrow_mut());
426        let weak_self = self.weak_self.clone();
427        self.scope.spawn_local(async move {
428            if let Some(this) = weak_self.upgrade() {
429                for request in pending_bind {
430                    this.bind_internal(request).await;
431                }
432
433                if have_bind_all_orphans_request {
434                    this.try_bind_all_available_internal(tracker).await;
435                }
436            }
437        });
438    }
439}
440
441impl BindManagerHandle {
442    pub fn new(bridge: Box<dyn BindManagerBridge>) -> Self {
443        Self(BindManager::new(bridge))
444    }
445
446    pub fn has_ongoing_bind(&self) -> bool {
447        self.0.bind_node_set.borrow().is_bind_ongoing()
448    }
449
450    pub fn bind(
451        &self,
452        node: &Rc<Node>,
453        driver_url_suffix: &str,
454        tracker: Rc<RefCell<BindResultTracker>>,
455    ) {
456        self.0.bind(node, driver_url_suffix, tracker);
457    }
458
459    pub async fn try_bind_all_available(&self) -> Vec<fdd::NodeBindingInfo> {
460        self.0.try_bind_all_available().await
461    }
462
463    pub fn record_inspect(&self, root: &fuchsia_inspect::Node) {
464        self.0.record_inspect(root);
465    }
466}