• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use clap::{App, AppSettings, Arg};
2 use dbus_projection::DisconnectWatcher;
3 use dbus_tokio::connection;
4 use futures::future;
5 use nix::sys::signal;
6 use std::error::Error;
7 use std::sync::{Arc, Condvar, Mutex};
8 use std::time::Duration;
9 use tokio::runtime::Builder;
10 use tokio::sync::mpsc::Sender;
11 
12 use bt_topshim::btif::get_btinterface;
13 use bt_topshim::topstack;
14 use btstack::battery_manager::BatteryManager;
15 use btstack::battery_provider_manager::BatteryProviderManager;
16 use btstack::battery_service::BatteryService;
17 use btstack::bluetooth::{Bluetooth, IBluetooth, SigData};
18 use btstack::bluetooth_admin::BluetoothAdmin;
19 use btstack::bluetooth_gatt::BluetoothGatt;
20 use btstack::bluetooth_logging::BluetoothLogging;
21 use btstack::bluetooth_media::BluetoothMedia;
22 use btstack::bluetooth_qa::BluetoothQA;
23 use btstack::dis::DeviceInformation;
24 use btstack::socket_manager::BluetoothSocketManager;
25 use btstack::suspend::Suspend;
26 use btstack::{Message, Stack};
27 
28 mod dbus_arg;
29 mod iface_battery_manager;
30 mod iface_battery_provider_manager;
31 mod iface_bluetooth;
32 mod iface_bluetooth_admin;
33 mod iface_bluetooth_gatt;
34 mod iface_bluetooth_media;
35 mod iface_bluetooth_qa;
36 mod iface_bluetooth_telephony;
37 mod iface_logging;
38 mod interface_manager;
39 
40 const DBUS_SERVICE_NAME: &str = "org.chromium.bluetooth";
41 const ADMIN_SETTINGS_FILE_PATH: &str = "/var/lib/bluetooth/admin_policy.json";
42 // Time to wait for API unregistration in DBus
43 const API_DISABLE_TIMEOUT_MS: Duration = Duration::from_millis(100);
44 // The maximum ACL disconnect timeout is 3.5s defined by BTA_DM_DISABLE_TIMER_MS
45 // and BTA_DM_DISABLE_TIMER_RETRIAL_MS
46 const STACK_TURN_OFF_TIMEOUT_MS: Duration = Duration::from_millis(4000);
47 // Time bt_stack_manager waits for cleanup
48 const STACK_CLEANUP_TIMEOUT_MS: Duration = Duration::from_millis(11000);
49 // Time bt_stack_manager waits for cleanup profiles
50 const STACK_CLEANUP_PROFILES_TIMEOUT_MS: Duration = Duration::from_millis(100);
51 // Extra time to wait before terminating the process
52 const EXTRA_WAIT_BEFORE_KILL_MS: Duration = Duration::from_millis(1000);
53 
54 const INIT_LOGGING_MAX_RETRY: u8 = 3;
55 
56 /// Runs the Bluetooth daemon serving D-Bus IPC.
main() -> Result<(), Box<dyn Error>>57 fn main() -> Result<(), Box<dyn Error>> {
58     let matches = App::new("Bluetooth Adapter Daemon")
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(
82             Arg::with_name("log-output")
83                 .long("log-output")
84                 .takes_value(true)
85                 .possible_values(&["syslog", "stderr"])
86                 .default_value("syslog")
87                 .help("Select log output"),
88         )
89         .get_matches();
90 
91     let is_debug = matches.is_present("debug");
92     let is_verbose_debug = matches.is_present("verbose-debug");
93     let log_output = matches.value_of("log-output").unwrap_or("syslog");
94 
95     let virt_index = matches.value_of("index").map_or(0, |idx| idx.parse::<i32>().unwrap_or(0));
96     let hci_index = matches.value_of("hci").map_or(0, |idx| idx.parse::<i32>().unwrap_or(0));
97 
98     let logging = Arc::new(Mutex::new(Box::new(BluetoothLogging::new(
99         is_debug,
100         is_verbose_debug,
101         log_output,
102     ))));
103     // TODO(b/307171804): Investigate why connecting to unix syslog might fail.
104     // Retry it a few times. Ignore the failure if fails too many times.
105     for _ in 0..INIT_LOGGING_MAX_RETRY {
106         match logging.lock().unwrap().initialize() {
107             Ok(_) => break,
108             Err(_) => continue,
109         }
110     }
111 
112     let (tx, rx) = Stack::create_channel();
113     let (api_tx, api_rx) = interface_manager::InterfaceManager::create_channel();
114     let sig_notifier = Arc::new(SigData {
115         enabled: Mutex::new(false),
116         enabled_notify: Condvar::new(),
117         thread_attached: Mutex::new(false),
118         thread_notify: Condvar::new(),
119         api_enabled: Mutex::new(false),
120         api_notify: Condvar::new(),
121     });
122 
123     // This needs to be built before any |topstack::get_runtime()| call!
124     let bt_sock_mgr_runtime = Arc::new(
125         Builder::new_multi_thread()
126             .worker_threads(1)
127             .max_blocking_threads(1)
128             .enable_all()
129             .build()
130             .expect("Failed to make socket runtime."),
131     );
132 
133     topstack::get_runtime().block_on(async {
134         // Connect to D-Bus system bus.
135         let (resource, conn) = connection::new_system_sync()?;
136 
137         // The `resource` is a task that should be spawned onto a tokio compatible
138         // reactor ASAP. If the resource ever finishes, we lost connection to D-Bus.
139         let conn_join_handle = tokio::spawn(async {
140             let err = resource.await;
141             panic!("Lost connection to D-Bus: {}", err);
142         });
143 
144         // Request a service name and quit if not able to.
145         conn.request_name(DBUS_SERVICE_NAME, false, true, false).await?;
146 
147         // Install SIGTERM handler so that we can properly shutdown
148         *SIG_DATA.lock().unwrap() = Some((tx.clone(), sig_notifier.clone()));
149         let sig_action_term = signal::SigAction::new(
150             signal::SigHandler::Handler(handle_sigterm),
151             signal::SaFlags::empty(),
152             signal::SigSet::empty(),
153         );
154         let sig_action_usr1 = signal::SigAction::new(
155             signal::SigHandler::Handler(handle_sigusr1),
156             signal::SaFlags::empty(),
157             signal::SigSet::empty(),
158         );
159         unsafe {
160             signal::sigaction(signal::SIGTERM, &sig_action_term).unwrap();
161             signal::sigaction(signal::SIGUSR1, &sig_action_usr1).unwrap();
162         }
163 
164         // Construct btstack profiles.
165         let intf = Arc::new(Mutex::new(get_btinterface()));
166         let bluetooth = Arc::new(Mutex::new(Box::new(Bluetooth::new(
167             virt_index,
168             hci_index,
169             tx.clone(),
170             api_tx.clone(),
171             sig_notifier.clone(),
172             intf.clone(),
173         ))));
174         let bluetooth_qa = Arc::new(Mutex::new(Box::new(BluetoothQA::new(tx.clone()))));
175         let battery_provider_manager =
176             Arc::new(Mutex::new(Box::new(BatteryProviderManager::new(tx.clone()))));
177 
178         bluetooth.lock().unwrap().init(hci_index);
179         bluetooth.lock().unwrap().enable();
180 
181         // These constructions require |intf| to be already init-ed.
182         let bt_sock_mgr = Arc::new(Mutex::new(Box::new(BluetoothSocketManager::new(
183             tx.clone(),
184             bt_sock_mgr_runtime,
185             intf.clone(),
186             bluetooth.clone(),
187         ))));
188         let bluetooth_media = Arc::new(Mutex::new(Box::new(BluetoothMedia::new(
189             tx.clone(),
190             api_tx.clone(),
191             intf.clone(),
192             bluetooth.clone(),
193             battery_provider_manager.clone(),
194         ))));
195         let bluetooth_gatt =
196             Arc::new(Mutex::new(Box::new(BluetoothGatt::new(intf.clone(), tx.clone()))));
197 
198         // These constructions don't need |intf| to be init-ed, but just depend on those who need.
199         let bluetooth_admin = Arc::new(Mutex::new(Box::new(BluetoothAdmin::new(
200             String::from(ADMIN_SETTINGS_FILE_PATH),
201             tx.clone(),
202             bluetooth.clone(),
203             bluetooth_media.clone(),
204             bt_sock_mgr.clone(),
205         ))));
206         let suspend = Arc::new(Mutex::new(Box::new(Suspend::new(
207             bluetooth.clone(),
208             intf.clone(),
209             bluetooth_gatt.clone(),
210             bluetooth_media.clone(),
211             tx.clone(),
212         ))));
213         let battery_service = Arc::new(Mutex::new(Box::new(BatteryService::new(
214             bluetooth_gatt.clone(),
215             battery_provider_manager.clone(),
216             tx.clone(),
217             api_tx.clone(),
218         ))));
219         let battery_manager = Arc::new(Mutex::new(Box::new(BatteryManager::new(
220             battery_provider_manager.clone(),
221             tx.clone(),
222         ))));
223         let dis = Arc::new(Mutex::new(Box::new(DeviceInformation::new(
224             bluetooth_gatt.clone(),
225             tx.clone(),
226         ))));
227 
228         // Run the stack main dispatch loop.
229         topstack::get_runtime().spawn(Stack::dispatch(
230             rx,
231             tx.clone(),
232             api_tx.clone(),
233             bluetooth.clone(),
234             bluetooth_gatt.clone(),
235             battery_service.clone(),
236             battery_manager.clone(),
237             battery_provider_manager.clone(),
238             bluetooth_media.clone(),
239             suspend.clone(),
240             bt_sock_mgr.clone(),
241             bluetooth_admin.clone(),
242             dis.clone(),
243             bluetooth_qa.clone(),
244         ));
245 
246         // Set up the disconnect watcher to monitor client disconnects.
247         let mut disconnect_watcher = DisconnectWatcher::new();
248         disconnect_watcher.setup_watch(conn.clone()).await;
249         let disconnect_watcher = Arc::new(Mutex::new(disconnect_watcher));
250 
251         tokio::spawn(interface_manager::InterfaceManager::dispatch(
252             api_rx,
253             virt_index,
254             conn,
255             conn_join_handle,
256             disconnect_watcher.clone(),
257             sig_notifier.clone(),
258             bluetooth.clone(),
259             bluetooth_admin.clone(),
260             bluetooth_gatt.clone(),
261             battery_manager.clone(),
262             battery_provider_manager.clone(),
263             bluetooth_media.clone(),
264             bluetooth_qa.clone(),
265             bt_sock_mgr.clone(),
266             suspend.clone(),
267             logging.clone(),
268         ));
269 
270         // Serve clients forever.
271         future::pending::<()>().await;
272         unreachable!()
273     })
274 }
275 
276 /// Data needed for signal handling.
277 static SIG_DATA: Mutex<Option<(Sender<Message>, Arc<SigData>)>> = Mutex::new(None);
278 
279 /// Try to cleanup the whole stack. Returns whether to clean up.
try_cleanup_stack(abort: bool) -> bool280 extern "C" fn try_cleanup_stack(abort: bool) -> bool {
281     let lock = SIG_DATA.try_lock();
282 
283     // If SIG_DATA is locked, it is likely the cleanup procedure is ongoing. No
284     // need to do anything here.
285     if lock.is_err() {
286         return false;
287     }
288 
289     if let Some((tx, notifier)) = lock.unwrap().as_ref() {
290         log::info!("Cleanup stack: disabling the adapter!");
291 
292         // Remove the API first to prevent clients calling while shutting down.
293         let guard = notifier.api_enabled.lock().unwrap();
294         if *guard {
295             let txl = tx.clone();
296             topstack::get_runtime().spawn(async move {
297                 // Remove the API first to prevent clients calling while shutting down.
298                 let _ = txl.send(Message::InterfaceShutdown).await;
299             });
300             log::info!(
301                 "Cleanup stack: Waiting for API shutdown to complete for {:?}",
302                 API_DISABLE_TIMEOUT_MS
303             );
304             let _ = notifier.api_notify.wait_timeout(guard, API_DISABLE_TIMEOUT_MS);
305         }
306 
307         let guard = notifier.enabled.lock().unwrap();
308         if *guard {
309             let txl = tx.clone();
310             topstack::get_runtime().spawn(async move {
311                 let _ = txl.send(Message::AdapterShutdown(abort)).await;
312             });
313             log::info!(
314                 "Cleanup stack: Waiting for stack to turn off for {:?}",
315                 STACK_TURN_OFF_TIMEOUT_MS
316             );
317             let _ = notifier.enabled_notify.wait_timeout(guard, STACK_TURN_OFF_TIMEOUT_MS);
318         }
319 
320         let guard = notifier.thread_attached.lock().unwrap();
321         if *guard {
322             let txl = tx.clone();
323             topstack::get_runtime().spawn(async move {
324                 // Clean up the profiles first as some of them might require main thread to clean up.
325                 let _ = txl.send(Message::CleanupProfiles).await;
326                 // Currently there is no good way to know when the profile is cleaned.
327                 // Simply add a small delay here.
328                 tokio::time::sleep(STACK_CLEANUP_PROFILES_TIMEOUT_MS).await;
329                 // Send the cleanup message to clean up the main thread.
330                 let _ = txl.send(Message::Cleanup).await;
331             });
332             log::info!(
333                 "Cleanup stack: Waiting for libbluetooth stack to clean up for {:?}",
334                 STACK_CLEANUP_TIMEOUT_MS
335             );
336             let _ = notifier.thread_notify.wait_timeout(guard, STACK_CLEANUP_TIMEOUT_MS);
337         }
338 
339         // Extra delay to give the rest of the cleanup processes some time to finish after
340         // finishing btif cleanup.
341         std::thread::sleep(EXTRA_WAIT_BEFORE_KILL_MS);
342     }
343     return true;
344 }
345 
handle_sigterm(_signum: i32)346 extern "C" fn handle_sigterm(_signum: i32) {
347     log::info!("SIGTERM received");
348     if !try_cleanup_stack(false) {
349         log::info!("Skipped to handle SIGTERM");
350         return;
351     }
352     log::info!("SIGTERM completed");
353     std::process::exit(0);
354 }
355 
356 /// Used to indicate controller needs reset
handle_sigusr1(_signum: i32)357 extern "C" fn handle_sigusr1(_signum: i32) {
358     log::info!("SIGUSR1 received");
359     if !try_cleanup_stack(true) {
360         log::info!("Skipped to handle SIGUSR1");
361         return;
362     }
363     log::info!("SIGUSR1 completed");
364     std::process::exit(0);
365 }
366