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

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

Refactor topshim with bindgen and unsafe code

Writing topshim interfaces is very tedious and lots of code is
duplicated in C++. Rather that depend on unsafe C++ code, we write
a small amount of unsafe Rust code and use macros to interact with the
native layer directly from Rust.

A few major changes introduced in this patch:
- Bindgen to get Rust interface into C
- Macros to call raw pointer functions directly
- Macros to handle converting a callback into an enum variant
- Refactor code to use new data structures
- Replace use of closures for callbacks with an enum and dispatch fn

This change also updates the bindgen requirement to 0.57 to match what
Android is already using.

BYPASS_INCLUSIVE_LANGUAGE_REASON=Bindgen dependency provides this api

Bug: 183208689
Tag: #floss
Test: atest --host bluetooth_test_gd
Change-Id: Iebe904ebc2643b48d1a371051fbf3c06f2bf04d4
parent ebf26de3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -180,6 +180,7 @@ class HostBuild():
        self.env['CARGO_TARGET_DIR'] = self.output_dir
        self.env['CARGO_HOME'] = os.path.join(self.output_dir, 'cargo_home')
        self.env['RUSTFLAGS'] = self._generate_rustflags()
        self.env['CXX_ROOT_PATH'] = os.path.join(self.platform_dir, 'bt')

        # Configure some GN variables
        if self.use_board:
+33 −85
Original line number Diff line number Diff line
use bt_topshim::btif;
use bt_topshim::btif::{ffi, BluetoothCallbacks, BluetoothInterface};
use bt_topshim::btif::{BaseCallbacks, BaseCallbacksDispatcher, BluetoothInterface};
use bt_topshim::topstack;
use num_traits::{FromPrimitive, ToPrimitive};
use std::convert::TryFrom;
use std::env;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::sync::mpsc::{Receiver, Sender};
@@ -14,126 +13,70 @@ use tokio::time::sleep;
// Required so that bt_shim is linked into the final image
extern crate bt_shim;

enum Callbacks {
    AdapterStateChanged(btif::BtState),
    AdapterPropertiesChanged(i32, i32, Vec<ffi::BtProperty>),
    RemoteDevicePropertiesChanged(i32, ffi::RustRawAddress, i32, Vec<ffi::BtProperty>),
    DeviceFound(i32, Vec<ffi::BtProperty>),
    DiscoveryStateChanged(btif::BtDiscoveryState),
}
struct Context {
    tx: Sender<Callbacks>,
    rx: Receiver<Callbacks>,
    callbacks: Arc<BluetoothCallbacks>,
    tx: Sender<BaseCallbacks>,
    rx: Receiver<BaseCallbacks>,
    dispatcher: Option<BaseCallbacksDispatcher>,
    intf: BluetoothInterface,
}

fn make_context(intf: BluetoothInterface) -> Context {
    let (tx, rx) = mpsc::channel::<Callbacks>(1);
    let (tx, rx) = mpsc::channel::<BaseCallbacks>(1);

    let (tx1, tx2, tx3, tx4, tx5) = (tx.clone(), tx.clone(), tx.clone(), tx.clone(), tx.clone());
    let cb = Arc::new(BluetoothCallbacks {
        adapter_state_changed: Box::new(move |state| {
    let tx1 = tx.clone();
    let dispatcher = btif::BaseCallbacksDispatcher {
        dispatch: Box::new(move |cb| {
            let txl = tx1.clone();
            topstack::get_runtime().spawn(async move {
                txl.send(Callbacks::AdapterStateChanged(state)).await;
            });
        }),
        adapter_properties_changed: Box::new(move |status, count, props| {
            let txl = tx2.clone();
            topstack::get_runtime().spawn(async move {
                txl.send(Callbacks::AdapterPropertiesChanged(status, count, props)).await;
            });
        }),
        remote_device_properties_changed: Box::new(move |status, address, count, props| {
            let txl = tx5.clone();
            topstack::get_runtime().spawn(async move {
                txl.send(Callbacks::RemoteDevicePropertiesChanged(status, address, count, props));
            });
        }),
        device_found: Box::new(move |count, props| {
            let txl = tx3.clone();
            topstack::get_runtime().spawn(async move {
                txl.send(Callbacks::DeviceFound(count, props)).await;
            });
        }),
        discovery_state_changed: Box::new(move |state| {
            let txl = tx4.clone();
            topstack::get_runtime().spawn(async move {
                txl.send(Callbacks::DiscoveryStateChanged(state)).await;
                txl.send(cb).await;
            });
        }),
        pin_request: Box::new(move |_address, _bdname, _cod, _min_16_digit| {
            println!("Pin request callback");
        }),
        ssp_request: Box::new(move |_address, _bdname, _cod, _variant, _passkey| {
            println!("Ssp request callback");
        }),
        bond_state_changed: Box::new(move |_status, _address, _state| {
            println!("Bond state changed");
        }),
        acl_state_changed: Box::new(move |_status, _address, _state, _hci_reason| {
            println!("Acl state changed");
        }),
    });
    };

    return Context { tx, rx, callbacks: cb, intf };
    return Context { tx, rx, dispatcher: Some(dispatcher), intf };
}

async fn mainloop(context: &mut Context) {
    'main: while let Some(cb) = context.rx.recv().await {
        match cb {
            Callbacks::AdapterStateChanged(state) => {
                println!("Adapter state changed to {}", state.to_i32().unwrap());
            BaseCallbacks::AdapterState(state) => {
                println!("Adapter state changed to {}", state.to_u32().unwrap());

                if state == btif::BtState::On {
                    context.intf.get_adapter_properties();
                }
            }
            Callbacks::AdapterPropertiesChanged(status, _count, properties) => {
                if status != 0 {
                    println!("Failed property change: {}", status);
            BaseCallbacks::AdapterProperties(status, _count, properties) => {
                if status != btif::BtStatus::Success {
                    println!("Failed property change: {:?}", status);
                }

                for p in properties {
                    let proptype = match btif::BtPropertyType::from_i32(p.prop_type) {
                        Some(x) => x,
                        None => btif::BtPropertyType::Unknown,
                    };
                    println!("Property {:?} is ({:?})", proptype, p.val);
                    println!("Property {:?} is ({:?})", p.prop_type, p.val);
                }

                // Scan for 5s and then cancel
                println!("Starting discovery");
                context.intf.start_discovery();
            }
            Callbacks::RemoteDevicePropertiesChanged(status, address, _count, properties) => {
                if status != 0 {
                    println!("Failed remote property change: {}", status);
            BaseCallbacks::RemoteDeviceProperties(status, address, _count, properties) => {
                if status != btif::BtStatus::Success {
                    println!("Failed remote property change: {:?}", status);
                }

                println!("Properties for {:?}", address.address);

                for p in properties {
                    let proptype = match btif::BtPropertyType::from_i32(p.prop_type) {
                        Some(x) => x,
                        None => btif::BtPropertyType::Unknown,
                    };
                    println!("Property {:?} is ({:?})", proptype, p.val);
                    println!("Property {:?} is ({:?})", p.prop_type, p.val);
                }
            }
            Callbacks::DeviceFound(_count, properties) => {
            BaseCallbacks::DeviceFound(_count, properties) => {
                print!("Device found: ");

                for p in properties {
                    let proptype = match btif::BtPropertyType::from_i32(p.prop_type) {
                        Some(x) => x,
                        None => btif::BtPropertyType::Unknown,
                    };

                    if proptype == btif::BtPropertyType::BdAddr {
                    if p.prop_type == btif::BtPropertyType::BdAddr {
                        print!(" Addr[{:?}]", p.val);
                    } else if proptype == btif::BtPropertyType::BdName {
                    } else if p.prop_type == btif::BtPropertyType::BdName {
                        print!(
                            " Name[{:?}]",
                            p.val.iter().map(|u| char::try_from(*u).unwrap()).collect::<String>()
@@ -143,7 +86,7 @@ async fn mainloop(context: &mut Context) {

                println!("");
            }
            Callbacks::DiscoveryStateChanged(state) => {
            BaseCallbacks::DiscoveryState(state) => {
                if state == btif::BtDiscoveryState::Started {
                    sleep(Duration::from_millis(5000)).await;
                    context.intf.cancel_discovery();
@@ -151,6 +94,7 @@ async fn mainloop(context: &mut Context) {
                    break 'main;
                }
            }
            _ => println!("{:?}", cb),
        }
    }
}
@@ -162,14 +106,18 @@ fn main() {
    let all_args: Vec<String> = env::args().collect();
    let args = all_args[1..].to_vec();

    let intf = BluetoothInterface::new();
    let intf = btif::get_btinterface().expect("Couldn't get bluetooth interface");
    let mut context = make_context(intf);

    topstack::get_runtime().block_on(async move {
        if !context.intf.initialize(context.callbacks.clone(), args) {
        if let Some(dispatcher) = context.dispatcher {
            if !context.intf.initialize(dispatcher, args) {
                panic!("Couldn't initialize bluetooth interface!");
            }

            context.dispatcher = None;
        }

        println!("Enabling...");
        context.intf.enable();

+4 −4
Original line number Diff line number Diff line
use bt_topshim::btif::BluetoothInterface;
use bt_topshim::btif::get_btinterface;
use bt_topshim::topstack;

use dbus::channel::MatchingReceiver;
@@ -12,7 +12,7 @@ use dbus_tokio::connection;

use futures::future;

use btstack::bluetooth::btif_bluetooth_callbacks;
use btstack::bluetooth::get_bt_dispatcher;
use btstack::bluetooth::Bluetooth;
use btstack::bluetooth_gatt::BluetoothGatt;
use btstack::Stack;
@@ -32,7 +32,7 @@ const OBJECT_BLUETOOTH_GATT: &str = "/org/chromium/bluetooth/gatt";
fn main() -> Result<(), Box<dyn Error>> {
    let (tx, rx) = Stack::create_channel();

    let intf = Arc::new(Mutex::new(BluetoothInterface::new()));
    let intf = Arc::new(Mutex::new(get_btinterface().unwrap()));
    let bluetooth = Arc::new(Mutex::new(Bluetooth::new(tx.clone(), intf.clone())));
    let bluetooth_gatt = Arc::new(Mutex::new(BluetoothGatt::new(intf.clone())));

@@ -59,7 +59,7 @@ fn main() -> Result<(), Box<dyn Error>> {
            }),
        )));

        intf.lock().unwrap().initialize(Arc::new(btif_bluetooth_callbacks(tx)), vec![]);
        intf.lock().unwrap().initialize(get_bt_dispatcher(tx), vec![]);

        // Run the stack main dispatch loop.
        topstack::get_runtime().spawn(Stack::dispatch(rx, bluetooth.clone()));
+19 −37
Original line number Diff line number Diff line
//! Anything related to the adapter API (IBluetooth).

use bt_topshim::btif::ffi;
use bt_topshim::btif::{BluetoothCallbacks, BluetoothInterface, BtState};
use bt_topshim::btif::{
    BaseCallbacksDispatcher, BluetoothInterface, BtProperty, BtPropertyType, BtState, BtStatus,
};
use bt_topshim::topstack;

use btif_macros::btif_callbacks_generator;
@@ -82,39 +83,26 @@ impl Bluetooth {
    }
}

#[btif_callbacks_generator(btif_bluetooth_callbacks, BluetoothCallbacks)]
pub(crate) trait BtifBluetoothCallbacks {
    #[stack_message(BluetoothAdapterStateChanged)]
    fn adapter_state_changed(&mut self, state: BtState);

    #[stack_message(BluetoothAdapterPropertiesChanged)]
    fn adapter_properties_changed(
        &mut self,
        status: i32,
        status: BtStatus,
        num_properties: i32,
        properties: Vec<ffi::BtProperty>,
        properties: Vec<BtProperty>,
    );
}

#[derive(FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(i32)]
#[derive(Debug)]
enum PropertyType {
    BDName = 0x01,
    BDAddr,
    Uuids,
    ClassOfDevice,
    TypeOfDevice,
    ServiceRecord,
    AdapterScanMode,
    AdapterBondedDevices,
    AdapterDiscoverableTimeout,
    RemoteFriendlyName,
    RemoteRssi,
    RemoteVersionInfo,
    RemoteLocalLeFeatures,
    RemoteDynamicAudioBuffer = 0x10,
    Unknown = 0x100,
pub fn get_bt_dispatcher(tx: Sender<Message>) -> BaseCallbacksDispatcher {
    BaseCallbacksDispatcher {
        dispatch: Box::new(move |cb| {
            let txl = tx.clone();
            topstack::get_runtime().spawn(async move {
                txl.send(Message::Base(cb)).await;
            });
        }),
    }
}

impl BtifBluetoothCallbacks for Bluetooth {
@@ -131,23 +119,17 @@ impl BtifBluetoothCallbacks for Bluetooth {
    #[allow(unused_variables)]
    fn adapter_properties_changed(
        &mut self,
        status: i32,
        status: BtStatus,
        num_properties: i32,
        properties: Vec<ffi::BtProperty>,
        properties: Vec<BtProperty>,
    ) {
        if status != 0 {
        if status != BtStatus::Success {
            return;
        }

        for prop in properties {
            let prop_type = PropertyType::from_i32(prop.prop_type);

            if prop_type.is_none() {
                continue;
            }

            match prop_type.unwrap() {
                PropertyType::BDAddr => {
            match prop.prop_type {
                BtPropertyType::BdAddr => {
                    self.update_local_address(&prop.val);
                }
                _ => {}
+17 −14
Original line number Diff line number Diff line
@@ -9,8 +9,8 @@ extern crate num_derive;
pub mod bluetooth;
pub mod bluetooth_gatt;

use bt_topshim::btif::ffi;
use bt_topshim::btif::BtState;
use bt_topshim::btif::{BaseCallbacks, BaseCallbacksDispatcher};

use std::convert::TryInto;
use std::fmt::{Debug, Formatter, Result};
@@ -55,8 +55,7 @@ impl BDAddr {

/// Message types that are sent to the stack main dispatch loop.
pub enum Message {
    BluetoothAdapterStateChanged(BtState),
    BluetoothAdapterPropertiesChanged(i32, i32, Vec<ffi::BtProperty>),
    Base(BaseCallbacks),
    BluetoothCallbackDisconnected(u32),
}

@@ -80,11 +79,12 @@ impl Stack {
            }

            match m.unwrap() {
                Message::BluetoothAdapterStateChanged(state) => {
                Message::Base(b) => match b {
                    BaseCallbacks::AdapterState(state) => {
                        bluetooth.lock().unwrap().adapter_state_changed(state);
                    }

                Message::BluetoothAdapterPropertiesChanged(status, num_properties, properties) => {
                    BaseCallbacks::AdapterProperties(status, num_properties, properties) => {
                        bluetooth.lock().unwrap().adapter_properties_changed(
                            status,
                            num_properties,
@@ -92,6 +92,9 @@ impl Stack {
                        );
                    }

                    _ => println!("Unhandled callback arm {:?}", b),
                },

                Message::BluetoothCallbackDisconnected(id) => {
                    bluetooth.lock().unwrap().callback_disconnected(id);
                }
Loading