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

Commit 9a06e3a6 authored by Archie Pusaka's avatar Archie Pusaka
Browse files

Floss: Always set scan parameters for LE scan

If the LE scan parameters are not specified, libbluetooth will default
to 3s for both the scan window and interval, which means 100% duty scan
cycle. This might leave the controller with no chance to do other
activities, e.g. connecting to LE devices.

This CL makes sure that we always set the scan parameters before every
LE scan start attempt.

Bug: 298602709
Tag: #floss
Test: m -j
Test: Activate FP background scan, power cycle BT adapter, then
      reconnect any HID LE device. Verify reconnection is immediate.
Change-Id: I4d88f1db1dcfb9c6ab92c2d667798398a0aa8277
parent 2dcade2c
Loading
Loading
Loading
Loading
+59 −21
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ use num_traits::clamp;
use rand::rngs::SmallRng;
use rand::{RngCore, SeedableRng};
use std::collections::{HashMap, HashSet};
use std::convert::TryInto;
use std::convert::{TryFrom, TryInto};
use std::sync::{Arc, Mutex, MutexGuard};
use tokio::sync::mpsc::Sender;

@@ -1144,7 +1144,7 @@ impl Default for GattWriteType {
    }
}

#[derive(Debug, FromPrimitive, ToPrimitive)]
#[derive(Debug, FromPrimitive, ToPrimitive, Clone)]
#[repr(u32)]
/// Scan type configuration.
pub enum ScanType {
@@ -1162,13 +1162,31 @@ impl Default for ScanType {
///
/// This configuration is general and supported on all Bluetooth hardware, irrelevant of the
/// hardware filter offload (APCF or MSFT).
#[derive(Debug, Default)]
#[derive(Debug, Clone)]
pub struct ScanSettings {
    pub interval: i32,
    pub window: i32,
    pub scan_type: ScanType,
}

impl ScanSettings {
    fn extract_scan_parameters(self) -> Option<(u16, u16)> {
        let interval = u16::try_from(self.interval);
        if interval.is_err() {
            println!("Invalid scan interval {}", self.interval);
            return None;
        }

        let window = u16::try_from(self.window);
        if window.is_err() {
            println!("Invalid scan window {}", self.window);
            return None;
        }

        return Some((interval.unwrap(), window.unwrap()));
    }
}

/// Represents scan result
#[derive(Debug)]
pub struct ScanResult {
@@ -1312,13 +1330,22 @@ impl GattAsyncIntf {
    ///
    /// Note: this does not need to be async, but declared as async for consistency in this struct.
    /// May be converted into real async in the future if btif supports it.
    async fn update_scan(&mut self) {
    async fn update_scan(&mut self, scanner_id: u8, scan_settings: Option<ScanSettings>) {
        if self.scanners.lock().unwrap().values().find(|scanner| scanner.is_active).is_some() {
            // Toggle the scan off and on so that we reset the scan parameters based on whether
            // we have active scanners using hardware filtering.
            // TODO(b/266752123): We can do more bookkeeping to optimize when we really need to
            // toggle. Also improve toggling API into 1 operation that guarantees correct ordering.
            self.gatt.as_ref().unwrap().lock().unwrap().scanner.stop_scan();
            if let Some(settings) = scan_settings {
                if let Some((scan_interval, scan_window)) = settings.extract_scan_parameters() {
                    self.gatt.as_ref().unwrap().lock().unwrap().scanner.set_scan_parameters(
                        scanner_id,
                        scan_interval,
                        scan_window,
                    );
                }
            }
            self.gatt.as_ref().unwrap().lock().unwrap().scanner.start_scan();
        } else {
            self.gatt.as_ref().unwrap().lock().unwrap().scanner.stop_scan();
@@ -1669,7 +1696,10 @@ impl BluetoothGatt {
                }
            }

            gatt_async.update_scan().await;
            let scan_settings = Self::find_scanner_by_id(&mut scanners.lock().unwrap(), scanner_id)
                .map_or(None, |s| s.scan_settings.clone());

            gatt_async.update_scan(scanner_id, scan_settings).await;
        });

        BtStatus::Success
@@ -1756,22 +1786,13 @@ impl BluetoothGatt {
    /// Start an active scan on given scanner id. This will look up and assign
    /// the correct ScanSettings for it as well.
    pub(crate) fn start_active_scan(&mut self, scanner_id: u8) -> BtStatus {
        let interval: u16 = sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanInterval)
            .try_into()
            .expect("Bad value configured for LeInquiryScanInterval");
        let window: u16 = sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanWindow)
            .try_into()
            .expect("Bad value configured for LeInquiryScanWindow");

        self.gatt
            .as_ref()
            .unwrap()
            .lock()
            .unwrap()
            .scanner
            .set_scan_parameters(scanner_id, interval, window);
        let settings = ScanSettings {
            interval: sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanInterval),
            window: sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanWindow),
            scan_type: ScanType::Active,
        };

        self.start_scan(scanner_id, ScanSettings::default(), /*filter=*/ None)
        self.start_scan(scanner_id, settings, /*filter=*/ None)
    }

    pub(crate) fn stop_active_scan(&mut self, scanner_id: u8) -> BtStatus {
@@ -1805,6 +1826,8 @@ struct ScannerInfo {
    monitor_handle: Option<u8>,
    // Used by start_scan() to determine if it is called because of system resuming.
    is_suspended: bool,
    // The scan parameters to use
    scan_settings: Option<ScanSettings>,
}

impl ScannerInfo {
@@ -1816,6 +1839,7 @@ impl ScannerInfo {
            filter: None,
            monitor_handle: None,
            is_suspended: false,
            scan_settings: None,
        }
    }
}
@@ -1906,6 +1930,16 @@ impl IBluetoothGatt for BluetoothGatt {
            return BtStatus::Busy;
        }

        // We're supposed to directly use the settings provided by the input parameter, but
        // currently UI is sending temporary variables instead. Therefore, load some preset values
        // known to work.
        // TODO(b/217274013): Fix UI plumbing and directly use the provided settings.
        let settings = ScanSettings {
            interval: sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanInterval),
            window: sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanWindow),
            scan_type: ScanType::Active,
        };

        // Multiplexing scanners happens at this layer. The implementations of start_scan
        // and stop_scan maintains the state of all registered scanners and based on the states
        // update the scanning and/or filter states of libbluetooth.
@@ -1915,6 +1949,7 @@ impl IBluetoothGatt for BluetoothGatt {
            if let Some(scanner) = Self::find_scanner_by_id(&mut scanners_lock, scanner_id) {
                scanner.is_active = true;
                scanner.filter = filter.clone();
                scanner.scan_settings = Some(settings);
            } else {
                log::warn!("Scanner {} not found", scanner_id);
                return BtStatus::Fail;
@@ -1975,7 +2010,10 @@ impl IBluetoothGatt for BluetoothGatt {
                }
            }

            gatt_async.update_scan().await;
            let scan_settings = Self::find_scanner_by_id(&mut scanners.lock().unwrap(), scanner_id)
                .map_or(None, |s| s.scan_settings.clone());

            gatt_async.update_scan(scanner_id, scan_settings).await;
        });

        BtStatus::Success