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