• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Anything related to the Admin API (IBluetoothAdmin).
2 
3 use std::collections::{HashMap, HashSet};
4 use std::fs::File;
5 use std::io::{Read, Result, Write};
6 use std::sync::{Arc, Mutex};
7 
8 use crate::bluetooth::{Bluetooth, BluetoothDevice, IBluetooth};
9 use crate::callbacks::Callbacks;
10 use crate::uuid::UuidHelper;
11 use crate::{Message, RPCProxy};
12 
13 use bt_topshim::btif::{BluetoothProperty, Uuid128Bit};
14 use log::{info, warn};
15 use serde_json::{json, Value};
16 use tokio::sync::mpsc::Sender;
17 
18 /// Defines the Admin API
19 pub trait IBluetoothAdmin {
20     /// Check if the given UUID is in the allowlist
is_service_allowed(&self, service: Uuid128Bit) -> bool21     fn is_service_allowed(&self, service: Uuid128Bit) -> bool;
22     /// Overwrite the current settings and store it to a file.
set_allowed_services(&mut self, services: Vec<Uuid128Bit>) -> bool23     fn set_allowed_services(&mut self, services: Vec<Uuid128Bit>) -> bool;
24     /// Get the allowlist in UUIDs
get_allowed_services(&self) -> Vec<Uuid128Bit>25     fn get_allowed_services(&self) -> Vec<Uuid128Bit>;
26     /// Get the PolicyEffect struct of a device
get_device_policy_effect(&self, device: BluetoothDevice) -> Option<PolicyEffect>27     fn get_device_policy_effect(&self, device: BluetoothDevice) -> Option<PolicyEffect>;
28     /// Register client callback
register_admin_policy_callback( &mut self, callback: Box<dyn IBluetoothAdminPolicyCallback + Send>, ) -> u3229     fn register_admin_policy_callback(
30         &mut self,
31         callback: Box<dyn IBluetoothAdminPolicyCallback + Send>,
32     ) -> u32;
33     /// Unregister client callback via callback ID
unregister_admin_policy_callback(&mut self, callback_id: u32) -> bool34     fn unregister_admin_policy_callback(&mut self, callback_id: u32) -> bool;
35 }
36 
37 /// Information of the effects to a remote device by the admin policies
38 #[derive(PartialEq, Clone, Debug)]
39 pub struct PolicyEffect {
40     /// Array of services that are blocked by policy
41     pub service_blocked: Vec<Uuid128Bit>,
42     /// Indicate if the device has an adapter-supported profile that is blocked by the policy
43     pub affected: bool,
44 }
45 
46 pub trait IBluetoothAdminPolicyCallback: RPCProxy {
47     /// This gets called when service allowlist changed.
on_service_allowlist_changed(&mut self, allowlist: Vec<Uuid128Bit>)48     fn on_service_allowlist_changed(&mut self, allowlist: Vec<Uuid128Bit>);
49     /// This gets called when
50     /// 1. a new device is found by adapter
51     /// 2. the policy effect to a device is changed due to
52     ///    the remote services changed or
53     ///    the service allowlist changed.
on_device_policy_effect_changed( &mut self, device: BluetoothDevice, new_policy_effect: Option<PolicyEffect>, )54     fn on_device_policy_effect_changed(
55         &mut self,
56         device: BluetoothDevice,
57         new_policy_effect: Option<PolicyEffect>,
58     );
59 }
60 
61 pub struct BluetoothAdmin {
62     path: String,
63     adapter: Option<Arc<Mutex<Box<Bluetooth>>>>,
64     allowed_services: HashSet<Uuid128Bit>,
65     callbacks: Callbacks<dyn IBluetoothAdminPolicyCallback + Send>,
66     device_policy_affect_cache: HashMap<BluetoothDevice, Option<PolicyEffect>>,
67     tx: Sender<Message>,
68 }
69 
70 impl BluetoothAdmin {
new(path: String, tx: Sender<Message>) -> BluetoothAdmin71     pub fn new(path: String, tx: Sender<Message>) -> BluetoothAdmin {
72         // default admin settings
73         let mut admin = BluetoothAdmin {
74             path,
75             adapter: None,
76             allowed_services: HashSet::new(), //empty means allowed all services
77             callbacks: Callbacks::new(tx.clone(), Message::AdminCallbackDisconnected),
78             device_policy_affect_cache: HashMap::new(),
79             tx: tx.clone(),
80         };
81 
82         if admin.load_config().is_err() {
83             warn!("Failed to load config file");
84         }
85         admin
86     }
87 
set_adapter(&mut self, adapter: Arc<Mutex<Box<Bluetooth>>>)88     pub fn set_adapter(&mut self, adapter: Arc<Mutex<Box<Bluetooth>>>) {
89         self.adapter = Some(adapter.clone());
90     }
91 
get_blocked_services(&self, remote_uuids: &Vec<Uuid128Bit>) -> Vec<Uuid128Bit>92     fn get_blocked_services(&self, remote_uuids: &Vec<Uuid128Bit>) -> Vec<Uuid128Bit> {
93         remote_uuids
94             .iter()
95             .filter(|&s| !self.is_service_allowed(s.clone()))
96             .cloned()
97             .collect::<Vec<Uuid128Bit>>()
98     }
99 
get_affected_status(&self, blocked_services: &Vec<Uuid128Bit>) -> bool100     fn get_affected_status(&self, blocked_services: &Vec<Uuid128Bit>) -> bool {
101         // return true if a supported profile is in blocked services.
102         blocked_services
103             .iter()
104             .find(|&uuid| {
105                 UuidHelper::is_known_profile(uuid)
106                     .map_or(false, |p| UuidHelper::is_profile_supported(&p))
107             })
108             .is_some()
109     }
110 
load_config(&mut self) -> Result<()>111     fn load_config(&mut self) -> Result<()> {
112         let mut file = File::open(&self.path)?;
113         let mut contents = String::new();
114         file.read_to_string(&mut contents)?;
115         let json = serde_json::from_str::<Value>(contents.as_str()).unwrap();
116         if let Some(_res) = self.load_config_from_json(&json) {
117             info!("Load settings from {} successfully", &self.path);
118         }
119         Ok(())
120     }
121 
load_config_from_json(&mut self, json: &Value) -> Option<bool>122     fn load_config_from_json(&mut self, json: &Value) -> Option<bool> {
123         let allowed_services: Vec<Uuid128Bit> = json
124             .get("allowed_services")?
125             .as_array()?
126             .iter()
127             .filter_map(|v| UuidHelper::from_string(v.as_str()?))
128             .collect();
129         self.set_allowed_services(allowed_services);
130         Some(true)
131     }
132 
write_config(&self) -> Result<()>133     fn write_config(&self) -> Result<()> {
134         let mut f = File::create(&self.path)?;
135         f.write_all(self.get_config_string().as_bytes()).and_then(|_| {
136             info!("Write settings into {} successfully", &self.path);
137             Ok(())
138         })
139     }
140 
get_config_string(&self) -> String141     fn get_config_string(&self) -> String {
142         serde_json::to_string_pretty(&json!({
143             "allowed_services":
144                 self.get_allowed_services()
145                     .iter()
146                     .map(UuidHelper::to_string)
147                     .collect::<Vec<String>>()
148         }))
149         .ok()
150         .unwrap()
151     }
152 
new_device_policy_effect(&self, uuids: Option<Vec<Uuid128Bit>>) -> Option<PolicyEffect>153     fn new_device_policy_effect(&self, uuids: Option<Vec<Uuid128Bit>>) -> Option<PolicyEffect> {
154         uuids.map(|uuids| {
155             let service_blocked = self.get_blocked_services(&uuids);
156             let affected = self.get_affected_status(&service_blocked);
157             PolicyEffect { service_blocked, affected }
158         })
159     }
160 
on_device_found(&mut self, remote_device: &BluetoothDevice)161     pub fn on_device_found(&mut self, remote_device: &BluetoothDevice) {
162         self.device_policy_affect_cache.insert(remote_device.clone(), None).or_else(|| {
163             self.callbacks.for_all_callbacks(|cb| {
164                 cb.on_device_policy_effect_changed(remote_device.clone(), None);
165             });
166             None
167         });
168     }
169 
on_device_cleared(&mut self, remote_device: &BluetoothDevice)170     pub fn on_device_cleared(&mut self, remote_device: &BluetoothDevice) {
171         self.device_policy_affect_cache.remove(remote_device);
172     }
173 
on_remote_device_properties_changed( &mut self, remote_device: &BluetoothDevice, properties: &Vec<BluetoothProperty>, )174     pub fn on_remote_device_properties_changed(
175         &mut self,
176         remote_device: &BluetoothDevice,
177         properties: &Vec<BluetoothProperty>,
178     ) {
179         let new_uuids = properties.iter().find_map(|p| match p {
180             BluetoothProperty::Uuids(uuids) => {
181                 Some(uuids.iter().map(|&x| x.uu.clone()).collect::<Vec<Uuid128Bit>>())
182             }
183             _ => None,
184         });
185 
186         // No need to update policy effect if remote UUID is not changed.
187         if new_uuids.is_none() {
188             return;
189         }
190 
191         let new_effect = self.new_device_policy_effect(new_uuids);
192         let cur_effect = self.device_policy_affect_cache.get(remote_device);
193 
194         if cur_effect.is_none() || *cur_effect.unwrap() != new_effect.clone() {
195             self.callbacks.for_all_callbacks(|cb| {
196                 cb.on_device_policy_effect_changed(remote_device.clone(), new_effect.clone())
197             });
198             self.device_policy_affect_cache.insert(remote_device.clone(), new_effect.clone());
199         }
200     }
201 }
202 
203 impl IBluetoothAdmin for BluetoothAdmin {
is_service_allowed(&self, service: Uuid128Bit) -> bool204     fn is_service_allowed(&self, service: Uuid128Bit) -> bool {
205         self.allowed_services.is_empty() || self.allowed_services.contains(&service)
206     }
207 
set_allowed_services(&mut self, services: Vec<Uuid128Bit>) -> bool208     fn set_allowed_services(&mut self, services: Vec<Uuid128Bit>) -> bool {
209         if self.get_allowed_services() == services {
210             // Allowlist is not changed.
211             return true;
212         }
213 
214         self.allowed_services.clear();
215 
216         for service in services.iter() {
217             self.allowed_services.insert(service.clone());
218         }
219 
220         if let Some(adapter) = &self.adapter {
221             let allowed_services = self.get_allowed_services();
222             adapter.lock().unwrap().toggle_enabled_profiles(&allowed_services);
223             if self.write_config().is_err() {
224                 warn!("Failed to write config");
225             }
226 
227             let allowed_services = self.get_allowed_services();
228             self.callbacks.for_all_callbacks(|cb| {
229                 cb.on_service_allowlist_changed(allowed_services.clone());
230             });
231 
232             let txl = self.tx.clone();
233             tokio::spawn(async move {
234                 let _ = txl.send(Message::AdminPolicyChanged).await;
235             });
236 
237             for (device, effect) in self.device_policy_affect_cache.clone().iter() {
238                 let uuids = adapter.lock().unwrap().get_remote_uuids(device.clone());
239                 let new_effect = self.new_device_policy_effect(Some(uuids));
240 
241                 if new_effect.clone() != *effect {
242                     self.callbacks.for_all_callbacks(|cb| {
243                         cb.on_device_policy_effect_changed(device.clone(), new_effect.clone())
244                     });
245                     self.device_policy_affect_cache.insert(device.clone(), new_effect.clone());
246                 }
247             }
248             return true;
249         }
250 
251         false
252     }
253 
get_allowed_services(&self) -> Vec<Uuid128Bit>254     fn get_allowed_services(&self) -> Vec<Uuid128Bit> {
255         self.allowed_services.iter().cloned().collect()
256     }
257 
get_device_policy_effect(&self, device: BluetoothDevice) -> Option<PolicyEffect>258     fn get_device_policy_effect(&self, device: BluetoothDevice) -> Option<PolicyEffect> {
259         if let Some(effect) = self.device_policy_affect_cache.get(&device) {
260             effect.clone()
261         } else {
262             warn!("Device not found in cache");
263             None
264         }
265     }
266 
register_admin_policy_callback( &mut self, callback: Box<dyn IBluetoothAdminPolicyCallback + Send>, ) -> u32267     fn register_admin_policy_callback(
268         &mut self,
269         callback: Box<dyn IBluetoothAdminPolicyCallback + Send>,
270     ) -> u32 {
271         self.callbacks.add_callback(callback)
272     }
273 
unregister_admin_policy_callback(&mut self, callback_id: u32) -> bool274     fn unregister_admin_policy_callback(&mut self, callback_id: u32) -> bool {
275         self.callbacks.remove_callback(callback_id)
276     }
277 }
278 
279 #[cfg(test)]
280 mod tests {
281     use crate::bluetooth_admin::{BluetoothAdmin, IBluetoothAdmin};
282     use crate::uuid::UuidHelper;
283     use crate::Stack;
284     use bt_topshim::btif::Uuid128Bit;
285 
286     // A workaround needed for linking. For more details, check the comment in
287     // system/gd/rust/topshim/facade/src/main.rs
288     #[allow(unused)]
289     use bt_shim::*;
290     use serde_json::{json, Value};
291 
292     #[test]
test_set_service_allowed()293     fn test_set_service_allowed() {
294         let (tx, _) = Stack::create_channel();
295         let mut admin = BluetoothAdmin::new(String::from(""), tx.clone());
296         let uuid1: Uuid128Bit = [1; 16];
297         let uuid2: Uuid128Bit = [2; 16];
298         let uuid3: Uuid128Bit = [3; 16];
299         let uuids = vec![uuid1.clone(), uuid2.clone(), uuid3.clone()];
300 
301         // Default admin allows everything
302         assert!(admin.is_service_allowed(uuid1));
303         assert!(admin.is_service_allowed(uuid2));
304         assert!(admin.is_service_allowed(uuid3));
305         assert_eq!(admin.get_blocked_services(&uuids), Vec::<Uuid128Bit>::new());
306 
307         admin.set_allowed_services(vec![uuid1.clone(), uuid3.clone()]);
308 
309         // Admin disallows uuid2 now
310         assert!(admin.is_service_allowed(uuid1));
311         assert!(!admin.is_service_allowed(uuid2));
312         assert!(admin.is_service_allowed(uuid3));
313         assert_eq!(admin.get_blocked_services(&uuids), vec![uuid2.clone()]);
314 
315         admin.set_allowed_services(vec![uuid2.clone()]);
316 
317         // Allowed services were overwritten.
318         assert!(!admin.is_service_allowed(uuid1));
319         assert!(admin.is_service_allowed(uuid2));
320         assert!(!admin.is_service_allowed(uuid3));
321         assert_eq!(admin.get_blocked_services(&uuids), vec![uuid1.clone(), uuid3.clone()]);
322     }
323 
get_sorted_allowed_services_from_config(admin: &BluetoothAdmin) -> Vec<String>324     fn get_sorted_allowed_services_from_config(admin: &BluetoothAdmin) -> Vec<String> {
325         let mut v = serde_json::from_str::<Value>(admin.get_config_string().as_str())
326             .unwrap()
327             .get("allowed_services")
328             .unwrap()
329             .as_array()
330             .unwrap()
331             .iter()
332             .map(|v| String::from(v.as_str().unwrap()))
333             .collect::<Vec<String>>();
334         v.sort();
335         v
336     }
337 
get_sorted_allowed_services(admin: &BluetoothAdmin) -> Vec<Uuid128Bit>338     fn get_sorted_allowed_services(admin: &BluetoothAdmin) -> Vec<Uuid128Bit> {
339         let mut v = admin.get_allowed_services();
340         v.sort();
341         v
342     }
343 
344     #[test]
test_config()345     fn test_config() {
346         let (tx, _) = Stack::create_channel();
347         let mut admin = BluetoothAdmin::new(String::from(""), tx.clone());
348         let a2dp_sink = "0000110b-0000-1000-8000-00805f9b34fb";
349         let a2dp_source = "0000110a-0000-1000-8000-00805f9b34fb";
350 
351         let a2dp_sink_uuid128 = UuidHelper::from_string(a2dp_sink).unwrap();
352         let a2dp_source_uuid128 = UuidHelper::from_string(a2dp_source).unwrap();
353 
354         let mut allowed_services = vec![a2dp_sink, a2dp_source];
355 
356         let mut allowed_services_128 = vec![a2dp_sink_uuid128, a2dp_source_uuid128];
357 
358         allowed_services.sort();
359         allowed_services_128.sort();
360 
361         // valid configuration
362         assert_eq!(
363             admin.load_config_from_json(&json!({
364                 "allowed_services": allowed_services.clone()
365             })),
366             Some(true)
367         );
368         assert_eq!(get_sorted_allowed_services(&admin), allowed_services_128);
369         assert_eq!(get_sorted_allowed_services_from_config(&admin), allowed_services);
370 
371         // invalid configuration
372         assert_eq!(admin.load_config_from_json(&json!({ "allowed_services": a2dp_sink })), None);
373         // config should remain unchanged
374         assert_eq!(get_sorted_allowed_services(&admin), allowed_services_128);
375         assert_eq!(get_sorted_allowed_services_from_config(&admin), allowed_services);
376     }
377 }
378