1 use crate::battery_manager::{Battery, BatterySet}; 2 use crate::battery_provider_manager::{ 3 BatteryProviderManager, IBatteryProviderCallback, IBatteryProviderManager, 4 }; 5 use crate::bluetooth::BluetoothDevice; 6 use crate::bluetooth_gatt::{ 7 BluetoothGatt, BluetoothGattService, IBluetoothGatt, IBluetoothGattCallback, 8 }; 9 use crate::callbacks::Callbacks; 10 use crate::uuid::UuidHelper; 11 use crate::Message; 12 use crate::RPCProxy; 13 use crate::{uuid, APIMessage, BluetoothAPI}; 14 use bt_topshim::btif::{BtTransport, DisplayAddress, RawAddress, Uuid}; 15 use bt_topshim::profiles::gatt::{GattStatus, LePhy}; 16 use log::debug; 17 use std::collections::HashMap; 18 use std::convert::TryInto; 19 use std::iter; 20 use std::sync::{Arc, Mutex}; 21 use tokio::sync::mpsc::Sender; 22 23 /// The UUID corresponding to the BatteryLevel characteristic defined by the BatteryService 24 /// specification. 25 pub const CHARACTERISTIC_BATTERY_LEVEL: &str = "00002A1-9000-0100-0800-000805F9B34FB"; 26 27 /// Represents the Floss BatteryService implementation. 28 pub struct BatteryService { 29 gatt: Arc<Mutex<Box<BluetoothGatt>>>, 30 battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, 31 battery_provider_id: u32, 32 /// Sender for callback communication with the main thread. 33 tx: Sender<Message>, 34 /// Sender for callback communication with the api message thread. 35 api_tx: Sender<APIMessage>, 36 callbacks: Callbacks<dyn IBatteryServiceCallback + Send>, 37 /// The GATT client ID needed for GATT calls. 38 client_id: Option<i32>, 39 /// Cached battery info keyed by remote device. 40 battery_sets: HashMap<RawAddress, BatterySet>, 41 /// Found handles for battery levels. Required for faster 42 /// refreshes than initiating another search. 43 handles: HashMap<RawAddress, i32>, 44 } 45 46 /// Enum for GATT callbacks to relay messages to the main processing thread. Newly supported 47 /// callbacks should add a corresponding entry here. 48 pub enum BatteryServiceActions { 49 /// Params: status, client_id 50 OnClientRegistered(GattStatus, i32), 51 /// Params: status, client_id, connected, addr 52 OnClientConnectionState(GattStatus, i32, bool, RawAddress), 53 /// Params: addr, services, status 54 OnSearchComplete(RawAddress, Vec<BluetoothGattService>, GattStatus), 55 /// Params: addr, status, handle, value 56 OnCharacteristicRead(RawAddress, GattStatus, i32, Vec<u8>), 57 /// Params: addr, handle, value 58 OnNotify(RawAddress, i32, Vec<u8>), 59 /// Params: remote_device, transport 60 Connect(BluetoothDevice, BtTransport), 61 /// Params: remote_device 62 Disconnect(BluetoothDevice), 63 } 64 65 /// API for Floss implementation of the Bluetooth Battery Service (BAS). BAS is built on GATT and 66 /// this implementation wraps all of the GATT calls and handles tracking battery information for the 67 /// client. 68 pub trait IBatteryService { 69 /// Registers a callback for interacting with BatteryService. register_callback(&mut self, callback: Box<dyn IBatteryServiceCallback + Send>) -> u3270 fn register_callback(&mut self, callback: Box<dyn IBatteryServiceCallback + Send>) -> u32; 71 72 /// Unregisters a callback. unregister_callback(&mut self, callback_id: u32)73 fn unregister_callback(&mut self, callback_id: u32); 74 75 /// Returns the battery info of the remote device if available in BatteryService's cache. get_battery_info(&self, remote_address: RawAddress) -> Option<BatterySet>76 fn get_battery_info(&self, remote_address: RawAddress) -> Option<BatterySet>; 77 78 /// Forces an explicit read of the device's battery level, including initiating battery level 79 /// tracking if not yet performed. refresh_battery_info(&self, remote_address: RawAddress) -> bool80 fn refresh_battery_info(&self, remote_address: RawAddress) -> bool; 81 } 82 83 /// Callback for interacting with BAS. 84 pub trait IBatteryServiceCallback: RPCProxy { 85 /// Called when the status of BatteryService has changed. Trying to read from devices that do 86 /// not support BAS will result in this method being called with BatteryServiceNotSupported. on_battery_service_status_updated( &mut self, remote_address: RawAddress, status: BatteryServiceStatus, )87 fn on_battery_service_status_updated( 88 &mut self, 89 remote_address: RawAddress, 90 status: BatteryServiceStatus, 91 ); 92 93 /// Invoked when battery level for a device has been changed due to notification. on_battery_info_updated(&mut self, remote_address: RawAddress, battery_info: BatterySet)94 fn on_battery_info_updated(&mut self, remote_address: RawAddress, battery_info: BatterySet); 95 } 96 97 impl BatteryService { 98 /// Construct a new BatteryService with callbacks relaying messages through tx. new( gatt: Arc<Mutex<Box<BluetoothGatt>>>, battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, tx: Sender<Message>, api_tx: Sender<APIMessage>, ) -> BatteryService99 pub fn new( 100 gatt: Arc<Mutex<Box<BluetoothGatt>>>, 101 battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, 102 tx: Sender<Message>, 103 api_tx: Sender<APIMessage>, 104 ) -> BatteryService { 105 let tx = tx.clone(); 106 let callbacks = Callbacks::new(tx.clone(), Message::BatteryServiceCallbackDisconnected); 107 let client_id = None; 108 let battery_sets = HashMap::new(); 109 let handles = HashMap::new(); 110 let battery_provider_id = battery_provider_manager 111 .lock() 112 .unwrap() 113 .register_battery_provider(Box::new(BatteryProviderCallback::new(tx.clone()))); 114 Self { 115 gatt, 116 battery_provider_manager, 117 battery_provider_id, 118 tx, 119 api_tx, 120 callbacks, 121 client_id, 122 battery_sets, 123 handles, 124 } 125 } 126 127 /// Must be called after BluetoothGatt's init_profiles method has completed. init(&self)128 pub fn init(&self) { 129 debug!("Registering GATT client for BatteryService"); 130 self.gatt.lock().unwrap().register_client( 131 // TODO(b/233101174): make dynamic or decide on a static UUID 132 String::from("e4d2acffcfaa42198f494606b7412117"), 133 Box::new(GattCallback::new(self.tx.clone(), self.api_tx.clone())), 134 false, 135 ); 136 } 137 138 /// Handles all callback messages in a central location to avoid deadlocks. handle_action(&mut self, action: BatteryServiceActions)139 pub fn handle_action(&mut self, action: BatteryServiceActions) { 140 match action { 141 BatteryServiceActions::OnClientRegistered(_status, client_id) => { 142 debug!("GATT client registered for BAS with id {}", client_id); 143 self.client_id = Some(client_id); 144 } 145 146 BatteryServiceActions::OnClientConnectionState(status, _client_id, connected, addr) => { 147 if !connected || status != GattStatus::Success { 148 return; 149 } 150 let client_id = match self.client_id { 151 Some(id) => id, 152 None => { 153 return; 154 } 155 }; 156 self.gatt.lock().unwrap().discover_services(client_id, addr); 157 } 158 159 BatteryServiceActions::OnSearchComplete(addr, services, status) => { 160 if status != GattStatus::Success { 161 debug!( 162 "GATT service discovery for {} failed with status {:?}", 163 DisplayAddress(&addr), 164 status 165 ); 166 self.drop_device(addr); 167 return; 168 } 169 let handle = match self.get_battery_level_handle(addr.clone(), services) { 170 Ok(battery_level_handle) => battery_level_handle, 171 Err(status) => { 172 if let Some(BatteryServiceStatus::BatteryServiceNotSupported) = status { 173 self.callbacks.for_all_callbacks(|callback| { 174 callback.on_battery_service_status_updated( 175 addr.clone(), 176 BatteryServiceStatus::BatteryServiceNotSupported, 177 ) 178 }); 179 } 180 self.drop_device(addr); 181 return; 182 } 183 }; 184 let client_id = match self.client_id { 185 Some(id) => id, 186 None => { 187 self.drop_device(addr); 188 return; 189 } 190 }; 191 self.handles.insert(addr, handle.clone()); 192 self.gatt.lock().unwrap().register_for_notification(client_id, addr, handle, true); 193 if let None = self.battery_sets.get(&addr) { 194 self.gatt.lock().unwrap().read_characteristic(client_id, addr, handle, 0); 195 } 196 } 197 198 BatteryServiceActions::OnCharacteristicRead(addr, status, handle, value) => { 199 if status != GattStatus::Success { 200 return; 201 } 202 match self.handles.get(&addr) { 203 Some(stored_handle) => { 204 if *stored_handle != handle { 205 return; 206 } 207 } 208 None => { 209 self.drop_device(addr); 210 return; 211 } 212 } 213 let battery_info = self.set_battery_info(&addr, &value); 214 self.callbacks.for_all_callbacks(|callback| { 215 callback.on_battery_info_updated(addr, battery_info.clone()); 216 }); 217 } 218 219 BatteryServiceActions::OnNotify(addr, _handle, value) => { 220 let battery_info = self.set_battery_info(&addr, &value); 221 self.callbacks.for_all_callbacks(|callback| { 222 callback.on_battery_info_updated(addr, battery_info.clone()); 223 }); 224 } 225 226 BatteryServiceActions::Connect(device, transport) => { 227 if transport != BtTransport::Le { 228 return; 229 } 230 self.init_device(device.address, transport); 231 } 232 233 BatteryServiceActions::Disconnect(device) => { 234 self.drop_device(device.address); 235 } 236 } 237 } 238 set_battery_info(&mut self, remote_address: &RawAddress, value: &Vec<u8>) -> BatterySet239 fn set_battery_info(&mut self, remote_address: &RawAddress, value: &Vec<u8>) -> BatterySet { 240 let level: Vec<_> = value.iter().cloned().chain(iter::repeat(0 as u8)).take(4).collect(); 241 let level = u32::from_le_bytes(level.try_into().unwrap()); 242 debug!("BAS received battery level for {}: {}", DisplayAddress(&remote_address), level); 243 let battery_set = self.battery_sets.entry(*remote_address).or_insert_with(|| { 244 BatterySet::new( 245 *remote_address, 246 uuid::BAS.to_string(), 247 "BAS".to_string(), 248 vec![Battery { percentage: level, variant: "".to_string() }], 249 ) 250 }); 251 self.battery_provider_manager 252 .lock() 253 .unwrap() 254 .set_battery_info(self.battery_provider_id, battery_set.clone()); 255 battery_set.clone() 256 } 257 init_device(&self, remote_address: RawAddress, transport: BtTransport)258 fn init_device(&self, remote_address: RawAddress, transport: BtTransport) { 259 let client_id = match self.client_id { 260 Some(id) => id, 261 None => return, 262 }; 263 debug!("Attempting GATT connection to {}", DisplayAddress(&remote_address)); 264 self.gatt.lock().unwrap().client_connect( 265 client_id, 266 remote_address, 267 false, 268 transport, 269 false, 270 LePhy::Phy1m, 271 ); 272 } 273 drop_device(&mut self, remote_address: RawAddress)274 fn drop_device(&mut self, remote_address: RawAddress) { 275 if self.handles.contains_key(&remote_address) { 276 // Let BatteryProviderManager know that BAS no longer has a battery for this device. 277 self.battery_provider_manager.lock().unwrap().remove_battery_info( 278 self.battery_provider_id, 279 remote_address.clone(), 280 uuid::BAS.to_string(), 281 ); 282 } 283 self.battery_sets.remove(&remote_address); 284 self.handles.remove(&remote_address); 285 match self.client_id { 286 Some(client_id) => { 287 self.gatt.lock().unwrap().client_disconnect(client_id, remote_address); 288 } 289 None => return, 290 } 291 } 292 get_battery_level_handle( &mut self, remote_address: RawAddress, services: Vec<BluetoothGattService>, ) -> Result<i32, Option<BatteryServiceStatus>>293 fn get_battery_level_handle( 294 &mut self, 295 remote_address: RawAddress, 296 services: Vec<BluetoothGattService>, 297 ) -> Result<i32, Option<BatteryServiceStatus>> { 298 let (bas_uuid, battery_level_uuid) = 299 match (Uuid::from_string(uuid::BAS), Uuid::from_string(CHARACTERISTIC_BATTERY_LEVEL)) { 300 (Some(bas_uuid), Some(battery_level_uuid)) => (bas_uuid, battery_level_uuid), 301 _ => { 302 return Err(None); 303 } 304 }; 305 // TODO(b/233101174): handle multiple instances of BAS 306 let bas = match services.iter().find(|service| service.uuid == bas_uuid) { 307 Some(bas) => bas, 308 None => return Err(Some(BatteryServiceStatus::BatteryServiceNotSupported)), 309 }; 310 let battery_level = match bas 311 .characteristics 312 .iter() 313 .find(|characteristic| characteristic.uuid == battery_level_uuid) 314 { 315 Some(battery_level) => battery_level, 316 None => { 317 debug!( 318 "Device {} has no BatteryLevel characteristic", 319 DisplayAddress(&remote_address) 320 ); 321 return Err(None); 322 } 323 }; 324 Ok(battery_level.instance_id) 325 } 326 327 /// Perform an explicit read on all devices BAS knows about. refresh_all_devices(&self)328 pub fn refresh_all_devices(&self) { 329 self.handles.keys().for_each(|&addr| { 330 self.refresh_device(addr); 331 }); 332 } 333 refresh_device(&self, remote_address: RawAddress) -> bool334 fn refresh_device(&self, remote_address: RawAddress) -> bool { 335 let client_id = match self.client_id { 336 Some(id) => id, 337 None => return false, 338 }; 339 let handle = match self.handles.get(&remote_address) { 340 Some(id) => *id, 341 None => return false, 342 }; 343 self.gatt.lock().unwrap().read_characteristic(client_id, remote_address, handle, 0); 344 true 345 } 346 347 /// Remove a callback due to disconnection or unregistration. remove_callback(&mut self, callback_id: u32)348 pub fn remove_callback(&mut self, callback_id: u32) { 349 self.callbacks.remove_callback(callback_id); 350 } 351 } 352 353 /// Status enum for relaying the state of BAS or a particular device. 354 pub enum BatteryServiceStatus { 355 /// Device does not report support for BAS. 356 BatteryServiceNotSupported, 357 } 358 359 impl IBatteryService for BatteryService { register_callback(&mut self, callback: Box<dyn IBatteryServiceCallback + Send>) -> u32360 fn register_callback(&mut self, callback: Box<dyn IBatteryServiceCallback + Send>) -> u32 { 361 self.callbacks.add_callback(callback) 362 } 363 unregister_callback(&mut self, callback_id: u32)364 fn unregister_callback(&mut self, callback_id: u32) { 365 self.remove_callback(callback_id); 366 } 367 get_battery_info(&self, remote_address: RawAddress) -> Option<BatterySet>368 fn get_battery_info(&self, remote_address: RawAddress) -> Option<BatterySet> { 369 self.battery_sets.get(&remote_address).cloned() 370 } 371 refresh_battery_info(&self, remote_address: RawAddress) -> bool372 fn refresh_battery_info(&self, remote_address: RawAddress) -> bool { 373 self.refresh_device(remote_address) 374 } 375 } 376 377 struct BatteryProviderCallback { 378 tx: Sender<Message>, 379 } 380 381 impl BatteryProviderCallback { new(tx: Sender<Message>) -> Self382 fn new(tx: Sender<Message>) -> Self { 383 Self { tx } 384 } 385 } 386 387 impl IBatteryProviderCallback for BatteryProviderCallback { refresh_battery_info(&mut self)388 fn refresh_battery_info(&mut self) { 389 let tx = self.tx.clone(); 390 tokio::spawn(async move { 391 let _ = tx.send(Message::BatteryServiceRefresh).await; 392 }); 393 } 394 } 395 396 impl RPCProxy for BatteryProviderCallback { get_object_id(&self) -> String397 fn get_object_id(&self) -> String { 398 "BAS BatteryProvider Callback".to_string() 399 } 400 } 401 402 struct GattCallback { 403 tx: Sender<Message>, 404 api_tx: Sender<APIMessage>, 405 } 406 407 impl GattCallback { new(tx: Sender<Message>, api_tx: Sender<APIMessage>) -> Self408 fn new(tx: Sender<Message>, api_tx: Sender<APIMessage>) -> Self { 409 Self { tx, api_tx } 410 } 411 } 412 413 impl IBluetoothGattCallback for GattCallback { 414 // All callback methods relay messages through the stack receiver to allow BAS to operate on 415 // requests serially. This reduces overall complexity including removing the need to share state 416 // data with callbacks. 417 on_client_registered(&mut self, status: GattStatus, client_id: i32)418 fn on_client_registered(&mut self, status: GattStatus, client_id: i32) { 419 let tx = self.tx.clone(); 420 let api_tx = self.api_tx.clone(); 421 tokio::spawn(async move { 422 let _ = tx 423 .send(Message::BatteryService(BatteryServiceActions::OnClientRegistered( 424 status, client_id, 425 ))) 426 .await; 427 let _ = api_tx.send(APIMessage::IsReady(BluetoothAPI::Battery)).await; 428 }); 429 } 430 on_client_connection_state( &mut self, status: GattStatus, client_id: i32, connected: bool, addr: RawAddress, )431 fn on_client_connection_state( 432 &mut self, 433 status: GattStatus, 434 client_id: i32, 435 connected: bool, 436 addr: RawAddress, 437 ) { 438 let tx = self.tx.clone(); 439 tokio::spawn(async move { 440 let _ = tx 441 .send(Message::BatteryService(BatteryServiceActions::OnClientConnectionState( 442 status, client_id, connected, addr, 443 ))) 444 .await; 445 }); 446 } 447 on_search_complete( &mut self, addr: RawAddress, services: Vec<BluetoothGattService>, status: GattStatus, )448 fn on_search_complete( 449 &mut self, 450 addr: RawAddress, 451 services: Vec<BluetoothGattService>, 452 status: GattStatus, 453 ) { 454 let tx = self.tx.clone(); 455 tokio::spawn(async move { 456 let _ = tx 457 .send(Message::BatteryService(BatteryServiceActions::OnSearchComplete( 458 addr, services, status, 459 ))) 460 .await; 461 }); 462 } 463 on_characteristic_read( &mut self, addr: RawAddress, status: GattStatus, handle: i32, value: Vec<u8>, )464 fn on_characteristic_read( 465 &mut self, 466 addr: RawAddress, 467 status: GattStatus, 468 handle: i32, 469 value: Vec<u8>, 470 ) { 471 let tx = self.tx.clone(); 472 tokio::spawn(async move { 473 let _ = tx 474 .send(Message::BatteryService(BatteryServiceActions::OnCharacteristicRead( 475 addr, status, handle, value, 476 ))) 477 .await; 478 }); 479 } 480 on_notify(&mut self, addr: RawAddress, handle: i32, value: Vec<u8>)481 fn on_notify(&mut self, addr: RawAddress, handle: i32, value: Vec<u8>) { 482 let tx = self.tx.clone(); 483 tokio::spawn(async move { 484 let _ = tx 485 .send(Message::BatteryService(BatteryServiceActions::OnNotify(addr, handle, value))) 486 .await; 487 }); 488 } 489 on_phy_update( &mut self, _addr: RawAddress, _tx_phy: LePhy, _rx_phy: LePhy, _status: GattStatus, )490 fn on_phy_update( 491 &mut self, 492 _addr: RawAddress, 493 _tx_phy: LePhy, 494 _rx_phy: LePhy, 495 _status: GattStatus, 496 ) { 497 } 498 on_phy_read( &mut self, _addr: RawAddress, _tx_phy: LePhy, _rx_phy: LePhy, _status: GattStatus, )499 fn on_phy_read( 500 &mut self, 501 _addr: RawAddress, 502 _tx_phy: LePhy, 503 _rx_phy: LePhy, 504 _status: GattStatus, 505 ) { 506 } 507 on_characteristic_write(&mut self, _addr: RawAddress, _status: GattStatus, _handle: i32)508 fn on_characteristic_write(&mut self, _addr: RawAddress, _status: GattStatus, _handle: i32) {} 509 on_execute_write(&mut self, _addr: RawAddress, _status: GattStatus)510 fn on_execute_write(&mut self, _addr: RawAddress, _status: GattStatus) {} 511 on_descriptor_read( &mut self, _addr: RawAddress, _status: GattStatus, _handle: i32, _value: Vec<u8>, )512 fn on_descriptor_read( 513 &mut self, 514 _addr: RawAddress, 515 _status: GattStatus, 516 _handle: i32, 517 _value: Vec<u8>, 518 ) { 519 } 520 on_descriptor_write(&mut self, _addr: RawAddress, _status: GattStatus, _handle: i32)521 fn on_descriptor_write(&mut self, _addr: RawAddress, _status: GattStatus, _handle: i32) {} 522 on_read_remote_rssi(&mut self, _addr: RawAddress, _rssi: i32, _status: GattStatus)523 fn on_read_remote_rssi(&mut self, _addr: RawAddress, _rssi: i32, _status: GattStatus) {} 524 on_configure_mtu(&mut self, _addr: RawAddress, _mtu: i32, _status: GattStatus)525 fn on_configure_mtu(&mut self, _addr: RawAddress, _mtu: i32, _status: GattStatus) {} 526 on_connection_updated( &mut self, _addr: RawAddress, _interval: i32, _latency: i32, _timeout: i32, _status: GattStatus, )527 fn on_connection_updated( 528 &mut self, 529 _addr: RawAddress, 530 _interval: i32, 531 _latency: i32, 532 _timeout: i32, 533 _status: GattStatus, 534 ) { 535 } 536 on_service_changed(&mut self, _addr: RawAddress)537 fn on_service_changed(&mut self, _addr: RawAddress) {} 538 } 539 540 impl RPCProxy for GattCallback { get_object_id(&self) -> String541 fn get_object_id(&self) -> String { 542 "BAS Gatt Callback".to_string() 543 } 544 } 545