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_next() {
359 Ok(value) => match value {
360 Some(v) => v,
361 None => 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 token = match &self.inner.read().access_proxy {
388 Some(proxy) => {
389 let (token, token_server) = fidl::endpoints::create_proxy();
390 let resp = proxy.make_discoverable(token_server).await?;
391 if let Err(err) = resp {
392 let err_msg = format_err!("Error: {:?}", err);
393 fx_err_and_bail!(&with_line!(tag), err_msg)
394 }
395 token
396 }
397 None => fx_err_and_bail!(
398 &with_line!(tag),
399 format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
400 ),
401 };
402 self.inner.write().discoverable_token = Some(token);
403 }
404 Ok(())
405 }
406
407 pub async fn set_name(&self, name: String) -> Result<(), Error> {
412 let tag = "BluetoothSysFacade::set_name";
413 match &self.inner.read().access_proxy {
414 Some(proxy) => {
415 let resp = proxy.set_local_name(&name);
416 if let Err(err) = resp {
417 let err_msg = format_err!("Error: {:?}", err);
418 fx_err_and_bail!(&with_line!(tag), err_msg)
419 }
420 Ok(())
421 }
422 None => fx_err_and_bail!(
423 &with_line!(tag),
424 format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
425 ),
426 }
427 }
428
429 pub async fn start_discovery(&self, discovery: bool) -> Result<(), Error> {
434 let tag = "BluetoothSysFacade::start_discovery";
435 if !discovery {
436 self.inner.write().discovery_token = None;
437 Ok(())
438 } else {
439 let token = match &self.inner.read().access_proxy {
440 Some(proxy) => {
441 let (token, token_server) = fidl::endpoints::create_proxy();
442 let resp = proxy.start_discovery(token_server).await?;
443 if let Err(err) = resp {
444 let err_msg = format_err!("Error: {:?}", err);
445 fx_err_and_bail!(&with_line!(tag), err_msg)
446 }
447 token
448 }
449 None => fx_err_and_bail!(
450 &with_line!(tag),
451 format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
452 ),
453 };
454 self.inner.write().discovery_token = Some(token);
455 Ok(())
456 }
457 }
458
459 pub async fn get_known_remote_devices(&self) -> Result<HashMap<u64, SerializablePeer>, Error> {
461 let tag = "BluetoothSysFacade::get_known_remote_devices";
462
463 loop {
464 let (discovered_devices, removed_peers) = match &mut self
465 .inner
466 .write()
467 .peer_watcher_stream
468 {
469 Some(stream) => {
470 match stream
471 .next()
472 .on_timeout(zx::MonotonicDuration::from_millis(100).after_now(), || None)
473 .await
474 {
475 Some(Ok(d)) => d,
476 Some(Err(e)) => fx_err_and_bail!(
477 &with_line!(tag),
478 format!("{:?}", format!("Peer Watcher Stream failed with: {:?}", e))
479 ),
480 None => break,
481 }
482 }
483 None => fx_err_and_bail!(
484 &with_line!(tag),
485 format!("{:?}", "Peer Watcher Stream not available")
486 ),
487 };
488
489 let serialized_peers_map: HashMap<u64, SerializablePeer> =
490 discovered_devices.iter().map(|d| (d.id.unwrap().value, d.into())).collect();
491
492 self.inner.write().discovered_device_list.extend(serialized_peers_map);
493
494 let mut known_devices = self.inner.write().discovered_device_list.clone();
495 for peer_id in removed_peers {
496 if known_devices.contains_key(&peer_id.value) {
497 info!(tag; "Peer {:?} removed.", peer_id);
498 known_devices.remove(&peer_id.value);
499 }
500 }
501 self.inner.write().discovered_device_list = known_devices;
502 }
503
504 Ok(self.inner.read().discovered_device_list.clone())
505 }
506
507 pub async fn forget(&self, id: u64) -> Result<(), Error> {
512 let tag = "BluetoothSysFacade::forget";
513 match &self.inner.read().access_proxy {
514 Some(proxy) => {
515 let resp = proxy.forget(&PeerId { value: id }).await?;
516 if let Err(err) = resp {
517 let err_msg = format_err!("Error: {:?}", err);
518 fx_err_and_bail!(&with_line!(tag), err_msg)
519 }
520 Ok(())
521 }
522 None => fx_err_and_bail!(
523 &with_line!(tag),
524 format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
525 ),
526 }
527 }
528
529 pub async fn connect(&self, id: u64) -> Result<(), Error> {
534 let tag = "BluetoothSysFacade::connect";
535 match &self.inner.read().access_proxy {
536 Some(proxy) => {
537 let resp = proxy.connect(&PeerId { value: id }).await?;
538 if let Err(err) = resp {
539 let err_msg = format_err!("Error: {:?}", err);
540 fx_err_and_bail!(&with_line!(tag), err_msg)
541 }
542 Ok(())
543 }
544 None => fx_err_and_bail!(
545 &with_line!(tag),
546 format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
547 ),
548 }
549 }
550
551 pub async fn pair(
568 &self,
569 id: u64,
570 pairing_security_level_value: Option<u64>,
571 bondable: Option<bool>,
572 transport_value: u64,
573 ) -> Result<(), Error> {
574 let tag = "BluetoothSysFacade::pair";
575
576 let pairing_security_level = match pairing_security_level_value {
577 Some(value) => match value {
578 1 => Some(PairingSecurityLevel::Encrypted),
579 2 => Some(PairingSecurityLevel::Authenticated),
580 _ => fx_err_and_bail!(
581 &with_line!(tag),
582 format!(
583 "Invalid pairing security level provided: {:?}",
584 pairing_security_level_value
585 )
586 ),
587 },
588 None => None,
589 };
590
591 let transport = match transport_value {
592 1 => TechnologyType::Classic,
593 2 => TechnologyType::LowEnergy,
594 _ => fx_err_and_bail!(
595 &with_line!(tag),
596 format!("Invalid transport provided: {:?}", transport_value)
597 ),
598 };
599
600 let bondable_mode = match bondable {
601 Some(v) => match v {
602 false => BondableMode::NonBondable,
603 true => BondableMode::Bondable,
604 },
605 None => BondableMode::Bondable,
606 };
607
608 let pairing_options = PairingOptions {
609 le_security_level: pairing_security_level,
610 bondable_mode: Some(bondable_mode),
611 transport: Some(transport),
612 ..Default::default()
613 };
614
615 let proxy = match &self.inner.read().access_proxy {
616 Some(p) => p.clone(),
617 None => fx_err_and_bail!(
618 &with_line!(tag),
619 format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
620 ),
621 };
622 let fut = async move {
623 let result = proxy.pair(&PeerId { value: id }, &pairing_options).await;
624 if let Err(err) = result {
625 error!(tag = &with_line!("BluetoothSysFacade::pair"), err:?; "Failed to pair with",);
626 }
627 };
628 fasync::Task::spawn(fut).detach();
629 Ok(())
630 }
631
632 pub async fn disconnect(&self, id: u64) -> Result<(), Error> {
637 let tag = "BluetoothSysFacade::disconnect";
638 match &self.inner.read().access_proxy {
639 Some(proxy) => {
640 let resp = proxy.disconnect(&PeerId { value: id }).await?;
641 if let Err(err) = resp {
642 let err_msg = format_err!("Error: {:?}", err);
643 fx_err_and_bail!(&with_line!(tag), err_msg)
644 }
645 Ok(())
646 }
647 None => fx_err_and_bail!(
648 &with_line!(tag),
649 format!("{:?}", ERR_NO_ACCESS_PROXY_DETECTED.to_string())
650 ),
651 }
652 }
653
654 pub async fn update_settings(&self, settings: Settings) -> Result<(), Error> {
659 let tag = "BluetoothSysFacade::update_settings";
660 match &self.inner.read().config_proxy {
661 Some(proxy) => {
662 let new_settings = proxy.update(&settings).await?;
663 info!("new core stack settings: {:?}", new_settings);
664 Ok(())
665 }
666 None => {
667 fx_err_and_bail!(&with_line!(tag), "No Bluetooth Configuration Proxy detected.")
668 }
669 }
670 }
671
672 pub async fn get_active_adapter_address(&self) -> Result<String, Error> {
674 let tag = "BluetoothSysFacade::get_active_adapter_address";
675
676 let host_info_list = match &mut self.inner.write().host_watcher_stream {
677 Some(stream) => {
678 match stream
679 .next()
680 .on_timeout(zx::MonotonicDuration::from_seconds(1).after_now(), || None)
681 .await
682 {
683 Some(r) => match r {
684 Ok(d) => d,
685 Err(e) => fx_err_and_bail!(
686 &with_line!(tag),
687 format!("{:?}", format!("Host Watcher Stream failed with: {:?}", e))
688 ),
689 },
690 None => {
691 match &self.inner.read().active_bt_address {
692 Some(addr) => return Ok(addr.to_string()),
693 None => fx_err_and_bail!(
694 &with_line!(tag),
695 format!(
696 "{:?}",
697 "No active adapter - Timed out waiting for host_watcher_stream update."
698 )
699 ),
700 };
701 }
702 }
703 }
704 None => fx_err_and_bail!(
705 &with_line!(tag),
706 format!("{:?}", "Host Watcher Stream not available")
707 ),
708 };
709
710 for host in host_info_list {
711 let host_active = host.active.unwrap();
712 if host_active {
713 match host.addresses {
714 Some(a) => {
715 let public_address = Address::from(a[0]).to_string();
716 self.inner.write().active_bt_address = Some(public_address.clone());
717 return Ok(public_address);
718 }
719 None => fx_err_and_bail!(&with_line!(tag), "Host address not found."),
720 }
721 }
722 }
723 fx_err_and_bail!(&with_line!(tag), "No active host found.")
724 }
725
726 pub fn cleanup(&self) {
728 let mut inner = self.inner.write();
729 inner.access_proxy = None;
730 inner.pairing_proxy = None;
731 inner.client_pin_sender = None;
732 inner.client_pin_receiver = None;
733 inner.discovered_device_list.clear();
734 inner.discoverable_token = None;
735 inner.discovery_token = None;
736 }
737
738 pub fn print(&self) {
740 let tag = "BluetoothSysFacade::print:";
741 let guard = self.inner.read();
742 info!(
743 tag = &with_line!(tag),
744 access:? = guard.access_proxy,
745 pairing:? = guard.pairing_proxy,
746 discovered_device_list:? = self.inner.read().discovered_device_list;
747 ""
748 );
749 }
750}