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