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

Commit 13971a2e authored by Sonny Sasaka's avatar Sonny Sasaka Committed by Gerrit Code Review
Browse files

Merge changes Iddee71b9,Ib5849380,Iddd729be,I962e7aeb,I25b7e022

* changes:
  Fix undefined reference of A2dpIntf::cleanup
  btclient: Add print_error macro
  btclient: Add command handler for enable and disable stack
  Add btclient client DBus proxy for IBluetoothManager
  Integrate dbus_projection for btmanagerd
parents 61f4738d 2d47288f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ edition = "2018"
rustyline = "8.0"
bt_topshim = { path = "../../topshim" }
btstack = { path = "../stack" }
manager_service = { path = "../mgmt" }

dbus = "0.9.2"
dbus-crossroads = "0.4.0"
+81 −9
Original line number Diff line number Diff line
use btstack::bluetooth::{BluetoothDevice, BluetoothTransport, IBluetooth};
use bt_topshim::btif::BtSspVariant;

use btstack::bluetooth::{BluetoothDevice, BluetoothTransport, IBluetooth, IBluetoothCallback};
use btstack::RPCProxy;

use manager_service::iface_bluetooth_manager::IBluetoothManager;

use num_traits::cast::FromPrimitive;

@@ -7,22 +12,81 @@ use std::sync::{Arc, Mutex};
use crate::console_yellow;
use crate::print_info;

struct BtCallback {
    objpath: String,
}

impl IBluetoothCallback for BtCallback {
    fn on_bluetooth_state_changed(&self, prev_state: u32, new_state: u32) {
        print_info!("Adapter state changed from {} to {}", prev_state, new_state);
    }

    fn on_bluetooth_address_changed(&self, addr: String) {
        print_info!("Address changed to {}", addr);
    }

    fn on_device_found(&self, remote_device: BluetoothDevice) {
        print_info!("Found device: {:?}", remote_device);
    }

    fn on_discovering_changed(&self, discovering: bool) {
        print_info!("Discovering: {}", discovering);
    }

    fn on_ssp_request(
        &self,
        remote_device: BluetoothDevice,
        _cod: u32,
        variant: BtSspVariant,
        passkey: u32,
    ) {
        if variant == BtSspVariant::PasskeyNotification {
            print_info!(
                "device {}{} would like to pair, enter passkey on remote device: {:06}",
                remote_device.address.to_string(),
                if remote_device.name.len() > 0 {
                    format!(" ({})", remote_device.name)
                } else {
                    String::from("")
                },
                passkey
            );
        }
    }
}

impl RPCProxy for BtCallback {
    fn register_disconnect(&mut self, _f: Box<dyn Fn() + Send>) {}

    fn get_object_id(&self) -> String {
        self.objpath.clone()
    }
}

/// Handles string command entered from command line.
pub struct CommandHandler<T: IBluetooth> {
    bluetooth: Arc<Mutex<Box<T>>>,
pub struct CommandHandler<TBluetoothManager: IBluetoothManager, TBluetooth: IBluetooth> {
    bluetooth_manager: Arc<Mutex<Box<TBluetoothManager>>>,
    bluetooth: Arc<Mutex<Box<TBluetooth>>>,

    is_bluetooth_callback_registered: bool,
}

impl<T: IBluetooth> CommandHandler<T> {
    pub fn new(bluetooth: Arc<Mutex<Box<T>>>) -> CommandHandler<T> {
        CommandHandler { bluetooth }
impl<TBluetoothManager: IBluetoothManager, TBluetooth: IBluetooth>
    CommandHandler<TBluetoothManager, TBluetooth>
{
    pub fn new(
        bluetooth_manager: Arc<Mutex<Box<TBluetoothManager>>>,
        bluetooth: Arc<Mutex<Box<TBluetooth>>>,
    ) -> CommandHandler<TBluetoothManager, TBluetooth> {
        CommandHandler { bluetooth_manager, bluetooth, is_bluetooth_callback_registered: false }
    }

    pub fn cmd_enable(&self, _cmd: String) {
        self.bluetooth.lock().unwrap().enable();
        self.bluetooth_manager.lock().unwrap().start(0);
    }

    pub fn cmd_disable(&self, _cmd: String) {
        self.bluetooth.lock().unwrap().disable();
        self.bluetooth_manager.lock().unwrap().stop(0);
    }

    pub fn cmd_get_address(&self, _cmd: String) {
@@ -30,7 +94,15 @@ impl<T: IBluetooth> CommandHandler<T> {
        print_info!("Local address = {}", addr);
    }

    pub fn cmd_start_discovery(&self, _cmd: String) {
    pub fn cmd_start_discovery(&mut self, _cmd: String) {
        // TODO: Register the BtCallback when getting a OnStateChangedCallback from btmanagerd.
        if !self.is_bluetooth_callback_registered {
            self.bluetooth.lock().unwrap().register_callback(Box::new(BtCallback {
                objpath: String::from("/org/chromium/bluetooth/client/bluetooth_callback"),
            }));
            self.is_bluetooth_callback_registered = true;
        }

        self.bluetooth.lock().unwrap().start_discovery();
    }

+17 −0
Original line number Diff line number Diff line
@@ -14,6 +14,13 @@ macro_rules! console_yellow {
    };
}

#[macro_export]
macro_rules! console_red {
    ( $text:expr ) => {
        format!("\x1b[1;31m{}\x1b[0m", $text).as_str()
    };
}

#[macro_export]
macro_rules! print_info {
    ( $($arg:tt)* ) => {
@@ -23,3 +30,13 @@ macro_rules! print_info {
        }
    };
}

#[macro_export]
macro_rules! print_error {
    ( $($arg:tt)* ) => {
        {
            print!("{}: ", console_red!("btclient:error"));
            println!($($arg)*);
        }
    };
}
+120 −20
Original line number Diff line number Diff line
@@ -3,7 +3,6 @@
use bt_topshim::btif::BtSspVariant;

use btstack::bluetooth::{BluetoothDevice, BluetoothTransport, IBluetooth, IBluetoothCallback};
use btstack::RPCProxy;

use dbus::arg::{AppendAll, RefArg};
use dbus::nonblock::SyncConnection;
@@ -14,6 +13,8 @@ use dbus_projection::{impl_dbus_arg_enum, DisconnectWatcher};

use dbus_macros::{dbus_method, dbus_propmap, generate_dbus_exporter};

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

use num_traits::{FromPrimitive, ToPrimitive};

use std::sync::{Arc, Mutex};
@@ -28,22 +29,20 @@ pub struct BluetoothDeviceDBus {
    address: String,
}

pub(crate) struct BluetoothDBus {
struct ClientDBusProxy {
    conn: Arc<SyncConnection>,
    cr: Arc<Mutex<Crossroads>>,
    bus_name: String,
    objpath: dbus::Path<'static>,
    interface: String,
}

impl BluetoothDBus {
    pub(crate) fn new(conn: Arc<SyncConnection>, cr: Arc<Mutex<Crossroads>>) -> BluetoothDBus {
        BluetoothDBus { conn: conn.clone(), cr: cr }
    }

impl ClientDBusProxy {
    fn create_proxy(&self) -> dbus::nonblock::Proxy<Arc<SyncConnection>> {
        let conn = self.conn.clone();
        // TODO: Adapter path should have hci number, e.g. /org/chromium/bluetooth/adapter/hci0.
        dbus::nonblock::Proxy::new(
            "org.chromium.bluetooth",
            "/org/chromium/bluetooth/adapter",
            self.bus_name.clone(),
            self.objpath.clone(),
            std::time::Duration::from_secs(2),
            conn,
        )
@@ -57,7 +56,7 @@ impl BluetoothDBus {
        let proxy = self.create_proxy();
        // We know that all APIs return immediately, so we can block on it for simplicity.
        let (ret,): (T,) = futures::executor::block_on(async {
            proxy.method_call("org.chromium.bluetooth.Bluetooth", member, args).await
            proxy.method_call(self.interface.clone(), member, args).await
        })
        .unwrap();

@@ -68,7 +67,7 @@ impl BluetoothDBus {
        let proxy = self.create_proxy();
        // We know that all APIs return immediately, so we can block on it for simplicity.
        let _: () = futures::executor::block_on(async {
            proxy.method_call("org.chromium.bluetooth.Bluetooth", member, args).await
            proxy.method_call(self.interface.clone(), member, args).await
        })
        .unwrap();
    }
@@ -77,7 +76,7 @@ impl BluetoothDBus {
#[allow(dead_code)]
struct IBluetoothCallbackDBus {}

impl RPCProxy for IBluetoothCallbackDBus {
impl btstack::RPCProxy for IBluetoothCallbackDBus {
    // Dummy implementations just to satisfy impl RPCProxy requirements.
    fn register_disconnect(&mut self, _f: Box<dyn Fn() + Send>) {}
    fn get_object_id(&self) -> String {
@@ -113,6 +112,25 @@ impl IBluetoothCallback for IBluetoothCallbackDBus {
    }
}

pub(crate) struct BluetoothDBus {
    client_proxy: ClientDBusProxy,
}

impl BluetoothDBus {
    pub(crate) fn new(conn: Arc<SyncConnection>, cr: Arc<Mutex<Crossroads>>) -> BluetoothDBus {
        // TODO: Adapter path should have hci number, e.g. /org/chromium/bluetooth/adapter/hci0.
        BluetoothDBus {
            client_proxy: ClientDBusProxy {
                conn: conn.clone(),
                cr: cr,
                bus_name: String::from("org.chromium.bluetooth"),
                objpath: dbus::Path::new("/org/chromium/bluetooth/adapter").unwrap(),
                interface: String::from("org.chromium.bluetooth.Bluetooth"),
            },
        }
    }
}

// TODO: These are boilerplate codes, consider creating a macro to generate.
impl IBluetooth for BluetoothDBus {
    fn register_callback(&mut self, callback: Box<dyn IBluetoothCallback + Send>) {
@@ -120,13 +138,13 @@ impl IBluetooth for BluetoothDBus {
        let path = dbus::Path::new(path_string.clone()).unwrap();
        export_bluetooth_callback_dbus_obj(
            path_string,
            self.conn.clone(),
            &mut self.cr.lock().unwrap(),
            self.client_proxy.conn.clone(),
            &mut self.client_proxy.cr.lock().unwrap(),
            Arc::new(Mutex::new(callback)),
            Arc::new(Mutex::new(DisconnectWatcher::new())),
        );

        self.method_noreturn("RegisterCallback", (path,))
        self.client_proxy.method_noreturn("RegisterCallback", (path,))
    }

    fn enable(&mut self) -> bool {
@@ -140,19 +158,19 @@ impl IBluetooth for BluetoothDBus {
    }

    fn get_address(&self) -> String {
        self.method("GetAddress", ())
        self.client_proxy.method("GetAddress", ())
    }

    fn start_discovery(&self) -> bool {
        self.method("StartDiscovery", ())
        self.client_proxy.method("StartDiscovery", ())
    }

    fn cancel_discovery(&self) -> bool {
        self.method("CancelDiscovery", ())
        self.client_proxy.method("CancelDiscovery", ())
    }

    fn create_bond(&self, device: BluetoothDevice, transport: BluetoothTransport) -> bool {
        self.method(
        self.client_proxy.method(
            "CreateBond",
            (
                BluetoothDevice::to_dbus(device).unwrap(),
@@ -161,3 +179,85 @@ impl IBluetooth for BluetoothDBus {
        )
    }
}

pub(crate) struct BluetoothManagerDBus {
    client_proxy: ClientDBusProxy,
}

impl BluetoothManagerDBus {
    pub(crate) fn new(
        conn: Arc<SyncConnection>,
        cr: Arc<Mutex<Crossroads>>,
    ) -> BluetoothManagerDBus {
        BluetoothManagerDBus {
            client_proxy: ClientDBusProxy {
                conn: conn.clone(),
                cr: cr,
                bus_name: String::from("org.chromium.bluetooth.Manager"),
                objpath: dbus::Path::new("/org/chromium/bluetooth/Manager").unwrap(),
                interface: String::from("org.chromium.bluetooth.Manager"),
            },
        }
    }
}

// TODO: These are boilerplate codes, consider creating a macro to generate.
impl IBluetoothManager for BluetoothManagerDBus {
    fn start(&mut self, hci_interface: i32) {
        self.client_proxy.method_noreturn("Start", (hci_interface,))
    }

    fn stop(&mut self, hci_interface: i32) {
        self.client_proxy.method_noreturn("Stop", (hci_interface,))
    }

    fn get_state(&mut self) -> i32 {
        self.client_proxy.method("GetState", ())
    }

    fn register_callback(&mut self, callback: Box<dyn IBluetoothManagerCallback + Send>) {
        let path_string = callback.get_object_id();
        let path = dbus::Path::new(path_string.clone()).unwrap();
        export_bluetooth_manager_callback_dbus_obj(
            path_string,
            self.client_proxy.conn.clone(),
            &mut self.client_proxy.cr.lock().unwrap(),
            Arc::new(Mutex::new(callback)),
            Arc::new(Mutex::new(DisconnectWatcher::new())),
        );

        self.client_proxy.method_noreturn("RegisterCallback", (path,))
    }

    fn get_floss_enabled(&mut self) -> bool {
        self.client_proxy.method("GetFlossEnabled", ())
    }

    fn set_floss_enabled(&mut self, enabled: bool) {
        self.client_proxy.method_noreturn("SetFlossEnabled", (enabled,))
    }

    fn list_hci_devices(&mut self) -> Vec<i32> {
        self.client_proxy.method("ListHciDevices", ())
    }
}

#[allow(dead_code)]
struct IBluetoothManagerCallbackDBus {}

impl manager_service::RPCProxy for IBluetoothManagerCallbackDBus {
    // Placeholder implementations just to satisfy impl RPCProxy requirements.
    fn register_disconnect(&mut self, _f: Box<dyn Fn() + Send>) {}
    fn get_object_id(&self) -> String {
        String::from("")
    }
}

#[generate_dbus_exporter(
    export_bluetooth_manager_callback_dbus_obj,
    "org.chromium.bluetooth.ManagerCallback"
)]
impl IBluetoothManagerCallback for IBluetoothManagerCallbackDBus {
    #[dbus_method("OnHciDeviceChanged")]
    fn on_hci_device_changed(&self, hci_interface: i32, present: bool) {}
}
+22 −52
Original line number Diff line number Diff line
use bt_topshim::btif::BtSspVariant;
use bt_topshim::topstack;

use btstack::bluetooth::{BluetoothDevice, IBluetooth, IBluetoothCallback};
use btstack::RPCProxy;

use dbus::channel::MatchingReceiver;

use dbus::message::MatchRule;

use dbus::nonblock::SyncConnection;

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

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

use crate::command_handler::CommandHandler;
use crate::dbus_iface::BluetoothDBus;
use crate::dbus_iface::{BluetoothDBus, BluetoothManagerDBus};
use crate::editor::AsyncEditor;

use dbus_crossroads::Crossroads;
@@ -24,50 +22,17 @@ mod dbus_arg;
mod dbus_iface;
mod editor;

struct BtCallback {
struct BtManagerCallback {
    objpath: String,
}

impl IBluetoothCallback for BtCallback {
    fn on_bluetooth_state_changed(&self, prev_state: u32, new_state: u32) {
        print_info!("Adapter state changed from {} to {}", prev_state, new_state);
    }

    fn on_bluetooth_address_changed(&self, addr: String) {
        print_info!("Address changed to {}", addr);
    }

    fn on_device_found(&self, remote_device: BluetoothDevice) {
        print_info!("Found device: {:?}", remote_device);
    }

    fn on_discovering_changed(&self, discovering: bool) {
        print_info!("Discovering: {}", discovering);
    }

    fn on_ssp_request(
        &self,
        remote_device: BluetoothDevice,
        _cod: u32,
        variant: BtSspVariant,
        passkey: u32,
    ) {
        if variant == BtSspVariant::PasskeyNotification {
            print_info!(
                "device {}{} would like to pair, enter passkey on remote device: {:06}",
                remote_device.address.to_string(),
                if remote_device.name.len() > 0 {
                    format!(" ({})", remote_device.name)
                } else {
                    String::from("")
                },
                passkey
            );
        }
impl IBluetoothManagerCallback for BtManagerCallback {
    fn on_hci_device_changed(&self, hci_interface: i32, present: bool) {
        print_info!("hci{} present = {}", hci_interface, present);
    }
}

impl RPCProxy for BtCallback {
impl manager_service::RPCProxy for BtManagerCallback {
    fn register_disconnect(&mut self, _f: Box<dyn Fn() + Send>) {}

    fn get_object_id(&self) -> String {
@@ -75,15 +40,18 @@ impl RPCProxy for BtCallback {
    }
}

struct API<T: IBluetooth> {
    bluetooth: Arc<Mutex<Box<T>>>,
struct API {
    bluetooth_manager: Arc<Mutex<Box<BluetoothManagerDBus>>>,
    bluetooth: Arc<Mutex<Box<BluetoothDBus>>>,
}

// This creates the API implementations over D-Bus.
fn create_api_dbus(conn: Arc<SyncConnection>, cr: Arc<Mutex<Crossroads>>) -> API<BluetoothDBus> {
    let bluetooth = Arc::new(Mutex::new(Box::new(BluetoothDBus::new(conn.clone(), cr))));
fn create_api_dbus(conn: Arc<SyncConnection>, cr: Arc<Mutex<Crossroads>>) -> API {
    let bluetooth = Arc::new(Mutex::new(Box::new(BluetoothDBus::new(conn.clone(), cr.clone()))));
    let bluetooth_manager =
        Arc::new(Mutex::new(Box::new(BluetoothManagerDBus::new(conn.clone(), cr.clone()))));

    API { bluetooth }
    API { bluetooth_manager, bluetooth }
}

/// Runs a command line program that interacts with a Bluetooth stack.
@@ -120,13 +88,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

        let api = create_api_dbus(conn, cr);

        api.bluetooth.lock().unwrap().register_callback(Box::new(BtCallback {
            objpath: String::from("/org/chromium/bluetooth/client/bluetooth_callback"),
        // TODO: Registering the callback should be done when btmanagerd is ready (detect with
        // ObjectManager).
        api.bluetooth_manager.lock().unwrap().register_callback(Box::new(BtManagerCallback {
            objpath: String::from("/org/chromium/bluetooth/client/bluetooth_manager_callback"),
        }));

        let handler = CommandHandler::<BluetoothDBus>::new(api.bluetooth.clone());
        let mut handler = CommandHandler::new(api.bluetooth_manager.clone(), api.bluetooth.clone());

        let handle_cmd = move |cmd: String| match cmd.split(' ').collect::<Vec<&str>>()[0] {
        let mut handle_cmd = move |cmd: String| match cmd.split(' ').collect::<Vec<&str>>()[0] {
            "enable" => handler.cmd_enable(cmd),
            "disable" => handler.cmd_disable(cmd),
            "get_address" => handler.cmd_get_address(cmd),
Loading