blob: 535423a97b2c12bd9e4ce520790a2a7042645e1c [file] [log] [blame]
use log::{error, info, warn};
use std::collections::HashMap;
use std::process::Command;
use crate::iface_bluetooth_experimental::IBluetoothExperimental;
use crate::iface_bluetooth_manager::{
AdapterWithEnabled, IBluetoothManager, IBluetoothManagerCallback,
};
use crate::state_machine::{
state_to_enabled, AdapterState, Message, StateMachineProxy, VirtualHciIndex,
};
use crate::{config_util, migrate};
const BLUEZ_INIT_TARGET: &str = "bluetoothd";
/// Implementation of IBluetoothManager.
pub struct BluetoothManager {
proxy: StateMachineProxy,
callbacks: HashMap<u32, Box<dyn IBluetoothManagerCallback + Send>>,
}
impl BluetoothManager {
pub fn new(proxy: StateMachineProxy) -> BluetoothManager {
BluetoothManager { proxy, callbacks: HashMap::new() }
}
fn is_adapter_enabled(&self, hci_device: VirtualHciIndex) -> bool {
state_to_enabled(self.proxy.get_process_state(hci_device))
}
fn is_adapter_present(&self, hci_device: VirtualHciIndex) -> bool {
self.proxy.get_state(hci_device, move |a| Some(a.present)).unwrap_or(false)
}
pub(crate) fn callback_hci_device_change(&mut self, hci_device: i32, present: bool) {
for (_, callback) in &mut self.callbacks {
callback.on_hci_device_changed(hci_device, present);
}
}
pub(crate) fn callback_hci_enabled_change(&mut self, hci_device: i32, enabled: bool) {
if enabled {
info!("Started {}", hci_device);
} else {
info!("Stopped {}", hci_device);
}
for (_, callback) in &mut self.callbacks {
callback.on_hci_enabled_changed(hci_device, enabled);
}
}
pub(crate) fn callback_default_adapter_change(&mut self, hci_device: i32) {
for (_, callback) in &mut self.callbacks {
callback.on_default_adapter_changed(hci_device);
}
}
pub(crate) fn callback_disconnected(&mut self, id: u32) {
self.callbacks.remove(&id);
}
}
impl IBluetoothManager for BluetoothManager {
fn start(&mut self, hci_interface: i32) {
info!("Starting {}", hci_interface);
if !config_util::modify_hci_n_enabled(hci_interface, true) {
error!("Config is not successfully modified");
}
let virt_hci = VirtualHciIndex(hci_interface);
// Store that this adapter is meant to be started in state machine.
self.proxy.modify_state(virt_hci, move |a: &mut AdapterState| a.config_enabled = true);
// Ignore the request if adapter is already enabled or not present.
if self.is_adapter_enabled(virt_hci) || !self.is_adapter_present(virt_hci) {
return;
}
self.proxy.start_bluetooth(virt_hci);
}
fn stop(&mut self, hci_interface: i32) {
info!("Stopping {}", hci_interface);
if !config_util::modify_hci_n_enabled(hci_interface, false) {
error!("Config is not successfully modified");
}
let virt_hci = VirtualHciIndex(hci_interface);
// Store that this adapter is meant to be stopped in state machine.
self.proxy.modify_state(virt_hci, move |a: &mut AdapterState| a.config_enabled = false);
// Ignore the request if adapter is already disabled.
if !self.is_adapter_enabled(virt_hci) {
return;
}
self.proxy.stop_bluetooth(virt_hci);
}
fn get_adapter_enabled(&mut self, hci_interface: i32) -> bool {
self.is_adapter_enabled(VirtualHciIndex(hci_interface))
}
fn register_callback(&mut self, mut callback: Box<dyn IBluetoothManagerCallback + Send>) {
let tx = self.proxy.get_tx();
let id = callback.register_disconnect(Box::new(move |cb_id| {
let tx = tx.clone();
tokio::spawn(async move {
let _result = tx.send(Message::CallbackDisconnected(cb_id)).await;
});
}));
self.callbacks.insert(id, callback);
}
fn get_floss_enabled(&mut self) -> bool {
self.proxy.get_floss_enabled()
}
fn set_floss_enabled(&mut self, enabled: bool) {
let prev = self.proxy.set_floss_enabled(enabled);
config_util::write_floss_enabled(enabled);
if prev != enabled && enabled {
if let Err(e) = Command::new("initctl").args(&["stop", BLUEZ_INIT_TARGET]).output() {
warn!("Failed to stop bluetoothd: {}", e);
}
migrate::migrate_bluez_devices();
for hci in config_util::list_hci_devices() {
if config_util::is_hci_n_enabled(hci) {
let _ = self.proxy.start_bluetooth(VirtualHciIndex(hci));
}
}
} else if prev != enabled {
for hci in config_util::list_hci_devices() {
if config_util::is_hci_n_enabled(hci) {
let _ = self.proxy.stop_bluetooth(VirtualHciIndex(hci));
}
}
migrate::migrate_floss_devices();
if let Err(e) = Command::new("initctl").args(&["start", BLUEZ_INIT_TARGET]).output() {
warn!("Failed to start bluetoothd: {}", e);
}
}
}
fn get_available_adapters(&mut self) -> Vec<AdapterWithEnabled> {
self.proxy
.get_valid_adapters()
.iter()
.map(|a| AdapterWithEnabled {
hci_interface: a.virt_hci.to_i32(),
enabled: state_to_enabled(a.state),
})
.collect::<Vec<AdapterWithEnabled>>()
}
fn get_default_adapter(&mut self) -> i32 {
self.proxy.get_default_adapter().to_i32()
}
fn set_desired_default_adapter(&mut self, adapter_index: i32) {
self.proxy.set_desired_default_adapter(VirtualHciIndex(adapter_index));
}
}
/// Implementation of IBluetoothExperimental
impl IBluetoothExperimental for BluetoothManager {
fn set_ll_privacy(&mut self, enabled: bool) {
let current_status = match config_util::read_floss_ll_privacy_enabled() {
Ok(true) => true,
_ => false,
};
if current_status == enabled {
return;
}
if let Err(e) = config_util::write_floss_ll_privacy_enabled(enabled) {
error!("Failed to write ll privacy status: {}", e);
return;
}
}
fn set_devcoredump(&mut self, enabled: bool) -> bool {
info!("Set floss devcoredump to {}", enabled);
config_util::write_coredump_state_to_file(enabled)
}
}