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