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