Loading system/gd/rust/linux/client/src/command_handler.rs +11 −2 Original line number Diff line number Diff line Loading @@ -973,9 +973,18 @@ impl CommandHandler { if let Ok(id) = scanner_id { self.context.lock().unwrap().gatt_dbus.as_mut().unwrap().start_scan( id, // TODO(b/217274432): Construct real settings and filters. // TODO(b/254870159): Construct real settings and filters depending on // command line options. ScanSettings { interval: 0, window: 0, scan_type: ScanType::Active }, None, Some(btstack::bluetooth_gatt::ScanFilter { rssi_high_threshold: 0, rssi_low_threshold: 0, rssi_low_timeout: 0, rssi_sampling_period: 0, condition: btstack::bluetooth_gatt::ScanFilterCondition::Patterns( vec![], ), }), ); self.context.lock().unwrap().active_scanner_ids.insert(id); } else { Loading system/gd/rust/linux/stack/src/async_helper.rs 0 → 100644 +85 −0 Original line number Diff line number Diff line use std::collections::HashMap; use std::sync::{Arc, Mutex}; use tokio::sync::oneshot; use tokio::time::Duration; /// Helper for managing an async topshim function. It takes care of calling the function, preparing /// the channel, waiting for the callback, and returning it in a Result. /// /// `R` is the type of the return. pub(crate) struct AsyncHelper<R> { // Name of the method that this struct helps. Useful for logging. method_name: String, // Keeps track of call_id. Increment each time and wrap to 0 when u32 max is reached. last_call_id: u32, // Keep pending calls' ids and senders. senders: Arc<Mutex<HashMap<u32, oneshot::Sender<R>>>>, } pub(crate) type CallbackSender<R> = Arc<Mutex<Box<(dyn Fn(u32, R) + Send)>>>; impl<R: 'static + Send> AsyncHelper<R> { pub(crate) fn new(method_name: &str) -> Self { Self { method_name: String::from(method_name), last_call_id: 0, senders: Arc::new(Mutex::new(HashMap::new())), } } /// Calls a topshim method that expects the async return to be delivered via a callback. pub(crate) async fn call_method<F>(&mut self, f: F, timeout_ms: Option<u64>) -> Result<R, ()> where F: Fn(u32), { // Create a oneshot channel to be used by the callback to notify us that the return is // available. let (tx, rx) = oneshot::channel(); // Use a unique method call ID so that we know which callback is corresponding to which // method call. The actual value of the ID does not matter as long as it's always unique, // so a simple increment (and wraps back to 0) is good enough. self.last_call_id = self.last_call_id.wrapping_add(1); // Keep track of the sender belonging to this call id. self.senders.lock().unwrap().insert(self.last_call_id, tx); // Call the method. `f` is freely defined by the user of this utility. This must be an // operation that expects a callback that will trigger sending of the return via the // oneshot channel. f(self.last_call_id); if let Some(timeout_ms) = timeout_ms { let senders = self.senders.clone(); let call_id = self.last_call_id; tokio::spawn(async move { tokio::time::sleep(Duration::from_millis(timeout_ms)).await; // If the timer expires first before a callback is triggered, we remove the sender // which will invalidate the channel which in turn will notify the receiver of // an error. // If the callback gets triggered first, this does nothing since the entry has been // removed when sending the response. senders.lock().unwrap().remove(&call_id); }); } // Wait for the callback and return when available. rx.await.map_err(|_| ()) } /// Returns a function to be invoked when callback is triggered. pub(crate) fn get_callback_sender(&self) -> CallbackSender<R> { let senders = self.senders.clone(); let method_name = self.method_name.clone(); return Arc::new(Mutex::new(Box::new(move |call_id, ret| { if let Some(sender) = senders.lock().unwrap().remove(&call_id) { sender.send(ret).ok(); } else { log::warn!("AsyncHelper {}: Sender no longer exists.", method_name); } }))); } } system/gd/rust/linux/stack/src/bluetooth_gatt.rs +234 −23 Original line number Diff line number Diff line Loading @@ -10,10 +10,12 @@ use bt_topshim::profiles::gatt::{ GattClientCallbacks, GattClientCallbacksDispatcher, GattScannerCallbacks, GattScannerCallbacksDispatcher, GattScannerInbandCallbacks, GattScannerInbandCallbacksDispatcher, GattServerCallbacksDispatcher, GattStatus, LePhy, MsftAdvMonitor, MsftAdvMonitorPattern, }; use bt_topshim::topstack; use bt_utils::adv_parser; use crate::async_helper::{AsyncHelper, CallbackSender}; use crate::bluetooth::{Bluetooth, IBluetooth}; use crate::bluetooth_adv::{ AdvertiseData, Advertisers, AdvertisingSetInfo, AdvertisingSetParameters, Loading @@ -28,6 +30,7 @@ use num_traits::clamp; use rand::rngs::SmallRng; use rand::{RngCore, SeedableRng}; use std::collections::{HashMap, HashSet}; use std::convert::TryInto; use std::sync::{Arc, Mutex, MutexGuard}; use tokio::sync::mpsc::Sender; Loading Loading @@ -665,7 +668,7 @@ pub struct ScanResult { pub adv_data: Vec<u8>, } #[derive(Debug)] #[derive(Debug, Clone)] pub struct ScanFilterPattern { /// Specifies the starting byte position of the pattern immediately following AD Type. pub start_position: u8, Loading @@ -681,7 +684,7 @@ pub struct ScanFilterPattern { /// Represents the condition for matching advertisements. /// /// Only pattern-based matching is implemented. #[derive(Debug)] #[derive(Debug, Clone)] pub enum ScanFilterCondition { /// All advertisements are matched. All, Loading @@ -704,7 +707,7 @@ pub enum ScanFilterCondition { /// This filter is intentionally modelled close to the MSFT hardware offload filter. /// Reference: /// https://learn.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events #[derive(Debug)] #[derive(Debug, Clone)] pub struct ScanFilter { /// Advertisements with RSSI above or equal this value is considered "found". pub rssi_high_threshold: u8, Loading @@ -726,6 +729,76 @@ pub struct ScanFilter { type ScannersMap = HashMap<Uuid, ScannerInfo>; const DEFAULT_ASYNC_TIMEOUT_MS: u64 = 5000; /// Abstraction for async GATT operations. Contains async methods for coordinating async operations /// more conveniently. struct GattAsyncIntf { scanners: Arc<Mutex<ScannersMap>>, gatt: Option<Arc<Mutex<Gatt>>>, async_helper_msft_adv_monitor_add: AsyncHelper<(u8, u8)>, async_helper_msft_adv_monitor_remove: AsyncHelper<u8>, async_helper_msft_adv_monitor_enable: AsyncHelper<u8>, } impl GattAsyncIntf { /// Adds an advertisement monitor. Returns monitor handle and status. async fn msft_adv_monitor_add(&mut self, monitor: MsftAdvMonitor) -> Result<(u8, u8), ()> { let gatt = self.gatt.as_ref().unwrap().clone(); self.async_helper_msft_adv_monitor_add .call_method( move |call_id| { gatt.lock().unwrap().scanner.msft_adv_monitor_add(call_id, &monitor); }, Some(DEFAULT_ASYNC_TIMEOUT_MS), ) .await } /// Removes an advertisement monitor. Returns status. async fn msft_adv_monitor_remove(&mut self, monitor_handle: u8) -> Result<u8, ()> { let gatt = self.gatt.as_ref().unwrap().clone(); self.async_helper_msft_adv_monitor_remove .call_method( move |call_id| { gatt.lock().unwrap().scanner.msft_adv_monitor_remove(call_id, monitor_handle); }, Some(DEFAULT_ASYNC_TIMEOUT_MS), ) .await } /// Enables/disables an advertisement monitor. Returns status. async fn msft_adv_monitor_enable(&mut self, enable: bool) -> Result<u8, ()> { let gatt = self.gatt.as_ref().unwrap().clone(); self.async_helper_msft_adv_monitor_enable .call_method( move |call_id| { gatt.lock().unwrap().scanner.msft_adv_monitor_enable(call_id, enable); }, Some(DEFAULT_ASYNC_TIMEOUT_MS), ) .await } /// Updates the topshim's scan state depending on the states of registered scanners. Scan is /// enabled if there is at least 1 active registered scanner. /// /// Note: this does not need to be async, but declared as async for consistency in this struct. /// May be converted into real async in the future if btif supports it. async fn update_scan(&mut self) { if self.scanners.lock().unwrap().values().find(|scanner| scanner.is_active).is_some() { self.gatt.as_ref().unwrap().lock().unwrap().scanner.start_scan(); } else { self.gatt.as_ref().unwrap().lock().unwrap().scanner.stop_scan(); } } } /// Implementation of the GATT API (IBluetoothGatt). pub struct BluetoothGatt { intf: Arc<Mutex<BluetoothInterface>>, Loading @@ -741,14 +814,25 @@ pub struct BluetoothGatt { scanners: Arc<Mutex<ScannersMap>>, advertisers: Advertisers, adv_mon_add_cb_sender: CallbackSender<(u8, u8)>, adv_mon_remove_cb_sender: CallbackSender<u8>, adv_mon_enable_cb_sender: CallbackSender<u8>, // Used for generating random UUIDs. SmallRng is chosen because it is fast, don't use this for // cryptography. small_rng: SmallRng, gatt_async: Arc<tokio::sync::Mutex<GattAsyncIntf>>, } impl BluetoothGatt { /// Constructs a new IBluetoothGatt implementation. pub fn new(intf: Arc<Mutex<BluetoothInterface>>, tx: Sender<Message>) -> BluetoothGatt { let scanners = Arc::new(Mutex::new(HashMap::new())); let async_helper_msft_adv_monitor_add = AsyncHelper::new("MsftAdvMonitorAdd"); let async_helper_msft_adv_monitor_remove = AsyncHelper::new("MsftAdvMonitorRemove"); let async_helper_msft_adv_monitor_enable = AsyncHelper::new("MsftAdvMonitorEnable"); BluetoothGatt { intf, gatt: None, Loading @@ -756,9 +840,19 @@ impl BluetoothGatt { context_map: ContextMap::new(tx.clone()), reliable_queue: HashSet::new(), scanner_callbacks: Callbacks::new(tx.clone(), Message::ScannerCallbackDisconnected), scanners: Arc::new(Mutex::new(HashMap::new())), scanners: scanners.clone(), small_rng: SmallRng::from_entropy(), advertisers: Advertisers::new(tx.clone()), adv_mon_add_cb_sender: async_helper_msft_adv_monitor_add.get_callback_sender(), adv_mon_remove_cb_sender: async_helper_msft_adv_monitor_remove.get_callback_sender(), adv_mon_enable_cb_sender: async_helper_msft_adv_monitor_enable.get_callback_sender(), gatt_async: Arc::new(tokio::sync::Mutex::new(GattAsyncIntf { scanners, gatt: None, async_helper_msft_adv_monitor_add, async_helper_msft_adv_monitor_remove, async_helper_msft_adv_monitor_enable, })), } } Loading Loading @@ -831,6 +925,12 @@ impl BluetoothGatt { gatt_adv_inband_callbacks_dispatcher, gatt_adv_callbacks_dispatcher, ); let gatt = self.gatt.clone(); let gatt_async = self.gatt_async.clone(); tokio::spawn(async move { gatt_async.lock().await.gatt = gatt; }); } /// Remove a scanner callback and unregisters all scanners associated with that callback. Loading Loading @@ -878,16 +978,6 @@ impl BluetoothGatt { todo!() } // Update the topshim's scan state depending on the states of registered scanners. Scan is // enabled if there is at least 1 active registered scanner. fn update_scan(&mut self) { if self.scanners.lock().unwrap().values().find(|scanner| scanner.is_active).is_some() { self.gatt.as_ref().unwrap().lock().unwrap().scanner.start_scan(); } else { self.gatt.as_ref().unwrap().lock().unwrap().scanner.stop_scan(); } } fn find_scanner_by_id<'a>( scanners: &'a mut MutexGuard<ScannersMap>, scanner_id: u8, Loading Loading @@ -978,6 +1068,49 @@ struct ScannerInfo { scanner_id: Option<u8>, // If one of scanners is active, we scan. is_active: bool, // Scan filter. filter: Option<ScanFilter>, // Adv monitor handle, if exists. monitor_handle: Option<u8>, } impl ScannerInfo { fn new(callback_id: u32) -> Self { Self { callback_id, scanner_id: None, is_active: false, filter: None, monitor_handle: None } } } impl Into<MsftAdvMonitorPattern> for &ScanFilterPattern { fn into(self) -> MsftAdvMonitorPattern { MsftAdvMonitorPattern { ad_type: self.ad_type, start_byte: self.start_position, pattern: self.content.clone(), } } } impl Into<Vec<MsftAdvMonitorPattern>> for &ScanFilterCondition { fn into(self) -> Vec<MsftAdvMonitorPattern> { match self { ScanFilterCondition::Patterns(patterns) => { patterns.iter().map(|pattern| pattern.into()).collect() } _ => vec![], } } } impl Into<MsftAdvMonitor> for &ScanFilter { fn into(self) -> MsftAdvMonitor { MsftAdvMonitor { rssi_high_threshold: self.rssi_high_threshold.try_into().unwrap(), rssi_low_threshold: self.rssi_low_threshold.try_into().unwrap(), rssi_low_timeout: self.rssi_low_timeout.try_into().unwrap(), rssi_sampling_period: self.rssi_sampling_period.try_into().unwrap(), patterns: (&self.condition).into(), } } } impl IBluetoothGatt for BluetoothGatt { Loading @@ -999,10 +1132,7 @@ impl IBluetoothGatt for BluetoothGatt { self.small_rng.fill_bytes(&mut bytes); let uuid = Uuid::from(bytes); self.scanners .lock() .unwrap() .insert(uuid, ScannerInfo { callback_id, scanner_id: None, is_active: false }); self.scanners.lock().unwrap().insert(uuid, ScannerInfo::new(callback_id)); // libbluetooth's register_scanner takes a UUID of the scanning application. This UUID does // not correspond to higher level concept of "application" so we use random UUID that Loading Loading @@ -1030,7 +1160,7 @@ impl IBluetoothGatt for BluetoothGatt { &mut self, scanner_id: u8, _settings: ScanSettings, _filter: Option<ScanFilter>, filter: Option<ScanFilter>, ) -> BtStatus { // Multiplexing scanners happens at this layer. The implementations of start_scan // and stop_scan maintains the state of all registered scanners and based on the states Loading @@ -1038,31 +1168,81 @@ impl IBluetoothGatt for BluetoothGatt { // TODO(b/217274432): Honor settings and filters. { let mut scanners_lock = self.scanners.lock().unwrap(); if let Some(scanner) = Self::find_scanner_by_id(&mut scanners_lock, scanner_id) { scanner.is_active = true; scanner.filter = filter.clone(); } else { log::warn!("Scanner {} not found", scanner_id); return BtStatus::Fail; } } self.update_scan(); let gatt_async = self.gatt_async.clone(); tokio::spawn(async move { // The three operations below (monitor add, monitor enable, update scan) happen one // after another, and cannot be interleaved with other GATT async operations. // So acquire the GATT async lock in the beginning of this block and will be released // at the end of this block. // TODO(b/217274432): Consider not using async model but instead add actions when // handling callbacks. let mut gatt_async = gatt_async.lock().await; if let Some(filter) = filter { let monitor_handle = match gatt_async.msft_adv_monitor_add((&filter).into()).await { Ok((handle, 0)) => handle, _ => { log::error!("Error adding advertisement monitor"); return; } }; log::debug!("Added adv monitor handle = {}", monitor_handle); if !gatt_async .msft_adv_monitor_enable(true) .await .map_or(false, |status| status == 0) { log::error!("Error enabling Advertisement Monitor"); } } gatt_async.update_scan().await; }); BtStatus::Success } fn stop_scan(&mut self, scanner_id: u8) -> BtStatus { { let monitor_handle = { let mut scanners_lock = self.scanners.lock().unwrap(); if let Some(scanner) = Self::find_scanner_by_id(&mut scanners_lock, scanner_id) { scanner.is_active = false; scanner.monitor_handle } else { log::warn!("Scanner {} not found", scanner_id); // Clients can assume success of the removal since the scanner does not exist. return BtStatus::Success; } }; let gatt_async = self.gatt_async.clone(); tokio::spawn(async move { // The two operations below (monitor remove, update scan) happen one after another, and // cannot be interleaved with other GATT async operations. // So acquire the GATT async lock in the beginning of this block and will be released // at the end of this block. let mut gatt_async = gatt_async.lock().await; if let Some(handle) = monitor_handle { let _res = gatt_async.msft_adv_monitor_remove(handle).await; } self.update_scan(); gatt_async.update_scan().await; }); BtStatus::Success } Loading Loading @@ -2297,6 +2477,20 @@ pub(crate) trait BtifGattScannerInbandCallbacks { btm_status: u8, ); #[btif_callback(MsftAdvMonitorAddCallback)] fn inband_msft_adv_monitor_add_callback( &mut self, call_id: u32, monitor_handle: u8, status: u8, ); #[btif_callback(MsftAdvMonitorRemoveCallback)] fn inband_msft_adv_monitor_remove_callback(&mut self, call_id: u32, status: u8); #[btif_callback(MsftAdvMonitorEnableCallback)] fn inband_msft_adv_monitor_enable_callback(&mut self, call_id: u32, status: u8); #[btif_callback(StartSyncCallback)] fn inband_start_sync_callback( &mut self, Loading Loading @@ -2386,6 +2580,23 @@ impl BtifGattScannerInbandCallbacks for BluetoothGatt { ); } fn inband_msft_adv_monitor_add_callback( &mut self, call_id: u32, monitor_handle: u8, status: u8, ) { (self.adv_mon_add_cb_sender.lock().unwrap())(call_id, (monitor_handle, status)); } fn inband_msft_adv_monitor_remove_callback(&mut self, call_id: u32, status: u8) { (self.adv_mon_remove_cb_sender.lock().unwrap())(call_id, status); } fn inband_msft_adv_monitor_enable_callback(&mut self, call_id: u32, status: u8) { (self.adv_mon_enable_cb_sender.lock().unwrap())(call_id, status); } fn inband_start_sync_callback( &mut self, status: u8, Loading system/gd/rust/linux/stack/src/lib.rs +1 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ extern crate num_derive; #[macro_use] extern crate lazy_static; pub mod async_helper; pub mod battery_manager; pub mod battery_provider_manager; pub mod battery_service; Loading system/gd/rust/topshim/gatt/gatt_ble_scanner_shim.cc +12 −12 Original line number Diff line number Diff line Loading @@ -245,20 +245,20 @@ void BleScannerIntf::ScanFilterEnable(bool enable) { scanner_intf_->ScanFilterEnable(enable, base::Bind(&BleScannerIntf::OnEnableCallback, base::Unretained(this))); } void BleScannerIntf::MsftAdvMonitorAdd(RustMsftAdvMonitor monitor) { void BleScannerIntf::MsftAdvMonitorAdd(uint32_t call_id, const RustMsftAdvMonitor& monitor) { scanner_intf_->MsftAdvMonitorAdd( internal::ConvertAdvMonitor(monitor), base::Bind(&BleScannerIntf::OnMsftAdvMonitorAddCallback, base::Unretained(this))); base::Bind(&BleScannerIntf::OnMsftAdvMonitorAddCallback, base::Unretained(this), call_id)); } void BleScannerIntf::MsftAdvMonitorRemove(uint8_t monitor_handle) { void BleScannerIntf::MsftAdvMonitorRemove(uint32_t call_id, uint8_t monitor_handle) { scanner_intf_->MsftAdvMonitorRemove( monitor_handle, base::Bind(&BleScannerIntf::OnMsftAdvMonitorRemoveCallback, base::Unretained(this))); monitor_handle, base::Bind(&BleScannerIntf::OnMsftAdvMonitorRemoveCallback, base::Unretained(this), call_id)); } void BleScannerIntf::MsftAdvMonitorEnable(bool enable) { void BleScannerIntf::MsftAdvMonitorEnable(uint32_t call_id, bool enable) { scanner_intf_->MsftAdvMonitorEnable( enable, base::Bind(&BleScannerIntf::OnMsftAdvMonitorEnableCallback, base::Unretained(this))); enable, base::Bind(&BleScannerIntf::OnMsftAdvMonitorEnableCallback, base::Unretained(this), call_id)); } void BleScannerIntf::SetScanParameters(uint8_t scanner_id, uint16_t scan_interval, uint16_t scan_window) { Loading Loading @@ -347,16 +347,16 @@ void BleScannerIntf::OnFilterConfigCallback( rusty::gdscan_filter_config_callback(filter_index, filt_type, avbl_space, action, btm_status); } void BleScannerIntf::OnMsftAdvMonitorAddCallback(uint8_t monitor_handle, uint8_t status) { rusty::gdscan_msft_adv_monitor_add_callback(monitor_handle, status); void BleScannerIntf::OnMsftAdvMonitorAddCallback(uint32_t call_id, uint8_t monitor_handle, uint8_t status) { rusty::gdscan_msft_adv_monitor_add_callback(call_id, monitor_handle, status); } void BleScannerIntf::OnMsftAdvMonitorRemoveCallback(uint8_t status) { rusty::gdscan_msft_adv_monitor_remove_callback(status); void BleScannerIntf::OnMsftAdvMonitorRemoveCallback(uint32_t call_id, uint8_t status) { rusty::gdscan_msft_adv_monitor_remove_callback(call_id, status); } void BleScannerIntf::OnMsftAdvMonitorEnableCallback(uint8_t status) { rusty::gdscan_msft_adv_monitor_enable_callback(status); void BleScannerIntf::OnMsftAdvMonitorEnableCallback(uint32_t call_id, uint8_t status) { rusty::gdscan_msft_adv_monitor_enable_callback(call_id, status); } void BleScannerIntf::OnPeriodicSyncStarted( Loading Loading
system/gd/rust/linux/client/src/command_handler.rs +11 −2 Original line number Diff line number Diff line Loading @@ -973,9 +973,18 @@ impl CommandHandler { if let Ok(id) = scanner_id { self.context.lock().unwrap().gatt_dbus.as_mut().unwrap().start_scan( id, // TODO(b/217274432): Construct real settings and filters. // TODO(b/254870159): Construct real settings and filters depending on // command line options. ScanSettings { interval: 0, window: 0, scan_type: ScanType::Active }, None, Some(btstack::bluetooth_gatt::ScanFilter { rssi_high_threshold: 0, rssi_low_threshold: 0, rssi_low_timeout: 0, rssi_sampling_period: 0, condition: btstack::bluetooth_gatt::ScanFilterCondition::Patterns( vec![], ), }), ); self.context.lock().unwrap().active_scanner_ids.insert(id); } else { Loading
system/gd/rust/linux/stack/src/async_helper.rs 0 → 100644 +85 −0 Original line number Diff line number Diff line use std::collections::HashMap; use std::sync::{Arc, Mutex}; use tokio::sync::oneshot; use tokio::time::Duration; /// Helper for managing an async topshim function. It takes care of calling the function, preparing /// the channel, waiting for the callback, and returning it in a Result. /// /// `R` is the type of the return. pub(crate) struct AsyncHelper<R> { // Name of the method that this struct helps. Useful for logging. method_name: String, // Keeps track of call_id. Increment each time and wrap to 0 when u32 max is reached. last_call_id: u32, // Keep pending calls' ids and senders. senders: Arc<Mutex<HashMap<u32, oneshot::Sender<R>>>>, } pub(crate) type CallbackSender<R> = Arc<Mutex<Box<(dyn Fn(u32, R) + Send)>>>; impl<R: 'static + Send> AsyncHelper<R> { pub(crate) fn new(method_name: &str) -> Self { Self { method_name: String::from(method_name), last_call_id: 0, senders: Arc::new(Mutex::new(HashMap::new())), } } /// Calls a topshim method that expects the async return to be delivered via a callback. pub(crate) async fn call_method<F>(&mut self, f: F, timeout_ms: Option<u64>) -> Result<R, ()> where F: Fn(u32), { // Create a oneshot channel to be used by the callback to notify us that the return is // available. let (tx, rx) = oneshot::channel(); // Use a unique method call ID so that we know which callback is corresponding to which // method call. The actual value of the ID does not matter as long as it's always unique, // so a simple increment (and wraps back to 0) is good enough. self.last_call_id = self.last_call_id.wrapping_add(1); // Keep track of the sender belonging to this call id. self.senders.lock().unwrap().insert(self.last_call_id, tx); // Call the method. `f` is freely defined by the user of this utility. This must be an // operation that expects a callback that will trigger sending of the return via the // oneshot channel. f(self.last_call_id); if let Some(timeout_ms) = timeout_ms { let senders = self.senders.clone(); let call_id = self.last_call_id; tokio::spawn(async move { tokio::time::sleep(Duration::from_millis(timeout_ms)).await; // If the timer expires first before a callback is triggered, we remove the sender // which will invalidate the channel which in turn will notify the receiver of // an error. // If the callback gets triggered first, this does nothing since the entry has been // removed when sending the response. senders.lock().unwrap().remove(&call_id); }); } // Wait for the callback and return when available. rx.await.map_err(|_| ()) } /// Returns a function to be invoked when callback is triggered. pub(crate) fn get_callback_sender(&self) -> CallbackSender<R> { let senders = self.senders.clone(); let method_name = self.method_name.clone(); return Arc::new(Mutex::new(Box::new(move |call_id, ret| { if let Some(sender) = senders.lock().unwrap().remove(&call_id) { sender.send(ret).ok(); } else { log::warn!("AsyncHelper {}: Sender no longer exists.", method_name); } }))); } }
system/gd/rust/linux/stack/src/bluetooth_gatt.rs +234 −23 Original line number Diff line number Diff line Loading @@ -10,10 +10,12 @@ use bt_topshim::profiles::gatt::{ GattClientCallbacks, GattClientCallbacksDispatcher, GattScannerCallbacks, GattScannerCallbacksDispatcher, GattScannerInbandCallbacks, GattScannerInbandCallbacksDispatcher, GattServerCallbacksDispatcher, GattStatus, LePhy, MsftAdvMonitor, MsftAdvMonitorPattern, }; use bt_topshim::topstack; use bt_utils::adv_parser; use crate::async_helper::{AsyncHelper, CallbackSender}; use crate::bluetooth::{Bluetooth, IBluetooth}; use crate::bluetooth_adv::{ AdvertiseData, Advertisers, AdvertisingSetInfo, AdvertisingSetParameters, Loading @@ -28,6 +30,7 @@ use num_traits::clamp; use rand::rngs::SmallRng; use rand::{RngCore, SeedableRng}; use std::collections::{HashMap, HashSet}; use std::convert::TryInto; use std::sync::{Arc, Mutex, MutexGuard}; use tokio::sync::mpsc::Sender; Loading Loading @@ -665,7 +668,7 @@ pub struct ScanResult { pub adv_data: Vec<u8>, } #[derive(Debug)] #[derive(Debug, Clone)] pub struct ScanFilterPattern { /// Specifies the starting byte position of the pattern immediately following AD Type. pub start_position: u8, Loading @@ -681,7 +684,7 @@ pub struct ScanFilterPattern { /// Represents the condition for matching advertisements. /// /// Only pattern-based matching is implemented. #[derive(Debug)] #[derive(Debug, Clone)] pub enum ScanFilterCondition { /// All advertisements are matched. All, Loading @@ -704,7 +707,7 @@ pub enum ScanFilterCondition { /// This filter is intentionally modelled close to the MSFT hardware offload filter. /// Reference: /// https://learn.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events #[derive(Debug)] #[derive(Debug, Clone)] pub struct ScanFilter { /// Advertisements with RSSI above or equal this value is considered "found". pub rssi_high_threshold: u8, Loading @@ -726,6 +729,76 @@ pub struct ScanFilter { type ScannersMap = HashMap<Uuid, ScannerInfo>; const DEFAULT_ASYNC_TIMEOUT_MS: u64 = 5000; /// Abstraction for async GATT operations. Contains async methods for coordinating async operations /// more conveniently. struct GattAsyncIntf { scanners: Arc<Mutex<ScannersMap>>, gatt: Option<Arc<Mutex<Gatt>>>, async_helper_msft_adv_monitor_add: AsyncHelper<(u8, u8)>, async_helper_msft_adv_monitor_remove: AsyncHelper<u8>, async_helper_msft_adv_monitor_enable: AsyncHelper<u8>, } impl GattAsyncIntf { /// Adds an advertisement monitor. Returns monitor handle and status. async fn msft_adv_monitor_add(&mut self, monitor: MsftAdvMonitor) -> Result<(u8, u8), ()> { let gatt = self.gatt.as_ref().unwrap().clone(); self.async_helper_msft_adv_monitor_add .call_method( move |call_id| { gatt.lock().unwrap().scanner.msft_adv_monitor_add(call_id, &monitor); }, Some(DEFAULT_ASYNC_TIMEOUT_MS), ) .await } /// Removes an advertisement monitor. Returns status. async fn msft_adv_monitor_remove(&mut self, monitor_handle: u8) -> Result<u8, ()> { let gatt = self.gatt.as_ref().unwrap().clone(); self.async_helper_msft_adv_monitor_remove .call_method( move |call_id| { gatt.lock().unwrap().scanner.msft_adv_monitor_remove(call_id, monitor_handle); }, Some(DEFAULT_ASYNC_TIMEOUT_MS), ) .await } /// Enables/disables an advertisement monitor. Returns status. async fn msft_adv_monitor_enable(&mut self, enable: bool) -> Result<u8, ()> { let gatt = self.gatt.as_ref().unwrap().clone(); self.async_helper_msft_adv_monitor_enable .call_method( move |call_id| { gatt.lock().unwrap().scanner.msft_adv_monitor_enable(call_id, enable); }, Some(DEFAULT_ASYNC_TIMEOUT_MS), ) .await } /// Updates the topshim's scan state depending on the states of registered scanners. Scan is /// enabled if there is at least 1 active registered scanner. /// /// Note: this does not need to be async, but declared as async for consistency in this struct. /// May be converted into real async in the future if btif supports it. async fn update_scan(&mut self) { if self.scanners.lock().unwrap().values().find(|scanner| scanner.is_active).is_some() { self.gatt.as_ref().unwrap().lock().unwrap().scanner.start_scan(); } else { self.gatt.as_ref().unwrap().lock().unwrap().scanner.stop_scan(); } } } /// Implementation of the GATT API (IBluetoothGatt). pub struct BluetoothGatt { intf: Arc<Mutex<BluetoothInterface>>, Loading @@ -741,14 +814,25 @@ pub struct BluetoothGatt { scanners: Arc<Mutex<ScannersMap>>, advertisers: Advertisers, adv_mon_add_cb_sender: CallbackSender<(u8, u8)>, adv_mon_remove_cb_sender: CallbackSender<u8>, adv_mon_enable_cb_sender: CallbackSender<u8>, // Used for generating random UUIDs. SmallRng is chosen because it is fast, don't use this for // cryptography. small_rng: SmallRng, gatt_async: Arc<tokio::sync::Mutex<GattAsyncIntf>>, } impl BluetoothGatt { /// Constructs a new IBluetoothGatt implementation. pub fn new(intf: Arc<Mutex<BluetoothInterface>>, tx: Sender<Message>) -> BluetoothGatt { let scanners = Arc::new(Mutex::new(HashMap::new())); let async_helper_msft_adv_monitor_add = AsyncHelper::new("MsftAdvMonitorAdd"); let async_helper_msft_adv_monitor_remove = AsyncHelper::new("MsftAdvMonitorRemove"); let async_helper_msft_adv_monitor_enable = AsyncHelper::new("MsftAdvMonitorEnable"); BluetoothGatt { intf, gatt: None, Loading @@ -756,9 +840,19 @@ impl BluetoothGatt { context_map: ContextMap::new(tx.clone()), reliable_queue: HashSet::new(), scanner_callbacks: Callbacks::new(tx.clone(), Message::ScannerCallbackDisconnected), scanners: Arc::new(Mutex::new(HashMap::new())), scanners: scanners.clone(), small_rng: SmallRng::from_entropy(), advertisers: Advertisers::new(tx.clone()), adv_mon_add_cb_sender: async_helper_msft_adv_monitor_add.get_callback_sender(), adv_mon_remove_cb_sender: async_helper_msft_adv_monitor_remove.get_callback_sender(), adv_mon_enable_cb_sender: async_helper_msft_adv_monitor_enable.get_callback_sender(), gatt_async: Arc::new(tokio::sync::Mutex::new(GattAsyncIntf { scanners, gatt: None, async_helper_msft_adv_monitor_add, async_helper_msft_adv_monitor_remove, async_helper_msft_adv_monitor_enable, })), } } Loading Loading @@ -831,6 +925,12 @@ impl BluetoothGatt { gatt_adv_inband_callbacks_dispatcher, gatt_adv_callbacks_dispatcher, ); let gatt = self.gatt.clone(); let gatt_async = self.gatt_async.clone(); tokio::spawn(async move { gatt_async.lock().await.gatt = gatt; }); } /// Remove a scanner callback and unregisters all scanners associated with that callback. Loading Loading @@ -878,16 +978,6 @@ impl BluetoothGatt { todo!() } // Update the topshim's scan state depending on the states of registered scanners. Scan is // enabled if there is at least 1 active registered scanner. fn update_scan(&mut self) { if self.scanners.lock().unwrap().values().find(|scanner| scanner.is_active).is_some() { self.gatt.as_ref().unwrap().lock().unwrap().scanner.start_scan(); } else { self.gatt.as_ref().unwrap().lock().unwrap().scanner.stop_scan(); } } fn find_scanner_by_id<'a>( scanners: &'a mut MutexGuard<ScannersMap>, scanner_id: u8, Loading Loading @@ -978,6 +1068,49 @@ struct ScannerInfo { scanner_id: Option<u8>, // If one of scanners is active, we scan. is_active: bool, // Scan filter. filter: Option<ScanFilter>, // Adv monitor handle, if exists. monitor_handle: Option<u8>, } impl ScannerInfo { fn new(callback_id: u32) -> Self { Self { callback_id, scanner_id: None, is_active: false, filter: None, monitor_handle: None } } } impl Into<MsftAdvMonitorPattern> for &ScanFilterPattern { fn into(self) -> MsftAdvMonitorPattern { MsftAdvMonitorPattern { ad_type: self.ad_type, start_byte: self.start_position, pattern: self.content.clone(), } } } impl Into<Vec<MsftAdvMonitorPattern>> for &ScanFilterCondition { fn into(self) -> Vec<MsftAdvMonitorPattern> { match self { ScanFilterCondition::Patterns(patterns) => { patterns.iter().map(|pattern| pattern.into()).collect() } _ => vec![], } } } impl Into<MsftAdvMonitor> for &ScanFilter { fn into(self) -> MsftAdvMonitor { MsftAdvMonitor { rssi_high_threshold: self.rssi_high_threshold.try_into().unwrap(), rssi_low_threshold: self.rssi_low_threshold.try_into().unwrap(), rssi_low_timeout: self.rssi_low_timeout.try_into().unwrap(), rssi_sampling_period: self.rssi_sampling_period.try_into().unwrap(), patterns: (&self.condition).into(), } } } impl IBluetoothGatt for BluetoothGatt { Loading @@ -999,10 +1132,7 @@ impl IBluetoothGatt for BluetoothGatt { self.small_rng.fill_bytes(&mut bytes); let uuid = Uuid::from(bytes); self.scanners .lock() .unwrap() .insert(uuid, ScannerInfo { callback_id, scanner_id: None, is_active: false }); self.scanners.lock().unwrap().insert(uuid, ScannerInfo::new(callback_id)); // libbluetooth's register_scanner takes a UUID of the scanning application. This UUID does // not correspond to higher level concept of "application" so we use random UUID that Loading Loading @@ -1030,7 +1160,7 @@ impl IBluetoothGatt for BluetoothGatt { &mut self, scanner_id: u8, _settings: ScanSettings, _filter: Option<ScanFilter>, filter: Option<ScanFilter>, ) -> BtStatus { // Multiplexing scanners happens at this layer. The implementations of start_scan // and stop_scan maintains the state of all registered scanners and based on the states Loading @@ -1038,31 +1168,81 @@ impl IBluetoothGatt for BluetoothGatt { // TODO(b/217274432): Honor settings and filters. { let mut scanners_lock = self.scanners.lock().unwrap(); if let Some(scanner) = Self::find_scanner_by_id(&mut scanners_lock, scanner_id) { scanner.is_active = true; scanner.filter = filter.clone(); } else { log::warn!("Scanner {} not found", scanner_id); return BtStatus::Fail; } } self.update_scan(); let gatt_async = self.gatt_async.clone(); tokio::spawn(async move { // The three operations below (monitor add, monitor enable, update scan) happen one // after another, and cannot be interleaved with other GATT async operations. // So acquire the GATT async lock in the beginning of this block and will be released // at the end of this block. // TODO(b/217274432): Consider not using async model but instead add actions when // handling callbacks. let mut gatt_async = gatt_async.lock().await; if let Some(filter) = filter { let monitor_handle = match gatt_async.msft_adv_monitor_add((&filter).into()).await { Ok((handle, 0)) => handle, _ => { log::error!("Error adding advertisement monitor"); return; } }; log::debug!("Added adv monitor handle = {}", monitor_handle); if !gatt_async .msft_adv_monitor_enable(true) .await .map_or(false, |status| status == 0) { log::error!("Error enabling Advertisement Monitor"); } } gatt_async.update_scan().await; }); BtStatus::Success } fn stop_scan(&mut self, scanner_id: u8) -> BtStatus { { let monitor_handle = { let mut scanners_lock = self.scanners.lock().unwrap(); if let Some(scanner) = Self::find_scanner_by_id(&mut scanners_lock, scanner_id) { scanner.is_active = false; scanner.monitor_handle } else { log::warn!("Scanner {} not found", scanner_id); // Clients can assume success of the removal since the scanner does not exist. return BtStatus::Success; } }; let gatt_async = self.gatt_async.clone(); tokio::spawn(async move { // The two operations below (monitor remove, update scan) happen one after another, and // cannot be interleaved with other GATT async operations. // So acquire the GATT async lock in the beginning of this block and will be released // at the end of this block. let mut gatt_async = gatt_async.lock().await; if let Some(handle) = monitor_handle { let _res = gatt_async.msft_adv_monitor_remove(handle).await; } self.update_scan(); gatt_async.update_scan().await; }); BtStatus::Success } Loading Loading @@ -2297,6 +2477,20 @@ pub(crate) trait BtifGattScannerInbandCallbacks { btm_status: u8, ); #[btif_callback(MsftAdvMonitorAddCallback)] fn inband_msft_adv_monitor_add_callback( &mut self, call_id: u32, monitor_handle: u8, status: u8, ); #[btif_callback(MsftAdvMonitorRemoveCallback)] fn inband_msft_adv_monitor_remove_callback(&mut self, call_id: u32, status: u8); #[btif_callback(MsftAdvMonitorEnableCallback)] fn inband_msft_adv_monitor_enable_callback(&mut self, call_id: u32, status: u8); #[btif_callback(StartSyncCallback)] fn inband_start_sync_callback( &mut self, Loading Loading @@ -2386,6 +2580,23 @@ impl BtifGattScannerInbandCallbacks for BluetoothGatt { ); } fn inband_msft_adv_monitor_add_callback( &mut self, call_id: u32, monitor_handle: u8, status: u8, ) { (self.adv_mon_add_cb_sender.lock().unwrap())(call_id, (monitor_handle, status)); } fn inband_msft_adv_monitor_remove_callback(&mut self, call_id: u32, status: u8) { (self.adv_mon_remove_cb_sender.lock().unwrap())(call_id, status); } fn inband_msft_adv_monitor_enable_callback(&mut self, call_id: u32, status: u8) { (self.adv_mon_enable_cb_sender.lock().unwrap())(call_id, status); } fn inband_start_sync_callback( &mut self, status: u8, Loading
system/gd/rust/linux/stack/src/lib.rs +1 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ extern crate num_derive; #[macro_use] extern crate lazy_static; pub mod async_helper; pub mod battery_manager; pub mod battery_provider_manager; pub mod battery_service; Loading
system/gd/rust/topshim/gatt/gatt_ble_scanner_shim.cc +12 −12 Original line number Diff line number Diff line Loading @@ -245,20 +245,20 @@ void BleScannerIntf::ScanFilterEnable(bool enable) { scanner_intf_->ScanFilterEnable(enable, base::Bind(&BleScannerIntf::OnEnableCallback, base::Unretained(this))); } void BleScannerIntf::MsftAdvMonitorAdd(RustMsftAdvMonitor monitor) { void BleScannerIntf::MsftAdvMonitorAdd(uint32_t call_id, const RustMsftAdvMonitor& monitor) { scanner_intf_->MsftAdvMonitorAdd( internal::ConvertAdvMonitor(monitor), base::Bind(&BleScannerIntf::OnMsftAdvMonitorAddCallback, base::Unretained(this))); base::Bind(&BleScannerIntf::OnMsftAdvMonitorAddCallback, base::Unretained(this), call_id)); } void BleScannerIntf::MsftAdvMonitorRemove(uint8_t monitor_handle) { void BleScannerIntf::MsftAdvMonitorRemove(uint32_t call_id, uint8_t monitor_handle) { scanner_intf_->MsftAdvMonitorRemove( monitor_handle, base::Bind(&BleScannerIntf::OnMsftAdvMonitorRemoveCallback, base::Unretained(this))); monitor_handle, base::Bind(&BleScannerIntf::OnMsftAdvMonitorRemoveCallback, base::Unretained(this), call_id)); } void BleScannerIntf::MsftAdvMonitorEnable(bool enable) { void BleScannerIntf::MsftAdvMonitorEnable(uint32_t call_id, bool enable) { scanner_intf_->MsftAdvMonitorEnable( enable, base::Bind(&BleScannerIntf::OnMsftAdvMonitorEnableCallback, base::Unretained(this))); enable, base::Bind(&BleScannerIntf::OnMsftAdvMonitorEnableCallback, base::Unretained(this), call_id)); } void BleScannerIntf::SetScanParameters(uint8_t scanner_id, uint16_t scan_interval, uint16_t scan_window) { Loading Loading @@ -347,16 +347,16 @@ void BleScannerIntf::OnFilterConfigCallback( rusty::gdscan_filter_config_callback(filter_index, filt_type, avbl_space, action, btm_status); } void BleScannerIntf::OnMsftAdvMonitorAddCallback(uint8_t monitor_handle, uint8_t status) { rusty::gdscan_msft_adv_monitor_add_callback(monitor_handle, status); void BleScannerIntf::OnMsftAdvMonitorAddCallback(uint32_t call_id, uint8_t monitor_handle, uint8_t status) { rusty::gdscan_msft_adv_monitor_add_callback(call_id, monitor_handle, status); } void BleScannerIntf::OnMsftAdvMonitorRemoveCallback(uint8_t status) { rusty::gdscan_msft_adv_monitor_remove_callback(status); void BleScannerIntf::OnMsftAdvMonitorRemoveCallback(uint32_t call_id, uint8_t status) { rusty::gdscan_msft_adv_monitor_remove_callback(call_id, status); } void BleScannerIntf::OnMsftAdvMonitorEnableCallback(uint8_t status) { rusty::gdscan_msft_adv_monitor_enable_callback(status); void BleScannerIntf::OnMsftAdvMonitorEnableCallback(uint32_t call_id, uint8_t status) { rusty::gdscan_msft_adv_monitor_enable_callback(call_id, status); } void BleScannerIntf::OnPeriodicSyncStarted( Loading