1use 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 access_proxy: Option<AccessProxy>,
39
40 pairing_proxy: Option<PairingProxy>,
42
43 config_proxy: Option<ConfigurationProxy>,
45
46 client_pin_sender: Option<mpsc::Sender<String>>,
48
49 client_pin_receiver: Option<mpsc::Receiver<String>>,
51
52 discovered_device_list: HashMap<u64, SerializablePeer>,
54
55 discoverable_token: Option<ProcedureTokenProxy>,
57
58 discovery_token: Option<ProcedureTokenProxy>,
60
61 #[derivative(Debug = "ignore")]
63 peer_watcher_stream: Option<HangingGetStream<AccessProxy, (Vec<Peer>, Vec<PeerId>)>>,
64
65 #[derivative(Debug = "ignore")]
67 host_watcher_stream: Option<HangingGetStream<HostWatcherProxy, Vec<HostInfo>>>,
68
69 active_bt_address: Option<String>,
71}
72
73#[derive(Debug)]
74pub struct BluetoothSysFacade {
75 initialized: RwLock<bool>,
76 inner: RwLock<InnerBluetoothSysFacade>,
77}
78
79impl 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); 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}