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