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