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