1 use dbus::{channel::MatchingReceiver, message::MatchRule, nonblock::SyncConnection};
2 use dbus_crossroads::Crossroads;
3 use dbus_projection::DisconnectWatcher;
4 
5 use std::sync::{Arc, Mutex};
6 use tokio::sync::mpsc::{channel, Receiver, Sender};
7 
8 use btstack::{
9     battery_manager::BatteryManager, battery_provider_manager::BatteryProviderManager,
10     battery_service::BatteryService, bluetooth::Bluetooth, bluetooth::IBluetooth,
11     bluetooth_admin::BluetoothAdmin, bluetooth_gatt::BluetoothGatt,
12     bluetooth_logging::BluetoothLogging, bluetooth_media::BluetoothMedia,
13     bluetooth_qa::BluetoothQA, socket_manager::BluetoothSocketManager, suspend::Suspend,
14     APIMessage, BluetoothAPI, Message,
15 };
16 
17 use crate::iface_battery_manager;
18 use crate::iface_battery_provider_manager;
19 use crate::iface_bluetooth;
20 use crate::iface_bluetooth_admin;
21 use crate::iface_bluetooth_gatt;
22 use crate::iface_bluetooth_media;
23 use crate::iface_bluetooth_qa;
24 use crate::iface_bluetooth_telephony;
25 use crate::iface_logging;
26 
27 pub(crate) struct InterfaceManager {}
28 
29 impl InterfaceManager {
make_object_name(idx: i32, name: &str) -> String30     fn make_object_name(idx: i32, name: &str) -> String {
31         format!("/org/chromium/bluetooth/hci{}/{}", idx, name)
32     }
33 
34     /// Creates an mpsc channel for passing messages to the main dispatch loop.
create_channel() -> (Sender<APIMessage>, Receiver<APIMessage>)35     pub fn create_channel() -> (Sender<APIMessage>, Receiver<APIMessage>) {
36         channel::<APIMessage>(1)
37     }
38 
39     /// Runs the dispatch loop for APIMessage
40     ///
41     /// # Arguments
42     ///
43     /// * `rx` - The receiver channel for APIMessage
44     /// * `tx` - The sender channel for Message
45     /// * `virt_index` - The virtual index of the adapter
46     /// * `conn` - The DBus connection
47     /// * `conn_join_handle` - The thread handle that's maintaining the DBus resource
48     /// * `disconnect_watcher` - DisconnectWatcher to monitor client disconnects
49     /// * `bluetooth` - Implementation of the Bluetooth API
50     /// other implementations follow.
51     ///
dispatch( mut rx: Receiver<APIMessage>, tx: Sender<Message>, virt_index: i32, conn: Arc<SyncConnection>, conn_join_handle: tokio::task::JoinHandle<()>, disconnect_watcher: Arc<Mutex<DisconnectWatcher>>, bluetooth: Arc<Mutex<Box<Bluetooth>>>, bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>, 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>>>, bluetooth_qa: Arc<Mutex<Box<BluetoothQA>>>, bt_sock_mgr: Arc<Mutex<Box<BluetoothSocketManager>>>, suspend: Arc<Mutex<Box<Suspend>>>, logging: Arc<Mutex<Box<BluetoothLogging>>>, )52     pub async fn dispatch(
53         mut rx: Receiver<APIMessage>,
54         tx: Sender<Message>,
55         virt_index: i32,
56         conn: Arc<SyncConnection>,
57         conn_join_handle: tokio::task::JoinHandle<()>,
58         disconnect_watcher: Arc<Mutex<DisconnectWatcher>>,
59         bluetooth: Arc<Mutex<Box<Bluetooth>>>,
60         bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>,
61         bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>,
62         battery_service: Arc<Mutex<Box<BatteryService>>>,
63         battery_manager: Arc<Mutex<Box<BatteryManager>>>,
64         battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>,
65         bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>,
66         bluetooth_qa: Arc<Mutex<Box<BluetoothQA>>>,
67         bt_sock_mgr: Arc<Mutex<Box<BluetoothSocketManager>>>,
68         suspend: Arc<Mutex<Box<Suspend>>>,
69         logging: Arc<Mutex<Box<BluetoothLogging>>>,
70     ) {
71         // Prepare D-Bus interfaces.
72         let cr = Arc::new(Mutex::new(Crossroads::new()));
73         cr.lock().unwrap().set_async_support(Some((
74             conn.clone(),
75             Box::new(|x| {
76                 tokio::spawn(x);
77             }),
78         )));
79 
80         // Announce the exported adapter objects so that clients can properly detect the readiness
81         // of the adapter APIs.
82         cr.lock().unwrap().set_object_manager_support(Some(conn.clone()));
83         let object_manager = cr.lock().unwrap().object_manager();
84         cr.lock().unwrap().insert("/", &[object_manager], {});
85 
86         // Set up handling of D-Bus methods. This must be done before exporting interfaces so that
87         // clients that rely on InterfacesAdded signal can rely on us being ready to handle methods
88         // on those exported interfaces.
89         let cr_clone = cr.clone();
90         conn.start_receive(
91             MatchRule::new_method_call(),
92             Box::new(move |msg, conn| {
93                 cr_clone.lock().unwrap().handle_message(msg, conn).unwrap();
94                 true
95             }),
96         );
97 
98         // Register D-Bus method handlers of IBluetooth.
99         let adapter_iface = iface_bluetooth::export_bluetooth_dbus_intf(
100             conn.clone(),
101             &mut cr.lock().unwrap(),
102             disconnect_watcher.clone(),
103         );
104         let qa_iface = iface_bluetooth_qa::export_bluetooth_qa_dbus_intf(
105             conn.clone(),
106             &mut cr.lock().unwrap(),
107             disconnect_watcher.clone(),
108         );
109         let qa_legacy_iface = iface_bluetooth::export_bluetooth_qa_legacy_dbus_intf(
110             conn.clone(),
111             &mut cr.lock().unwrap(),
112             disconnect_watcher.clone(),
113         );
114         let socket_mgr_iface = iface_bluetooth::export_socket_mgr_intf(
115             conn.clone(),
116             &mut cr.lock().unwrap(),
117             disconnect_watcher.clone(),
118         );
119         let suspend_iface = iface_bluetooth::export_suspend_dbus_intf(
120             conn.clone(),
121             &mut cr.lock().unwrap(),
122             disconnect_watcher.clone(),
123         );
124         let logging_iface = iface_logging::export_bluetooth_logging_dbus_intf(
125             conn.clone(),
126             &mut cr.lock().unwrap(),
127             disconnect_watcher.clone(),
128         );
129 
130         // Register D-Bus method handlers of IBluetoothGatt.
131         let gatt_iface = iface_bluetooth_gatt::export_bluetooth_gatt_dbus_intf(
132             conn.clone(),
133             &mut cr.lock().unwrap(),
134             disconnect_watcher.clone(),
135         );
136 
137         let media_iface = iface_bluetooth_media::export_bluetooth_media_dbus_intf(
138             conn.clone(),
139             &mut cr.lock().unwrap(),
140             disconnect_watcher.clone(),
141         );
142 
143         let telephony_iface = iface_bluetooth_telephony::export_bluetooth_telephony_dbus_intf(
144             conn.clone(),
145             &mut cr.lock().unwrap(),
146             disconnect_watcher.clone(),
147         );
148 
149         let battery_provider_manager_iface =
150             iface_battery_provider_manager::export_battery_provider_manager_dbus_intf(
151                 conn.clone(),
152                 &mut cr.lock().unwrap(),
153                 disconnect_watcher.clone(),
154             );
155 
156         let battery_manager_iface = iface_battery_manager::export_battery_manager_dbus_intf(
157             conn.clone(),
158             &mut cr.lock().unwrap(),
159             disconnect_watcher.clone(),
160         );
161 
162         let admin_iface = iface_bluetooth_admin::export_bluetooth_admin_dbus_intf(
163             conn.clone(),
164             &mut cr.lock().unwrap(),
165             disconnect_watcher.clone(),
166         );
167 
168         // Create mixin object for Bluetooth + Suspend interfaces.
169         let mixin = Box::new(iface_bluetooth::BluetoothMixin {
170             adapter: bluetooth.clone(),
171             qa: bluetooth.clone(),
172             suspend: suspend.clone(),
173             socket_mgr: bt_sock_mgr.clone(),
174         });
175 
176         loop {
177             let m = rx.recv().await;
178 
179             if m.is_none() {
180                 eprintln!("APIMessage dispatch loop quit");
181                 break;
182             }
183 
184             match m.unwrap() {
185                 APIMessage::IsReady(api) => match api {
186                     BluetoothAPI::Adapter => {
187                         cr.lock().unwrap().insert(
188                             Self::make_object_name(virt_index, "adapter"),
189                             &[adapter_iface, qa_legacy_iface, socket_mgr_iface, suspend_iface],
190                             mixin.clone(),
191                         );
192 
193                         cr.lock().unwrap().insert(
194                             Self::make_object_name(virt_index, "admin"),
195                             &[admin_iface],
196                             bluetooth_admin.clone(),
197                         );
198 
199                         cr.lock().unwrap().insert(
200                             Self::make_object_name(virt_index, "logging"),
201                             &[logging_iface],
202                             logging.clone(),
203                         );
204 
205                         cr.lock().unwrap().insert(
206                             Self::make_object_name(virt_index, "qa"),
207                             &[qa_iface],
208                             bluetooth_qa.clone(),
209                         );
210 
211                         // AdvertiseManager selects the stack per is_le_ext_adv_supported.
212                         // Initialize it after Adapter is ready.
213                         let bt_clone = bluetooth.clone();
214                         let gatt_clone = bluetooth_gatt.clone();
215                         tokio::spawn(async move {
216                             let is_le_ext_adv_supported =
217                                 bt_clone.lock().unwrap().is_le_extended_advertising_supported();
218                             gatt_clone
219                                 .lock()
220                                 .unwrap()
221                                 .init_adv_manager(bt_clone, is_le_ext_adv_supported);
222                         });
223                     }
224                     BluetoothAPI::Gatt => {
225                         cr.lock().unwrap().insert(
226                             Self::make_object_name(virt_index, "gatt"),
227                             &[gatt_iface],
228                             bluetooth_gatt.clone(),
229                         );
230 
231                         // Battery service is on top of Gatt. Only initialize it after
232                         // GATT is ready.
233                         let bs = battery_service.clone();
234                         tokio::spawn(async move {
235                             bs.lock().unwrap().init();
236                         });
237                     }
238                     BluetoothAPI::Media => {
239                         cr.lock().unwrap().insert(
240                             Self::make_object_name(virt_index, "media"),
241                             &[media_iface],
242                             bluetooth_media.clone(),
243                         );
244 
245                         cr.lock().unwrap().insert(
246                             Self::make_object_name(virt_index, "telephony"),
247                             &[telephony_iface],
248                             bluetooth_media.clone(),
249                         );
250                     }
251                     BluetoothAPI::Battery => {
252                         cr.lock().unwrap().insert(
253                             Self::make_object_name(virt_index, "battery_provider_manager"),
254                             &[battery_provider_manager_iface],
255                             battery_provider_manager.clone(),
256                         );
257 
258                         cr.lock().unwrap().insert(
259                             Self::make_object_name(virt_index, "battery_manager"),
260                             &[battery_manager_iface],
261                             battery_manager.clone(),
262                         );
263                     }
264                 },
265 
266                 APIMessage::ShutDown => {
267                     // To shut down the connection, call _handle.abort() and drop the connection.
268                     conn_join_handle.abort();
269                     drop(conn);
270 
271                     let tx = tx.clone();
272                     tokio::spawn(async move {
273                         let _ = tx.send(Message::AdapterShutdown).await;
274                     });
275                     break;
276                 }
277             }
278         }
279     }
280 }
281