Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 38a266a4 authored by howardchung's avatar howardchung
Browse files

Floss: Implement basic bluetoothAdmin interface

Implement proto type of bluetoothAdmin and implement some basic
functions.

Bug: 239470589
Test: run build.py --target test and test it along with the top
of this chain
Tag: #floss

Change-Id: I74a880cbe59c96308d1e5fa69c911dd0c4b6d73f
parent 78f93b2e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ use btstack::{
    battery_provider_manager::BatteryProviderManager,
    battery_service::BatteryService,
    bluetooth::{get_bt_dispatcher, Bluetooth, IBluetooth},
    bluetooth_admin::BluetoothAdmin,
    bluetooth_gatt::BluetoothGatt,
    bluetooth_media::BluetoothMedia,
    socket_manager::BluetoothSocketManager,
@@ -125,6 +126,7 @@ fn main() -> Result<(), Box<dyn Error>> {
        battery_provider_manager.clone(),
        tx.clone(),
    ))));
    let bluetooth_admin = Arc::new(Mutex::new(Box::new(BluetoothAdmin::new())));
    let bluetooth = Arc::new(Mutex::new(Box::new(Bluetooth::new(
        tx.clone(),
        intf.clone(),
@@ -288,6 +290,7 @@ fn main() -> Result<(), Box<dyn Error>> {

            let adapter = bluetooth.clone();
            bluetooth_media.lock().unwrap().set_adapter(adapter.clone());
            bluetooth_admin.lock().unwrap().set_adapter(adapter.clone());

            let mut bluetooth = bluetooth.lock().unwrap();
            bluetooth.init_profiles();
+3 −0
Original line number Diff line number Diff line
@@ -22,3 +22,6 @@ tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros',

[lib]
path = "src/lib.rs"

[build-dependencies]
pkg-config = "0.3.19"
+16 −0
Original line number Diff line number Diff line
fn main() {
    let target_dir = std::env::var_os("CARGO_TARGET_DIR").unwrap();

    // The main linking point with c++ code is the libbluetooth-static.a
    // These includes all the symbols built via C++ but doesn't include other
    // links (i.e. pkg-config)
    println!("cargo:rustc-link-lib=static=bluetooth-static");
    println!("cargo:rustc-link-search=native={}", target_dir.clone().into_string().unwrap());

    // A few dynamic links
    println!("cargo:rustc-link-lib=dylib=flatbuffers");
    println!("cargo:rustc-link-lib=dylib=protobuf");
    println!("cargo:rustc-link-lib=dylib=resolv");

    println!("cargo:rerun-if-changed=build.rs");
}
+131 −0
Original line number Diff line number Diff line
//! Anything related to the Admin API (IBluetoothAdmin).

use std::collections::HashSet;
use std::sync::{Arc, Mutex};

use crate::bluetooth::{Bluetooth, BluetoothDevice, IBluetooth};
use bt_topshim::btif::Uuid128Bit;
use log::warn;

/// Defines the Admin API
pub trait IBluetoothAdmin {
    /// Check if the given UUID is in the allowlist
    fn is_service_allowed(&self, service: Uuid128Bit) -> bool;
    /// Overwrite the current settings and store it to a file.
    fn set_allowed_services(&mut self, services: Vec<Uuid128Bit>) -> bool;
    /// Get the allowlist in UUIDs
    fn get_allowed_services(&self) -> Vec<Uuid128Bit>;
    /// Get the PolicyEffect struct of a device
    fn get_device_policy_effect(&self, device: BluetoothDevice) -> Option<PolicyEffect>;
}

/// Information of the effects to a remote device by the admin policies
pub struct PolicyEffect {
    pub service_blocked: Vec<Uuid128Bit>,
}

pub struct BluetoothAdmin {
    adapter: Option<Arc<Mutex<Box<Bluetooth>>>>,
    allowed_services: HashSet<Uuid128Bit>,
}

impl BluetoothAdmin {
    pub fn new() -> BluetoothAdmin {
        // TODO: Load all admin settings from a file.
        BluetoothAdmin {
            adapter: None,
            allowed_services: HashSet::new(), //empty means allowed all services
        }
    }

    pub fn set_adapter(&mut self, adapter: Arc<Mutex<Box<Bluetooth>>>) {
        self.adapter = Some(adapter);
    }

    fn get_blocked_services(&self, remote_uuids: &Vec<Uuid128Bit>) -> Vec<Uuid128Bit> {
        remote_uuids
            .iter()
            .filter(|&s| !self.is_service_allowed(s.clone()))
            .cloned()
            .collect::<Vec<Uuid128Bit>>()
    }
}

impl IBluetoothAdmin for BluetoothAdmin {
    fn is_service_allowed(&self, service: Uuid128Bit) -> bool {
        self.allowed_services.is_empty() || self.allowed_services.contains(&service)
    }

    fn set_allowed_services(&mut self, services: Vec<Uuid128Bit>) -> bool {
        self.allowed_services.clear();

        for service in services.iter() {
            self.allowed_services.insert(service.clone());
        }

        // TODO: Toggle profiles here.
        true
    }

    fn get_allowed_services(&self) -> Vec<Uuid128Bit> {
        self.allowed_services.iter().cloned().collect()
    }

    fn get_device_policy_effect(&self, device: BluetoothDevice) -> Option<PolicyEffect> {
        if let Some(adapter) = &self.adapter {
            let service_blocked =
                self.get_blocked_services(&adapter.lock().unwrap().get_remote_uuids(device));

            if service_blocked.is_empty() {
                None
            } else {
                Some(PolicyEffect { service_blocked })
            }
        } else {
            warn!("Adapter not found");
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::bluetooth_admin::{BluetoothAdmin, IBluetoothAdmin};
    use bt_topshim::btif::Uuid128Bit;

    // A workaround needed for linking. For more details, check the comment in
    // system/gd/rust/topshim/facade/src/main.rs
    #[allow(unused)]
    use bt_shim::*;

    #[test]
    fn test_set_service_allowed() {
        let mut admin = BluetoothAdmin::new();
        let uuid1: Uuid128Bit = [1; 16];
        let uuid2: Uuid128Bit = [2; 16];
        let uuid3: Uuid128Bit = [3; 16];
        let uuids = vec![uuid1.clone(), uuid2.clone(), uuid3.clone()];

        // Default admin allows everything
        assert!(admin.is_service_allowed(uuid1));
        assert!(admin.is_service_allowed(uuid2));
        assert!(admin.is_service_allowed(uuid3));
        assert_eq!(admin.get_blocked_services(&uuids), Vec::<Uuid128Bit>::new());

        admin.set_allowed_services(vec![uuid1.clone(), uuid3.clone()]);

        // Admin disallows uuid2 now
        assert!(admin.is_service_allowed(uuid1));
        assert!(!admin.is_service_allowed(uuid2));
        assert!(admin.is_service_allowed(uuid3));
        assert_eq!(admin.get_blocked_services(&uuids), vec![uuid2.clone()]);

        admin.set_allowed_services(vec![uuid2.clone()]);

        // Allowed services were overwritten.
        assert!(!admin.is_service_allowed(uuid1));
        assert!(admin.is_service_allowed(uuid2));
        assert!(!admin.is_service_allowed(uuid3));
        assert_eq!(admin.get_blocked_services(&uuids), vec![uuid1.clone(), uuid3.clone()]);
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ pub mod battery_manager;
pub mod battery_provider_manager;
pub mod battery_service;
pub mod bluetooth;
pub mod bluetooth_admin;
pub mod bluetooth_adv;
pub mod bluetooth_gatt;
pub mod bluetooth_media;