1 //! Floss Bluetooth stack.
2 //!
3 //! This crate provides the API implementation of the Fluoride/GD Bluetooth
4 //! stack, independent of any RPC projection.
5
6 pub mod battery_manager;
7 pub mod battery_provider_manager;
8 pub mod battery_service;
9 pub mod bluetooth;
10 pub mod bluetooth_admin;
11 pub mod bluetooth_adv;
12 pub mod bluetooth_gatt;
13 pub mod bluetooth_logging;
14 pub mod bluetooth_media;
15 pub mod bluetooth_qa;
16 pub mod callbacks;
17 pub mod dis;
18 pub mod socket_manager;
19 pub mod suspend;
20 pub mod uuid;
21
22 use bluetooth_qa::{BluetoothQA, IBluetoothQA};
23 use log::{debug, info};
24 use num_derive::{FromPrimitive, ToPrimitive};
25 use std::sync::{Arc, Mutex};
26 use tokio::sync::mpsc::{channel, Receiver, Sender};
27 use tokio::time::{sleep, Duration};
28
29 use crate::battery_manager::{BatteryManager, BatterySet};
30 use crate::battery_provider_manager::BatteryProviderManager;
31 use crate::battery_service::{
32 BatteryService, BatteryServiceActions, BATTERY_SERVICE_GATT_CLIENT_APP_ID,
33 };
34 use crate::bluetooth::{
35 dispatch_base_callbacks, dispatch_hid_host_callbacks, dispatch_sdp_callbacks, AdapterActions,
36 Bluetooth, BluetoothDevice, IBluetooth,
37 };
38 use crate::bluetooth_admin::{AdminActions, BluetoothAdmin, IBluetoothAdmin};
39 use crate::bluetooth_adv::{dispatch_le_adv_callbacks, AdvertiserActions};
40 use crate::bluetooth_gatt::{
41 dispatch_gatt_client_callbacks, dispatch_gatt_server_callbacks, dispatch_le_scanner_callbacks,
42 dispatch_le_scanner_inband_callbacks, BluetoothGatt, GattActions,
43 };
44 use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions};
45 use crate::dis::{DeviceInformation, ServiceCallbacks};
46 use crate::socket_manager::{BluetoothSocketManager, SocketActions};
47 use crate::suspend::{Suspend, SuspendActions};
48 use bt_topshim::btif::{
49 BaseCallbacks, BtAclState, BtBondState, BtTransport, DisplayAddress, RawAddress, Uuid,
50 };
51 use bt_topshim::profiles::a2dp::A2dpCallbacks;
52 use bt_topshim::profiles::avrcp::AvrcpCallbacks;
53 use bt_topshim::profiles::csis::CsisClientCallbacks;
54 use bt_topshim::profiles::gatt::{
55 GattAdvCallbacks, GattAdvInbandCallbacks, GattClientCallbacks, GattScannerCallbacks,
56 GattScannerInbandCallbacks, GattServerCallbacks,
57 };
58 use bt_topshim::profiles::hfp::HfpCallbacks;
59 use bt_topshim::profiles::hid_host::{BthhReportType, HHCallbacks};
60 use bt_topshim::profiles::le_audio::LeAudioClientCallbacks;
61 use bt_topshim::profiles::sdp::SdpCallbacks;
62 use bt_topshim::profiles::vc::VolumeControlCallbacks;
63
64 /// Message types that are sent to the stack main dispatch loop.
65 pub enum Message {
66 /// Remove the DBus API. Call it before other AdapterShutdown.
67 InterfaceShutdown,
68 /// Disable the adapter by calling btif disable.
69 /// Param: bool to indicate abort(true) or graceful shutdown(false).
70 /// Use abort when we believe adapter is already in a bad state.
71 AdapterShutdown(bool),
72 /// Clean up the adapter by calling btif cleanup.
73 Cleanup,
74 /// Clean up the media by calling profile cleanup.
75 CleanupProfiles,
76
77 // Adapter is enabled and ready.
78 AdapterReady,
79
80 // Callbacks from libbluetooth
81 A2dp(A2dpCallbacks),
82 Avrcp(AvrcpCallbacks),
83 Base(BaseCallbacks),
84 GattClient(GattClientCallbacks),
85 GattServer(GattServerCallbacks),
86 LeAudioClient(LeAudioClientCallbacks),
87 LeScanner(GattScannerCallbacks),
88 LeScannerInband(GattScannerInbandCallbacks),
89 LeAdvInband(GattAdvInbandCallbacks),
90 LeAdv(GattAdvCallbacks),
91 HidHost(HHCallbacks),
92 Hfp(HfpCallbacks),
93 Sdp(SdpCallbacks),
94 VolumeControl(VolumeControlCallbacks),
95 CsisClient(CsisClientCallbacks),
96 CreateBondWithRetry(BluetoothDevice, BtTransport, u32, Duration),
97
98 // Actions within the stack
99 Media(MediaActions),
100 MediaCallbackDisconnected(u32),
101 TelephonyCallbackDisconnected(u32),
102
103 // Client callback disconnections
104 AdapterCallbackDisconnected(u32),
105 ConnectionCallbackDisconnected(u32),
106
107 AdapterActions(AdapterActions),
108
109 // Follows IBluetooth's on_device_(dis)connected and bond_state callbacks
110 // but doesn't require depending on Bluetooth.
111 // Params: Address, BR/EDR ACL state, BLE ACL state, bond state, transport
112 OnDeviceConnectionOrBondStateChanged(
113 RawAddress,
114 BtAclState,
115 BtAclState,
116 BtBondState,
117 BtTransport,
118 ),
119
120 // Suspend related
121 SuspendActions(SuspendActions),
122
123 // Scanner related
124 ScannerCallbackDisconnected(u32),
125
126 // Advertising related
127 AdvertiserCallbackDisconnected(u32),
128 AdvertiserActions(AdvertiserActions),
129
130 SocketManagerActions(SocketActions),
131 SocketManagerCallbackDisconnected(u32),
132
133 // Battery related
134 BatteryProviderManagerCallbackDisconnected(u32),
135 BatteryProviderManagerBatteryUpdated(RawAddress, BatterySet),
136 BatteryServiceCallbackDisconnected(u32),
137 BatteryService(BatteryServiceActions),
138 BatteryServiceRefresh,
139 BatteryManagerCallbackDisconnected(u32),
140
141 GattActions(GattActions),
142 GattClientCallbackDisconnected(u32),
143 GattServerCallbackDisconnected(u32),
144
145 // Admin policy related
146 AdminCallbackDisconnected(u32),
147 AdminActions(AdminActions),
148 HidHostEnable,
149
150 // Dis callbacks
151 Dis(ServiceCallbacks),
152
153 // Device removal
154 DisconnectDevice(BluetoothDevice),
155
156 // Qualification Only
157 QaCallbackDisconnected(u32),
158 QaAddMediaPlayer(String, bool),
159 QaRfcommSendMsc(u8, RawAddress),
160 QaFetchDiscoverableMode,
161 QaFetchConnectable,
162 QaSetConnectable(bool),
163 QaFetchAlias,
164 QaGetHidReport(RawAddress, BthhReportType, u8),
165 QaSetHidReport(RawAddress, BthhReportType, String),
166 QaSendHidData(RawAddress, String),
167 QaSendHidVirtualUnplug(RawAddress),
168
169 // UHid callbacks
170 UHidHfpOutputCallback(RawAddress, u8, u8),
171 UHidTelephonyUseCallback(RawAddress, bool),
172
173 // This message is sent when either HID, media, or GATT client, is disconnected.
174 // Note that meida sends this when the profiles are disconnected as a whole, that is, it will
175 // not be called when AVRCP is disconnected but not A2DP, as an example.
176 ProfileDisconnected(RawAddress),
177 }
178
179 /// Returns a callable object that dispatches a BTIF callback to Message
180 ///
181 /// The returned object would make sure the order of how the callbacks arrive the same as how they
182 /// goes to Message.
183 ///
184 /// Example
185 /// ```ignore
186 /// // Create a dispatcher in btstack
187 /// let gatt_client_callbacks_dispatcher = topshim::gatt::GattClientCallbacksDispatcher {
188 /// dispatch: make_message_dispatcher(tx.clone(), Message::GattClient),
189 /// };
190 ///
191 /// // Register the dispatcher to topshim
192 /// bt_topshim::topstack::get_dispatchers()
193 /// .lock()
194 /// .unwrap()
195 /// .set::<topshim::gatt::GattClientCb>(Arc::new(Mutex::new(gatt_client_callbacks_dispatcher)))
196 /// ```
make_message_dispatcher<F, Cb>(tx: Sender<Message>, f: F) -> Box<dyn Fn(Cb) + Send> where Cb: Send + 'static, F: Fn(Cb) -> Message + Send + Copy + 'static,197 pub(crate) fn make_message_dispatcher<F, Cb>(tx: Sender<Message>, f: F) -> Box<dyn Fn(Cb) + Send>
198 where
199 Cb: Send + 'static,
200 F: Fn(Cb) -> Message + Send + Copy + 'static,
201 {
202 let async_mutex = Arc::new(tokio::sync::Mutex::new(()));
203 let dispatch_queue = Arc::new(Mutex::new(std::collections::VecDeque::new()));
204
205 Box::new(move |cb| {
206 let tx = tx.clone();
207 let async_mutex = async_mutex.clone();
208 let dispatch_queue = dispatch_queue.clone();
209 // Enqueue the callbacks at the synchronized block to ensure the order.
210 dispatch_queue.lock().unwrap().push_back(cb);
211 bt_topshim::topstack::get_runtime().spawn(async move {
212 // Acquire the lock first to ensure |pop_front| and |tx.send| not
213 // interrupted by the other async threads.
214 let _guard = async_mutex.lock().await;
215 // Consume exactly one callback.
216 let cb = dispatch_queue.lock().unwrap().pop_front().unwrap();
217 let _ = tx.send(f(cb)).await;
218 });
219 })
220 }
221
222 pub enum BluetoothAPI {
223 Adapter,
224 Admin,
225 Battery,
226 Media,
227 Gatt,
228 }
229
230 /// Message types that are sent to the InterfaceManager's dispatch loop.
231 pub enum APIMessage {
232 /// Indicates a subcomponent is ready to receive DBus messages.
233 IsReady(BluetoothAPI),
234 /// Indicates bluetooth is shutting down, so we remove all DBus endpoints.
235 ShutDown,
236 }
237
238 /// Represents suspend mode of a module.
239 ///
240 /// Being in suspend mode means that the module pauses some activities if required for suspend and
241 /// some subsequent API calls will be blocked with a retryable error.
242 #[derive(FromPrimitive, ToPrimitive, Debug, PartialEq, Clone)]
243 pub enum SuspendMode {
244 Normal = 0,
245 Suspending = 1,
246 Suspended = 2,
247 Resuming = 3,
248 }
249
250 /// Umbrella class for the Bluetooth stack.
251 pub struct Stack {}
252
253 impl Stack {
254 /// Creates an mpsc channel for passing messages to the main dispatch loop.
create_channel() -> (Sender<Message>, Receiver<Message>)255 pub fn create_channel() -> (Sender<Message>, Receiver<Message>) {
256 channel::<Message>(1)
257 }
258
259 /// Runs the main dispatch loop.
dispatch( mut rx: Receiver<Message>, tx: Sender<Message>, api_tx: Sender<APIMessage>, bluetooth: Arc<Mutex<Box<Bluetooth>>>, bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>, battery_service: Arc<Mutex<Box<BatteryService>>>, battery_manager: Arc<Mutex<Box<BatteryManager>>>, battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>, suspend: Arc<Mutex<Box<Suspend>>>, bluetooth_socketmgr: Arc<Mutex<Box<BluetoothSocketManager>>>, bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>, bluetooth_dis: Arc<Mutex<Box<DeviceInformation>>>, bluetooth_qa: Arc<Mutex<Box<BluetoothQA>>>, )260 pub async fn dispatch(
261 mut rx: Receiver<Message>,
262 tx: Sender<Message>,
263 api_tx: Sender<APIMessage>,
264 bluetooth: Arc<Mutex<Box<Bluetooth>>>,
265 bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>,
266 battery_service: Arc<Mutex<Box<BatteryService>>>,
267 battery_manager: Arc<Mutex<Box<BatteryManager>>>,
268 battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>,
269 bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>,
270 suspend: Arc<Mutex<Box<Suspend>>>,
271 bluetooth_socketmgr: Arc<Mutex<Box<BluetoothSocketManager>>>,
272 bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>,
273 bluetooth_dis: Arc<Mutex<Box<DeviceInformation>>>,
274 bluetooth_qa: Arc<Mutex<Box<BluetoothQA>>>,
275 ) {
276 loop {
277 let m = rx.recv().await;
278
279 if m.is_none() {
280 eprintln!("Message dispatch loop quit");
281 break;
282 }
283
284 match m.unwrap() {
285 Message::InterfaceShutdown => {
286 let txl = api_tx.clone();
287 tokio::spawn(async move {
288 let _ = txl.send(APIMessage::ShutDown).await;
289 });
290 }
291
292 Message::AdapterShutdown(abort) => {
293 bluetooth_gatt.lock().unwrap().enable(false);
294 bluetooth.lock().unwrap().shutdown_adapter(abort);
295 }
296
297 Message::Cleanup => {
298 bluetooth.lock().unwrap().cleanup();
299 }
300
301 Message::CleanupProfiles => {
302 bluetooth_media.lock().unwrap().cleanup();
303 }
304
305 Message::AdapterReady => {
306 // Initialize objects that need the adapter to be fully
307 // enabled before running.
308
309 // Init Media and pass it to Bluetooth.
310 bluetooth_media.lock().unwrap().initialize();
311 bluetooth.lock().unwrap().set_media(bluetooth_media.clone());
312 // Init Gatt and pass it to Bluetooth.
313 bluetooth_gatt.lock().unwrap().init_profiles(api_tx.clone());
314 bluetooth_gatt.lock().unwrap().enable(true);
315 bluetooth.lock().unwrap().set_gatt_and_init_scanner(bluetooth_gatt.clone());
316 // Init AdvertiseManager. It selects the stack per is_le_ext_adv_supported
317 // so it can only be done after Adapter is ready.
318 bluetooth_gatt.lock().unwrap().init_adv_manager(bluetooth.clone());
319 // Battery service and device information service are on top of Gatt.
320 // Only initialize them after GATT is ready.
321 bluetooth_dis.lock().unwrap().initialize();
322 battery_service.lock().unwrap().init();
323 // Initialize Admin. This toggles the enabled profiles.
324 bluetooth_admin.lock().unwrap().initialize(api_tx.clone());
325 }
326
327 Message::A2dp(a) => {
328 bluetooth_media.lock().unwrap().dispatch_a2dp_callbacks(a);
329 }
330
331 Message::Avrcp(av) => {
332 bluetooth_media.lock().unwrap().dispatch_avrcp_callbacks(av);
333 }
334
335 Message::Base(b) => {
336 dispatch_base_callbacks(bluetooth.lock().unwrap().as_mut(), b);
337 }
338
339 // When pairing is busy for any reason, the bond cannot be created.
340 // Allow retries until it is ready for bonding.
341 Message::CreateBondWithRetry(device, bt_transport, num_attempts, retry_delay) => {
342 if num_attempts == 0 {
343 continue;
344 }
345
346 let mut bt = bluetooth.lock().unwrap();
347 if !bt.is_pairing_busy() {
348 bt.create_bond(device, bt_transport);
349 continue;
350 }
351
352 let txl = tx.clone();
353 tokio::spawn(async move {
354 sleep(retry_delay).await;
355 let _ = txl
356 .send(Message::CreateBondWithRetry(
357 device,
358 bt_transport,
359 num_attempts - 1,
360 retry_delay,
361 ))
362 .await;
363 });
364 }
365
366 Message::GattClient(m) => {
367 dispatch_gatt_client_callbacks(bluetooth_gatt.lock().unwrap().as_mut(), m);
368 }
369
370 Message::GattServer(m) => {
371 dispatch_gatt_server_callbacks(bluetooth_gatt.lock().unwrap().as_mut(), m);
372 }
373
374 Message::LeAudioClient(a) => {
375 bluetooth_media.lock().unwrap().dispatch_le_audio_callbacks(a);
376 }
377
378 Message::VolumeControl(a) => {
379 bluetooth_media.lock().unwrap().dispatch_vc_callbacks(a);
380 }
381
382 Message::CsisClient(a) => {
383 bluetooth_media.lock().unwrap().dispatch_csis_callbacks(a);
384 }
385
386 Message::LeScanner(m) => {
387 dispatch_le_scanner_callbacks(bluetooth_gatt.lock().unwrap().as_mut(), m);
388 }
389
390 Message::LeScannerInband(m) => {
391 dispatch_le_scanner_inband_callbacks(
392 bluetooth_gatt.lock().unwrap().as_mut(),
393 m,
394 );
395 }
396
397 Message::LeAdvInband(m) => {
398 debug!("Received LeAdvInband message: {:?}. This is unexpected!", m);
399 }
400
401 Message::LeAdv(m) => {
402 dispatch_le_adv_callbacks(bluetooth_gatt.lock().unwrap().as_mut(), m);
403 }
404
405 Message::Hfp(hf) => {
406 bluetooth_media.lock().unwrap().dispatch_hfp_callbacks(hf);
407 }
408
409 Message::HidHost(h) => {
410 dispatch_hid_host_callbacks(bluetooth.lock().unwrap().as_mut(), h);
411 }
412
413 Message::Sdp(s) => {
414 dispatch_sdp_callbacks(bluetooth.lock().unwrap().as_mut(), s);
415 }
416
417 Message::Media(action) => {
418 bluetooth_media.lock().unwrap().dispatch_media_actions(action);
419 }
420
421 Message::MediaCallbackDisconnected(cb_id) => {
422 bluetooth_media.lock().unwrap().remove_callback(cb_id);
423 }
424
425 Message::TelephonyCallbackDisconnected(cb_id) => {
426 bluetooth_media.lock().unwrap().remove_telephony_callback(cb_id);
427 }
428
429 Message::AdapterCallbackDisconnected(id) => {
430 bluetooth.lock().unwrap().adapter_callback_disconnected(id);
431 }
432
433 Message::ConnectionCallbackDisconnected(id) => {
434 bluetooth.lock().unwrap().connection_callback_disconnected(id);
435 }
436
437 Message::AdapterActions(action) => {
438 bluetooth.lock().unwrap().handle_actions(action);
439 }
440
441 // Any service needing an updated list of devices can have an update method
442 // triggered from here rather than needing a reference to Bluetooth.
443 Message::OnDeviceConnectionOrBondStateChanged(
444 addr,
445 _bredr_acl_state,
446 ble_acl_state,
447 bond_state,
448 _transport,
449 ) => {
450 if ble_acl_state == BtAclState::Connected && bond_state == BtBondState::Bonded {
451 info!("BAS: Connecting to {}", DisplayAddress(&addr));
452 battery_service.lock().unwrap().init_device(addr);
453 }
454 }
455
456 Message::SuspendActions(action) => {
457 suspend.lock().unwrap().handle_action(action);
458 }
459
460 Message::ScannerCallbackDisconnected(id) => {
461 bluetooth_gatt.lock().unwrap().remove_scanner_callback(id);
462 }
463
464 Message::AdvertiserCallbackDisconnected(id) => {
465 bluetooth_gatt.lock().unwrap().remove_adv_callback(id);
466 }
467
468 Message::AdvertiserActions(action) => {
469 bluetooth_gatt.lock().unwrap().handle_adv_action(action);
470 }
471
472 Message::SocketManagerActions(action) => {
473 bluetooth_socketmgr.lock().unwrap().handle_actions(action);
474 }
475 Message::SocketManagerCallbackDisconnected(id) => {
476 bluetooth_socketmgr.lock().unwrap().remove_callback(id);
477 }
478 Message::BatteryProviderManagerBatteryUpdated(remote_address, battery_set) => {
479 battery_manager
480 .lock()
481 .unwrap()
482 .handle_battery_updated(remote_address, battery_set);
483 }
484 Message::BatteryProviderManagerCallbackDisconnected(id) => {
485 battery_provider_manager.lock().unwrap().remove_battery_provider_callback(id);
486 }
487 Message::BatteryServiceCallbackDisconnected(id) => {
488 battery_service.lock().unwrap().remove_callback(id);
489 }
490 Message::BatteryService(action) => {
491 battery_service.lock().unwrap().handle_action(action);
492 }
493 Message::BatteryServiceRefresh => {
494 battery_service.lock().unwrap().refresh_all_devices();
495 }
496 Message::BatteryManagerCallbackDisconnected(id) => {
497 battery_manager.lock().unwrap().remove_callback(id);
498 }
499 Message::GattActions(action) => {
500 bluetooth_gatt.lock().unwrap().handle_action(action);
501 }
502 Message::GattClientCallbackDisconnected(id) => {
503 bluetooth_gatt.lock().unwrap().remove_client_callback(id);
504 }
505 Message::GattServerCallbackDisconnected(id) => {
506 bluetooth_gatt.lock().unwrap().remove_server_callback(id);
507 }
508 Message::AdminCallbackDisconnected(id) => {
509 bluetooth_admin.lock().unwrap().unregister_admin_policy_callback(id);
510 }
511 Message::AdminActions(action) => {
512 bluetooth_admin.lock().unwrap().handle_action(action);
513 }
514 Message::HidHostEnable => {
515 bluetooth.lock().unwrap().enable_hidhost();
516 }
517 Message::Dis(callback) => {
518 bluetooth_dis.lock().unwrap().handle_callbacks(&callback);
519 }
520 Message::DisconnectDevice(addr) => {
521 bluetooth.lock().unwrap().disconnect_all_enabled_profiles(addr);
522 }
523 // Qualification Only
524 Message::QaAddMediaPlayer(name, browsing_supported) => {
525 bluetooth_media.lock().unwrap().add_player(name, browsing_supported);
526 }
527 Message::QaRfcommSendMsc(dlci, addr) => {
528 bluetooth_socketmgr.lock().unwrap().rfcomm_send_msc(dlci, addr);
529 }
530 Message::QaCallbackDisconnected(id) => {
531 bluetooth_qa.lock().unwrap().unregister_qa_callback(id);
532 }
533 Message::QaFetchDiscoverableMode => {
534 let mode = bluetooth.lock().unwrap().get_discoverable_mode_internal();
535 bluetooth_qa.lock().unwrap().on_fetch_discoverable_mode_completed(mode);
536 }
537 Message::QaFetchConnectable => {
538 let connectable = bluetooth.lock().unwrap().get_connectable_internal();
539 bluetooth_qa.lock().unwrap().on_fetch_connectable_completed(connectable);
540 }
541 Message::QaSetConnectable(mode) => {
542 let succeed = bluetooth.lock().unwrap().set_connectable_internal(mode);
543 bluetooth_qa.lock().unwrap().on_set_connectable_completed(succeed);
544 }
545 Message::QaFetchAlias => {
546 let alias = bluetooth.lock().unwrap().get_alias_internal();
547 bluetooth_qa.lock().unwrap().on_fetch_alias_completed(alias);
548 }
549 Message::QaGetHidReport(addr, report_type, report_id) => {
550 let status = bluetooth.lock().unwrap().get_hid_report_internal(
551 addr,
552 report_type,
553 report_id,
554 );
555 bluetooth_qa.lock().unwrap().on_get_hid_report_completed(status);
556 }
557 Message::QaSetHidReport(addr, report_type, report) => {
558 let status = bluetooth.lock().unwrap().set_hid_report_internal(
559 addr,
560 report_type,
561 report,
562 );
563 bluetooth_qa.lock().unwrap().on_set_hid_report_completed(status);
564 }
565 Message::QaSendHidData(addr, data) => {
566 let status = bluetooth.lock().unwrap().send_hid_data_internal(addr, data);
567 bluetooth_qa.lock().unwrap().on_send_hid_data_completed(status);
568 }
569 Message::QaSendHidVirtualUnplug(addr) => {
570 let status = bluetooth.lock().unwrap().send_hid_virtual_unplug_internal(addr);
571 bluetooth_qa.lock().unwrap().on_send_hid_virtual_unplug_completed(status);
572 }
573
574 // UHid callbacks
575 Message::UHidHfpOutputCallback(addr, id, data) => {
576 bluetooth_media
577 .lock()
578 .unwrap()
579 .dispatch_uhid_hfp_output_callback(addr, id, data);
580 }
581
582 Message::UHidTelephonyUseCallback(addr, state) => {
583 bluetooth_media
584 .lock()
585 .unwrap()
586 .dispatch_uhid_telephony_use_callback(addr, state);
587 }
588
589 Message::ProfileDisconnected(addr) => {
590 let bas_app_uuid =
591 Uuid::from_string(String::from(BATTERY_SERVICE_GATT_CLIENT_APP_ID))
592 .expect("BAS Uuid failed to be parsed");
593 // Ideally we would also check that there are no open sockets for this device
594 // but Floss does not manage socket state so there is no reasonable way for us
595 // to know whether a socket is open or not.
596 if bluetooth_gatt.lock().unwrap().get_connected_applications(&addr)
597 == vec![bas_app_uuid]
598 && !bluetooth.lock().unwrap().is_initiated_hh_connection(&addr)
599 && bluetooth_media.lock().unwrap().get_connected_profiles(&addr).is_empty()
600 {
601 info!(
602 "BAS: Disconnecting from {} since it's the last active profile",
603 DisplayAddress(&addr)
604 );
605 battery_service.lock().unwrap().drop_device(addr);
606 }
607 }
608 }
609 }
610 }
611 }
612
613 /// Signifies that the object may be a proxy to a remote RPC object.
614 ///
615 /// An object that implements RPCProxy trait signifies that the object may be a proxy to a remote
616 /// RPC object. Therefore the object may be disconnected and thus should implement
617 /// `register_disconnect` to let others observe the disconnection event.
618 pub trait RPCProxy {
619 /// Registers disconnect observer that will be notified when the remote object is disconnected.
register_disconnect(&mut self, _f: Box<dyn Fn(u32) + Send>) -> u32620 fn register_disconnect(&mut self, _f: Box<dyn Fn(u32) + Send>) -> u32 {
621 0
622 }
623
624 /// Returns the ID of the object. For example this would be an object path in D-Bus RPC.
get_object_id(&self) -> String625 fn get_object_id(&self) -> String {
626 String::from("")
627 }
628
629 /// Unregisters callback with this id.
unregister(&mut self, _id: u32) -> bool630 fn unregister(&mut self, _id: u32) -> bool {
631 false
632 }
633
634 /// Makes this object available for remote call.
export_for_rpc(self: Box<Self>)635 fn export_for_rpc(self: Box<Self>) {}
636 }
637