• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use btstack::bluetooth_qa::BluetoothQA;
2 use clap::{App, AppSettings, Arg};
3 use dbus::{channel::MatchingReceiver, message::MatchRule};
4 use dbus_crossroads::Crossroads;
5 use dbus_tokio::connection;
6 use futures::future;
7 use lazy_static::lazy_static;
8 use nix::sys::signal;
9 use std::error::Error;
10 use std::sync::{Arc, Condvar, Mutex};
11 use std::time::Duration;
12 use tokio::time;
13 
14 // Necessary to link right entries.
15 #[allow(unused_imports)]
16 use bt_shim;
17 
18 use bt_topshim::{btif::get_btinterface, topstack};
19 use btstack::{
20     battery_manager::BatteryManager,
21     battery_provider_manager::BatteryProviderManager,
22     battery_service::BatteryService,
23     bluetooth::{get_bt_dispatcher, Bluetooth, IBluetooth},
24     bluetooth_admin::BluetoothAdmin,
25     bluetooth_gatt::BluetoothGatt,
26     bluetooth_logging::BluetoothLogging,
27     bluetooth_media::BluetoothMedia,
28     dis::DeviceInformation,
29     socket_manager::BluetoothSocketManager,
30     suspend::Suspend,
31     Message, Stack,
32 };
33 use dbus_projection::DisconnectWatcher;
34 use tokio::sync::mpsc::Sender;
35 
36 mod dbus_arg;
37 mod iface_battery_manager;
38 mod iface_battery_provider_manager;
39 mod iface_bluetooth;
40 mod iface_bluetooth_admin;
41 mod iface_bluetooth_gatt;
42 mod iface_bluetooth_media;
43 mod iface_bluetooth_qa;
44 mod iface_bluetooth_telephony;
45 mod iface_logging;
46 
47 const DBUS_SERVICE_NAME: &str = "org.chromium.bluetooth";
48 const ADMIN_SETTINGS_FILE_PATH: &str = "/var/lib/bluetooth/admin_policy.json";
49 // The maximum ACL disconnect timeout is 3.5s defined by BTA_DM_DISABLE_TIMER_MS
50 // and BTA_DM_DISABLE_TIMER_RETRIAL_MS
51 const STACK_TURN_OFF_TIMEOUT_MS: Duration = Duration::from_millis(4000);
52 
53 const VERBOSE_ONLY_LOG_TAGS: &[&str] = &[
54     "bt_bta_av", // AV apis
55     "btm_sco",   // SCO data path logs
56     "l2c_csm",   // L2CAP state machine
57     "l2c_link",  // L2CAP link layer logs
58     "sco_hci",   // SCO over HCI
59     "uipc",      // Userspace IPC implementation
60 ];
61 
make_object_name(idx: i32, name: &str) -> String62 fn make_object_name(idx: i32, name: &str) -> String {
63     String::from(format!("/org/chromium/bluetooth/hci{}/{}", idx, name))
64 }
65 
66 /// Runs the Bluetooth daemon serving D-Bus IPC.
main() -> Result<(), Box<dyn Error>>67 fn main() -> Result<(), Box<dyn Error>> {
68     let matches = App::new("Bluetooth Adapter Daemon")
69         // Allows multiple INIT_ flags to be given at the end of the arguments.
70         .setting(AppSettings::TrailingVarArg)
71         .arg(
72             Arg::with_name("hci")
73                 .long("hci")
74                 .value_name("HCI")
75                 .takes_value(true)
76                 .help("The HCI index"),
77         )
78         .arg(
79             Arg::with_name("index")
80                 .long("index")
81                 .value_name("INDEX")
82                 .takes_value(true)
83                 .help("The Virtual index"),
84         )
85         .arg(Arg::with_name("debug").long("debug").short("d").help("Enables debug level logs"))
86         .arg(
87             Arg::with_name("verbose-debug")
88                 .long("verbose-debug")
89                 .short("v")
90                 .help("Enables VERBOSE and additional tags for debug logging. Use with --debug."),
91         )
92         .arg(Arg::from_usage("[init-flags] 'Fluoride INIT_ flags'").multiple(true))
93         .arg(
94             Arg::with_name("log-output")
95                 .long("log-output")
96                 .takes_value(true)
97                 .possible_values(&["syslog", "stderr"])
98                 .default_value("syslog")
99                 .help("Select log output"),
100         )
101         .get_matches();
102 
103     let is_debug = matches.is_present("debug");
104     let is_verbose_debug = matches.is_present("verbose-debug");
105     let log_output = matches.value_of("log-output").unwrap_or("syslog");
106 
107     let adapter_index = matches.value_of("index").map_or(0, |idx| idx.parse::<i32>().unwrap_or(0));
108     let hci_index = matches.value_of("hci").map_or(0, |idx| idx.parse::<i32>().unwrap_or(0));
109 
110     // The remaining flags are passed down to Fluoride as is.
111     let mut init_flags: Vec<String> = match matches.values_of("init-flags") {
112         Some(args) => args.map(|s| String::from(s)).collect(),
113         None => vec![],
114     };
115 
116     // Set GD debug flag if debug is enabled.
117     if is_debug {
118         // Limit tags if verbose debug logging isn't enabled.
119         if !is_verbose_debug {
120             init_flags.push(format!(
121                 "INIT_logging_debug_disabled_for_tags={}",
122                 VERBOSE_ONLY_LOG_TAGS.join(",")
123             ));
124             init_flags.push(String::from("INIT_default_log_level_str=LOG_DEBUG"));
125         } else {
126             init_flags.push(String::from("INIT_default_log_level_str=LOG_VERBOSE"));
127         }
128     }
129 
130     // Forward --hci to Fluoride.
131     init_flags.push(format!("--hci={}", hci_index));
132     let logging = Arc::new(Mutex::new(Box::new(BluetoothLogging::new(is_debug, log_output))));
133 
134     // Always treat discovery as classic only
135     init_flags.push(String::from("INIT_classic_discovery_only=true"));
136 
137     let (tx, rx) = Stack::create_channel();
138     let sig_notifier = Arc::new((Mutex::new(false), Condvar::new()));
139 
140     let intf = Arc::new(Mutex::new(get_btinterface().unwrap()));
141     let bluetooth_gatt =
142         Arc::new(Mutex::new(Box::new(BluetoothGatt::new(intf.clone(), tx.clone()))));
143     let battery_provider_manager =
144         Arc::new(Mutex::new(Box::new(BatteryProviderManager::new(tx.clone()))));
145     let battery_service = Arc::new(Mutex::new(Box::new(BatteryService::new(
146         bluetooth_gatt.clone(),
147         battery_provider_manager.clone(),
148         tx.clone(),
149     ))));
150     let battery_manager = Arc::new(Mutex::new(Box::new(BatteryManager::new(
151         battery_provider_manager.clone(),
152         tx.clone(),
153     ))));
154     let bluetooth_media = Arc::new(Mutex::new(Box::new(BluetoothMedia::new(
155         tx.clone(),
156         intf.clone(),
157         battery_provider_manager.clone(),
158     ))));
159     let bluetooth_admin = Arc::new(Mutex::new(Box::new(BluetoothAdmin::new(
160         String::from(ADMIN_SETTINGS_FILE_PATH),
161         tx.clone(),
162     ))));
163     let bluetooth = Arc::new(Mutex::new(Box::new(Bluetooth::new(
164         adapter_index,
165         tx.clone(),
166         sig_notifier.clone(),
167         intf.clone(),
168         bluetooth_admin.clone(),
169         bluetooth_gatt.clone(),
170         bluetooth_media.clone(),
171     ))));
172     let suspend = Arc::new(Mutex::new(Box::new(Suspend::new(
173         bluetooth.clone(),
174         intf.clone(),
175         bluetooth_gatt.clone(),
176         bluetooth_media.clone(),
177         tx.clone(),
178     ))));
179     let bt_sock_mgr = Arc::new(Mutex::new(Box::new(BluetoothSocketManager::new(
180         tx.clone(),
181         bluetooth_admin.clone(),
182     ))));
183     let bluetooth_qa = Arc::new(Mutex::new(Box::new(BluetoothQA::new(tx.clone()))));
184 
185     let dis =
186         Arc::new(Mutex::new(Box::new(DeviceInformation::new(bluetooth_gatt.clone(), tx.clone()))));
187 
188     topstack::get_runtime().block_on(async {
189         // Connect to D-Bus system bus.
190         let (resource, conn) = connection::new_system_sync()?;
191 
192         // The `resource` is a task that should be spawned onto a tokio compatible
193         // reactor ASAP. If the resource ever finishes, we lost connection to D-Bus.
194         tokio::spawn(async {
195             let err = resource.await;
196             panic!("Lost connection to D-Bus: {}", err);
197         });
198 
199         // Request a service name and quit if not able to.
200         conn.request_name(DBUS_SERVICE_NAME, false, true, false).await?;
201 
202         // Prepare D-Bus interfaces.
203         let cr = Arc::new(Mutex::new(Crossroads::new()));
204         cr.lock().unwrap().set_async_support(Some((
205             conn.clone(),
206             Box::new(|x| {
207                 tokio::spawn(x);
208             }),
209         )));
210 
211         // Announce the exported adapter objects so that clients can properly detect the readiness
212         // of the adapter APIs.
213         cr.lock().unwrap().set_object_manager_support(Some(conn.clone()));
214         let object_manager = cr.lock().unwrap().object_manager();
215         cr.lock().unwrap().insert("/", &[object_manager], {});
216 
217         // Run the stack main dispatch loop.
218         topstack::get_runtime().spawn(Stack::dispatch(
219             rx,
220             bluetooth.clone(),
221             bluetooth_gatt.clone(),
222             battery_service.clone(),
223             battery_manager.clone(),
224             battery_provider_manager.clone(),
225             bluetooth_media.clone(),
226             suspend.clone(),
227             bt_sock_mgr.clone(),
228             bluetooth_admin.clone(),
229             dis.clone(),
230             bluetooth_qa.clone(),
231         ));
232 
233         // Set up the disconnect watcher to monitor client disconnects.
234         let disconnect_watcher = Arc::new(Mutex::new(DisconnectWatcher::new()));
235         disconnect_watcher.lock().unwrap().setup_watch(conn.clone()).await;
236 
237         // Set up handling of D-Bus methods. This must be done before exporting interfaces so that
238         // clients that rely on InterfacesAdded signal can rely on us being ready to handle methods
239         // on those exported interfaces.
240         let cr_clone = cr.clone();
241         conn.start_receive(
242             MatchRule::new_method_call(),
243             Box::new(move |msg, conn| {
244                 cr_clone.lock().unwrap().handle_message(msg, conn).unwrap();
245                 true
246             }),
247         );
248 
249         // Register D-Bus method handlers of IBluetooth.
250         let adapter_iface = iface_bluetooth::export_bluetooth_dbus_intf(
251             conn.clone(),
252             &mut cr.lock().unwrap(),
253             disconnect_watcher.clone(),
254         );
255         let qa_iface = iface_bluetooth_qa::export_bluetooth_qa_dbus_intf(
256             conn.clone(),
257             &mut cr.lock().unwrap(),
258             disconnect_watcher.clone(),
259         );
260         let qa_legacy_iface = iface_bluetooth::export_bluetooth_qa_legacy_dbus_intf(
261             conn.clone(),
262             &mut cr.lock().unwrap(),
263             disconnect_watcher.clone(),
264         );
265         let socket_mgr_iface = iface_bluetooth::export_socket_mgr_intf(
266             conn.clone(),
267             &mut cr.lock().unwrap(),
268             disconnect_watcher.clone(),
269         );
270         let suspend_iface = iface_bluetooth::export_suspend_dbus_intf(
271             conn.clone(),
272             &mut cr.lock().unwrap(),
273             disconnect_watcher.clone(),
274         );
275         let logging_iface = iface_logging::export_bluetooth_logging_dbus_intf(
276             conn.clone(),
277             &mut cr.lock().unwrap(),
278             disconnect_watcher.clone(),
279         );
280 
281         // Register D-Bus method handlers of IBluetoothGatt.
282         let gatt_iface = iface_bluetooth_gatt::export_bluetooth_gatt_dbus_intf(
283             conn.clone(),
284             &mut cr.lock().unwrap(),
285             disconnect_watcher.clone(),
286         );
287 
288         let media_iface = iface_bluetooth_media::export_bluetooth_media_dbus_intf(
289             conn.clone(),
290             &mut cr.lock().unwrap(),
291             disconnect_watcher.clone(),
292         );
293 
294         let telephony_iface = iface_bluetooth_telephony::export_bluetooth_telephony_dbus_intf(
295             conn.clone(),
296             &mut cr.lock().unwrap(),
297             disconnect_watcher.clone(),
298         );
299 
300         let battery_provider_manager_iface =
301             iface_battery_provider_manager::export_battery_provider_manager_dbus_intf(
302                 conn.clone(),
303                 &mut cr.lock().unwrap(),
304                 disconnect_watcher.clone(),
305             );
306 
307         let battery_manager_iface = iface_battery_manager::export_battery_manager_dbus_intf(
308             conn.clone(),
309             &mut cr.lock().unwrap(),
310             disconnect_watcher.clone(),
311         );
312 
313         let admin_iface = iface_bluetooth_admin::export_bluetooth_admin_dbus_intf(
314             conn.clone(),
315             &mut cr.lock().unwrap(),
316             disconnect_watcher.clone(),
317         );
318 
319         // Create mixin object for Bluetooth + Suspend interfaces.
320         let mixin = Box::new(iface_bluetooth::BluetoothMixin {
321             adapter: bluetooth.clone(),
322             qa: bluetooth.clone(),
323             suspend: suspend.clone(),
324             socket_mgr: bt_sock_mgr.clone(),
325         });
326 
327         cr.lock().unwrap().insert(
328             make_object_name(adapter_index, "adapter"),
329             &[adapter_iface, qa_legacy_iface, socket_mgr_iface, suspend_iface],
330             mixin,
331         );
332 
333         cr.lock().unwrap().insert(
334             make_object_name(adapter_index, "gatt"),
335             &[gatt_iface],
336             bluetooth_gatt.clone(),
337         );
338 
339         cr.lock().unwrap().insert(
340             make_object_name(adapter_index, "media"),
341             &[media_iface],
342             bluetooth_media.clone(),
343         );
344 
345         cr.lock().unwrap().insert(
346             make_object_name(adapter_index, "telephony"),
347             &[telephony_iface],
348             bluetooth_media.clone(),
349         );
350 
351         cr.lock().unwrap().insert(
352             make_object_name(adapter_index, "battery_provider_manager"),
353             &[battery_provider_manager_iface],
354             battery_provider_manager.clone(),
355         );
356 
357         cr.lock().unwrap().insert(
358             make_object_name(adapter_index, "battery_manager"),
359             &[battery_manager_iface],
360             battery_manager.clone(),
361         );
362 
363         cr.lock().unwrap().insert(
364             make_object_name(adapter_index, "admin"),
365             &[admin_iface],
366             bluetooth_admin.clone(),
367         );
368 
369         cr.lock().unwrap().insert(
370             make_object_name(adapter_index, "logging"),
371             &[logging_iface],
372             logging.clone(),
373         );
374 
375         cr.lock().unwrap().insert(
376             make_object_name(adapter_index, "qa"),
377             &[qa_iface],
378             bluetooth_qa.clone(),
379         );
380 
381         // Hold locks and initialize all interfaces. This must be done AFTER DBus is
382         // initialized so DBus can properly enforce user policies.
383         {
384             intf.lock().unwrap().initialize(get_bt_dispatcher(tx.clone()), init_flags);
385 
386             let adapter = bluetooth.clone();
387             bluetooth_media.lock().unwrap().set_adapter(adapter.clone());
388             bluetooth_admin.lock().unwrap().set_adapter(adapter.clone());
389 
390             let mut bluetooth = bluetooth.lock().unwrap();
391             bluetooth.init_profiles();
392             bluetooth.enable();
393 
394             bluetooth_gatt.lock().unwrap().init_profiles(tx.clone(), adapter.clone());
395             // TODO(b/247093293): Gatt topshim api is only usable some
396             // time after init. Investigate why this delay is needed
397             // and make it a blocking part of init before removing
398             // this.
399             tokio::spawn(async move {
400                 time::sleep(Duration::from_millis(500)).await;
401                 battery_service.lock().unwrap().init();
402             });
403             bt_sock_mgr.lock().unwrap().initialize(intf.clone());
404 
405             // Install SIGTERM handler so that we can properly shutdown
406             *SIG_DATA.lock().unwrap() = Some((tx.clone(), sig_notifier.clone()));
407 
408             let sig_action = signal::SigAction::new(
409                 signal::SigHandler::Handler(handle_sigterm),
410                 signal::SaFlags::empty(),
411                 signal::SigSet::empty(),
412             );
413 
414             unsafe {
415                 signal::sigaction(signal::SIGTERM, &sig_action).unwrap();
416             }
417         }
418 
419         // Initialize the bluetooth_qa
420         bluetooth.lock().unwrap().cache_discoverable_mode_into_qa();
421 
422         // Serve clients forever.
423         future::pending::<()>().await;
424         unreachable!()
425     })
426 }
427 
428 lazy_static! {
429     /// Data needed for signal handling.
430     static ref SIG_DATA: Mutex<Option<(Sender<Message>, Arc<(Mutex<bool>, Condvar)>)>> = Mutex::new(None);
431 }
432 
handle_sigterm(_signum: i32)433 extern "C" fn handle_sigterm(_signum: i32) {
434     let guard = SIG_DATA.lock().unwrap();
435     if let Some((tx, notifier)) = guard.as_ref() {
436         log::debug!("Handling SIGTERM by disabling the adapter!");
437         let txl = tx.clone();
438         tokio::spawn(async move {
439             // Send the shutdown message here.
440             let _ = txl.send(Message::Shutdown).await;
441         });
442 
443         let guard = notifier.0.lock().unwrap();
444         if *guard {
445             log::debug!("Waiting for stack to turn off for {:?}", STACK_TURN_OFF_TIMEOUT_MS);
446             let _ = notifier.1.wait_timeout(guard, STACK_TURN_OFF_TIMEOUT_MS);
447         }
448     }
449 
450     log::debug!("Sigterm completed");
451     std::process::exit(0);
452 }
453