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