Skip to main content

sl4f_lib/bluetooth/
bt_sys_facade.rs

1// Copyright 2020 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 anyhow::Error;
6use async_utils::hanging_get::client::HangingGetStream;
7use fidl::endpoints::{Proxy, RequestStream};
8use fidl_fuchsia_bluetooth::PeerId;
9use fidl_fuchsia_bluetooth_sys::{
10    AccessMarker, AccessProxy, BondableMode, ConfigurationMarker, ConfigurationProxy, HostInfo,
11    HostWatcherMarker, HostWatcherProxy, InputCapability, OutputCapability, PairingDelegateMarker,
12    PairingDelegateRequest, PairingDelegateRequestStream, PairingMarker, PairingMethod,
13    PairingOptions, PairingProxy, PairingSecurityLevel, Peer, ProcedureTokenProxy, Settings,
14    TechnologyType,
15};
16use fuchsia_async::{self as fasync, DurationExt, TimeoutExt};
17use fuchsia_bluetooth::types::Address;
18use fuchsia_component as component;
19use log::{error, info};
20
21use fuchsia_sync::RwLock;
22use std::collections::HashMap;
23
24use crate::bluetooth::types::SerializablePeer;
25use crate::common_utils::common::macros::{fx_err_and_bail, with_line};
26
27use futures::channel::mpsc;
28use futures::stream::StreamExt;
29
30use derivative::Derivative;
31
32static ERR_NO_ACCESS_PROXY_DETECTED: &'static str = "No Bluetooth Access Proxy detected.";
33
34#[derive(Derivative)]
35#[derivative(Debug)]
36struct InnerBluetoothSysFacade {
37    /// The current Bluetooth Access Interface Proxy
38    access_proxy: Option<AccessProxy>,
39
40    /// The connection to the Bluetooth Pairing interface.
41    pairing_proxy: Option<PairingProxy>,
42
43    /// The current fuchsia.bluetooth.sys.Configuration Proxy
44    config_proxy: Option<ConfigurationProxy>,
45
46    /// The MPSC Sender object for sending the pin to the pairing delegate.
47    client_pin_sender: Option<mpsc::Sender<String>>,
48
49    /// The MPSC Receiver object for sending the pin out from the pairing delegate.
50    client_pin_receiver: Option<mpsc::Receiver<String>>,
51
52    /// Discovered device list
53    discovered_device_list: HashMap<u64, SerializablePeer>,
54
55    /// Discoverable token
56    discoverable_token: Option<ProcedureTokenProxy>,
57
58    /// Discovery token
59    discovery_token: Option<ProcedureTokenProxy>,
60
61    /// Peer Watcher Stream for incomming and dropped peers
62    #[derivative(Debug = "ignore")]
63    peer_watcher_stream: Option<HangingGetStream<AccessProxy, (Vec<Peer>, Vec<PeerId>)>>,
64
65    /// Host Watcher Stream for watching hosts
66    #[derivative(Debug = "ignore")]
67    host_watcher_stream: Option<HangingGetStream<HostWatcherProxy, Vec<HostInfo>>>,
68
69    /// Current active BT address
70    active_bt_address: Option<String>,
71}
72
73#[derive(Debug)]
74pub struct BluetoothSysFacade {
75    initialized: RwLock<bool>,
76    inner: RwLock<InnerBluetoothSysFacade>,
77}
78
79/// Perform Bluetooth Access operations.
80///
81/// Note this object is shared among all threads created by server.
82impl BluetoothSysFacade {
83    pub fn new() -> BluetoothSysFacade {
84        BluetoothSysFacade {
85            initialized: RwLock::new(false),
86            inner: RwLock::new(InnerBluetoothSysFacade {
87                access_proxy: None,
88                pairing_proxy: None,
89                config_proxy: None,
90                client_pin_sender: None,
91                client_pin_receiver: None,
92                discovered_device_list: HashMap::new(),
93                discoverable_token: None,
94                discovery_token: None,
95                peer_watcher_stream: None,
96                host_watcher_stream: None,
97                active_bt_address: None,
98            }),
99        }
100    }
101
102    pub fn init_proxies(&self) -> Result<(), Error> {
103        if *self.initialized.read() {
104            return Ok(());
105        }
106        *self.initialized.write() = true;
107
108        let tag = "BluetoothSysFacade::init_proxies";
109        let mut inner = self.inner.write();
110        let access_proxy = match inner.access_proxy.clone() {
111            Some(proxy) => {
112                info!(tag = &with_line!(tag); "Current access proxy: {:?}", proxy);
113                Ok(proxy)
114            }
115            None => {
116                info!(tag = &with_line!(tag); "Setting new access proxy");
117                let proxy = component::client::connect_to_protocol::<AccessMarker>();
118                if let Err(err) = proxy {
119                    fx_err_and_bail!(
120                        &with_line!(tag),
121                        format_err!("Failed to create access proxy: {:?}", err)
122                    );
123                }
124                proxy
125            }
126        };
127
128        let access_proxy = access_proxy.unwrap();
129        inner.access_proxy = Some(access_proxy.clone());
130
131        inner.peer_watcher_stream =
132            Some(HangingGetStream::new_with_fn_ptr(access_proxy, AccessProxy::watch_peers));
133
134        if inner.pairing_proxy.as_ref().map_or(true, |p| p.is_closed()) {
135            info!(tag = &with_line!(tag); "Setting new Pairing proxy");
136            let proxy = component::client::connect_to_protocol::<PairingMarker>();
137            if let Err(err) = proxy {
138                fx_err_and_bail!(
139                    &with_line!(tag),
140                    format_err!("Failed to create Pairing proxy: {:?}", err)
141                );
142            }
143            inner.pairing_proxy = Some(proxy.expect("is Ok"));
144        }
145
146        let host_watcher_proxy = match component::client::connect_to_protocol::<HostWatcherMarker>()
147        {
148            Ok(proxy) => proxy,
149            Err(err) => fx_err_and_bail!(
150                &with_line!(tag),
151                format_err!("Failed to connect to HostWatcher: {}", err)
152            ),
153        };
154
155        inner.host_watcher_stream =
156            Some(HangingGetStream::new_with_fn_ptr(host_watcher_proxy, HostWatcherProxy::watch));
157
158        let configuration_proxy =
159            match component::client::connect_to_protocol::<ConfigurationMarker>() {
160                Ok(proxy) => proxy,
161                Err(err) => fx_err_and_bail!(
162                    &with_line!(tag),
163                    format_err!("Failed to connect to configuration service: {}", err)
164                ),
165            };
166        inner.config_proxy = Some(configuration_proxy);
167
168        Ok(())
169    }
170
171    pub async fn monitor_pairing_delegate_request_stream(
172        mut stream: PairingDelegateRequestStream,
173        mut pin_receiver: mpsc::Receiver<String>,
174        mut pin_sender: mpsc::Sender<String>,
175    ) -> Result<(), Error> {
176        let tag = "BluetoothSysFacade::monitor_pairing_delegate_request_stream";
177        while let Some(request) = stream.next().await {
178            match request {
179                Ok(r) => match r {
180                    PairingDelegateRequest::OnPairingComplete {
181                        id,
182                        success,
183                        control_handle: _,
184                    } => {
185                        let status = match success {
186                            true => "Success",
187                            false => "Failure",
188                        };
189                        info!(
190                            tag = &with_line!(tag),
191                            id = id.value,
192                            status;
193                            "Pairing complete for peer",
194                        );
195                    }
196                    PairingDelegateRequest::OnPairingRequest {
197                        peer,
198                        method,
199                        displayed_passkey,
200                        responder,
201                    } => {
202                        let _res = pin_sender.try_send(displayed_passkey.to_string());
203
204                        let address = match &peer.address {
205                            Some(address) => Address::from(address).to_string(),
206                            None => "Unknown Address".to_string(),
207                        };
208                        info!(
209                            tag = &with_line!(tag);
210                            "Pairing request from peer: {}",
211                            match &peer.name {
212                                Some(name) => format!("{} ({})", name, address),
213                                None => address.clone(),
214                            }
215                        );
216                        let consent = true;
217                        let default_passkey = "000000".to_string();
218                        let (confirm, entered_passkey) = match method {
219                            PairingMethod::Consent => (consent, None),
220                            PairingMethod::PasskeyComparison => (consent, None),
221                            PairingMethod::PasskeyDisplay => {
222                                info!(
223                                    "Passkey {:?} provided for 'Passkey Display`.",
224                                    displayed_passkey
225                                );
226                                (true, None)
227                            }
228                            PairingMethod::PasskeyEntry => {
229                                let timeout = zx::MonotonicDuration::from_seconds(30); // Spec defined timeout
230                                let pin = match pin_receiver
231                                    .next()
232                                    .on_timeout(timeout.after_now(), || None)
233                                    .await
234                                {
235                                    Some(p) => p,
236                                    _ => {
237                                        error!(
238                                            tag = &with_line!(tag);
239                                            "No pairing pin found from remote host."
240                                        );
241                                        default_passkey
242                                    }
243                                };
244
245                                (consent, Some(pin))
246                            }
247                        };
248                        let _ = responder.send(
249                            confirm,
250                            match entered_passkey {
251                                Some(passkey) => passkey.parse::<u32>().unwrap(),
252                                None => 0u32,
253                            },
254                        );
255                    }
256                    PairingDelegateRequest::OnRemoteKeypress {
257                        id,
258                        keypress,
259                        control_handle: _,
260                    } => {
261                        info!(
262                            tag = &with_line!(tag),
263                            id = id.value,
264                            keypress:?;
265                            "Unhandled OnRemoteKeypress for Device"
266                        );
267                    }
268                },
269                Err(r) => return Err(format_err!("Error during handling request stream: {:?}", r)),
270            };
271        }
272        Ok(())
273    }
274
275    /// Starts the pairing delegate with I/O Capabilities as required inputs.
276    ///
277    /// # Arguments
278    /// * `input` - A String representing the input capability.
279    ///       Available values: NONE, CONFIRMATION, KEYBOARD
280    /// * `output` - A String representing the output capability
281    ///       Available values: NONE, DISPLAY
282    pub async fn accept_pairing(&self, input: &str, output: &str) -> Result<(), Error> {
283        let tag = "BluetoothSysFacade::accept_pairing";
284        let input_capability = match input {
285            "NONE" => InputCapability::None,
286            "CONFIRMATION" => InputCapability::Confirmation,
287            "KEYBOARD" => InputCapability::Keyboard,
288            _ => {
289                fx_err_and_bail!(&with_line!(tag), format!("Invalid Input Capability {:?}", input))
290            }
291        };
292        let output_capability = match output {
293            "NONE" => OutputCapability::None,
294            "DISPLAY" => OutputCapability::Display,
295            _ => fx_err_and_bail!(
296                &with_line!(tag),
297                format!("Invalid Output Capability {:?}", output)
298            ),
299        };
300
301        info!(tag = &with_line!(tag); "Accepting pairing");
302        let (delegate_local, delegate_remote) = zx::Channel::create();
303        let delegate_local = fasync::Channel::from_channel(delegate_local);
304        let delegate_ptr =
305            fidl::endpoints::ClientEnd::<PairingDelegateMarker>::new(delegate_remote);
306        let _result = match &self.inner.read().pairing_proxy {
307            Some(p) => p.set_pairing_delegate(input_capability, output_capability, delegate_ptr),
308            None => fx_err_and_bail!(&with_line!(tag), "No Bluetooth Pairing Proxy Set."),
309        };
310        let delegate_request_stream = PairingDelegateRequestStream::from_channel(delegate_local);
311
312        let (sender, pin_receiver) = mpsc::channel(10);
313        let (pin_sender, receiever) = mpsc::channel(10);
314        let pairing_delegate_fut = BluetoothSysFacade::monitor_pairing_delegate_request_stream(
315            delegate_request_stream,
316            pin_receiver,
317            pin_sender,
318        );
319
320        self.inner.write().client_pin_sender = Some(sender);
321        self.inner.write().client_pin_receiver = Some(receiever);
322
323        let fut = async {
324            let result = pairing_delegate_fut.await;
325            if let Err(error) = result {
326                error!(
327                    tag = &with_line!("BluetoothSysFacade::accept_pairing"),
328                    error:?;
329                    "Failed to create or monitor the pairing service delegate",
330                );
331            }
332        };
333        fasync::Task::spawn(fut).detach();
334
335        Ok(())
336    }
337
338    /// Sets an access proxy to use if one is not already in use.
339    pub async fn init_access_proxy(&self) -> Result<(), Error> {
340        self.init_proxies()
341    }
342
343    pub async fn input_pairing_pin(&self, pin: String) -> Result<(), Error> {
344        let tag = "BluetoothSysFacade::input_pairing_pin";
345        match self.inner.read().client_pin_sender.clone() {
346            Some(mut sender) => sender.try_send(pin)?,
347            None => {
348                let err_msg = "No sender setup for pairing delegate.".to_string();
349                fx_err_and_bail!(&with_line!(tag), err_msg)
350            }
351        };
352        Ok(())
353    }
354
355    pub async fn get_pairing_pin(&self) -> Result<String, Error> {
356        let tag = "BluetoothSysFacade::get_pairing_pin";
357        let pin = match &mut self.inner.write().client_pin_receiver {
358            Some(receiever) => match receiever.try_recv() {
359                Ok(v) => v,
360                Err(e) if e.is_closed() => {
361                    return Err(format_err!("Error getting pin from pairing delegate."));
362                }
363                Err(_e) => {
364                    let err_msg = "No pairing pin sent from the pairing delegate.".to_string();
365                    fx_err_and_bail!(&with_line!(tag), err_msg)
366                }
367            },
368            None => {
369                let err_str = "No receiever setup for pairing delegate.".to_string();
370                error!(tag = &with_line!(tag); "{}", err_str);
371                bail!(err_str)
372            }
373        };
374        Ok(pin)
375    }
376
377    /// Sets the current access proxy to be discoverable.
378    ///
379    /// # Arguments
380    /// * 'discoverable' - A bool object for setting Bluetooth device discoverable or not.
381    pub async fn set_discoverable(&self, discoverable: bool) -> Result<(), Error> {
382        let tag = "BluetoothSysFacade::set_discoverable";
383
384        if !discoverable {
385            self.inner.write().discoverable_token = None;
386        } else {
387            let proxy_opt = self.inner.read().access_proxy.clone();
388            let token = match proxy_opt {
389                Some(proxy) => {
390                    let (token, token_server) = fidl::endpoints::create_proxy();
391                    let resp = proxy.make_discoverable(token_server).await?;
392                    if let Err(err) = resp {
393                        let err_msg = format_err!("Error: {:?}", err);
394                        fx_err_and_bail!(&with_line!(tag), err_msg)
395                    }
396                    token
397                }
398                None => fx_err_and_bail!(
399                    &with_line!(tag),
400                    format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
401                ),
402            };
403            self.inner.write().discoverable_token = Some(token);
404        }
405        Ok(())
406    }
407
408    /// Sets the current access proxy name.
409    ///
410    /// # Arguments
411    /// * 'name' - A String object representing the name to set.
412    pub async fn set_name(&self, name: String) -> Result<(), Error> {
413        let tag = "BluetoothSysFacade::set_name";
414        match &self.inner.read().access_proxy {
415            Some(proxy) => {
416                let resp = proxy.set_local_name(&name);
417                if let Err(err) = resp {
418                    let err_msg = format_err!("Error: {:?}", err);
419                    fx_err_and_bail!(&with_line!(tag), err_msg)
420                }
421                Ok(())
422            }
423            None => fx_err_and_bail!(
424                &with_line!(tag),
425                format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
426            ),
427        }
428    }
429
430    /// Starts discovery on the Bluetooth Access Proxy.
431    ///
432    /// # Arguments
433    /// * 'discovery' - A bool representing starting and stopping discovery.
434    pub async fn start_discovery(&self, discovery: bool) -> Result<(), Error> {
435        let tag = "BluetoothSysFacade::start_discovery";
436        if !discovery {
437            self.inner.write().discovery_token = None;
438            Ok(())
439        } else {
440            let proxy_opt = self.inner.read().access_proxy.clone();
441            let token = match proxy_opt {
442                Some(proxy) => {
443                    let (token, token_server) = fidl::endpoints::create_proxy();
444                    let resp = proxy.start_discovery(token_server).await?;
445                    if let Err(err) = resp {
446                        let err_msg = format_err!("Error: {:?}", err);
447                        fx_err_and_bail!(&with_line!(tag), err_msg)
448                    }
449                    token
450                }
451                None => fx_err_and_bail!(
452                    &with_line!(tag),
453                    format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
454                ),
455            };
456            self.inner.write().discovery_token = Some(token);
457            Ok(())
458        }
459    }
460
461    /// Returns a hashmap of the known devices on the Bluetooth Access proxy.
462    pub async fn get_known_remote_devices(&self) -> Result<HashMap<u64, SerializablePeer>, Error> {
463        let tag = "BluetoothSysFacade::get_known_remote_devices";
464
465        loop {
466            let mut stream = match self.inner.write().peer_watcher_stream.take() {
467                Some(stream) => stream,
468                None => fx_err_and_bail!(
469                    &with_line!(tag),
470                    format!("{:?}", "Peer Watcher Stream not available")
471                ),
472            };
473
474            let stream_result = stream
475                .next()
476                .on_timeout(zx::MonotonicDuration::from_millis(100).after_now(), || None)
477                .await;
478
479            self.inner.write().peer_watcher_stream = Some(stream);
480
481            let (discovered_devices, removed_peers) = match stream_result {
482                Some(Ok(d)) => d,
483                Some(Err(e)) => fx_err_and_bail!(
484                    &with_line!(tag),
485                    format!("{:?}", format!("Peer Watcher Stream failed with: {:?}", e))
486                ),
487                None => break,
488            };
489
490            let serialized_peers_map: HashMap<u64, SerializablePeer> =
491                discovered_devices.iter().map(|d| (d.id.unwrap().value, d.into())).collect();
492
493            {
494                let mut inner_guard = self.inner.write();
495
496                inner_guard.discovered_device_list.extend(serialized_peers_map);
497
498                for peer_id in removed_peers {
499                    if inner_guard.discovered_device_list.remove(&peer_id.value).is_some() {
500                        info!(tag; "Peer {:?} removed.", peer_id);
501                    }
502                }
503            }
504        }
505
506        Ok(self.inner.read().discovered_device_list.clone())
507    }
508
509    /// Forgets (Unbonds) an input device ID.
510    ///
511    /// # Arguments
512    /// * `id` - A u64 representing the device ID.
513    pub async fn forget(&self, id: u64) -> Result<(), Error> {
514        let tag = "BluetoothSysFacade::forget";
515        let proxy_opt = self.inner.read().access_proxy.clone();
516        match proxy_opt {
517            Some(proxy) => {
518                let resp = proxy.forget(&PeerId { value: id }).await?;
519                if let Err(err) = resp {
520                    let err_msg = format_err!("Error: {:?}", err);
521                    fx_err_and_bail!(&with_line!(tag), err_msg)
522                }
523                Ok(())
524            }
525            None => fx_err_and_bail!(
526                &with_line!(tag),
527                format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
528            ),
529        }
530    }
531
532    /// Connects over BR/EDR to an input device ID.
533    ///
534    /// # Arguments
535    /// * `id` - A u64 representing the device ID.
536    pub async fn connect(&self, id: u64) -> Result<(), Error> {
537        let tag = "BluetoothSysFacade::connect";
538        let proxy_opt = self.inner.read().access_proxy.clone();
539        match proxy_opt {
540            Some(proxy) => {
541                let resp = proxy.connect(&PeerId { value: id }).await?;
542                if let Err(err) = resp {
543                    let err_msg = format_err!("Error: {:?}", err);
544                    fx_err_and_bail!(&with_line!(tag), err_msg)
545                }
546                Ok(())
547            }
548            None => fx_err_and_bail!(
549                &with_line!(tag),
550                format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
551            ),
552        }
553    }
554
555    /// Sends an outgoing pairing request over BR/EDR or LE to an input device ID.
556    ///
557    /// # Arguments
558    /// * `id` - A u64 representing the device ID.
559    /// * `pairing_security_level_value` - The security level required for this pairing request
560    ///        represented as a u64. (Only for LE pairing)
561    ///        Available Values
562    ///        1 - ENCRYPTED: Encrypted without MITM protection (unauthenticated)
563    ///        2 - AUTHENTICATED: Encrypted with MITM protection (authenticated).
564    ///        None: Used for BR/EDR
565    /// * `bondable` - A bool representing whether the pairing mode is bondable or not. None is
566    ///        also accepted. False if non bondable, True if bondable.
567    /// * `transport_value` - A u64 representing the transport type.
568    ///        Available Values
569    ///        1 - BREDR: Classic BR/EDR transport
570    ///        2 - LE: Bluetooth Low Energy Transport
571    pub async fn pair(
572        &self,
573        id: u64,
574        pairing_security_level_value: Option<u64>,
575        bondable: Option<bool>,
576        transport_value: u64,
577    ) -> Result<(), Error> {
578        let tag = "BluetoothSysFacade::pair";
579
580        let pairing_security_level = match pairing_security_level_value {
581            Some(value) => match value {
582                1 => Some(PairingSecurityLevel::Encrypted),
583                2 => Some(PairingSecurityLevel::Authenticated),
584                _ => fx_err_and_bail!(
585                    &with_line!(tag),
586                    format!(
587                        "Invalid pairing security level provided: {:?}",
588                        pairing_security_level_value
589                    )
590                ),
591            },
592            None => None,
593        };
594
595        let transport = match transport_value {
596            1 => TechnologyType::Classic,
597            2 => TechnologyType::LowEnergy,
598            _ => fx_err_and_bail!(
599                &with_line!(tag),
600                format!("Invalid transport provided: {:?}", transport_value)
601            ),
602        };
603
604        let bondable_mode = match bondable {
605            Some(v) => match v {
606                false => BondableMode::NonBondable,
607                true => BondableMode::Bondable,
608            },
609            None => BondableMode::Bondable,
610        };
611
612        let pairing_options = PairingOptions {
613            le_security_level: pairing_security_level,
614            bondable_mode: Some(bondable_mode),
615            transport: Some(transport),
616            ..Default::default()
617        };
618
619        let proxy = match &self.inner.read().access_proxy {
620            Some(p) => p.clone(),
621            None => fx_err_and_bail!(
622                &with_line!(tag),
623                format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
624            ),
625        };
626        let fut = async move {
627            let result = proxy.pair(&PeerId { value: id }, &pairing_options).await;
628            if let Err(err) = result {
629                error!(tag = &with_line!("BluetoothSysFacade::pair"), err:?; "Failed to pair with",);
630            }
631        };
632        fasync::Task::spawn(fut).detach();
633        Ok(())
634    }
635
636    /// Disconnects an active BR/EDR connection by input device ID.
637    ///
638    /// # Arguments
639    /// * `id` - A u64 representing the device ID.
640    pub async fn disconnect(&self, id: u64) -> Result<(), Error> {
641        let tag = "BluetoothSysFacade::disconnect";
642        let proxy_opt = self.inner.read().access_proxy.clone();
643        match proxy_opt {
644            Some(proxy) => {
645                let resp = proxy.disconnect(&PeerId { value: id }).await?;
646                if let Err(err) = resp {
647                    let err_msg = format_err!("Error: {:?}", err);
648                    fx_err_and_bail!(&with_line!(tag), err_msg)
649                }
650                Ok(())
651            }
652            None => fx_err_and_bail!(
653                &with_line!(tag),
654                format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
655            ),
656        }
657    }
658
659    /// Updates the configuration of the active host device
660    ///
661    /// # Arguments
662    /// * `settings` - The table of settings. Any settings that are not present will not be changed.
663    pub async fn update_settings(&self, settings: Settings) -> Result<(), Error> {
664        let tag = "BluetoothSysFacade::update_settings";
665        let proxy_opt = self.inner.read().config_proxy.clone();
666        match proxy_opt {
667            Some(proxy) => {
668                let new_settings = proxy.update(&settings).await?;
669                info!("new core stack settings: {:?}", new_settings);
670                Ok(())
671            }
672            None => {
673                fx_err_and_bail!(&with_line!(tag), "No Bluetooth Configuration Proxy detected.")
674            }
675        }
676    }
677
678    /// Returns the current Active Adapter's Address.
679    pub async fn get_active_adapter_address(&self) -> Result<String, Error> {
680        let tag = "BluetoothSysFacade::get_active_adapter_address";
681
682        let mut stream = match self.inner.write().host_watcher_stream.take() {
683            Some(stream) => stream,
684            None => fx_err_and_bail!(
685                &with_line!(tag),
686                format!("{:?}", "Host Watcher Stream not available")
687            ),
688        };
689
690        let stream_result = stream
691            .next()
692            .on_timeout(zx::MonotonicDuration::from_seconds(1).after_now(), || None)
693            .await;
694
695        self.inner.write().host_watcher_stream = Some(stream);
696
697        let host_info_list = match stream_result {
698            Some(Ok(d)) => d,
699            Some(Err(e)) => fx_err_and_bail!(
700                &with_line!(tag),
701                format!("{:?}", format!("Host Watcher Stream failed with: {:?}", e))
702            ),
703            None => match &self.inner.read().active_bt_address {
704                Some(addr) => return Ok(addr.to_string()),
705                None => fx_err_and_bail!(
706                    &with_line!(tag),
707                    format!(
708                        "{:?}",
709                        "No active adapter - Timed out waiting for host_watcher_stream update."
710                    )
711                ),
712            },
713        };
714
715        for host in host_info_list {
716            let host_active = host.active.unwrap();
717            if host_active {
718                match host.addresses {
719                    Some(a) => {
720                        let public_address = Address::from(a[0]).to_string();
721                        self.inner.write().active_bt_address = Some(public_address.clone());
722                        return Ok(public_address);
723                    }
724                    None => fx_err_and_bail!(&with_line!(tag), "Host address not found."),
725                }
726            }
727        }
728        fx_err_and_bail!(&with_line!(tag), "No active host found.")
729    }
730
731    /// Cleans up objects in use.
732    pub fn cleanup(&self) {
733        let mut inner = self.inner.write();
734        inner.access_proxy = None;
735        inner.pairing_proxy = None;
736        inner.client_pin_sender = None;
737        inner.client_pin_receiver = None;
738        inner.discovered_device_list.clear();
739        inner.discoverable_token = None;
740        inner.discovery_token = None;
741    }
742
743    /// Prints useful information.
744    pub fn print(&self) {
745        let tag = "BluetoothSysFacade::print:";
746        let guard = self.inner.read();
747        info!(
748            tag = &with_line!(tag),
749            access:? = guard.access_proxy,
750            pairing:? = guard.pairing_proxy,
751            discovered_device_list:? = self.inner.read().discovered_device_list;
752            ""
753        );
754    }
755}