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

Commit fa50f94b authored by Abhishek Pandit-Subedi's avatar Abhishek Pandit-Subedi Committed by Abhishek Pandit-Subedi
Browse files

floss: Cache adapter state during startup

Cache the adapter enabled state on startup so that btmanagerd is always
aware if an adapter is enabled/disabled.

Bug: 194431843
Tag: #floss
Test: Verify on ChromeOS via btclient
Change-Id: I098c846dfd779da5a13ce37ff549c631d25b9d4f
parent 9bf54293
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ use log::{error, info};

use manager_service::iface_bluetooth_manager::{IBluetoothManager, IBluetoothManagerCallback};

use std::collections::HashMap;
use std::process::Command;
use std::sync::atomic::Ordering;

@@ -14,20 +15,44 @@ pub struct BluetoothManager {
    manager_context: ManagerContext,
    callbacks: Vec<(u32, Box<dyn IBluetoothManagerCallback + Send>)>,
    callbacks_last_id: u32,
    cached_devices: HashMap<i32, bool>,
}

impl BluetoothManager {
    pub(crate) fn new(manager_context: ManagerContext) -> BluetoothManager {
        BluetoothManager { manager_context, callbacks: vec![], callbacks_last_id: 0 }
        BluetoothManager {
            manager_context,
            callbacks: vec![],
            callbacks_last_id: 0,
            cached_devices: HashMap::new(),
        }
    }

    pub(crate) fn callback_hci_device_change(&mut self, hci_device: i32, present: bool) {
        if present {
            // Default device to false or whatever was already existing in cache
            self.cached_devices.entry(hci_device).or_insert(false);
        } else {
            // Remove device and ignore if it's not there
            self.cached_devices.remove(&hci_device);
        }

    pub(crate) fn callback_hci_device_change(&self, hci_device: i32, present: bool) {
        for (_, callback) in &self.callbacks {
            callback.on_hci_device_changed(hci_device, present);
        }
    }

    pub(crate) fn callback_hci_enabled_change(&self, hci_device: i32, enabled: bool) {
    pub(crate) fn callback_hci_enabled_change(&mut self, hci_device: i32, enabled: bool) {
        // Update existing entry or insert new one
        match self.cached_devices.get_mut(&hci_device) {
            Some(dev) => {
                *dev = enabled;
            }
            _ => {
                self.cached_devices.insert(hci_device, enabled);
            }
        };

        for (_, callback) in &self.callbacks {
            callback.on_hci_enabled_changed(hci_device, enabled);
        }
+9 −0
Original line number Diff line number Diff line
@@ -130,6 +130,15 @@ fn hci_devices_string_to_int(devices: Vec<String>) -> Vec<i32> {
        .collect()
}

pub fn list_pid_files(pid_dir: &str) -> Vec<String> {
    match std::fs::read_dir(pid_dir) {
        Ok(entries) => entries
            .map(|e| e.unwrap().path().file_name().unwrap().to_str().unwrap().to_string())
            .collect::<Vec<_>>(),
        _ => Vec::new(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
+26 −0
Original line number Diff line number Diff line
@@ -141,6 +141,14 @@ fn hci_devices_inotify_async_fd() -> AsyncFd<inotify::Inotify> {
    AsyncFd::new(detector).expect("failed to add async fd")
}

/// On startup, get and cache all hci devices by emitting the callback
fn startup_hci_devices(manager: &Arc<std::sync::Mutex<Box<BluetoothManager>>>) {
    let devices = crate::config_util::list_hci_devices();
    for device in devices {
        manager.lock().unwrap().callback_hci_device_change(device, true);
    }
}

/// Given an hci sysfs path, returns the index of the hci device at the path.
fn get_hci_index_from_device(path: &str) -> Option<i32> {
    let re = Regex::new(r"hci([0-9]+)").unwrap();
@@ -168,6 +176,9 @@ pub async fn mainloop<PM>(
    let timeout_clone = command_timeout.clone();
    let timeout_tx = context.tx.clone();

    // First set up hci states
    startup_hci_devices(&bluetooth_manager);

    tokio::spawn(async move {
        loop {
            let _expired = timeout_clone.expired().await;
@@ -178,6 +189,21 @@ pub async fn mainloop<PM>(
        }
    });

    // Get a list of active pid files to determine initial adapter status
    let init_tx = context.tx.clone();
    tokio::spawn(async move {
        let files = crate::config_util::list_pid_files(PID_DIR);
        for file in files {
            let _ = init_tx
                .send_timeout(
                    Message::PidChange(inotify::EventMask::CREATE, Some(file)),
                    TX_SEND_TIMEOUT_DURATION,
                )
                .await
                .unwrap();
        }
    });

    // Set up a PID file listener to emit PID inotify messages
    let mut pid_async_fd = pid_inotify_async_fd();
    let pid_tx = context.tx.clone();