1 use log::{error, warn};
2 
3 use std::collections::HashMap;
4 use std::process::Command;
5 use std::sync::{Arc, Mutex};
6 
7 use configparser::ini::Ini;
8 use glob::glob;
9 
10 use crate::powerd_suspend_manager::SuspendManagerContext;
11 
12 use crate::iface_bluetooth_experimental::IBluetoothExperimental;
13 use crate::iface_bluetooth_manager::{
14     AdapterWithEnabled, IBluetoothManager, IBluetoothManagerCallback,
15 };
16 use crate::state_machine::{
17     state_to_enabled, AdapterState, Message, ProcessState, StateMachineProxy, VirtualHciIndex,
18 };
19 use crate::{config_util, migrate};
20 
21 const BLUEZ_INIT_TARGET: &str = "bluetoothd";
22 const INVALID_VER: u16 = 0xffff;
23 
24 /// Implementation of IBluetoothManager.
25 pub struct BluetoothManager {
26     proxy: StateMachineProxy,
27     callbacks: HashMap<u32, Box<dyn IBluetoothManagerCallback + Send>>,
28     suspend_manager_context: Option<Arc<Mutex<SuspendManagerContext>>>,
29 }
30 
31 impl BluetoothManager {
new(proxy: StateMachineProxy) -> BluetoothManager32     pub fn new(proxy: StateMachineProxy) -> BluetoothManager {
33         BluetoothManager { proxy, callbacks: HashMap::new(), suspend_manager_context: None }
34     }
35 
set_suspend_manager_context(&mut self, context: Arc<Mutex<SuspendManagerContext>>)36     pub fn set_suspend_manager_context(&mut self, context: Arc<Mutex<SuspendManagerContext>>) {
37         self.suspend_manager_context = Some(context);
38     }
39 
is_adapter_enabled(&self, hci_device: VirtualHciIndex) -> bool40     fn is_adapter_enabled(&self, hci_device: VirtualHciIndex) -> bool {
41         state_to_enabled(self.proxy.get_process_state(hci_device))
42     }
43 
is_adapter_present(&self, hci_device: VirtualHciIndex) -> bool44     fn is_adapter_present(&self, hci_device: VirtualHciIndex) -> bool {
45         self.proxy.get_state(hci_device, move |a| Some(a.present)).unwrap_or(false)
46     }
47 
callback_hci_device_change(&mut self, hci: VirtualHciIndex, present: bool)48     pub(crate) fn callback_hci_device_change(&mut self, hci: VirtualHciIndex, present: bool) {
49         if present {
50             warn!("Presence added: {}", hci);
51         } else {
52             warn!("Presence removed: {}", hci);
53         }
54         for (_, callback) in &mut self.callbacks {
55             callback.on_hci_device_changed(hci.to_i32(), present);
56         }
57     }
58 
callback_hci_enabled_change(&mut self, hci: VirtualHciIndex, enabled: bool)59     pub(crate) fn callback_hci_enabled_change(&mut self, hci: VirtualHciIndex, enabled: bool) {
60         if enabled {
61             warn!("Started {}", hci);
62         } else {
63             warn!("Stopped {}", hci);
64         }
65 
66         for (_, callback) in &mut self.callbacks {
67             callback.on_hci_enabled_changed(hci.to_i32(), enabled);
68         }
69     }
70 
callback_default_adapter_change(&mut self, hci: VirtualHciIndex)71     pub(crate) fn callback_default_adapter_change(&mut self, hci: VirtualHciIndex) {
72         for (_, callback) in &mut self.callbacks {
73             callback.on_default_adapter_changed(hci.to_i32());
74         }
75     }
76 
callback_disconnected(&mut self, id: u32)77     pub(crate) fn callback_disconnected(&mut self, id: u32) {
78         self.callbacks.remove(&id);
79     }
80 
81     /// Restarts all TurningOn/On adapters to make sure the configuration is reloaded.
restart_adapters(&mut self)82     pub(crate) fn restart_adapters(&mut self) {
83         self.proxy
84             .get_adapters()
85             .iter()
86             .filter(|a| a.state == ProcessState::TurningOn || a.state == ProcessState::On)
87             .for_each(|a| self.proxy.restart_bluetooth(a.virt_hci));
88     }
89 }
90 
91 impl IBluetoothManager for BluetoothManager {
start(&mut self, hci: i32)92     fn start(&mut self, hci: i32) {
93         let hci = VirtualHciIndex(hci);
94         warn!("Starting {}", hci);
95 
96         if !config_util::modify_hci_n_enabled(hci, true) {
97             error!("{}: Config is not successfully modified", hci);
98         }
99 
100         // Store that this adapter is meant to be started in state machine.
101         self.proxy.modify_state(hci, move |a: &mut AdapterState| a.config_enabled = true);
102 
103         // Ignore the request if adapter is already enabled or not present.
104         if self.is_adapter_enabled(hci) {
105             warn!("{} is already enabled.", hci);
106             return;
107         }
108 
109         if !self.is_adapter_present(hci) {
110             warn!("{} is not present.", hci);
111             return;
112         }
113 
114         self.proxy.start_bluetooth(hci);
115     }
116 
stop(&mut self, hci: i32)117     fn stop(&mut self, hci: i32) {
118         let hci = VirtualHciIndex(hci);
119         warn!("Stopping {}", hci);
120 
121         if !config_util::modify_hci_n_enabled(hci, false) {
122             error!("{}: Config is not successfully modified", hci);
123         }
124 
125         // Store that this adapter is meant to be stopped in state machine.
126         self.proxy.modify_state(hci, move |a: &mut AdapterState| a.config_enabled = false);
127 
128         // Ignore the request if adapter is already disabled.
129         if !self.is_adapter_enabled(hci) {
130             warn!("{} is already stopped", hci);
131             return;
132         }
133 
134         self.proxy.stop_bluetooth(hci);
135     }
136 
get_adapter_enabled(&mut self, hci_interface: i32) -> bool137     fn get_adapter_enabled(&mut self, hci_interface: i32) -> bool {
138         self.is_adapter_enabled(VirtualHciIndex(hci_interface))
139     }
140 
register_callback(&mut self, mut callback: Box<dyn IBluetoothManagerCallback + Send>)141     fn register_callback(&mut self, mut callback: Box<dyn IBluetoothManagerCallback + Send>) {
142         let tx = self.proxy.get_tx();
143 
144         let id = callback.register_disconnect(Box::new(move |cb_id| {
145             let tx = tx.clone();
146             tokio::spawn(async move {
147                 let _result = tx.send(Message::CallbackDisconnected(cb_id)).await;
148             });
149         }));
150 
151         self.callbacks.insert(id, callback);
152     }
153 
get_floss_enabled(&mut self) -> bool154     fn get_floss_enabled(&mut self) -> bool {
155         self.proxy.get_floss_enabled()
156     }
157 
set_floss_enabled(&mut self, enabled: bool)158     fn set_floss_enabled(&mut self, enabled: bool) {
159         warn!("Set Floss Enabeld={}", enabled);
160         let prev = self.proxy.set_floss_enabled(enabled);
161         config_util::write_floss_enabled(enabled);
162 
163         if prev != enabled && enabled {
164             if let Err(e) = Command::new("initctl").args(&["stop", BLUEZ_INIT_TARGET]).output() {
165                 warn!("Failed to stop bluetoothd: {}", e);
166             }
167             migrate::migrate_bluez_devices();
168             for hci in self.proxy.get_valid_adapters().iter().map(|a| a.virt_hci) {
169                 if config_util::is_hci_n_enabled(hci) {
170                     self.proxy.start_bluetooth(hci);
171                 }
172             }
173         } else if prev != enabled {
174             for hci in self.proxy.get_valid_adapters().iter().map(|a| a.virt_hci) {
175                 if config_util::is_hci_n_enabled(hci) {
176                     self.proxy.stop_bluetooth(hci);
177                 }
178             }
179             migrate::migrate_floss_devices();
180             if let Err(e) = Command::new("initctl").args(&["start", BLUEZ_INIT_TARGET]).output() {
181                 warn!("Failed to start bluetoothd: {}", e);
182             }
183         }
184     }
185 
get_available_adapters(&mut self) -> Vec<AdapterWithEnabled>186     fn get_available_adapters(&mut self) -> Vec<AdapterWithEnabled> {
187         self.proxy
188             .get_valid_adapters()
189             .iter()
190             // Don't present the queued device to the user.
191             .filter(|a| !a.has_queued_present)
192             .map(|a| AdapterWithEnabled {
193                 hci_interface: a.virt_hci.to_i32(),
194                 enabled: state_to_enabled(a.state),
195             })
196             .collect::<Vec<AdapterWithEnabled>>()
197     }
198 
get_default_adapter(&mut self) -> i32199     fn get_default_adapter(&mut self) -> i32 {
200         self.proxy.get_default_adapter().to_i32()
201     }
202 
set_desired_default_adapter(&mut self, adapter_index: i32)203     fn set_desired_default_adapter(&mut self, adapter_index: i32) {
204         self.proxy.set_desired_default_adapter(VirtualHciIndex(adapter_index));
205     }
206 
get_floss_api_version(&mut self) -> u32207     fn get_floss_api_version(&mut self) -> u32 {
208         let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u16>().unwrap_or(INVALID_VER);
209         let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u16>().unwrap_or(INVALID_VER);
210         ((major as u32) << 16) | (minor as u32)
211     }
212 
set_tablet_mode(&mut self, tablet_mode: bool)213     fn set_tablet_mode(&mut self, tablet_mode: bool) {
214         match &self.suspend_manager_context {
215             Some(ctx) => ctx.lock().unwrap().tablet_mode = tablet_mode,
216             None => warn!("Context not available to set tablet mode."),
217         }
218     }
219 }
220 
221 /// Helper function that check if there is at least one LE device in Floss config file.
config_with_le_device_entry(filename: &str) -> bool222 fn config_with_le_device_entry(filename: &str) -> bool {
223     let mut floss_conf = Ini::new_cs();
224     let floss_map = match floss_conf.load(filename) {
225         Ok(map) => map,
226         Err(err) => {
227             warn!("Error opening ini file while loading Floss devices for {}: {}", filename, err);
228             return false;
229         }
230     };
231     for (sec, props) in floss_map {
232         // Skip all the non-device sections
233         if !sec.contains(":") {
234             continue;
235         }
236         // Invalid entries have no DevType
237         if !props.contains_key("DevType") {
238             continue;
239         }
240         for (k, v) in props {
241             if k == "DevType" {
242                 let val = v.unwrap_or_default().to_string();
243                 // "1" BREDR, "2" LE, "3" DUAL
244                 if val != "1" {
245                     return true;
246                 }
247             }
248         }
249     }
250     return false;
251 }
252 
253 /// Check if there are any LE Floss devices in storage.
floss_have_le_devices() -> bool254 fn floss_have_le_devices() -> bool {
255     let globbed = match glob(migrate::FLOSS_CONF_FILE) {
256         Ok(v) => v,
257         Err(_) => {
258             warn!("Didn't find Floss conf file to search devices");
259             return false;
260         }
261     };
262 
263     for entry in globbed {
264         if config_with_le_device_entry(entry.unwrap_or_default().to_str().unwrap_or_default()) {
265             return true;
266         }
267     }
268     return false;
269 }
270 
271 /// Implementation of IBluetoothExperimental
272 impl IBluetoothExperimental for BluetoothManager {
set_ll_privacy(&mut self, enabled: bool) -> bool273     fn set_ll_privacy(&mut self, enabled: bool) -> bool {
274         warn!("Set Floss LL Privacy={}", enabled);
275         let current_status = match config_util::read_floss_ll_privacy_enabled() {
276             Ok(true) => true,
277             _ => false,
278         };
279         let current_address_status = match config_util::read_floss_address_privacy_enabled() {
280             Ok(true) => true,
281             _ => false,
282         };
283 
284         let mut need_restart = current_status != enabled;
285 
286         if current_status != enabled {
287             if let Err(e) = config_util::write_floss_ll_privacy_enabled(enabled) {
288                 error!("Failed to write ll privacy status: {}", e);
289                 return false;
290             }
291         }
292 
293         // Make change only when LL privacy status is not consistent with address policy and
294         // there is no LE devices in storage.
295         if current_address_status != enabled && !floss_have_le_devices() {
296             // Keep address policy aligned with LL privacy status.
297             if let Err(e) = config_util::write_floss_address_privacy_enabled(enabled) {
298                 error!("Failed to write address privacy status {}: {}", enabled, e);
299             } else {
300                 need_restart = true;
301             }
302         }
303 
304         if need_restart {
305             self.restart_adapters();
306         }
307 
308         return true;
309     }
310 
set_devcoredump(&mut self, enabled: bool) -> bool311     fn set_devcoredump(&mut self, enabled: bool) -> bool {
312         warn!("Set Floss DevCoreDump={}", enabled);
313         config_util::write_coredump_state_to_file(enabled)
314     }
315 }
316