1 use crate::bluetooth_manager::BluetoothManager;
2 use crate::config_util;
3 use crate::time::Alarm;
4 use bt_utils::socket::{
5 BtSocket, HciChannels, MgmtCommand, MgmtCommandResponse, MgmtEvent, HCI_DEV_NONE,
6 };
7
8 use libc;
9 use log::{debug, error, info, warn};
10 use nix::sys::signal::{self, Signal};
11 use nix::unistd::Pid;
12 use std::collections::{BTreeMap, HashMap};
13 use std::convert::TryFrom;
14 use std::fmt::{Display, Formatter};
15 use std::process::{Child, Command, Stdio};
16 use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
17 use std::sync::{Arc, Mutex};
18 use tokio::io::unix::AsyncFd;
19 use tokio::sync::mpsc;
20 use tokio::time::{Duration, Instant};
21
22 /// Directory for Bluetooth pid file
23 pub const PID_DIR: &str = "/var/run/bluetooth";
24
25 /// Number of times to try restarting before resetting the adapter.
26 pub const RESET_ON_RESTART_COUNT: i32 = 2;
27
28 /// Time to wait from when IndexRemoved is sent to mgmt socket to when we send
29 /// it to the state machine. This debounce exists because when the Index is
30 /// removed due to adapter lost, userspace requires some time to actually close
31 /// the socket.
32 pub const INDEX_REMOVED_DEBOUNCE_TIME: Duration = Duration::from_millis(150);
33
34 /// Period to check the PID existence. Ideally adapter should clean up the PID
35 /// file by itself and uses it as the stopped signal. This is a backup mechanism
36 /// to avoid dead process + PID not cleaned up from happening.
37 pub const PID_RUNNING_CHECK_PERIOD: Duration = Duration::from_secs(60);
38
39 const HCI_BIND_MAX_RETRY: i32 = 2;
40
41 const HCI_BIND_RETRY_INTERVAL: Duration = Duration::from_millis(10);
42
43 #[derive(Debug, PartialEq, Copy, Clone)]
44 #[repr(u32)]
45 pub enum ProcessState {
46 Off = 0, // Bluetooth is not running or is not available.
47 TurningOn = 1, // We are not notified that the Bluetooth is running
48 On = 2, // Bluetooth is running
49 TurningOff = 3, // We are not notified that the Bluetooth is stopped
50 PendingRestart = 4, // Bluetooth is turning on and will be restarted after started
51 Restarting = 5, // Bluetooth is turning off and will be started after stopped
52 }
53
54 /// Check whether adapter is enabled by checking internal state.
state_to_enabled(state: ProcessState) -> bool55 pub fn state_to_enabled(state: ProcessState) -> bool {
56 matches!(state, ProcessState::On | ProcessState::TurningOff)
57 }
58
59 /// Device path of hci device in sysfs. This will uniquely identify a Bluetooth
60 /// host controller even when the hci index changes.
61 pub type DevPath = String;
62
63 /// An invalid hci index.
64 pub const INVALID_HCI_INDEX: i32 = -1;
65
66 /// Hci index that doesn't necessarily map to the physical hciN value. Make sure
67 /// that |VirtualHciIndex| and |RealHciIndex| don't easily convert to each other
68 /// to protect from logical errors.
69 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
70 pub struct VirtualHciIndex(pub i32);
71 impl VirtualHciIndex {
to_i32(self) -> i3272 pub(crate) fn to_i32(self) -> i32 {
73 self.0
74 }
75 }
76 impl Display for VirtualHciIndex {
fmt(&self, f: &mut Formatter) -> std::fmt::Result77 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
78 write!(f, "VirtHci{}", self.0)
79 }
80 }
81
82 /// Hci index that maps to real system index.
83 #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
84 pub struct RealHciIndex(pub i32);
85 impl RealHciIndex {
to_i32(self) -> i3286 pub(crate) fn to_i32(self) -> i32 {
87 self.0
88 }
89 }
90 impl Display for RealHciIndex {
fmt(&self, f: &mut Formatter) -> std::fmt::Result91 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
92 write!(f, "RealHci{}", self.0)
93 }
94 }
95
96 /// Adapter state actions
97 #[derive(Debug)]
98 pub enum AdapterStateActions {
99 StartBluetooth(VirtualHciIndex),
100 StopBluetooth(VirtualHciIndex),
101 RestartBluetooth(VirtualHciIndex),
102 BluetoothStarted(i32, VirtualHciIndex), // PID and HCI
103 BluetoothStopped(VirtualHciIndex),
104 HciDevicePresence(DevPath, RealHciIndex, bool),
105 }
106
107 /// Enum of all the messages that state machine handles.
108 #[derive(Debug)]
109 pub enum Message {
110 AdapterStateChange(AdapterStateActions),
111 PidChange(inotify::EventMask, Option<String>),
112 CallbackDisconnected(u32),
113 CommandTimeout(VirtualHciIndex),
114 SetDesiredDefaultAdapter(VirtualHciIndex),
115 }
116
117 pub struct StateMachineContext {
118 tx: mpsc::Sender<Message>,
119 rx: mpsc::Receiver<Message>,
120 state_machine: StateMachineInternal,
121 }
122
123 impl StateMachineContext {
new(state_machine: StateMachineInternal) -> StateMachineContext124 fn new(state_machine: StateMachineInternal) -> StateMachineContext {
125 let (tx, rx) = mpsc::channel::<Message>(10);
126 StateMachineContext { tx, rx, state_machine }
127 }
128
get_proxy(&self) -> StateMachineProxy129 pub fn get_proxy(&self) -> StateMachineProxy {
130 StateMachineProxy {
131 floss_enabled: self.state_machine.floss_enabled.clone(),
132 default_adapter: self.state_machine.default_adapter.clone(),
133 state: self.state_machine.state.clone(),
134 tx: self.tx.clone(),
135 }
136 }
137 }
138
139 /// Creates a new state machine.
140 ///
141 /// # Arguments
142 /// `invoker` - What type of process manager to use.
create_new_state_machine_context(invoker: Invoker) -> StateMachineContext143 pub fn create_new_state_machine_context(invoker: Invoker) -> StateMachineContext {
144 let floss_enabled = config_util::is_floss_enabled();
145 let desired_adapter = config_util::get_default_adapter();
146 let process_manager = StateMachineInternal::make_process_manager(invoker);
147
148 StateMachineContext::new(StateMachineInternal::new(
149 process_manager,
150 floss_enabled,
151 desired_adapter,
152 ))
153 }
154
155 #[derive(Clone)]
156 /// Proxy object to give access to certain internals of the state machine. For more detailed
157 /// documentation, see |StateMachineInternal|.
158 ///
159 /// Always construct this using |StateMachineContext::get_proxy(&self)|.
160 pub struct StateMachineProxy {
161 /// Shared state about whether floss is enabled.
162 floss_enabled: Arc<AtomicBool>,
163
164 /// Shared state about what the default adapter should be.
165 default_adapter: Arc<AtomicI32>,
166
167 /// Shared internal state about each adapter's state.
168 state: Arc<Mutex<BTreeMap<VirtualHciIndex, AdapterState>>>,
169
170 /// Sender to future that mutates |StateMachineInternal| states.
171 tx: mpsc::Sender<Message>,
172 }
173
174 const TX_SEND_TIMEOUT_DURATION: Duration = Duration::from_secs(3);
175
176 /// Duration to use for timeouts when starting/stopping adapters.
177 /// GD start timeout is set for 12 seconds. This timeout needs to be longer than that otherwise
178 /// Floss could crash.
179 const COMMAND_TIMEOUT_DURATION: Duration = Duration::from_secs(15);
180
181 impl StateMachineProxy {
start_bluetooth(&self, hci: VirtualHciIndex)182 pub fn start_bluetooth(&self, hci: VirtualHciIndex) {
183 let tx = self.tx.clone();
184 tokio::spawn(async move {
185 let _ = tx
186 .send(Message::AdapterStateChange(AdapterStateActions::StartBluetooth(hci)))
187 .await;
188 });
189 }
190
stop_bluetooth(&self, hci: VirtualHciIndex)191 pub fn stop_bluetooth(&self, hci: VirtualHciIndex) {
192 let tx = self.tx.clone();
193 tokio::spawn(async move {
194 let _ =
195 tx.send(Message::AdapterStateChange(AdapterStateActions::StopBluetooth(hci))).await;
196 });
197 }
198
restart_bluetooth(&self, hci: VirtualHciIndex)199 pub fn restart_bluetooth(&self, hci: VirtualHciIndex) {
200 let tx = self.tx.clone();
201 tokio::spawn(async move {
202 let _ = tx
203 .send(Message::AdapterStateChange(AdapterStateActions::RestartBluetooth(hci)))
204 .await;
205 });
206 }
207
208 /// Read state for an hci device.
get_state<T, F>(&self, hci: VirtualHciIndex, call: F) -> Option<T> where F: Fn(&AdapterState) -> Option<T>,209 pub fn get_state<T, F>(&self, hci: VirtualHciIndex, call: F) -> Option<T>
210 where
211 F: Fn(&AdapterState) -> Option<T>,
212 {
213 match self.state.lock().unwrap().get(&hci) {
214 Some(a) => call(a),
215 None => None,
216 }
217 }
218
get_process_state(&self, hci: VirtualHciIndex) -> ProcessState219 pub fn get_process_state(&self, hci: VirtualHciIndex) -> ProcessState {
220 self.get_state(hci, move |a: &AdapterState| Some(a.state)).unwrap_or(ProcessState::Off)
221 }
222
modify_state<F>(&mut self, hci: VirtualHciIndex, call: F) where F: Fn(&mut AdapterState),223 pub fn modify_state<F>(&mut self, hci: VirtualHciIndex, call: F)
224 where
225 F: Fn(&mut AdapterState),
226 {
227 call(&mut *self.state.lock().unwrap().entry(hci).or_insert(AdapterState::new(
228 String::new(),
229 RealHciIndex(hci.to_i32()),
230 hci,
231 )))
232 }
233
get_tx(&self) -> mpsc::Sender<Message>234 pub fn get_tx(&self) -> mpsc::Sender<Message> {
235 self.tx.clone()
236 }
237
get_floss_enabled(&self) -> bool238 pub fn get_floss_enabled(&self) -> bool {
239 self.floss_enabled.load(Ordering::Relaxed)
240 }
241
242 /// Sets the |floss_enabled| atomic variable.
243 ///
244 /// # Returns
245 /// Previous value of |floss_enabled|
set_floss_enabled(&mut self, enabled: bool) -> bool246 pub fn set_floss_enabled(&mut self, enabled: bool) -> bool {
247 self.floss_enabled.swap(enabled, Ordering::Relaxed)
248 }
249
get_adapters(&self) -> Vec<AdapterState>250 pub fn get_adapters(&self) -> Vec<AdapterState> {
251 self.state.lock().unwrap().iter().map(|(_, a)| a.clone()).collect::<Vec<AdapterState>>()
252 }
253
get_valid_adapters(&self) -> Vec<AdapterState>254 pub fn get_valid_adapters(&self) -> Vec<AdapterState> {
255 self.state
256 .lock()
257 .unwrap()
258 .iter()
259 // Filter to adapters that are present or enabled.
260 .filter(|&(_, a)| a.present || state_to_enabled(a.state))
261 .map(|(_, a)| a.clone())
262 .collect::<Vec<AdapterState>>()
263 }
264
265 /// Get the default adapter.
get_default_adapter(&mut self) -> VirtualHciIndex266 pub fn get_default_adapter(&mut self) -> VirtualHciIndex {
267 VirtualHciIndex(self.default_adapter.load(Ordering::Relaxed))
268 }
269
270 /// Set the desired default adapter.
set_desired_default_adapter(&mut self, adapter: VirtualHciIndex)271 pub fn set_desired_default_adapter(&mut self, adapter: VirtualHciIndex) {
272 let tx = self.tx.clone();
273 tokio::spawn(async move {
274 let _ = tx.send(Message::SetDesiredDefaultAdapter(adapter)).await;
275 });
276 }
277 }
278
pid_inotify_async_fd() -> AsyncFd<inotify::Inotify>279 fn pid_inotify_async_fd() -> AsyncFd<inotify::Inotify> {
280 let mut pid_detector = inotify::Inotify::init().expect("cannot use inotify");
281 pid_detector
282 .add_watch(PID_DIR, inotify::WatchMask::CREATE | inotify::WatchMask::DELETE)
283 .expect("failed to add watch on pid directory");
284 AsyncFd::new(pid_detector).expect("failed to add async fd for pid detector")
285 }
286
287 /// Given an pid path, returns the adapter index for that pid path.
get_hci_index_from_pid_path(path: &str) -> Option<VirtualHciIndex>288 fn get_hci_index_from_pid_path(path: &str) -> Option<VirtualHciIndex> {
289 path.rsplit_once('/')
290 .or_else(|| Some(("", path))) // Contains no '/', so |path| is the last component.
291 .and_then(|tup| tup.1.strip_prefix("bluetooth"))
292 .and_then(|s| s.strip_suffix(".pid"))
293 .and_then(|p| p.parse::<i32>().ok())
294 .map(VirtualHciIndex)
295 }
296
event_name_to_string(name: Option<&std::ffi::OsStr>) -> Option<String>297 fn event_name_to_string(name: Option<&std::ffi::OsStr>) -> Option<String> {
298 if let Some(val) = &name {
299 if let Some(strval) = val.to_str() {
300 return Some(strval.to_string());
301 }
302 }
303
304 None
305 }
306
307 // List existing pids and then configure inotify on pid dir.
configure_pid(pid_tx: mpsc::Sender<Message>)308 fn configure_pid(pid_tx: mpsc::Sender<Message>) {
309 // Configure PID listener.
310 tokio::spawn(async move {
311 debug!("Spawned pid notify task");
312
313 // Get a list of active pid files to determine initial adapter status
314 let files = config_util::list_pid_files(PID_DIR);
315 for file in files {
316 pid_tx
317 .send_timeout(
318 Message::PidChange(inotify::EventMask::CREATE, Some(file)),
319 TX_SEND_TIMEOUT_DURATION,
320 )
321 .await
322 .unwrap();
323 }
324
325 // Set up a PID file listener to emit PID inotify messages
326 let mut pid_async_fd = pid_inotify_async_fd();
327
328 loop {
329 let r = pid_async_fd.readable_mut();
330 let mut fd_ready =
331 r.await.expect(format!("pid file in {} never became readable", PID_DIR).as_str());
332 let mut buffer: [u8; 1024] = [0; 1024];
333 debug!("Found new pid inotify entries. Reading them");
334 match fd_ready.try_io(|inner| inner.get_mut().read_events(&mut buffer)) {
335 Ok(Ok(events)) => {
336 for event in events {
337 debug!("got some events from pid {:?}", event.mask);
338 pid_tx
339 .send_timeout(
340 Message::PidChange(event.mask, event_name_to_string(event.name)),
341 TX_SEND_TIMEOUT_DURATION,
342 )
343 .await
344 .unwrap();
345 }
346 }
347 Err(_) | Ok(Err(_)) => panic!("Inotify watcher on {} failed.", PID_DIR),
348 }
349 fd_ready.clear_ready();
350 drop(fd_ready);
351 }
352 });
353 }
354
355 // Configure the HCI socket listener and prepare the system to receive mgmt events for index added
356 // and index removed.
configure_hci(hci_tx: mpsc::Sender<Message>)357 fn configure_hci(hci_tx: mpsc::Sender<Message>) {
358 let mut btsock = BtSocket::new();
359
360 // If the bluetooth socket isn't available, the kernel module is not loaded and we can't
361 // actually listen to it for index added/removed events.
362 match btsock.open() {
363 -1 => {
364 panic!(
365 "Bluetooth socket unavailable (errno {}). Try loading the kernel module first.",
366 std::io::Error::last_os_error().raw_os_error().unwrap_or(0)
367 );
368 }
369 x => debug!("Socket open at fd: {}", x),
370 }
371
372 tokio::spawn(async move {
373 // Bind to control channel (which is used for mgmt commands). We provide
374 // HCI_DEV_NONE because we don't actually need a valid HCI dev for some MGMT commands.
375 let mut bind_succ = false;
376 for _i in 0..HCI_BIND_MAX_RETRY {
377 match btsock.bind_channel(HciChannels::Control, HCI_DEV_NONE) {
378 -1 => {
379 match std::io::Error::last_os_error().raw_os_error().unwrap_or(0) {
380 libc::EINVAL => {
381 // If MGMT hasn't been initialized EINVAL will be returned.
382 // Just wait for a short time and try again.
383 debug!("Got EINVAL in bind. Wait and try again");
384 tokio::time::sleep(HCI_BIND_RETRY_INTERVAL).await;
385 continue;
386 }
387 others => {
388 panic!("Failed to bind control channel with errno={}", others);
389 }
390 }
391 }
392 _ => {
393 bind_succ = true;
394 break;
395 }
396 };
397 }
398
399 if !bind_succ {
400 panic!("bind failed too many times!!");
401 }
402
403 debug!("Spawned hci notify task");
404
405 // Make this into an AsyncFD and start using it for IO
406 let mut hci_afd = AsyncFd::new(btsock).expect("Failed to add async fd for BT socket.");
407
408 // Start by first reading the index list
409 match hci_afd.writable_mut().await {
410 Ok(mut guard) => {
411 let _ = guard.try_io(|sock| {
412 let command = MgmtCommand::ReadIndexList;
413 sock.get_mut().write_mgmt_packet(command.into());
414 Ok(())
415 });
416 }
417 Err(e) => debug!("Failed to write to hci socket: {:?}", e),
418 };
419
420 // Now listen only for devices that are newly added or removed.
421 loop {
422 if let Ok(mut guard) = hci_afd.readable_mut().await {
423 let result = guard.try_io(|sock| Ok(sock.get_mut().read_mgmt_packet()));
424 let packet = match result {
425 Ok(v) => v.unwrap_or(None),
426 Err(_) => None,
427 };
428
429 if let Some(p) = packet {
430 debug!("Got a valid packet from btsocket: {:?}", p);
431
432 if let Ok(ev) = MgmtEvent::try_from(p) {
433 debug!("Got a valid mgmt event: {:?}", ev);
434
435 match ev {
436 MgmtEvent::CommandComplete { opcode: _, status: _, response } => {
437 if let MgmtCommandResponse::ReadIndexList {
438 num_intf: _,
439 interfaces,
440 } = response
441 {
442 for hci in interfaces {
443 let hci = RealHciIndex(hci.into());
444 debug!("IndexList response: {}", hci);
445 // We need devpath for an index or we don't use it.
446 if let Some(d) = config_util::get_devpath_for_hci(hci) {
447 hci_tx
448 .send_timeout(
449 Message::AdapterStateChange(
450 AdapterStateActions::HciDevicePresence(
451 d, hci, true,
452 ),
453 ),
454 TX_SEND_TIMEOUT_DURATION,
455 )
456 .await
457 .unwrap();
458 } else {
459 error!("IndexList: Could not get devpath for {}", hci);
460 }
461 }
462 }
463 }
464 MgmtEvent::IndexAdded(hci) => {
465 let hci = RealHciIndex(hci.into());
466 debug!("IndexAdded: {}", hci);
467 // We need devpath for an index or we don't use it.
468 if let Some(d) = config_util::get_devpath_for_hci(hci) {
469 hci_tx
470 .send_timeout(
471 Message::AdapterStateChange(
472 AdapterStateActions::HciDevicePresence(
473 d, hci, true,
474 ),
475 ),
476 TX_SEND_TIMEOUT_DURATION,
477 )
478 .await
479 .unwrap();
480 } else {
481 error!("IndexAdded: Could not get devpath for {}", hci);
482 }
483 }
484 MgmtEvent::IndexRemoved(hci) => {
485 let hci = RealHciIndex(hci.into());
486 debug!("IndexRemoved: {}", hci);
487 let devpath =
488 config_util::get_devpath_for_hci(hci).unwrap_or_default();
489 // Only send presence removed if the device is removed
490 // and not when userchannel takes exclusive access. This needs to
491 // be delayed a bit for when the socket legitimately disappears as
492 // it takes some time for userspace to close the socket.
493 //
494 // It's possible for devpath to be empty in this case because the
495 // index is being removed. Handlers of HciDevicePresence need to
496 // be aware of this case.
497 let txl = hci_tx.clone();
498 tokio::spawn(async move {
499 tokio::time::sleep(INDEX_REMOVED_DEBOUNCE_TIME).await;
500 if !config_util::check_hci_device_exists(hci) {
501 txl.send_timeout(
502 Message::AdapterStateChange(
503 AdapterStateActions::HciDevicePresence(
504 devpath, hci, false,
505 ),
506 ),
507 TX_SEND_TIMEOUT_DURATION,
508 )
509 .await
510 .unwrap();
511 }
512 });
513 }
514 }
515 }
516 } else {
517 // Got nothing from the previous read so clear the ready bit.
518 guard.clear_ready();
519 }
520 }
521 }
522 });
523 }
524
525 /// Handle command timeouts per hci interface.
526 struct CommandTimeout {
527 pub waker: Arc<Alarm>,
528 expired: bool,
529 per_hci_timeout: HashMap<VirtualHciIndex, Instant>,
530 duration: Duration,
531 }
532
533 impl CommandTimeout {
new() -> Self534 pub fn new() -> Self {
535 CommandTimeout {
536 waker: Arc::new(Alarm::new()),
537 per_hci_timeout: HashMap::new(),
538 expired: true,
539 duration: COMMAND_TIMEOUT_DURATION,
540 }
541 }
542
543 /// Set next command timeout. If no waker is active, reset to duration.
set_next(&mut self, hci: VirtualHciIndex)544 fn set_next(&mut self, hci: VirtualHciIndex) {
545 let wake = Instant::now() + self.duration;
546 self.per_hci_timeout.entry(hci).and_modify(|v| *v = wake).or_insert(wake);
547
548 if self.expired {
549 self.waker.reset(self.duration);
550 self.expired = false;
551 }
552 }
553
554 /// Remove command timeout for hci interface.
cancel(&mut self, hci: VirtualHciIndex)555 fn cancel(&mut self, hci: VirtualHciIndex) {
556 self.per_hci_timeout.remove(&hci);
557 }
558
559 /// Expire entries that are older than now and set next wake.
560 /// Returns list of expired hci entries.
expire(&mut self) -> Vec<VirtualHciIndex>561 fn expire(&mut self) -> Vec<VirtualHciIndex> {
562 let now = Instant::now();
563
564 let mut completed: Vec<VirtualHciIndex> = Vec::new();
565 let mut next_expiry = now + self.duration;
566
567 for (hci, expiry) in &self.per_hci_timeout {
568 if *expiry < now {
569 completed.push(*hci);
570 } else if *expiry < next_expiry {
571 next_expiry = *expiry;
572 }
573 }
574
575 for hci in &completed {
576 self.per_hci_timeout.remove(hci);
577 }
578
579 // If there are any remaining wakeups, reset the wake.
580 if !self.per_hci_timeout.is_empty() {
581 let duration: Duration = next_expiry - now;
582 self.waker.reset(duration);
583 self.expired = false;
584 } else {
585 self.expired = true;
586 }
587
588 completed
589 }
590
591 /// Handles a specific timeout action.
handle_timeout_action(&mut self, hci: VirtualHciIndex, action: CommandTimeoutAction)592 fn handle_timeout_action(&mut self, hci: VirtualHciIndex, action: CommandTimeoutAction) {
593 match action {
594 CommandTimeoutAction::ResetTimer => self.set_next(hci),
595 CommandTimeoutAction::CancelTimer => self.cancel(hci),
596 CommandTimeoutAction::DoNothing => (),
597 }
598 }
599 }
600
mainloop( mut context: StateMachineContext, bluetooth_manager: Arc<Mutex<Box<BluetoothManager>>>, )601 pub async fn mainloop(
602 mut context: StateMachineContext,
603 bluetooth_manager: Arc<Mutex<Box<BluetoothManager>>>,
604 ) {
605 // Set up a command timeout listener to emit timeout messages
606 let cmd_timeout = Arc::new(Mutex::new(CommandTimeout::new()));
607
608 let ct = cmd_timeout.clone();
609 let timeout_tx = context.tx.clone();
610
611 tokio::spawn(async move {
612 let timer = ct.lock().unwrap().waker.clone();
613 loop {
614 let _expired = timer.expired().await;
615 let completed = ct.lock().unwrap().expire();
616 for hci in completed {
617 timeout_tx
618 .send_timeout(Message::CommandTimeout(hci), TX_SEND_TIMEOUT_DURATION)
619 .await
620 .unwrap();
621 }
622 }
623 });
624
625 // Set up an HCI device listener to emit HCI device inotify messages.
626 // This is also responsible for configuring the initial list of HCI devices available on the
627 // system.
628 configure_hci(context.tx.clone());
629 configure_pid(context.tx.clone());
630
631 // Listen for all messages and act on them
632 loop {
633 let m = context.rx.recv().await;
634
635 if m.is_none() {
636 warn!("Exiting manager mainloop");
637 break;
638 }
639
640 debug!("Message handler: {:?}", m);
641
642 match m.unwrap() {
643 // Adapter action has changed
644 Message::AdapterStateChange(adapter_action) => {
645 // Grab previous state from lock and release
646 let hci: VirtualHciIndex;
647 let next_state;
648 let prev_state;
649
650 match &adapter_action {
651 AdapterStateActions::StartBluetooth(i) => {
652 hci = *i;
653 prev_state = context.state_machine.get_process_state(hci);
654
655 let action;
656 (next_state, action) = context.state_machine.action_start_bluetooth(hci);
657 cmd_timeout.lock().unwrap().handle_timeout_action(hci, action);
658 }
659 AdapterStateActions::StopBluetooth(i) => {
660 hci = *i;
661 prev_state = context.state_machine.get_process_state(hci);
662
663 let action;
664 (next_state, action) = context.state_machine.action_stop_bluetooth(hci);
665 cmd_timeout.lock().unwrap().handle_timeout_action(hci, action);
666 }
667 AdapterStateActions::RestartBluetooth(i) => {
668 hci = *i;
669 prev_state = context.state_machine.get_process_state(hci);
670
671 let action;
672 (next_state, action) = context.state_machine.action_restart_bluetooth(hci);
673 cmd_timeout.lock().unwrap().handle_timeout_action(hci, action);
674 }
675 AdapterStateActions::BluetoothStarted(pid, i) => {
676 hci = *i;
677 prev_state = context.state_machine.get_process_state(hci);
678
679 let action;
680 (next_state, action) =
681 context.state_machine.action_on_bluetooth_started(*pid, hci);
682 cmd_timeout.lock().unwrap().handle_timeout_action(hci, action);
683
684 if context.state_machine.has_queued_present(hci) {
685 context.state_machine.modify_state(hci, |a: &mut AdapterState| {
686 a.has_queued_present = false;
687 });
688 bluetooth_manager.lock().unwrap().callback_hci_device_change(hci, true);
689 }
690 }
691 AdapterStateActions::BluetoothStopped(i) => {
692 hci = *i;
693 prev_state = context.state_machine.get_process_state(hci);
694
695 let action;
696 (next_state, action) =
697 context.state_machine.action_on_bluetooth_stopped(hci);
698 cmd_timeout.lock().unwrap().handle_timeout_action(hci, action);
699 }
700
701 AdapterStateActions::HciDevicePresence(devpath, i, present) => {
702 let previous_real_hci = match context
703 .state_machine
704 .get_virtual_id_by_devpath(devpath.clone())
705 {
706 Some(v) => context
707 .state_machine
708 .get_state(v, |a: &AdapterState| Some(a.real_hci)),
709 None => None,
710 };
711 hci = context.state_machine.get_updated_virtual_id(devpath.clone(), *i);
712
713 // If this is really a new hci device, load the enabled state from the disk.
714 if previous_real_hci.is_none() {
715 context.state_machine.modify_state(hci, |a: &mut AdapterState| {
716 a.config_enabled = config_util::is_hci_n_enabled(hci);
717 });
718 }
719
720 // If the real hci changed, we need to set the previous present to the
721 // opposite of the current present so that we don't no-op the action.
722 if previous_real_hci.is_some()
723 && previous_real_hci
724 != context
725 .state_machine
726 .get_state(hci, |a: &AdapterState| Some(a.real_hci))
727 {
728 context.state_machine.modify_state(hci, |a: &mut AdapterState| {
729 a.present = !present;
730 });
731 }
732
733 prev_state = context.state_machine.get_process_state(hci);
734
735 // Don't bother the clients if presence is unchanged. But still execute the
736 // state machine here in case there is anything else to be done (e.g.,
737 // verify the next state).
738 let presence_changed = *present
739 != context
740 .state_machine
741 .get_state(hci, |a: &AdapterState| Some(a.present))
742 .unwrap_or(false);
743
744 let adapter_change_action;
745 let timeout_action;
746 (next_state, adapter_change_action, timeout_action) =
747 context.state_machine.action_on_hci_presence_changed(hci, *present);
748
749 cmd_timeout.lock().unwrap().handle_timeout_action(hci, timeout_action);
750
751 match adapter_change_action {
752 AdapterChangeAction::NewDefaultAdapter(new_hci) => {
753 context
754 .state_machine
755 .default_adapter
756 .store(new_hci.to_i32(), Ordering::Relaxed);
757 bluetooth_manager
758 .lock()
759 .unwrap()
760 .callback_default_adapter_change(new_hci);
761 }
762
763 AdapterChangeAction::DoNothing => (),
764 };
765
766 if presence_changed {
767 // If present switched to true and we're turning on the adapter,
768 // defer the callback until the next BluetoothStarted or CommandTimeout
769 // so the clients won't get an unexpected state change after present.
770 let queue_present = *present && next_state == ProcessState::TurningOn;
771
772 // Always modify_state to make sure it's reset on queue_present=false,
773 // e.g., when a hci is removed while its presence is still queued.
774 context.state_machine.modify_state(hci, |a: &mut AdapterState| {
775 a.has_queued_present = queue_present;
776 });
777
778 if !queue_present {
779 bluetooth_manager
780 .lock()
781 .unwrap()
782 .callback_hci_device_change(hci, *present);
783 }
784 }
785 }
786 };
787
788 // All actions and the resulting state changes should be logged for debugging.
789 info!(
790 "{}: Action={:?}, Previous State({:?}), Next State({:?})",
791 hci, adapter_action, prev_state, next_state
792 );
793
794 // Only emit enabled event for certain transitions
795 let prev_enabled = state_to_enabled(prev_state);
796 let next_enabled = state_to_enabled(next_state);
797 if prev_enabled != next_enabled {
798 bluetooth_manager
799 .lock()
800 .unwrap()
801 .callback_hci_enabled_change(hci, next_enabled);
802 }
803 }
804
805 // Monitored pid directory has a change
806 Message::PidChange(mask, filename) => match (mask, &filename) {
807 (inotify::EventMask::CREATE, Some(fname)) => {
808 let path = std::path::Path::new(PID_DIR).join(fname);
809 match (
810 get_hci_index_from_pid_path(fname),
811 tokio::fs::read(path.clone()).await.ok(),
812 ) {
813 (Some(hci), Some(s)) => {
814 let pid = String::from_utf8(s)
815 .expect("invalid pid file")
816 .parse::<i32>()
817 .unwrap_or(0);
818 debug!("Sending bluetooth started action for {}, pid={}", hci, pid);
819 context
820 .tx
821 .send_timeout(
822 Message::AdapterStateChange(
823 AdapterStateActions::BluetoothStarted(pid, hci),
824 ),
825 TX_SEND_TIMEOUT_DURATION,
826 )
827 .await
828 .unwrap();
829 let handle = tokio::spawn(async move {
830 debug!("{}: Spawned process monitor", hci);
831 loop {
832 tokio::time::sleep(PID_RUNNING_CHECK_PERIOD).await;
833 // Check if process exists by sending kill -0.
834 match nix::sys::signal::kill(Pid::from_raw(pid), None) {
835 Err(nix::errno::Errno::ESRCH) => {
836 warn!("{}: Process died; Removing PID file", hci);
837 if let Err(e) = std::fs::remove_file(path) {
838 warn!("{}: Failed to remove: {}", hci, e);
839 }
840 break;
841 }
842 Err(e) => {
843 // Other errno should rarely happen:
844 // EINVAL: The value of the sig argument is an invalid
845 // or unsupported signal number.
846 // EPERM: The process does not have permission to send
847 // the signal to any receiving process.
848 error!("{}: Failed to send signal: {}", hci, e);
849 break;
850 }
851 _ => {}
852 }
853 }
854 });
855 if let Some(handle) = context
856 .state_machine
857 .process_monitor
858 .lock()
859 .unwrap()
860 .insert(fname.clone(), handle)
861 {
862 warn!("{}: Aborting old handler", hci);
863 handle.abort();
864 }
865 }
866 _ => debug!("Invalid pid path: {}", fname),
867 }
868 }
869 (inotify::EventMask::DELETE, Some(fname)) => {
870 if let Some(hci) = get_hci_index_from_pid_path(fname) {
871 debug!("Sending bluetooth stopped action for {}", hci);
872 context
873 .tx
874 .send_timeout(
875 Message::AdapterStateChange(AdapterStateActions::BluetoothStopped(
876 hci,
877 )),
878 TX_SEND_TIMEOUT_DURATION,
879 )
880 .await
881 .unwrap();
882 match context.state_machine.process_monitor.lock().unwrap().remove(fname) {
883 Some(handle) => handle.abort(),
884 None => {
885 warn!("{}: Process exited but process monitor not found", hci)
886 }
887 }
888 }
889 }
890 _ => debug!("Ignored event {:?} - {:?}", mask, &filename),
891 },
892
893 // Callback client has disconnected
894 Message::CallbackDisconnected(id) => {
895 bluetooth_manager.lock().unwrap().callback_disconnected(id);
896 }
897
898 // Handle command timeouts
899 Message::CommandTimeout(hci) => {
900 debug!(
901 "{}: Expired action, state={:?}",
902 hci,
903 context.state_machine.get_process_state(hci)
904 );
905 let timeout_action = context.state_machine.action_on_command_timeout(hci);
906 match timeout_action {
907 StateMachineTimeoutActions::Noop => (),
908 _ => cmd_timeout.lock().unwrap().set_next(hci),
909 }
910
911 if context.state_machine.has_queued_present(hci) {
912 context.state_machine.modify_state(hci, |a: &mut AdapterState| {
913 a.has_queued_present = false;
914 });
915 bluetooth_manager.lock().unwrap().callback_hci_device_change(hci, true);
916 }
917 }
918
919 Message::SetDesiredDefaultAdapter(hci) => {
920 debug!("Changing desired default adapter to {}", hci);
921 match context.state_machine.set_desired_default_adapter(hci) {
922 AdapterChangeAction::NewDefaultAdapter(new_hci) => {
923 context
924 .state_machine
925 .default_adapter
926 .store(new_hci.to_i32(), Ordering::Relaxed);
927 bluetooth_manager.lock().unwrap().callback_default_adapter_change(new_hci);
928 }
929 AdapterChangeAction::DoNothing => (),
930 }
931 }
932 }
933 }
934 }
935
936 /// Trait that needs to be implemented by the native process manager for the
937 /// targeted system. This is used to manage adapter processes.
938 pub trait ProcessManager {
939 /// Start the adapter process.
940 ///
941 /// # Args
942 /// * `virtual_hci` - Virtual index of adapter used for apis.
943 /// * `real_hci` - Real index of the adapter on the system. This can
944 /// change during a single boot.
start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex)945 fn start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex);
946
947 /// Stop the adapter process.
948 ///
949 /// This should block the thread until the btadapterd process is completely stopped,
950 /// that is, another btadapterd process with the same index is ready to be |start|.
951 ///
952 /// # Args
953 /// * `virtual_hci` - Virtual index of adapter used for apis.
954 /// * `real_hci` - Real index of the adapter on the system.
stop(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex)955 fn stop(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex);
956 }
957
958 pub enum Invoker {
959 #[allow(dead_code)]
960 NativeInvoker,
961 SystemdInvoker,
962 UpstartInvoker,
963 }
964
965 #[derive(Default)]
966 pub struct NativeInvoker {
967 process_container: HashMap<VirtualHciIndex, Child>,
968 }
969
970 impl NativeInvoker {
new() -> Self971 pub fn new() -> Self {
972 Default::default()
973 }
974 }
975
976 impl ProcessManager for NativeInvoker {
start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex)977 fn start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex) {
978 if self.process_container.contains_key(&virtual_hci) {
979 return;
980 }
981 match Command::new("/usr/bin/btadapterd")
982 .arg(format!("INDEX={} HCI={}", virtual_hci.to_i32(), real_hci.to_i32()))
983 .stdout(Stdio::piped())
984 .spawn()
985 {
986 Ok(p) => {
987 self.process_container.insert(virtual_hci, p);
988 }
989 Err(e) => error!("Failed to start btadapterd: {}", e),
990 }
991 }
stop(&mut self, virtual_hci: VirtualHciIndex, _real_hci: RealHciIndex)992 fn stop(&mut self, virtual_hci: VirtualHciIndex, _real_hci: RealHciIndex) {
993 if let Some(mut p) = self.process_container.remove(&virtual_hci) {
994 if let Err(e) = signal::kill(Pid::from_raw(p.id() as i32), Signal::SIGTERM) {
995 warn!("Failed to send signal, process could have exited: {}", e);
996 }
997 let _ = p.wait();
998 } else {
999 warn!("Process doesn't exist");
1000 }
1001 }
1002 }
1003
1004 #[derive(Default)]
1005 pub struct UpstartInvoker {}
1006
1007 impl UpstartInvoker {
new() -> Self1008 pub fn new() -> Self {
1009 Default::default()
1010 }
1011 }
1012
1013 impl ProcessManager for UpstartInvoker {
start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex)1014 fn start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex) {
1015 if let Err(e) = Command::new("initctl")
1016 .args([
1017 "start",
1018 "btadapterd",
1019 format!("INDEX={}", virtual_hci.to_i32()).as_str(),
1020 format!("HCI={}", real_hci.to_i32()).as_str(),
1021 ])
1022 .output()
1023 {
1024 error!("Failed to start btadapterd: {}", e);
1025 }
1026 }
1027
stop(&mut self, virtual_hci: VirtualHciIndex, _real_hci: RealHciIndex)1028 fn stop(&mut self, virtual_hci: VirtualHciIndex, _real_hci: RealHciIndex) {
1029 // Currently in the upstart script, only INDEX is used for identifying the instance. Thus,
1030 // intentionally NOT passing HCI to upstart, to avoid the following confusing situation:
1031 // 1. UpstartInvoker: start btadapterd INDEX=0 HCI=0
1032 // 2. Kernel: The HCI0 crashed, and became HCI1
1033 // 3. UpstartInvoker: stop btadapterd INDEX=0 HCI=1 <---- This is confusing
1034 if let Err(e) = Command::new("initctl")
1035 .args(["stop", "btadapterd", format!("INDEX={}", virtual_hci.to_i32()).as_str()])
1036 .output()
1037 {
1038 error!("Failed to stop btadapterd: {}", e);
1039 }
1040 }
1041 }
1042
1043 #[derive(Default)]
1044 pub struct SystemdInvoker {}
1045
1046 impl SystemdInvoker {
new() -> Self1047 pub fn new() -> Self {
1048 Default::default()
1049 }
1050 }
1051
1052 impl ProcessManager for SystemdInvoker {
start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex)1053 fn start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex) {
1054 Command::new("systemctl")
1055 .args([
1056 "restart",
1057 format!("btadapterd@{}_{}.service", virtual_hci.to_i32(), real_hci.to_i32())
1058 .as_str(),
1059 ])
1060 .output()
1061 .expect("failed to start bluetooth");
1062 }
1063
stop(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex)1064 fn stop(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex) {
1065 // FIXME(b/307625503): If the real index changed (could be caused by FW crash or USB issues)
1066 // then this function would be broken. Need a re-design of the virtual/real index management
1067 // that is compatible other invokers.
1068 Command::new("systemctl")
1069 .args([
1070 "stop",
1071 format!("btadapterd@{}_{}.service", virtual_hci.to_i32(), real_hci.to_i32())
1072 .as_str(),
1073 ])
1074 .output()
1075 .expect("failed to stop bluetooth");
1076 }
1077 }
1078
1079 /// Stored state of each adapter in the state machine.
1080 #[derive(Clone, Debug)]
1081 pub struct AdapterState {
1082 /// Current adapter process state.
1083 pub state: ProcessState,
1084
1085 /// Device path for this adapter. This should be consistent across removal
1086 /// and addition of devices.
1087 pub devpath: DevPath,
1088
1089 /// Real hci index for this adapter. This can change after boot as adapters are
1090 /// removed and re-added. Use the devpath for a more consistent look-up.
1091 pub real_hci: RealHciIndex,
1092
1093 /// Virtual hci index for this adapter. This can be decoupled from the real
1094 /// hci index and is usually the first |real_hci| value that it shows up as.
1095 pub virt_hci: VirtualHciIndex,
1096
1097 /// PID for process using this adapter.
1098 pub pid: i32,
1099
1100 /// Whether this hci device is listed as present.
1101 pub present: bool,
1102
1103 /// Whether the 'present' notification is being deferred until adapter is ready.
1104 pub has_queued_present: bool,
1105
1106 /// Whether this hci device is configured to be enabled.
1107 pub config_enabled: bool,
1108
1109 /// How many times this adapter has attempted to restart without success.
1110 pub restart_count: i32,
1111 }
1112
1113 impl AdapterState {
new(devpath: DevPath, real_hci: RealHciIndex, virt_hci: VirtualHciIndex) -> Self1114 pub fn new(devpath: DevPath, real_hci: RealHciIndex, virt_hci: VirtualHciIndex) -> Self {
1115 AdapterState {
1116 state: ProcessState::Off,
1117 devpath,
1118 real_hci,
1119 virt_hci,
1120 present: false,
1121 has_queued_present: false,
1122 config_enabled: false,
1123 pid: 0,
1124 restart_count: 0,
1125 }
1126 }
1127 }
1128
1129 /// Internal and core implementation of the state machine.
1130 struct StateMachineInternal {
1131 /// Is Floss currently enabled?
1132 floss_enabled: Arc<AtomicBool>,
1133
1134 /// Current default adapter.
1135 default_adapter: Arc<AtomicI32>,
1136
1137 /// Desired default adapter.
1138 desired_adapter: VirtualHciIndex,
1139
1140 /// Keep track of per hci state. Key = hci id, Value = State. This must be a BTreeMap because
1141 /// we depend on ordering for |get_lowest_available_adapter|.
1142 state: Arc<Mutex<BTreeMap<VirtualHciIndex, AdapterState>>>,
1143
1144 /// Trace the process existence for each pid file and clean it up if needed.
1145 process_monitor: Arc<Mutex<HashMap<String, tokio::task::JoinHandle<()>>>>,
1146
1147 /// Process manager implementation.
1148 process_manager: Box<dyn ProcessManager + Send>,
1149 }
1150
1151 #[derive(Debug, PartialEq)]
1152 enum StateMachineTimeoutActions {
1153 RetryStart,
1154 RetryStop,
1155 Noop,
1156 }
1157
1158 #[derive(Debug, PartialEq)]
1159 enum CommandTimeoutAction {
1160 CancelTimer,
1161 DoNothing,
1162 ResetTimer,
1163 }
1164
1165 /// Actions to take when the default adapter may have changed.
1166 #[derive(Debug, PartialEq)]
1167 enum AdapterChangeAction {
1168 DoNothing,
1169 NewDefaultAdapter(VirtualHciIndex),
1170 }
1171
1172 // Core state machine implementations.
1173 impl StateMachineInternal {
new( process_manager: Box<dyn ProcessManager + Send>, floss_enabled: bool, desired_adapter: VirtualHciIndex, ) -> StateMachineInternal1174 pub fn new(
1175 process_manager: Box<dyn ProcessManager + Send>,
1176 floss_enabled: bool,
1177 desired_adapter: VirtualHciIndex,
1178 ) -> StateMachineInternal {
1179 StateMachineInternal {
1180 floss_enabled: Arc::new(AtomicBool::new(floss_enabled)),
1181 default_adapter: Arc::new(AtomicI32::new(desired_adapter.to_i32())),
1182 desired_adapter,
1183 state: Arc::new(Mutex::new(BTreeMap::new())),
1184 process_monitor: Arc::new(Mutex::new(HashMap::new())),
1185 process_manager,
1186 }
1187 }
1188
make_process_manager(invoker: Invoker) -> Box<dyn ProcessManager + Send>1189 pub(crate) fn make_process_manager(invoker: Invoker) -> Box<dyn ProcessManager + Send> {
1190 match invoker {
1191 Invoker::NativeInvoker => Box::new(NativeInvoker::new()),
1192 Invoker::SystemdInvoker => Box::new(SystemdInvoker::new()),
1193 Invoker::UpstartInvoker => Box::new(UpstartInvoker::new()),
1194 }
1195 }
1196
get_real_hci_by_virtual_id(&self, hci_id: VirtualHciIndex) -> RealHciIndex1197 pub(crate) fn get_real_hci_by_virtual_id(&self, hci_id: VirtualHciIndex) -> RealHciIndex {
1198 self.state
1199 .lock()
1200 .unwrap()
1201 .get(&hci_id)
1202 .map(|a: &AdapterState| a.real_hci)
1203 .unwrap_or(RealHciIndex(hci_id.to_i32()))
1204 }
1205
1206 /// Find the virtual id of an hci device using a devpath.
get_virtual_id_by_devpath(&self, devpath: DevPath) -> Option<VirtualHciIndex>1207 pub(crate) fn get_virtual_id_by_devpath(&self, devpath: DevPath) -> Option<VirtualHciIndex> {
1208 if devpath.is_empty() {
1209 return None;
1210 }
1211
1212 for (k, v) in self.state.lock().unwrap().iter() {
1213 if v.devpath == devpath {
1214 return Some(*k);
1215 }
1216 }
1217
1218 None
1219 }
1220
1221 /// Find the virtual id of an hci device using a real hci id.
get_virtual_id_by_real_id(&self, hci: RealHciIndex) -> Option<VirtualHciIndex>1222 pub(crate) fn get_virtual_id_by_real_id(&self, hci: RealHciIndex) -> Option<VirtualHciIndex> {
1223 for (k, v) in self.state.lock().unwrap().iter() {
1224 if v.real_hci == hci {
1225 return Some(*k);
1226 }
1227 }
1228
1229 None
1230 }
1231
get_next_virtual_id( &mut self, real_hci: RealHciIndex, devpath: Option<DevPath>, ) -> VirtualHciIndex1232 pub(crate) fn get_next_virtual_id(
1233 &mut self,
1234 real_hci: RealHciIndex,
1235 devpath: Option<DevPath>,
1236 ) -> VirtualHciIndex {
1237 let new_virt = match self.state.lock().unwrap().keys().next_back() {
1238 Some(v) => VirtualHciIndex(v.to_i32() + 1),
1239 None => VirtualHciIndex(0),
1240 };
1241 self.modify_state(new_virt, |a: &mut AdapterState| {
1242 a.real_hci = real_hci;
1243 if let Some(d) = devpath.as_ref() {
1244 a.devpath = d.clone();
1245 }
1246 });
1247
1248 new_virt
1249 }
1250
1251 /// Identify the virtual hci for the given real hci. We need to match both
1252 /// the RealHci and devpath for it to be considered a match. Update the
1253 /// real_hci and devpath entries for the virtual adapter where it makes sense.
get_updated_virtual_id( &mut self, devpath: DevPath, real_hci: RealHciIndex, ) -> VirtualHciIndex1254 pub(crate) fn get_updated_virtual_id(
1255 &mut self,
1256 devpath: DevPath,
1257 real_hci: RealHciIndex,
1258 ) -> VirtualHciIndex {
1259 let by_devpath = self.get_virtual_id_by_devpath(devpath.clone());
1260 let by_real = self.get_virtual_id_by_real_id(real_hci);
1261
1262 match (by_devpath, by_real) {
1263 (Some(dev), Some(real)) => {
1264 // Devpath matches expectations of real hci index.
1265 if dev == real {
1266 return real;
1267 }
1268
1269 // If dev device doesn't match real device, replace the real id
1270 // in non-matching entry with fake value and update devpath matching
1271 // one with new real hci.
1272 self.modify_state(dev, |a: &mut AdapterState| {
1273 a.real_hci = real_hci;
1274 });
1275 self.modify_state(real, |a: &mut AdapterState| {
1276 a.real_hci = RealHciIndex(INVALID_HCI_INDEX);
1277 });
1278
1279 dev
1280 }
1281 (Some(dev), None) => {
1282 // Device found by path and needs real_hci to be updated.
1283 self.modify_state(dev, |a: &mut AdapterState| {
1284 a.real_hci = real_hci;
1285 });
1286
1287 dev
1288 }
1289 (None, Some(real)) => {
1290 // If the real index is found but no entry exists with that devpath,
1291 // this is likely because the entry was added before the devpath became known.
1292 if !devpath.is_empty() {
1293 self.modify_state(real, |a: &mut AdapterState| {
1294 a.devpath = devpath.clone();
1295 });
1296 }
1297
1298 real
1299 }
1300 (None, None) => {
1301 // This is a brand new device. Add a new virtual device with this
1302 // real id and devpath.
1303 self.get_next_virtual_id(real_hci, Some(devpath))
1304 }
1305 }
1306
1307 // match should return on all branches above.
1308 }
1309
is_known(&self, hci: VirtualHciIndex) -> bool1310 fn is_known(&self, hci: VirtualHciIndex) -> bool {
1311 self.state.lock().unwrap().contains_key(&hci)
1312 }
1313
get_floss_enabled(&self) -> bool1314 fn get_floss_enabled(&self) -> bool {
1315 self.floss_enabled.load(Ordering::Relaxed)
1316 }
1317
1318 #[cfg(test)]
set_floss_enabled(&mut self, enabled: bool) -> bool1319 fn set_floss_enabled(&mut self, enabled: bool) -> bool {
1320 self.floss_enabled.swap(enabled, Ordering::Relaxed)
1321 }
1322
1323 #[cfg(test)]
set_config_enabled(&mut self, hci: VirtualHciIndex, enabled: bool)1324 fn set_config_enabled(&mut self, hci: VirtualHciIndex, enabled: bool) {
1325 self.modify_state(hci, move |a: &mut AdapterState| {
1326 a.config_enabled = enabled;
1327 });
1328 }
1329
has_queued_present(&self, hci: VirtualHciIndex) -> bool1330 fn has_queued_present(&self, hci: VirtualHciIndex) -> bool {
1331 self.get_state(hci, |a: &AdapterState| Some(a.has_queued_present)).unwrap_or(false)
1332 }
1333
get_process_state(&self, hci: VirtualHciIndex) -> ProcessState1334 fn get_process_state(&self, hci: VirtualHciIndex) -> ProcessState {
1335 self.get_state(hci, move |a: &AdapterState| Some(a.state)).unwrap_or(ProcessState::Off)
1336 }
1337
get_state<T, F>(&self, hci: VirtualHciIndex, call: F) -> Option<T> where F: Fn(&AdapterState) -> Option<T>,1338 fn get_state<T, F>(&self, hci: VirtualHciIndex, call: F) -> Option<T>
1339 where
1340 F: Fn(&AdapterState) -> Option<T>,
1341 {
1342 match self.state.lock().unwrap().get(&hci) {
1343 Some(a) => call(a),
1344 None => None,
1345 }
1346 }
1347
modify_state<F>(&mut self, hci: VirtualHciIndex, call: F) where F: Fn(&mut AdapterState),1348 fn modify_state<F>(&mut self, hci: VirtualHciIndex, call: F)
1349 where
1350 F: Fn(&mut AdapterState),
1351 {
1352 call(&mut *self.state.lock().unwrap().entry(hci).or_insert(AdapterState::new(
1353 String::new(),
1354 RealHciIndex(hci.to_i32()),
1355 hci,
1356 )))
1357 }
1358
1359 /// Attempt to reset an hci device. Always set the state to ProcessState::Stopped
1360 /// as we expect this device to disappear and reappear.
reset_hci(&mut self, hci: RealHciIndex)1361 fn reset_hci(&mut self, hci: RealHciIndex) {
1362 if !config_util::reset_hci_device(hci) {
1363 error!("Attempted reset recovery of {} and failed.", hci);
1364 }
1365 }
1366
1367 /// Gets the lowest present or enabled adapter.
get_lowest_available_adapter(&self) -> Option<VirtualHciIndex>1368 fn get_lowest_available_adapter(&self) -> Option<VirtualHciIndex> {
1369 self.state
1370 .lock()
1371 .unwrap()
1372 .iter()
1373 // Filter to adapters that are present or enabled.
1374 .filter(|&(_, a)| a.present)
1375 .map(|(_, a)| a.virt_hci)
1376 .next()
1377 }
1378
1379 /// Set the desired default adapter. Returns a NewDefaultAdapter action if the default
1380 /// adapter was changed as a result (meaning the newly desired adapter is either present or
1381 /// enabled).
set_desired_default_adapter(&mut self, adapter: VirtualHciIndex) -> AdapterChangeAction1382 pub fn set_desired_default_adapter(&mut self, adapter: VirtualHciIndex) -> AdapterChangeAction {
1383 self.desired_adapter = adapter;
1384
1385 // Desired adapter isn't current and it is present. It becomes the new default adapter.
1386 if self.default_adapter.load(Ordering::Relaxed) != adapter.to_i32()
1387 && self.get_state(adapter, move |a: &AdapterState| Some(a.present)).unwrap_or(false)
1388 {
1389 self.default_adapter.store(adapter.to_i32(), Ordering::Relaxed);
1390 return AdapterChangeAction::NewDefaultAdapter(adapter);
1391 }
1392
1393 // Desired adapter is either current or not present|enabled so leave the previous default
1394 // adapter.
1395 AdapterChangeAction::DoNothing
1396 }
1397
1398 /// Returns the next state and an action to reset timer if we are starting bluetooth process.
action_start_bluetooth( &mut self, hci: VirtualHciIndex, ) -> (ProcessState, CommandTimeoutAction)1399 pub fn action_start_bluetooth(
1400 &mut self,
1401 hci: VirtualHciIndex,
1402 ) -> (ProcessState, CommandTimeoutAction) {
1403 let state = self.get_process_state(hci);
1404 let present = self.get_state(hci, move |a: &AdapterState| Some(a.present)).unwrap_or(false);
1405 let floss_enabled = self.get_floss_enabled();
1406
1407 match state {
1408 // If adapter is off, we should turn it on when present and floss is enabled.
1409 // If adapter is turning on and we get another start request, we should just
1410 // repeat the same action which resets the timeout mechanism.
1411 ProcessState::Off | ProcessState::TurningOn if present && floss_enabled => {
1412 self.modify_state(hci, move |s: &mut AdapterState| {
1413 s.state = ProcessState::TurningOn
1414 });
1415 self.process_manager.start(hci, self.get_real_hci_by_virtual_id(hci));
1416 (ProcessState::TurningOn, CommandTimeoutAction::ResetTimer)
1417 }
1418 // Otherwise (enabled states) no op
1419 _ => (state, CommandTimeoutAction::DoNothing),
1420 }
1421 }
1422
1423 /// Returns the next state and an action to reset or cancel timer if we are stopping bluetooth
1424 /// process.
action_stop_bluetooth( &mut self, hci: VirtualHciIndex, ) -> (ProcessState, CommandTimeoutAction)1425 pub fn action_stop_bluetooth(
1426 &mut self,
1427 hci: VirtualHciIndex,
1428 ) -> (ProcessState, CommandTimeoutAction) {
1429 if !self.is_known(hci) {
1430 warn!("Attempting to stop unknown device {}", hci);
1431 return (ProcessState::Off, CommandTimeoutAction::DoNothing);
1432 }
1433
1434 let state = self.get_process_state(hci);
1435 match state {
1436 // If adapter is turning off and we get another stop request, we should just
1437 // repeat the same action which resets the timeout mechanism.
1438 ProcessState::On | ProcessState::TurningOff => {
1439 self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::TurningOff);
1440 self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci));
1441 (ProcessState::TurningOff, CommandTimeoutAction::ResetTimer)
1442 }
1443 // Otherwise (disabled states) no op
1444 _ => (state, CommandTimeoutAction::DoNothing),
1445 }
1446 }
1447
1448 /// Returns the next state and an action to reset timer if we are restarting bluetooth process.
1449 /// This action aims to make sure the configuration is reloaded. Only TurningOn/On states are
1450 /// affected.
action_restart_bluetooth( &mut self, hci: VirtualHciIndex, ) -> (ProcessState, CommandTimeoutAction)1451 pub fn action_restart_bluetooth(
1452 &mut self,
1453 hci: VirtualHciIndex,
1454 ) -> (ProcessState, CommandTimeoutAction) {
1455 if !self.is_known(hci) {
1456 warn!("Attempting to restart unknown device {}", hci);
1457 return (ProcessState::Off, CommandTimeoutAction::DoNothing);
1458 }
1459
1460 let state = self.get_process_state(hci);
1461 let present = self.get_state(hci, move |a: &AdapterState| Some(a.present)).unwrap_or(false);
1462 let floss_enabled = self.get_floss_enabled();
1463
1464 match state {
1465 ProcessState::On if present && floss_enabled => {
1466 self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::Restarting);
1467 self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci));
1468 (ProcessState::Restarting, CommandTimeoutAction::ResetTimer)
1469 }
1470 ProcessState::TurningOn if present && floss_enabled => {
1471 self.modify_state(hci, |s: &mut AdapterState| {
1472 s.state = ProcessState::PendingRestart
1473 });
1474 (ProcessState::PendingRestart, CommandTimeoutAction::DoNothing)
1475 }
1476 _ => (state, CommandTimeoutAction::DoNothing),
1477 }
1478 }
1479
1480 /// Returns the next state and an action. Except a restart is pending,
1481 /// always return the action to cancel timer even with unknown interfaces.
action_on_bluetooth_started( &mut self, pid: i32, hci: VirtualHciIndex, ) -> (ProcessState, CommandTimeoutAction)1482 pub fn action_on_bluetooth_started(
1483 &mut self,
1484 pid: i32,
1485 hci: VirtualHciIndex,
1486 ) -> (ProcessState, CommandTimeoutAction) {
1487 if !self.is_known(hci) {
1488 warn!("Unknown device {} is started; capturing that process", hci);
1489 self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::Off);
1490 }
1491
1492 let state = self.get_process_state(hci);
1493 let present = self.get_state(hci, move |a: &AdapterState| Some(a.present)).unwrap_or(false);
1494 let floss_enabled = self.get_floss_enabled();
1495
1496 if state == ProcessState::PendingRestart && present && floss_enabled {
1497 self.modify_state(hci, |s: &mut AdapterState| {
1498 s.state = ProcessState::Restarting;
1499 s.restart_count = 0;
1500 s.pid = pid;
1501 });
1502 self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci));
1503 return (ProcessState::Restarting, CommandTimeoutAction::ResetTimer);
1504 }
1505
1506 self.modify_state(hci, |s: &mut AdapterState| {
1507 s.state = ProcessState::On;
1508 s.restart_count = 0;
1509 s.pid = pid;
1510 });
1511 (ProcessState::On, CommandTimeoutAction::CancelTimer)
1512 }
1513
1514 /// Returns the next state and an action to cancel (turned off) or reset timer (restarting).
1515 /// If unexpected, Bluetooth probably crashed, returns an action to reset the timer to restart
1516 /// timeout.
action_on_bluetooth_stopped( &mut self, hci: VirtualHciIndex, ) -> (ProcessState, CommandTimeoutAction)1517 pub fn action_on_bluetooth_stopped(
1518 &mut self,
1519 hci: VirtualHciIndex,
1520 ) -> (ProcessState, CommandTimeoutAction) {
1521 let state = self.get_process_state(hci);
1522 let (present, config_enabled) = self
1523 .get_state(hci, move |a: &AdapterState| Some((a.present, a.config_enabled)))
1524 .unwrap_or((false, false));
1525 let floss_enabled = self.get_floss_enabled();
1526
1527 match state {
1528 // Normal shut down behavior.
1529 ProcessState::TurningOff => {
1530 self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::Off);
1531 (ProcessState::Off, CommandTimeoutAction::CancelTimer)
1532 }
1533 ProcessState::Restarting if floss_enabled && config_enabled => {
1534 self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::TurningOn);
1535 self.process_manager.start(hci, self.get_real_hci_by_virtual_id(hci));
1536 (ProcessState::TurningOn, CommandTimeoutAction::ResetTimer)
1537 }
1538 // Running bluetooth stopped unexpectedly.
1539 ProcessState::On if floss_enabled && config_enabled => {
1540 let restart_count =
1541 self.get_state(hci, |a: &AdapterState| Some(a.restart_count)).unwrap_or(0);
1542
1543 // This is an unexpectedly stop, which means the ProcessManager might not yet be
1544 // ready to restart the same instance. Explicitly call stop to make sure we can move
1545 // on to the next step.
1546 warn!(
1547 "{} stopped unexpectedly, first wait for the process to completely exit.",
1548 hci
1549 );
1550 self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci));
1551
1552 if !present {
1553 // If the index doesn't present, we have nothing to do - We can't even trigger
1554 // the hardware reset because the sysfs reset entry would disappear as well.
1555 // After the index presents, we shall try restarting.
1556 warn!("{} exited. After {} restarts, index disappeared.", hci, restart_count);
1557 self.modify_state(hci, |s: &mut AdapterState| {
1558 s.state = ProcessState::Off;
1559 s.restart_count = 0;
1560 });
1561 (ProcessState::Off, CommandTimeoutAction::CancelTimer)
1562 } else if restart_count >= RESET_ON_RESTART_COUNT {
1563 // If we've restarted a number of times, attempt to use the reset mechanism
1564 // instead of retrying a start.
1565 warn!(
1566 "{} exited. After {} restarts, trying a reset recovery.",
1567 hci, restart_count
1568 );
1569 // Reset the restart count since we're attempting a reset now.
1570 self.modify_state(hci, |s: &mut AdapterState| {
1571 s.state = ProcessState::Off;
1572 s.restart_count = 0;
1573 });
1574 let real_hci = self
1575 .get_state(hci, |a: &AdapterState| Some(a.real_hci))
1576 .unwrap_or(RealHciIndex(hci.to_i32()));
1577 self.reset_hci(real_hci);
1578 (ProcessState::Off, CommandTimeoutAction::CancelTimer)
1579 } else {
1580 warn!("{} exited. Try restarting (attempt #{})", hci, restart_count + 1);
1581 self.modify_state(hci, |s: &mut AdapterState| {
1582 s.state = ProcessState::TurningOn;
1583 s.restart_count += 1;
1584 });
1585 self.process_manager.start(hci, self.get_real_hci_by_virtual_id(hci));
1586 (ProcessState::TurningOn, CommandTimeoutAction::ResetTimer)
1587 }
1588 }
1589 _ => {
1590 warn!(
1591 "{} stopped unexpectedly from {:?}. Adapter present={}, Floss enabled={}",
1592 hci, state, present, floss_enabled
1593 );
1594 self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::Off);
1595 (ProcessState::Off, CommandTimeoutAction::CancelTimer)
1596 }
1597 }
1598 }
1599
1600 /// Triggered on Bluetooth start/stop timeout. Return the actions that the
1601 /// state machine has taken, for the external context to reset the timer.
action_on_command_timeout( &mut self, hci: VirtualHciIndex, ) -> StateMachineTimeoutActions1602 pub fn action_on_command_timeout(
1603 &mut self,
1604 hci: VirtualHciIndex,
1605 ) -> StateMachineTimeoutActions {
1606 let state = self.get_process_state(hci);
1607 let floss_enabled = self.get_floss_enabled();
1608 let (present, config_enabled) = self
1609 .get_state(hci, |a: &AdapterState| Some((a.present, a.config_enabled)))
1610 .unwrap_or((false, false));
1611
1612 match state {
1613 // If Floss is not enabled, just send |Stop| to process manager and end the state
1614 // machine actions.
1615 ProcessState::TurningOn | ProcessState::PendingRestart if !floss_enabled => {
1616 warn!("{}: Timed out turning on but floss is disabled", hci);
1617 self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::Off);
1618 self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci));
1619 StateMachineTimeoutActions::Noop
1620 }
1621 // If turning on and hci is enabled, restart the process if we are below
1622 // the restart count. Otherwise, reset and mark turned off.
1623 ProcessState::TurningOn | ProcessState::PendingRestart if config_enabled => {
1624 let restart_count =
1625 self.get_state(hci, |a: &AdapterState| Some(a.restart_count)).unwrap_or(0);
1626
1627 // Explicitly call stop to make sure the ProcessManager is ready to restart the
1628 // same instance.
1629 warn!(
1630 "{} timed out while starting, first wait for the process to completely exit.",
1631 hci
1632 );
1633 self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci));
1634
1635 if !present {
1636 // If the index doesn't present, we have nothing to do - We can't even trigger
1637 // the hardware reset because the sysfs reset entry would disappear as well.
1638 // After the index presents, we shall try restarting.
1639 warn!("{} exited. After {} restarts, index disappeared.", hci, restart_count);
1640 self.modify_state(hci, |s: &mut AdapterState| {
1641 s.state = ProcessState::Off;
1642 s.restart_count = 0;
1643 });
1644 StateMachineTimeoutActions::Noop
1645 } else if restart_count >= RESET_ON_RESTART_COUNT {
1646 // If we've restarted a number of times, attempt to use the reset mechanism
1647 // instead of retrying a start.
1648 warn!(
1649 "{} exited. After {} restarts, trying a reset recovery.",
1650 hci, restart_count
1651 );
1652 // Reset the restart count since we're attempting a reset now.
1653 self.modify_state(hci, |s: &mut AdapterState| {
1654 s.state = ProcessState::Off;
1655 s.restart_count = 0;
1656 });
1657 let real_hci = self
1658 .get_state(hci, |s: &AdapterState| Some(s.real_hci))
1659 .unwrap_or(RealHciIndex(hci.to_i32()));
1660 self.reset_hci(real_hci);
1661 StateMachineTimeoutActions::Noop
1662 } else {
1663 warn!("{} exited. Try restarting (attempt #{})", hci, restart_count + 1);
1664 self.modify_state(hci, |s: &mut AdapterState| {
1665 s.state = ProcessState::TurningOn;
1666 s.restart_count += 1;
1667 });
1668 self.process_manager.start(hci, self.get_real_hci_by_virtual_id(hci));
1669 StateMachineTimeoutActions::RetryStart
1670 }
1671 }
1672 ProcessState::TurningOff | ProcessState::Restarting => {
1673 info!("Killing bluetooth {}", hci);
1674 self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci));
1675 StateMachineTimeoutActions::RetryStop
1676 }
1677 _ => StateMachineTimeoutActions::Noop,
1678 }
1679 }
1680
1681 /// Handle when an hci device presence has changed.
1682 ///
1683 /// This will start adapters that are configured to be enabled if the presence is newly added.
1684 ///
1685 /// # Return
1686 /// Target process state.
action_on_hci_presence_changed( &mut self, hci: VirtualHciIndex, present: bool, ) -> (ProcessState, AdapterChangeAction, CommandTimeoutAction)1687 pub fn action_on_hci_presence_changed(
1688 &mut self,
1689 hci: VirtualHciIndex,
1690 present: bool,
1691 ) -> (ProcessState, AdapterChangeAction, CommandTimeoutAction) {
1692 let prev_present = self.get_state(hci, |a: &AdapterState| Some(a.present)).unwrap_or(false);
1693 let prev_state = self.get_process_state(hci);
1694
1695 // No-op if same as previous present.
1696 if prev_present == present {
1697 return (prev_state, AdapterChangeAction::DoNothing, CommandTimeoutAction::DoNothing);
1698 }
1699
1700 self.modify_state(hci, |a: &mut AdapterState| a.present = present);
1701 let floss_enabled = self.get_floss_enabled();
1702
1703 let (next_state, timeout_action) =
1704 match self.get_state(hci, |a: &AdapterState| Some((a.state, a.config_enabled))) {
1705 // Start the adapter if present, config is enabled and floss is enabled.
1706 Some((ProcessState::Off, true)) if floss_enabled && present => {
1707 // Restart count will increment for each time a Start doesn't succeed.
1708 // Going from `off` -> `turning on` here usually means either
1709 // a) Recovery from a previously unstartable state.
1710 // b) Fresh device.
1711 // Both should reset the restart count.
1712 self.modify_state(hci, |a: &mut AdapterState| a.restart_count = 0);
1713
1714 self.action_start_bluetooth(hci)
1715 }
1716 _ => (prev_state, CommandTimeoutAction::DoNothing),
1717 };
1718
1719 let default_adapter = VirtualHciIndex(self.default_adapter.load(Ordering::Relaxed));
1720 let desired_adapter = self.desired_adapter;
1721
1722 // Two scenarios here:
1723 // 1) The newly present adapter is the desired adapter.
1724 // * Switch to it immediately as the default adapter.
1725 // 2) The current default adapter is no longer present or enabled.
1726 // * Switch to the lowest numbered adapter present or do nothing.
1727 //
1728 let adapter_change_action = if present && hci == desired_adapter && hci != default_adapter {
1729 AdapterChangeAction::NewDefaultAdapter(desired_adapter)
1730 } else if !present && hci == default_adapter {
1731 match self.get_lowest_available_adapter() {
1732 Some(v) => AdapterChangeAction::NewDefaultAdapter(v),
1733 None => AdapterChangeAction::DoNothing,
1734 }
1735 } else {
1736 AdapterChangeAction::DoNothing
1737 };
1738
1739 (next_state, adapter_change_action, timeout_action)
1740 }
1741 }
1742
1743 #[cfg(test)]
1744 mod tests {
1745 use super::*;
1746 use std::collections::VecDeque;
1747
1748 #[derive(Debug, PartialEq)]
1749 enum ExecutedCommand {
1750 Start,
1751 Stop,
1752 }
1753
1754 struct MockProcessManager {
1755 last_command: VecDeque<ExecutedCommand>,
1756 expectations: Vec<Option<String>>,
1757 }
1758
1759 impl MockProcessManager {
new() -> MockProcessManager1760 fn new() -> MockProcessManager {
1761 MockProcessManager { last_command: VecDeque::new(), expectations: Vec::new() }
1762 }
1763
expect_start(&mut self)1764 fn expect_start(&mut self) {
1765 self.last_command.push_back(ExecutedCommand::Start);
1766 }
1767
expect_stop(&mut self)1768 fn expect_stop(&mut self) {
1769 self.last_command.push_back(ExecutedCommand::Stop);
1770 }
1771 }
1772
1773 impl ProcessManager for MockProcessManager {
start(&mut self, _virt: VirtualHciIndex, _real: RealHciIndex)1774 fn start(&mut self, _virt: VirtualHciIndex, _real: RealHciIndex) {
1775 self.expectations.push(match self.last_command.pop_front() {
1776 Some(x) => {
1777 if x == ExecutedCommand::Start {
1778 None
1779 } else {
1780 Some(format!("Got [Start], Expected: [{:?}]", x))
1781 }
1782 }
1783 None => Some("Got [Start], Expected: None".to_string()),
1784 });
1785 }
1786
stop(&mut self, _virt: VirtualHciIndex, _real: RealHciIndex)1787 fn stop(&mut self, _virt: VirtualHciIndex, _real: RealHciIndex) {
1788 self.expectations.push(match self.last_command.pop_front() {
1789 Some(x) => {
1790 if x == ExecutedCommand::Stop {
1791 None
1792 } else {
1793 Some(format!("Got [Stop], Expected: [{:?}]", x))
1794 }
1795 }
1796 None => Some("Got [Stop], Expected: None".to_string()),
1797 });
1798 }
1799 }
1800
1801 impl Drop for MockProcessManager {
drop(&mut self)1802 fn drop(&mut self) {
1803 assert_eq!(self.last_command.len(), 0);
1804 let exp: &[String] = &[];
1805 // Check that we had 0 false expectations.
1806 assert_eq!(
1807 self.expectations
1808 .iter()
1809 .filter(|&v| !v.is_none())
1810 .map(|v| v.as_ref().unwrap().clone())
1811 .collect::<Vec<String>>()
1812 .as_slice(),
1813 exp
1814 );
1815 }
1816 }
1817
1818 // For tests, this is the default adapter we want
1819 const DEFAULT_ADAPTER: VirtualHciIndex = VirtualHciIndex(0);
1820 const ALT_ADAPTER: VirtualHciIndex = VirtualHciIndex(1);
1821
make_state_machine(process_manager: MockProcessManager) -> StateMachineInternal1822 fn make_state_machine(process_manager: MockProcessManager) -> StateMachineInternal {
1823 StateMachineInternal::new(Box::new(process_manager), true, DEFAULT_ADAPTER)
1824 }
1825
1826 #[test]
initial_state_is_off()1827 fn initial_state_is_off() {
1828 tokio::runtime::Runtime::new().unwrap().block_on(async {
1829 let process_manager = MockProcessManager::new();
1830 let state_machine = make_state_machine(process_manager);
1831 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off);
1832 })
1833 }
1834
1835 #[test]
off_turnoff_should_noop()1836 fn off_turnoff_should_noop() {
1837 tokio::runtime::Runtime::new().unwrap().block_on(async {
1838 let process_manager = MockProcessManager::new();
1839 let mut state_machine = make_state_machine(process_manager);
1840 state_machine.action_stop_bluetooth(DEFAULT_ADAPTER);
1841 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off);
1842 })
1843 }
1844
1845 #[test]
off_turnon_should_turningon()1846 fn off_turnon_should_turningon() {
1847 tokio::runtime::Runtime::new().unwrap().block_on(async {
1848 let mut process_manager = MockProcessManager::new();
1849 // Expect to send start command
1850 process_manager.expect_start();
1851 let mut state_machine = make_state_machine(process_manager);
1852 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
1853 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
1854 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
1855 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOn);
1856 })
1857 }
1858
1859 #[test]
turningon_turnon_again_resends_start()1860 fn turningon_turnon_again_resends_start() {
1861 tokio::runtime::Runtime::new().unwrap().block_on(async {
1862 let mut process_manager = MockProcessManager::new();
1863 // Expect to send start command just once
1864 process_manager.expect_start();
1865 process_manager.expect_start();
1866 let mut state_machine = make_state_machine(process_manager);
1867 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
1868 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
1869 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
1870 assert_eq!(
1871 state_machine.action_start_bluetooth(DEFAULT_ADAPTER),
1872 (ProcessState::TurningOn, CommandTimeoutAction::ResetTimer)
1873 );
1874 })
1875 }
1876
1877 #[test]
turningon_bluetooth_started()1878 fn turningon_bluetooth_started() {
1879 tokio::runtime::Runtime::new().unwrap().block_on(async {
1880 let mut process_manager = MockProcessManager::new();
1881 process_manager.expect_start();
1882 let mut state_machine = make_state_machine(process_manager);
1883 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
1884 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
1885 state_machine.action_on_bluetooth_started(0, DEFAULT_ADAPTER);
1886 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::On);
1887 })
1888 }
1889
1890 #[test]
turningon_bluetooth_different_hci_started()1891 fn turningon_bluetooth_different_hci_started() {
1892 tokio::runtime::Runtime::new().unwrap().block_on(async {
1893 let mut process_manager = MockProcessManager::new();
1894 process_manager.expect_start();
1895 let mut state_machine = make_state_machine(process_manager);
1896 state_machine.action_on_hci_presence_changed(ALT_ADAPTER, true);
1897 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
1898 state_machine.action_start_bluetooth(ALT_ADAPTER);
1899 state_machine.action_on_bluetooth_started(1, ALT_ADAPTER);
1900 assert_eq!(state_machine.get_process_state(ALT_ADAPTER), ProcessState::On);
1901 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off);
1902 })
1903 }
1904
1905 #[test]
turningon_timeout()1906 fn turningon_timeout() {
1907 tokio::runtime::Runtime::new().unwrap().block_on(async {
1908 let mut process_manager = MockProcessManager::new();
1909 process_manager.expect_start();
1910 process_manager.expect_stop();
1911 process_manager.expect_start(); // start bluetooth again
1912 let mut state_machine = make_state_machine(process_manager);
1913 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
1914 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
1915 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
1916 assert_eq!(
1917 state_machine.action_on_command_timeout(DEFAULT_ADAPTER),
1918 StateMachineTimeoutActions::RetryStart
1919 );
1920 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOn);
1921 })
1922 }
1923
1924 #[test]
turningon_turnoff_should_noop()1925 fn turningon_turnoff_should_noop() {
1926 tokio::runtime::Runtime::new().unwrap().block_on(async {
1927 let mut process_manager = MockProcessManager::new();
1928 process_manager.expect_start();
1929 let mut state_machine = make_state_machine(process_manager);
1930 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
1931 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
1932 state_machine.action_stop_bluetooth(DEFAULT_ADAPTER);
1933 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOn);
1934 })
1935 }
1936
1937 #[test]
on_turnoff_should_turningoff_and_send_command()1938 fn on_turnoff_should_turningoff_and_send_command() {
1939 tokio::runtime::Runtime::new().unwrap().block_on(async {
1940 let mut process_manager = MockProcessManager::new();
1941 process_manager.expect_start();
1942 // Expect to send stop command
1943 process_manager.expect_stop();
1944 let mut state_machine = make_state_machine(process_manager);
1945 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
1946 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
1947 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
1948 state_machine.action_on_bluetooth_started(0, DEFAULT_ADAPTER);
1949 state_machine.action_stop_bluetooth(DEFAULT_ADAPTER);
1950 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOff);
1951 })
1952 }
1953
1954 #[test]
on_bluetooth_stopped_multicase()1955 fn on_bluetooth_stopped_multicase() {
1956 // Normal bluetooth stopped should restart.
1957 tokio::runtime::Runtime::new().unwrap().block_on(async {
1958 let mut process_manager = MockProcessManager::new();
1959 process_manager.expect_start();
1960 // Expect to wait for stopped and start again
1961 process_manager.expect_stop();
1962 process_manager.expect_start();
1963 let mut state_machine = make_state_machine(process_manager);
1964 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
1965 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
1966 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
1967 state_machine.action_on_bluetooth_started(0, DEFAULT_ADAPTER);
1968 assert_eq!(
1969 state_machine.action_on_bluetooth_stopped(DEFAULT_ADAPTER),
1970 (ProcessState::TurningOn, CommandTimeoutAction::ResetTimer)
1971 );
1972 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOn);
1973 });
1974
1975 // Stopped with no presence should not restart even if config enabled.
1976 tokio::runtime::Runtime::new().unwrap().block_on(async {
1977 let mut process_manager = MockProcessManager::new();
1978 process_manager.expect_start();
1979 // Expect to wait for stopped
1980 process_manager.expect_stop();
1981 let mut state_machine = make_state_machine(process_manager);
1982 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
1983 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
1984 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
1985 state_machine.action_on_bluetooth_started(0, DEFAULT_ADAPTER);
1986 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, false);
1987 assert_eq!(
1988 state_machine.action_on_bluetooth_stopped(DEFAULT_ADAPTER),
1989 (ProcessState::Off, CommandTimeoutAction::CancelTimer)
1990 );
1991 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off);
1992 });
1993
1994 // If floss was disabled and we see stopped, we shouldn't restart.
1995 tokio::runtime::Runtime::new().unwrap().block_on(async {
1996 let mut process_manager = MockProcessManager::new();
1997 process_manager.expect_start();
1998 let mut state_machine = make_state_machine(process_manager);
1999 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
2000 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
2001 state_machine.action_on_bluetooth_started(0, DEFAULT_ADAPTER);
2002 state_machine.set_floss_enabled(false);
2003 assert_eq!(
2004 state_machine.action_on_bluetooth_stopped(DEFAULT_ADAPTER),
2005 (ProcessState::Off, CommandTimeoutAction::CancelTimer)
2006 );
2007 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off);
2008 });
2009 }
2010
2011 #[test]
turningoff_bluetooth_down_should_off()2012 fn turningoff_bluetooth_down_should_off() {
2013 tokio::runtime::Runtime::new().unwrap().block_on(async {
2014 let mut process_manager = MockProcessManager::new();
2015 process_manager.expect_start();
2016 process_manager.expect_stop();
2017 let mut state_machine = make_state_machine(process_manager);
2018 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
2019 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
2020 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
2021 state_machine.action_on_bluetooth_started(0, DEFAULT_ADAPTER);
2022 state_machine.action_stop_bluetooth(DEFAULT_ADAPTER);
2023 state_machine.action_on_bluetooth_stopped(DEFAULT_ADAPTER);
2024 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off);
2025 })
2026 }
2027
2028 #[test]
restart_bluetooth()2029 fn restart_bluetooth() {
2030 tokio::runtime::Runtime::new().unwrap().block_on(async {
2031 let mut process_manager = MockProcessManager::new();
2032 process_manager.expect_start();
2033 process_manager.expect_stop();
2034 process_manager.expect_start();
2035 let mut state_machine = make_state_machine(process_manager);
2036 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
2037 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
2038 state_machine.action_on_bluetooth_started(0, DEFAULT_ADAPTER);
2039 state_machine.action_stop_bluetooth(DEFAULT_ADAPTER);
2040 state_machine.action_on_bluetooth_stopped(DEFAULT_ADAPTER);
2041 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
2042 state_machine.action_on_bluetooth_started(0, DEFAULT_ADAPTER);
2043 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::On);
2044 })
2045 }
2046
2047 #[test]
start_bluetooth_without_device_fails()2048 fn start_bluetooth_without_device_fails() {
2049 tokio::runtime::Runtime::new().unwrap().block_on(async {
2050 let process_manager = MockProcessManager::new();
2051 let mut state_machine = make_state_machine(process_manager);
2052 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
2053 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off);
2054 });
2055 }
2056
2057 #[test]
start_bluetooth_without_floss_fails()2058 fn start_bluetooth_without_floss_fails() {
2059 tokio::runtime::Runtime::new().unwrap().block_on(async {
2060 let process_manager = MockProcessManager::new();
2061 let mut state_machine = make_state_machine(process_manager);
2062 state_machine.set_floss_enabled(false);
2063 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
2064 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
2065 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
2066 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off);
2067 });
2068 }
2069
2070 #[test]
on_timeout_multicase()2071 fn on_timeout_multicase() {
2072 // If a timeout occurs while turning on or off with floss enabled..
2073 tokio::runtime::Runtime::new().unwrap().block_on(async {
2074 let mut process_manager = MockProcessManager::new();
2075 process_manager.expect_start();
2076 // Expect a stop and start for timeout.
2077 process_manager.expect_stop();
2078 process_manager.expect_start();
2079 // Expect another stop for stop timeout.
2080 process_manager.expect_stop();
2081 process_manager.expect_stop();
2082 let mut state_machine = make_state_machine(process_manager);
2083 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
2084 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
2085 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
2086 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOn);
2087 assert_eq!(
2088 state_machine.action_on_command_timeout(DEFAULT_ADAPTER),
2089 StateMachineTimeoutActions::RetryStart
2090 );
2091 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOn);
2092 state_machine.action_on_bluetooth_started(0, DEFAULT_ADAPTER);
2093 state_machine.action_stop_bluetooth(DEFAULT_ADAPTER);
2094 assert_eq!(
2095 state_machine.action_on_command_timeout(DEFAULT_ADAPTER),
2096 StateMachineTimeoutActions::RetryStop
2097 );
2098 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOff);
2099 });
2100
2101 // If a timeout occurs during turning on and floss is disabled, stop the adapter.
2102 tokio::runtime::Runtime::new().unwrap().block_on(async {
2103 let mut process_manager = MockProcessManager::new();
2104 process_manager.expect_start();
2105 // Expect a stop for timeout since floss is disabled.
2106 process_manager.expect_stop();
2107 let mut state_machine = make_state_machine(process_manager);
2108 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
2109 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
2110 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
2111 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOn);
2112 state_machine.set_floss_enabled(false);
2113 assert_eq!(
2114 state_machine.action_on_command_timeout(DEFAULT_ADAPTER),
2115 StateMachineTimeoutActions::Noop
2116 );
2117 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off);
2118 });
2119
2120 // If a timeout occurs during TurningOn phase, use config_enabled to decide eventual state.
2121 tokio::runtime::Runtime::new().unwrap().block_on(async {
2122 let mut process_manager = MockProcessManager::new();
2123 process_manager.expect_start();
2124 process_manager.expect_stop();
2125 let mut state_machine = make_state_machine(process_manager);
2126 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true);
2127 state_machine.set_config_enabled(DEFAULT_ADAPTER, true);
2128 state_machine.action_start_bluetooth(DEFAULT_ADAPTER);
2129 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOn);
2130 state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, false);
2131 assert_eq!(
2132 state_machine.action_on_command_timeout(DEFAULT_ADAPTER),
2133 StateMachineTimeoutActions::Noop
2134 );
2135 assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off);
2136 });
2137 }
2138
2139 #[test]
test_updated_virtual_id()2140 fn test_updated_virtual_id() {
2141 let process_manager = MockProcessManager::new();
2142 let mut state_machine = make_state_machine(process_manager);
2143
2144 // Note: Test ordering matters here. When re-ordering, keep track of what
2145 // the previous and next states are expected to be. Cases below will also
2146 // denote which match arm it's trying to test.
2147
2148 // Case #1: (None, None)
2149 // Insert a devpath + real index at 0. Expect virtual index of 0.
2150 assert_eq!(
2151 state_machine.get_updated_virtual_id("/fake/bt0".into(), RealHciIndex(0)),
2152 VirtualHciIndex(0)
2153 );
2154
2155 // Case #2: (None, None)
2156 // Inserting a real index of 2 will still get you a virtual index of 1.
2157 // We insert in increasing order.
2158 assert_eq!(
2159 state_machine.get_updated_virtual_id("/fake/bt1".into(), RealHciIndex(2)),
2160 VirtualHciIndex(1)
2161 );
2162
2163 // Case #3: (Some(dev), None)
2164 // Inserting a new real hci for an existing devpath should return the same virtual index.
2165 assert_eq!(
2166 state_machine.get_updated_virtual_id("/fake/bt0".into(), RealHciIndex(12)),
2167 VirtualHciIndex(0)
2168 );
2169 assert_eq!(
2170 Some(RealHciIndex(12)),
2171 state_machine.get_state(VirtualHciIndex(0), |a: &AdapterState| Some(a.real_hci))
2172 );
2173
2174 // Case #4: (Some(dev), Some(real)) if dev == real
2175 // When devpath and real hci match, expect a stable virtual index.
2176 assert_eq!(
2177 state_machine.get_updated_virtual_id("/fake/bt0".into(), RealHciIndex(12)),
2178 VirtualHciIndex(0)
2179 );
2180
2181 // Case #5: (None, None) and (None, Some(real))
2182 // If we inserted previously without a devpath, assign this devpath to the index.
2183 assert_eq!(
2184 state_machine.get_updated_virtual_id(String::new(), RealHciIndex(0)),
2185 VirtualHciIndex(2)
2186 );
2187 assert_eq!(
2188 Some(String::new()),
2189 state_machine.get_state(VirtualHciIndex(2), |a: &AdapterState| Some(a.devpath.clone()))
2190 );
2191 assert_eq!(
2192 state_machine.get_updated_virtual_id("/fake/bt2".into(), RealHciIndex(0)),
2193 VirtualHciIndex(2)
2194 );
2195 assert_eq!(
2196 Some("/fake/bt2".into()),
2197 state_machine.get_state(VirtualHciIndex(2), |a: &AdapterState| Some(a.devpath.clone()))
2198 );
2199
2200 // Case #6: (Some(dev), Some(real)) if dev != real
2201 // We always prefer the virtual index pointed to by the devpath.
2202 assert_eq!(
2203 state_machine.get_updated_virtual_id("/fake/bt0".into(), RealHciIndex(0)),
2204 VirtualHciIndex(0)
2205 );
2206 assert_eq!(
2207 Some("/fake/bt0".to_string()),
2208 state_machine.get_state(VirtualHciIndex(0), |a: &AdapterState| Some(a.devpath.clone()))
2209 );
2210 assert_eq!(
2211 Some(RealHciIndex(0)),
2212 state_machine.get_state(VirtualHciIndex(0), |a: &AdapterState| Some(a.real_hci))
2213 );
2214 assert_eq!(
2215 Some(RealHciIndex(INVALID_HCI_INDEX)),
2216 state_machine.get_state(VirtualHciIndex(2), |a: &AdapterState| Some(a.real_hci))
2217 );
2218 }
2219
2220 #[test]
path_to_pid()2221 fn path_to_pid() {
2222 assert_eq!(
2223 get_hci_index_from_pid_path("/var/run/bluetooth/bluetooth0.pid"),
2224 Some(VirtualHciIndex(0))
2225 );
2226 assert_eq!(get_hci_index_from_pid_path("bluetooth0.pid"), Some(VirtualHciIndex(0)));
2227 assert_eq!(
2228 get_hci_index_from_pid_path("/var/run/bluetooth/bluetooth1.pid"),
2229 Some(VirtualHciIndex(1))
2230 );
2231 assert_eq!(get_hci_index_from_pid_path("bluetooth1.pid"), Some(VirtualHciIndex(1)));
2232 assert_eq!(
2233 get_hci_index_from_pid_path("/var/run/bluetooth/bluetooth10.pid"),
2234 Some(VirtualHciIndex(10))
2235 );
2236 assert_eq!(get_hci_index_from_pid_path("bluetooth10.pid"), Some(VirtualHciIndex(10)));
2237 assert_eq!(get_hci_index_from_pid_path("/var/run/bluetooth/garbage"), None);
2238 assert_eq!(get_hci_index_from_pid_path("garbage"), None);
2239 }
2240 }
2241