1 use clap::{App, AppSettings, Arg};
2 use dbus_projection::DisconnectWatcher;
3 use dbus_tokio::connection;
4 use futures::future;
5 use lazy_static::lazy_static;
6 use nix::sys::signal;
7 use std::error::Error;
8 use std::sync::{Arc, Condvar, Mutex};
9 use std::time::Duration;
10 use tokio::sync::mpsc::Sender;
11 
12 // Necessary to link right entries.
13 #[allow(unused_imports)]
14 use bt_shim;
15 
16 use bt_topshim::{btif::get_btinterface, topstack};
17 use btstack::{
18     battery_manager::BatteryManager,
19     battery_provider_manager::BatteryProviderManager,
20     battery_service::BatteryService,
21     bluetooth::{Bluetooth, IBluetooth, SigData},
22     bluetooth_admin::BluetoothAdmin,
23     bluetooth_gatt::BluetoothGatt,
24     bluetooth_logging::BluetoothLogging,
25     bluetooth_media::BluetoothMedia,
26     bluetooth_qa::BluetoothQA,
27     dis::DeviceInformation,
28     socket_manager::BluetoothSocketManager,
29     suspend::Suspend,
30     Message, Stack,
31 };
32 
33 mod dbus_arg;
34 mod iface_battery_manager;
35 mod iface_battery_provider_manager;
36 mod iface_bluetooth;
37 mod iface_bluetooth_admin;
38 mod iface_bluetooth_gatt;
39 mod iface_bluetooth_media;
40 mod iface_bluetooth_qa;
41 mod iface_bluetooth_telephony;
42 mod iface_logging;
43 mod interface_manager;
44 
45 const DBUS_SERVICE_NAME: &str = "org.chromium.bluetooth";
46 const ADMIN_SETTINGS_FILE_PATH: &str = "/var/lib/bluetooth/admin_policy.json";
47 // The maximum ACL disconnect timeout is 3.5s defined by BTA_DM_DISABLE_TIMER_MS
48 // and BTA_DM_DISABLE_TIMER_RETRIAL_MS
49 const STACK_TURN_OFF_TIMEOUT_MS: Duration = Duration::from_millis(4000);
50 // Time bt_stack_manager waits for cleanup
51 const STACK_CLEANUP_TIMEOUT_MS: Duration = Duration::from_millis(1000);
52 
53 const INIT_LOGGING_MAX_RETRY: u8 = 3;
54 
55 /// Runs the Bluetooth daemon serving D-Bus IPC.
main() -> Result<(), Box<dyn Error>>56 fn main() -> Result<(), Box<dyn Error>> {
57     let matches = App::new("Bluetooth Adapter Daemon")
58         // Allows multiple INIT_ flags to be given at the end of the arguments.
59         .setting(AppSettings::TrailingVarArg)
60         .arg(
61             Arg::with_name("hci")
62                 .long("hci")
63                 .value_name("HCI")
64                 .takes_value(true)
65                 .help("The HCI index"),
66         )
67         .arg(
68             Arg::with_name("index")
69                 .long("index")
70                 .value_name("INDEX")
71                 .takes_value(true)
72                 .help("The Virtual index"),
73         )
74         .arg(Arg::with_name("debug").long("debug").short("d").help("Enables debug level logs"))
75         .arg(
76             Arg::with_name("verbose-debug")
77                 .long("verbose-debug")
78                 .short("v")
79                 .help("Enables VERBOSE and additional tags for debug logging. Use with --debug."),
80         )
81         .arg(Arg::from_usage("[init-flags] 'Fluoride INIT_ flags'").multiple(true))
82         .arg(
83             Arg::with_name("log-output")
84                 .long("log-output")
85                 .takes_value(true)
86                 .possible_values(&["syslog", "stderr"])
87                 .default_value("syslog")
88                 .help("Select log output"),
89         )
90         .get_matches();
91 
92     let is_debug = matches.is_present("debug");
93     let is_verbose_debug = matches.is_present("verbose-debug");
94     let log_output = matches.value_of("log-output").unwrap_or("syslog");
95 
96     let virt_index = matches.value_of("index").map_or(0, |idx| idx.parse::<i32>().unwrap_or(0));
97     let hci_index = matches.value_of("hci").map_or(0, |idx| idx.parse::<i32>().unwrap_or(0));
98 
99     // The remaining flags are passed down to Fluoride as is.
100     let mut init_flags: Vec<String> = match matches.values_of("init-flags") {
101         Some(args) => args.map(|s| String::from(s)).collect(),
102         None => vec![],
103     };
104 
105     // Forward --hci to Fluoride.
106     init_flags.push(format!("--hci={}", hci_index));
107 
108     let logging = Arc::new(Mutex::new(Box::new(BluetoothLogging::new(
109         is_debug,
110         is_verbose_debug,
111         log_output,
112     ))));
113     // TODO(b/307171804): Investigate why connecting to unix syslog might fail.
114     // Retry it a few times. Ignore the failure if fails too many times.
115     for _ in 0..INIT_LOGGING_MAX_RETRY {
116         match logging.lock().unwrap().initialize() {
117             Ok(_) => break,
118             Err(_) => continue,
119         }
120     }
121 
122     // Always treat discovery as classic only
123     init_flags.push(String::from("INIT_classic_discovery_only=true"));
124 
125     let (tx, rx) = Stack::create_channel();
126     let (api_tx, api_rx) = interface_manager::InterfaceManager::create_channel();
127     let sig_notifier = Arc::new(SigData {
128         enabled: Mutex::new(false),
129         enabled_notify: Condvar::new(),
130         thread_attached: Mutex::new(false),
131         thread_notify: Condvar::new(),
132     });
133 
134     let intf = Arc::new(Mutex::new(get_btinterface().unwrap()));
135     let bluetooth_gatt =
136         Arc::new(Mutex::new(Box::new(BluetoothGatt::new(intf.clone(), tx.clone()))));
137     let battery_provider_manager =
138         Arc::new(Mutex::new(Box::new(BatteryProviderManager::new(tx.clone()))));
139     let battery_service = Arc::new(Mutex::new(Box::new(BatteryService::new(
140         bluetooth_gatt.clone(),
141         battery_provider_manager.clone(),
142         tx.clone(),
143         api_tx.clone(),
144     ))));
145     let battery_manager = Arc::new(Mutex::new(Box::new(BatteryManager::new(
146         battery_provider_manager.clone(),
147         tx.clone(),
148     ))));
149     let bluetooth_media = Arc::new(Mutex::new(Box::new(BluetoothMedia::new(
150         tx.clone(),
151         intf.clone(),
152         battery_provider_manager.clone(),
153     ))));
154     let bluetooth_admin = Arc::new(Mutex::new(Box::new(BluetoothAdmin::new(
155         String::from(ADMIN_SETTINGS_FILE_PATH),
156         tx.clone(),
157     ))));
158     let bluetooth = Arc::new(Mutex::new(Box::new(Bluetooth::new(
159         virt_index,
160         hci_index,
161         tx.clone(),
162         api_tx.clone(),
163         sig_notifier.clone(),
164         intf.clone(),
165         bluetooth_admin.clone(),
166         bluetooth_gatt.clone(),
167         bluetooth_media.clone(),
168     ))));
169     let suspend = Arc::new(Mutex::new(Box::new(Suspend::new(
170         bluetooth.clone(),
171         intf.clone(),
172         bluetooth_gatt.clone(),
173         bluetooth_media.clone(),
174         tx.clone(),
175     ))));
176     let bt_sock_mgr = Arc::new(Mutex::new(Box::new(BluetoothSocketManager::new(
177         tx.clone(),
178         bluetooth_admin.clone(),
179     ))));
180     let bluetooth_qa = Arc::new(Mutex::new(Box::new(BluetoothQA::new(tx.clone()))));
181 
182     let dis =
183         Arc::new(Mutex::new(Box::new(DeviceInformation::new(bluetooth_gatt.clone(), tx.clone()))));
184 
185     topstack::get_runtime().block_on(async {
186         // Connect to D-Bus system bus.
187         let (resource, conn) = connection::new_system_sync()?;
188 
189         // The `resource` is a task that should be spawned onto a tokio compatible
190         // reactor ASAP. If the resource ever finishes, we lost connection to D-Bus.
191         let conn_join_handle = tokio::spawn(async {
192             let err = resource.await;
193             panic!("Lost connection to D-Bus: {}", err);
194         });
195 
196         // Request a service name and quit if not able to.
197         conn.request_name(DBUS_SERVICE_NAME, false, true, false).await?;
198 
199         // Run the stack main dispatch loop.
200         topstack::get_runtime().spawn(Stack::dispatch(
201             rx,
202             tx.clone(),
203             api_tx.clone(),
204             bluetooth.clone(),
205             bluetooth_gatt.clone(),
206             battery_service.clone(),
207             battery_manager.clone(),
208             battery_provider_manager.clone(),
209             bluetooth_media.clone(),
210             suspend.clone(),
211             bt_sock_mgr.clone(),
212             bluetooth_admin.clone(),
213             dis.clone(),
214             bluetooth_qa.clone(),
215         ));
216 
217         // Set up the disconnect watcher to monitor client disconnects.
218         let disconnect_watcher = Arc::new(Mutex::new(DisconnectWatcher::new()));
219         disconnect_watcher.lock().unwrap().setup_watch(conn.clone()).await;
220 
221         tokio::spawn(interface_manager::InterfaceManager::dispatch(
222             api_rx,
223             tx.clone(),
224             virt_index,
225             conn,
226             conn_join_handle,
227             disconnect_watcher.clone(),
228             bluetooth.clone(),
229             bluetooth_admin.clone(),
230             bluetooth_gatt.clone(),
231             battery_service.clone(),
232             battery_manager.clone(),
233             battery_provider_manager.clone(),
234             bluetooth_media.clone(),
235             bluetooth_qa.clone(),
236             bt_sock_mgr.clone(),
237             suspend.clone(),
238             logging.clone(),
239         ));
240 
241         // Hold locks and initialize all interfaces. This must be done AFTER DBus is
242         // initialized so DBus can properly enforce user policies.
243         {
244             let adapter = bluetooth.clone();
245             bluetooth_media.lock().unwrap().set_adapter(adapter.clone());
246             bluetooth_admin.lock().unwrap().set_adapter(adapter.clone());
247 
248             let mut bluetooth = bluetooth.lock().unwrap();
249             bluetooth.init(init_flags);
250             bluetooth.enable();
251 
252             bluetooth_gatt.lock().unwrap().init_profiles(tx.clone(), api_tx.clone());
253             bt_sock_mgr.lock().unwrap().initialize(intf.clone());
254 
255             // Install SIGTERM handler so that we can properly shutdown
256             *SIG_DATA.lock().unwrap() = Some((tx.clone(), sig_notifier.clone()));
257 
258             let sig_action_term = signal::SigAction::new(
259                 signal::SigHandler::Handler(handle_sigterm),
260                 signal::SaFlags::empty(),
261                 signal::SigSet::empty(),
262             );
263 
264             let sig_action_int = signal::SigAction::new(
265                 signal::SigHandler::Handler(handle_sigint),
266                 signal::SaFlags::empty(),
267                 signal::SigSet::empty(),
268             );
269 
270             unsafe {
271                 signal::sigaction(signal::SIGTERM, &sig_action_term).unwrap();
272                 signal::sigaction(signal::SIGINT, &sig_action_int).unwrap();
273             }
274         }
275 
276         // Serve clients forever.
277         future::pending::<()>().await;
278         unreachable!()
279     })
280 }
281 
282 lazy_static! {
283     /// Data needed for signal handling.
284     static ref SIG_DATA: Mutex<Option<(Sender<Message>, Arc<SigData>)>> = Mutex::new(None);
285 }
286 
handle_sigterm(_signum: i32)287 extern "C" fn handle_sigterm(_signum: i32) {
288     let guard = SIG_DATA.lock().unwrap();
289     if let Some((tx, notifier)) = guard.as_ref() {
290         log::debug!("Handling SIGTERM by disabling the adapter!");
291         let txl = tx.clone();
292         tokio::spawn(async move {
293             // Send the shutdown message here.
294             let _ = txl.send(Message::InterfaceShutdown).await;
295         });
296 
297         let guard = notifier.enabled.lock().unwrap();
298         if *guard {
299             log::debug!("Waiting for stack to turn off for {:?}", STACK_TURN_OFF_TIMEOUT_MS);
300             let _ = notifier.enabled_notify.wait_timeout(guard, STACK_TURN_OFF_TIMEOUT_MS);
301         }
302 
303         log::debug!("SIGTERM cleaning up the stack.");
304         let txl = tx.clone();
305         tokio::spawn(async move {
306             // Send the cleanup message here.
307             let _ = txl.send(Message::Cleanup).await;
308         });
309 
310         let guard = notifier.thread_attached.lock().unwrap();
311         if *guard {
312             log::debug!("Waiting for stack to clean up for {:?}", STACK_CLEANUP_TIMEOUT_MS);
313             let _ = notifier.thread_notify.wait_timeout(guard, STACK_CLEANUP_TIMEOUT_MS);
314         }
315     }
316 
317     log::debug!("Sigterm completed");
318     std::process::exit(0);
319 }
320 
handle_sigint(_signum: i32)321 extern "C" fn handle_sigint(_signum: i32) {
322     // Assumed this is from HAL Host, which is likely caused by chipset error.
323     // In this case, don't crash the daemon and don't try to power off the adapter.
324     log::debug!("Sigint completed");
325     std::process::exit(0);
326 }
327