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

Commit 8826331b authored by Abhishek Pandit-Subedi's avatar Abhishek Pandit-Subedi
Browse files

floss: Trigger LE scan during discovery

Since we treat start/stop discovery as classic only, we need to
start/stop an LE scanner alongside discovery to capture LE devices.
Also set the flag to make discovery classic only.

Bug: 274967984
Tag: #floss
Test: Manual test on ChromeOS with btclient and UI
Change-Id: Ia31171fad6c2644cbe2273d15c705e4e05272a2f
parent 738bd1b8
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -182,3 +182,20 @@ genrule {
        "blueberry/facade/topshim/facade_pb2_grpc.py",
    ],
}

// Export system headers for rules that can't simply use `include_dirs`
cc_library_headers {
    name: "libbluetooth_system_headers",
    defaults: ["libchrome_support_defaults"],
    visibility: [
        "//packages/modules/Bluetooth/system:__subpackages__",
    ],
    export_include_dirs: ["./"],
    vendor_available: true,
    host_supported: true,
    apex_available: [
        "//apex_available:platform",
        "com.android.btservices",
    ],
    min_sdk_version: "30",
}
+6 −2
Original line number Diff line number Diff line
@@ -102,6 +102,9 @@ fn main() -> Result<(), Box<dyn Error>> {
    // Forward --hci to Fluoride.
    init_flags.push(format!("--hci={}", hci_index));

    // Always treat discovery as classic only
    init_flags.push(String::from("INIT_classic_discovery_only=true"));

    let (tx, rx) = Stack::create_channel();
    let sig_notifier = Arc::new((Mutex::new(false), Condvar::new()));

@@ -131,10 +134,11 @@ fn main() -> Result<(), Box<dyn Error>> {
    let bluetooth = Arc::new(Mutex::new(Box::new(Bluetooth::new(
        adapter_index,
        tx.clone(),
        intf.clone(),
        bluetooth_media.clone(),
        sig_notifier.clone(),
        intf.clone(),
        bluetooth_admin.clone(),
        bluetooth_gatt.clone(),
        bluetooth_media.clone(),
    ))));
    let suspend = Arc::new(Mutex::new(Box::new(Suspend::new(
        bluetooth.clone(),
+176 −33
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ use bt_topshim::btif::{
};
use bt_topshim::{
    metrics,
    profiles::gatt::GattStatus,
    profiles::hid_host::{
        BthhConnectionState, BthhHidInfo, BthhProtocolMode, BthhReportType, BthhStatus,
        HHCallbacks, HHCallbacksDispatcher, HidHost,
@@ -37,6 +38,7 @@ use tokio::time;

use crate::battery_service::BatteryServiceActions;
use crate::bluetooth_admin::{BluetoothAdmin, IBluetoothAdmin};
use crate::bluetooth_gatt::{BluetoothGatt, IBluetoothGatt, IScannerCallback, ScanResult};
use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions};
use crate::callbacks::Callbacks;
use crate::uuid::{Profile, UuidHelper, HOGP};
@@ -254,6 +256,12 @@ pub enum DelayedActions {

    /// Connect to all supported profiles on target device.
    ConnectAllProfiles(BluetoothDevice),

    /// Scanner for BLE discovery is registered with given status and scanner id.
    BleDiscoveryScannerRegistered(Uuid128Bit, u8, GattStatus),

    /// Scanner for BLE discovery is reporting a result.
    BleDiscoveryScannerResult(ScanResult),
}

/// Serializable device used in various apis.
@@ -331,19 +339,24 @@ impl BluetoothDeviceContext {

    pub(crate) fn update_properties(&mut self, in_properties: &Vec<BluetoothProperty>) {
        for prop in in_properties {
            // Handle merging of certain properties.
            match &prop {
                BluetoothProperty::BdAddr(bdaddr) => {
                    self.info.address = bdaddr.to_string();
                    self.properties.insert(prop.get_type(), prop.clone());
                }
                BluetoothProperty::BdName(bdname) => {
                    if !bdname.is_empty() {
                        self.info.name = bdname.clone();
                        self.properties.insert(prop.get_type(), prop.clone());
                    }
                _ => {}
                }

                _ => {
                    self.properties.insert(prop.get_type(), prop.clone());
                }
            }
        }
    }

    /// Mark this device as seen.
    pub(crate) fn seen(&mut self) {
@@ -431,8 +444,11 @@ pub struct Bluetooth {

    adapter_index: i32,
    bonded_devices: HashMap<String, BluetoothDeviceContext>,
    bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>,
    ble_scanner_id: Option<u8>,
    ble_scanner_uuid: Option<Uuid128Bit>,
    bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>,
    bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>,
    bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>,
    callbacks: Callbacks<dyn IBluetoothCallback + Send>,
    connection_callbacks: Callbacks<dyn IBluetoothConnectionCallback + Send>,
    discovering_started: Instant,
@@ -461,10 +477,11 @@ impl Bluetooth {
    pub fn new(
        adapter_index: i32,
        tx: Sender<Message>,
        intf: Arc<Mutex<BluetoothInterface>>,
        bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>,
        sig_notifier: Arc<(Mutex<bool>, Condvar)>,
        intf: Arc<Mutex<BluetoothInterface>>,
        bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>,
        bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>,
        bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>,
    ) -> Bluetooth {
        Bluetooth {
            adapter_index,
@@ -475,8 +492,11 @@ impl Bluetooth {
                Message::ConnectionCallbackDisconnected,
            ),
            hh: None,
            bluetooth_media,
            ble_scanner_id: None,
            ble_scanner_uuid: None,
            bluetooth_admin,
            bluetooth_gatt,
            bluetooth_media,
            discovering_started: Instant::now(),
            intf,
            is_connectable: false,
@@ -807,6 +827,63 @@ impl Bluetooth {
            DelayedActions::ConnectAllProfiles(device) => {
                self.connect_all_enabled_profiles(device);
            }

            DelayedActions::BleDiscoveryScannerRegistered(uuid, scanner_id, status) => {
                if let Some(app_uuid) = self.ble_scanner_uuid {
                    if app_uuid == uuid {
                        if status == GattStatus::Success {
                            self.ble_scanner_id = Some(scanner_id);
                        } else {
                            log::error!("BLE discovery scanner failed to register: {:?}", status);
                        }
                    }
                }
            }

            DelayedActions::BleDiscoveryScannerResult(result) => {
                let addr = RawAddress::from_string(result.address);

                let properties = match addr {
                    Some(v) => {
                        let mut props = vec![];
                        props.push(BluetoothProperty::BdName(result.name.clone()));
                        props.push(BluetoothProperty::BdAddr(v.clone()));
                        if result.service_uuids.len() > 0 {
                            props.push(BluetoothProperty::Uuids(
                                result
                                    .service_uuids
                                    .iter()
                                    .map(|&v| Uuid::from(v.clone()))
                                    .collect(),
                            ));
                        }
                        props.push(BluetoothProperty::RemoteRssi(result.rssi));

                        props
                    }
                    None => {
                        return;
                    }
                };

                // Generate a vector of properties from ScanResult.
                let device = BluetoothDevice::from_properties(&properties);
                let address = device.address.clone();

                if let Some(existing) = self.found_devices.get_mut(&address) {
                    existing.update_properties(&properties);
                    existing.seen();
                } else {
                    let device_with_props = BluetoothDeviceContext::new(
                        BtBondState::NotBonded,
                        BtAclState::Disconnected,
                        device,
                        Instant::now(),
                        properties,
                    );
                    self.found_devices.insert(address.clone(), device_with_props);
                }
            }
        }
    }

@@ -1005,15 +1082,8 @@ impl BtifBluetoothCallbacks for Bluetooth {
            return;
        }

        if self.state == BtState::On {
            match self.create_pid_file() {
                Err(err) => warn!("create_pid_file() error: {}", err),
                _ => (),
            }
            self.bluetooth_media.lock().unwrap().initialize();
        }

        if self.state == BtState::Off {
        match self.state {
            BtState::Off => {
                self.properties.clear();
                match self.remove_pid_file() {
                    Err(err) => warn!("remove_pid_file() error: {}", err),
@@ -1023,19 +1093,38 @@ impl BtifBluetoothCallbacks for Bluetooth {
                // Let the signal notifier know we are turned off.
                *self.sig_notifier.0.lock().unwrap() = false;
                self.sig_notifier.1.notify_all();
        } else {
            }

            BtState::On => {
                // Initialize media
                self.bluetooth_media.lock().unwrap().initialize();

                // Trigger properties update
                self.intf.lock().unwrap().get_adapter_properties();

                // Also need to manually request some properties
                self.intf.lock().unwrap().get_adapter_property(BtPropertyType::ClassOfDevice);

                // Initialize the BLE scanner for discovery.
                let callback_id = self.bluetooth_gatt.lock().unwrap().register_scanner_callback(
                    Box::new(BleDiscoveryCallbacks::new(self.tx.clone())),
                );
                self.ble_scanner_uuid =
                    Some(self.bluetooth_gatt.lock().unwrap().register_scanner(callback_id));

                // Ensure device is connectable so that disconnected device can reconnect
                self.set_connectable(true);

                // Notify the signal notifier that we are turned on.
                *self.sig_notifier.0.lock().unwrap() = true;
                self.sig_notifier.1.notify_all();

                // Signal that the stack is up and running.
                match self.create_pid_file() {
                    Err(err) => warn!("create_pid_file() error: {}", err),
                    _ => (),
                }
            }
        }
    }

@@ -1157,6 +1246,15 @@ impl BtifBluetoothCallbacks for Bluetooth {
        if !is_discovering && self.freshness_check.is_none() {
            self.trigger_freshness_check();
        }

        // Start or stop BLE scanning based on discovering state
        if let Some(scanner_id) = self.ble_scanner_id {
            if is_discovering {
                self.bluetooth_gatt.lock().unwrap().start_active_scan(scanner_id);
            } else {
                self.bluetooth_gatt.lock().unwrap().stop_active_scan(scanner_id);
            }
        }
    }

    fn ssp_request(
@@ -1433,6 +1531,51 @@ impl BtifBluetoothCallbacks for Bluetooth {
    }
}

struct BleDiscoveryCallbacks {
    tx: Sender<Message>,
}

impl BleDiscoveryCallbacks {
    fn new(tx: Sender<Message>) -> Self {
        Self { tx }
    }
}

// Handle BLE scanner results.
impl IScannerCallback for BleDiscoveryCallbacks {
    fn on_scanner_registered(&self, uuid: Uuid128Bit, scanner_id: u8, status: GattStatus) {
        let tx = self.tx.clone();
        tokio::spawn(async move {
            let _ = tx
                .send(Message::DelayedAdapterActions(
                    DelayedActions::BleDiscoveryScannerRegistered(uuid, scanner_id, status),
                ))
                .await;
        });
    }

    fn on_scan_result(&self, scan_result: ScanResult) {
        let tx = self.tx.clone();
        tokio::spawn(async move {
            let _ = tx
                .send(Message::DelayedAdapterActions(DelayedActions::BleDiscoveryScannerResult(
                    scan_result,
                )))
                .await;
        });
    }

    fn on_advertisement_found(&self, _scanner_id: u8, _scan_result: ScanResult) {}
    fn on_advertisement_lost(&self, _scanner_id: u8, _scan_result: ScanResult) {}
    fn on_suspend_mode_change(&self, _suspend_mode: SuspendMode) {}
}

impl RPCProxy for BleDiscoveryCallbacks {
    fn get_object_id(&self) -> String {
        "BLE Discovery Callback".to_string()
    }
}

// TODO: Add unit tests for this implementation
impl IBluetooth for Bluetooth {
    fn register_callback(&mut self, callback: Box<dyn IBluetoothCallback + Send>) {
+26 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ use bt_topshim::profiles::gatt::{
    GattScannerInbandCallbacks, GattScannerInbandCallbacksDispatcher, GattServerCallbacks,
    GattServerCallbacksDispatcher, GattStatus, LePhy, MsftAdvMonitor, MsftAdvMonitorPattern,
};
use bt_topshim::sysprop;
use bt_topshim::topstack;
use bt_utils::adv_parser;
use bt_utils::array_utils;
@@ -1714,6 +1715,31 @@ impl BluetoothGatt {

        self.advertisers.set_suspend_mode(SuspendMode::Normal);
    }

    /// 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::Property::LeInquiryScanInterval)
            .try_into()
            .expect("Bad value configured for LeInquiryScanInterval");
        let window: u16 = sysprop::get_i32(sysprop::Property::LeInquiryScanWindow)
            .try_into()
            .expect("Bad value configured for LeInquiryScanWindow");

        self.gatt
            .as_ref()
            .unwrap()
            .lock()
            .unwrap()
            .scanner
            .set_scan_parameters(scanner_id, interval, window);

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

    pub(crate) fn stop_active_scan(&mut self, scanner_id: u8) -> BtStatus {
        self.stop_scan(scanner_id)
    }
}

#[derive(Debug, FromPrimitive, ToPrimitive)]
+5 −1
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ rust_bindgen {
        "--allowlist-function=btgatt_.*",
        "--allowlist-function=btsdp.*",
        "--allowlist-function=hal_util_.*",
        "--allowlist-function=osi_property_get.*",
        "--allowlist-type=bt_.*",
        "--allowlist-type=bthh_.*",
        "--allowlist-type=btgatt_.*",
@@ -137,8 +138,11 @@ rust_bindgen {
    shared_libs: [
        "libc++",
    ],
    // The bindgen rule can only include headers via header_libs and does not
    // support include_dirs. Make sure newly added headers have the correct
    // header export target listed here.
    header_libs: [
        "libbluetooth_headers",
        "libbluetooth_system_headers",
    ],
    include_dirs: ["packages/modules/Bluetooth/system"],
}
Loading