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