blob: 60cb8e93ce68d023122b2a7ba34afaa4e8ceef14 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use failure::Error;
use fidl::endpoints::RequestStream;
use fidl_fuchsia_bluetooth_control::{
ControlMarker, ControlProxy, PairingDelegateMarker, PairingDelegateRequest,
PairingDelegateRequestStream, PairingMethod,
};
use fuchsia_async::{self as fasync, TimeoutExt};
use fuchsia_bluetooth::error::Error as BTError;
use fuchsia_component as component;
use fuchsia_syslog::macros::*;
use fuchsia_zircon::{self as zx, DurationNum};
use parking_lot::RwLock;
use std::collections::HashMap;
use crate::bluetooth::types::CustomRemoteDevice;
use crate::server::sl4f::macros::with_line;
use futures::channel::mpsc;
use futures::stream::StreamExt;
static ERR_NO_CONTROL_PROXY_DETECTED: &'static str = "No Bluetooth Control Proxy detected.";
#[derive(Debug)]
struct InnerBluetoothControlFacade {
/// The current Bluetooth Control Interface Proxy
control_interface_proxy: Option<ControlProxy>,
/// The MPSC Sender object for sending the pin to the pairing delegate.
client_pin_sender: Option<mpsc::Sender<String>>,
/// The MPSC Receiver object for sending the pin out from the pairing delegate.
client_pin_receiver: Option<mpsc::Receiver<String>>,
/// Discovered device list
discovered_device_list: HashMap<String, CustomRemoteDevice>,
}
#[derive(Debug)]
pub struct BluetoothControlFacade {
inner: RwLock<InnerBluetoothControlFacade>,
}
/// Perform Bluetooth Control operations.
///
/// Note this object is shared among all threads created by server.
///
impl BluetoothControlFacade {
pub fn new() -> BluetoothControlFacade {
BluetoothControlFacade {
inner: RwLock::new(InnerBluetoothControlFacade {
control_interface_proxy: None,
client_pin_sender: None,
client_pin_receiver: None,
discovered_device_list: HashMap::new(),
}),
}
}
pub fn create_control_interface_proxy(&self) -> Result<ControlProxy, Error> {
let tag = "BluetoothControlFacade::create_control_interface_proxy";
match self.inner.read().control_interface_proxy.clone() {
Some(control_interface_proxy) => {
fx_log_info!(
tag: &with_line!(tag),
"Current control interface proxy: {:?}",
control_interface_proxy
);
Ok(control_interface_proxy)
}
None => {
fx_log_info!(tag: &with_line!(tag), "Setting new control interface proxy");
let control_interface_proxy =
component::client::connect_to_service::<ControlMarker>();
if let Err(err) = control_interface_proxy {
fx_log_err!(
tag: &with_line!(tag),
"Failed to create control interface proxy: {:?}",
err
);
bail!("Failed to create control interface proxy: {:?}", err);
}
control_interface_proxy
}
}
}
pub async fn monitor_pairing_delegate_request_stream(
mut stream: PairingDelegateRequestStream,
mut pin_receiver: mpsc::Receiver<String>,
mut pin_sender: mpsc::Sender<String>,
) -> Result<(), Error> {
let tag = "BluetoothControlFacade::monitor_pairing_delegate_request_stream";
while let Some(request) = await!(stream.next()) {
match request {
Ok(r) => match r {
PairingDelegateRequest::OnPairingComplete {
device_id,
status,
control_handle: _,
} => {
fx_log_info!(
tag: &with_line!(tag),
"Pairing complete for peer (id: {}, status: {})",
device_id,
match status.error {
None => format!("{:?}", "success"),
Some(error) => format!("{:?}", error),
}
);
}
PairingDelegateRequest::OnPairingRequest {
device,
method,
displayed_passkey,
responder,
} => {
if let Some(key) = displayed_passkey {
let _res = pin_sender.try_send(key);
}
fx_log_info!(
tag: &with_line!(tag),
"Pairing request from peer: {}",
match &device.name {
Some(name) => format!("{} ({})", name, &device.address),
None => device.address,
}
);
let consent = true;
let default_passkey = "000000".to_string();
let (confirm, entered_passkey) = match method {
PairingMethod::Consent => (consent, None),
PairingMethod::PasskeyComparison => (consent, None),
PairingMethod::PasskeyDisplay => (consent, None),
PairingMethod::PasskeyEntry => {
let timeout = 10.seconds();
let pin = match await!(pin_receiver
.next()
.on_timeout(timeout.after_now(), || None))
{
Some(p) => p,
_ => {
fx_log_err!(
tag: &with_line!(tag),
"No pairing pin found from remote host."
);
default_passkey
}
};
(consent, Some(pin))
}
};
let _ =
responder.send(confirm, entered_passkey.as_ref().map(String::as_ref));
}
PairingDelegateRequest::OnRemoteKeypress {
device_id,
keypress,
control_handle: _,
} => {
fx_log_info!(
tag: &with_line!(tag),
"Unhandled OnRemoteKeypress for Device: {} | {:?}",
device_id,
keypress
);
}
},
Err(r) => bail!("Error during handling request stream: {:?}", r),
};
}
Ok(())
}
pub async fn accept_pairing(&self) -> Result<(), Error> {
let tag = "BluetoothControlFacade::accept_pairing";
fx_log_info!(tag: &with_line!(tag), "Accepting pairing");
let (delegate_local, delegate_remote) = zx::Channel::create()?;
let delegate_local = fasync::Channel::from_channel(delegate_local)?;
let delegate_ptr =
fidl::endpoints::ClientEnd::<PairingDelegateMarker>::new(delegate_remote);
let pairing_delegate_result = match &self.inner.read().control_interface_proxy {
Some(p) => p.set_pairing_delegate(Some(delegate_ptr)),
None => {
let err_str = "No Bluetooth Control Interface Proxy Set.";
fx_log_err!(tag: &with_line!(tag), "{:?}", err_str);
bail!("{:?}", err_str)
}
};
let delegate_request_stream = PairingDelegateRequestStream::from_channel(delegate_local);
let (sender, pin_receiver) = mpsc::channel(10);
let (pin_sender, receiever) = mpsc::channel(10);
let pairing_delegate_fut = BluetoothControlFacade::monitor_pairing_delegate_request_stream(
delegate_request_stream,
pin_receiver,
pin_sender,
);
self.inner.write().client_pin_sender = Some(sender);
self.inner.write().client_pin_receiver = Some(receiever);
let monitor_pairing_delegate_future = async {
let result = await!(pairing_delegate_result);
if let Err(err) = result {
fx_log_err!(
tag: &with_line!("BluetoothControlFacade::accept_pairing"),
"Failed to take ownership of Bluetooth Pairing: {:?}",
err
);
}
};
fasync::spawn(monitor_pairing_delegate_future);
let fut = async {
let result = await!(pairing_delegate_fut);
if let Err(err) = result {
fx_log_err!(
tag: &with_line!("BluetoothControlFacade::accept_pairing"),
"Failed to create or monitor the pairing service delegate: {:?}",
err
);
}
};
fasync::spawn(fut);
Ok(())
}
/// Sets a control proxy to use if one is not already in use.
pub async fn init_control_interface_proxy(&self) -> Result<(), Error> {
self.inner.write().control_interface_proxy = Some(self.create_control_interface_proxy()?);
Ok(())
}
pub async fn input_pairing_pin(&self, pin: String) -> Result<(), Error> {
let tag = "BluetoothControlFacade::input_pairing_pin";
match self.inner.read().client_pin_sender.clone() {
Some(mut sender) => sender.try_send(pin)?,
None => {
let err_str = "No sender setup for pairing delegate.".to_string();
fx_log_err!(tag: &with_line!(tag), "{}", err_str);
bail!(err_str)
}
};
Ok(())
}
pub async fn get_pairing_pin(&self) -> Result<String, Error> {
let tag = "BluetoothControlFacade::get_pairing_pin";
let pin = match &mut self.inner.write().client_pin_receiver {
Some(receiever) => match receiever.try_next() {
Ok(value) => match value {
Some(v) => v,
None => bail!("Error getting pin from pairing delegate."),
},
Err(_e) => {
let err_str = "No pairing pin sent from the pairing delegate.".to_string();
fx_log_err!(tag: &with_line!(tag), "{}", err_str);
bail!("No pairing pin sent from the pairing delegate.")
}
},
None => {
let err_str = "No receiever setup for pairing delegate.".to_string();
fx_log_err!(tag: &with_line!(tag), "{}", err_str);
bail!(err_str)
}
};
Ok(pin)
}
/// Sets the current control proxy to be discoverable.
///
/// # Arguments
/// * 'discoverable' - A bool object for setting Bluetooth device discoverable or not.
pub async fn set_discoverable(&self, discoverable: bool) -> Result<(), Error> {
let tag = "BluetoothControlFacade::set_discoverable";
match &self.inner.read().control_interface_proxy {
Some(proxy) => {
let resp = await!(proxy.set_discoverable(discoverable))?;
match resp.error {
Some(err) => {
fx_log_err!(tag: &with_line!(tag), "Error: {:?}", err);
bail!(BTError::from(*err))
}
None => Ok(()),
}
}
None => {
fx_log_err!(
tag: &with_line!(tag),
"{:?}",
ERR_NO_CONTROL_PROXY_DETECTED.to_string()
);
bail!(ERR_NO_CONTROL_PROXY_DETECTED.to_string())
}
}
}
/// Sets the current control proxy name.
///
/// # Arguments
/// * 'name' - A String object representing the name to set.
pub async fn set_name(&self, name: String) -> Result<(), Error> {
let tag = "BluetoothControlFacade::set_name";
match &self.inner.read().control_interface_proxy {
Some(proxy) => {
let resp = await!(proxy.set_name(Some(&name)))?;
match resp.error {
Some(err) => {
fx_log_err!(tag: &with_line!(tag), "Error: {:?}", err);
bail!(BTError::from(*err))
}
None => Ok(()),
}
}
None => {
fx_log_err!(
tag: &with_line!(tag),
"{:?}",
ERR_NO_CONTROL_PROXY_DETECTED.to_string()
);
bail!(ERR_NO_CONTROL_PROXY_DETECTED.to_string())
}
}
}
/// Requests discovery on the Bluetooth Control Proxy.
///
/// # Arguments
/// * 'discovery' - A bool representing starting and stopping discovery.
pub async fn request_discovery(&self, discovery: bool) -> Result<(), Error> {
let tag = "BluetoothControlFacade::request_discovery";
match &self.inner.read().control_interface_proxy {
Some(proxy) => {
let resp = await!(proxy.request_discovery(discovery))?;
match resp.error {
Some(err) => {
fx_log_err!(tag: &with_line!(tag), "Error: {:?}", err);
bail!(BTError::from(*err))
}
None => Ok(()),
}
}
None => {
fx_log_err!(
tag: &with_line!(tag),
"{:?}",
ERR_NO_CONTROL_PROXY_DETECTED.to_string()
);
bail!(ERR_NO_CONTROL_PROXY_DETECTED.to_string())
}
}
}
/// Returns a hash of the known devices on the Bluetooth Control proxy.
pub async fn get_known_remote_devices(
&self,
) -> Result<HashMap<String, CustomRemoteDevice>, Error> {
let tag = "BluetoothControlFacade::get_known_remote_devices";
&self.inner.write().discovered_device_list.clear();
let discovered_devices = match &self.inner.read().control_interface_proxy {
Some(proxy) => await!(proxy.get_known_remote_devices())?,
None => {
fx_log_err!(
tag: &with_line!(tag),
"{:?}",
ERR_NO_CONTROL_PROXY_DETECTED.to_string()
);
bail!(ERR_NO_CONTROL_PROXY_DETECTED.to_string())
}
};
self.inner.write().discovered_device_list =
discovered_devices.iter().map(|d| (d.identifier.clone(), d.into())).collect();
Ok(self.inner.read().discovered_device_list.clone())
}
/// Forgets (Unbonds) an input device ID.
///
/// # Arguments
/// * 'id' - A String representing the device ID.
pub async fn forget(&self, id: String) -> Result<(), Error> {
let tag = "BluetoothControlFacade::forget";
match &self.inner.read().control_interface_proxy {
Some(proxy) => {
let resp = await!(proxy.forget(&id))?;
match resp.error {
Some(err) => {
fx_log_err!(tag: &with_line!(tag), "Error: {:?}", err);
bail!(BTError::from(*err))
}
None => Ok(()),
}
}
None => {
fx_log_err!(
tag: &with_line!(tag),
"{:?}",
ERR_NO_CONTROL_PROXY_DETECTED.to_string()
);
bail!(ERR_NO_CONTROL_PROXY_DETECTED.to_string())
}
}
}
/// Connects over BR/EDR to an input device ID.
///
/// # Arguments
/// * 'id' - A String representing the device ID.
pub async fn connect(&self, id: String) -> Result<(), Error> {
let tag = "BluetoothControlFacade::connect";
match &self.inner.read().control_interface_proxy {
Some(proxy) => {
let resp = await!(proxy.connect(&id))?;
match resp.error {
Some(err) => {
fx_log_err!(tag: &with_line!(tag), "Error: {:?}", err);
bail!(BTError::from(*err))
}
None => Ok(()),
}
}
None => {
fx_log_err!(
tag: &with_line!(tag),
"{:?}",
ERR_NO_CONTROL_PROXY_DETECTED.to_string()
);
bail!(ERR_NO_CONTROL_PROXY_DETECTED.to_string())
}
}
}
/// Disconnects an active BR/EDR connection by input device ID.
///
/// # Arguments
/// * 'id' - A String representing the device ID.
pub async fn disconnect(&self, id: String) -> Result<(), Error> {
let tag = "BluetoothControlFacade::disconnect";
match &self.inner.read().control_interface_proxy {
Some(proxy) => {
let resp = await!(proxy.disconnect(&id))?;
match resp.error {
Some(err) => {
fx_log_err!(tag: &with_line!(tag), "Error: {:?}", err);
bail!(BTError::from(*err))
}
None => Ok(()),
}
}
None => {
fx_log_err!(
tag: &with_line!(tag),
"{:?}",
ERR_NO_CONTROL_PROXY_DETECTED.to_string()
);
bail!(ERR_NO_CONTROL_PROXY_DETECTED.to_string())
}
}
}
/// Returns the current Active Adapter's Address.
pub async fn get_active_adapter_address(&self) -> Result<String, Error> {
let result = match &self.inner.read().control_interface_proxy {
Some(proxy) => {
if let Some(adapter) = await!(proxy.get_active_adapter_info())? {
adapter.address
} else {
bail!("No Active Adapter")
}
}
None => bail!(ERR_NO_CONTROL_PROXY_DETECTED.to_string()),
};
Ok(result)
}
/// Cleans up objects in use.
pub fn cleanup(&self) {
self.inner.write().control_interface_proxy = None;
self.inner.write().discovered_device_list.clear();
}
/// Prints useful information.
pub fn print(&self) {
let tag = "BluetoothControlFacade::print:";
fx_log_info!(
tag: &with_line!(tag),
"control_interface_proxy: {:?}",
self.inner.read().control_interface_proxy
);
fx_log_info!(
tag: &with_line!(tag),
"discovered_device_list: {:?}",
self.inner.read().discovered_device_list
);
}
}