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

Commit 51c59227 authored by Sonny Sasaka's avatar Sonny Sasaka Committed by Gerrit Code Review
Browse files

Merge changes Ibbb0a115,I40ec2aae

* changes:
  Export callback object as a D-Bus object
  Refactor `dyn I...` to be inside `Box<dyn I...>`
parents f64ab6dd 380a28e0
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -8,12 +8,12 @@ use crate::console_yellow;
use crate::print_info;

/// Handles string command entered from command line.
pub struct CommandHandler {
    bluetooth: Arc<Mutex<dyn IBluetooth>>,
pub struct CommandHandler<T: IBluetooth> {
    bluetooth: Arc<Mutex<Box<T>>>,
}

impl CommandHandler {
    pub fn new(bluetooth: Arc<Mutex<dyn IBluetooth>>) -> CommandHandler {
impl<T: IBluetooth> CommandHandler<T> {
    pub fn new(bluetooth: Arc<Mutex<Box<T>>>) -> CommandHandler<T> {
        CommandHandler { bluetooth }
    }

+71 −14
Original line number Diff line number Diff line
//! D-Bus proxy implementations of the APIs.

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

use dbus::arg::{AppendAll, RefArg};
use dbus::nonblock::SyncConnection;

use dbus_projection::impl_dbus_arg_enum;
use dbus_crossroads::Crossroads;

use dbus_macros::dbus_propmap;
use dbus_projection::{impl_dbus_arg_enum, DisconnectWatcher};

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

use num_traits::{FromPrimitive, ToPrimitive};

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

use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust};

@@ -24,25 +27,31 @@ pub struct BluetoothDeviceDBus {

pub(crate) struct BluetoothDBus {
    conn: Arc<SyncConnection>,
    cr: Arc<Mutex<Crossroads>>,
}

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

    fn method<A: AppendAll, T: 'static + dbus::arg::Arg + for<'z> dbus::arg::Get<'z>>(
        &self,
        member: &str,
        args: A,
    ) -> T {
    fn create_proxy(&self) -> dbus::nonblock::Proxy<Arc<SyncConnection>> {
        let conn = self.conn.clone();
        let proxy = dbus::nonblock::Proxy::new(
        // 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",
            std::time::Duration::from_secs(2),
            conn,
        );
        )
    }

    fn method<A: AppendAll, T: 'static + dbus::arg::Arg + for<'z> dbus::arg::Get<'z>>(
        &self,
        member: &str,
        args: A,
    ) -> T {
        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
@@ -51,12 +60,60 @@ impl BluetoothDBus {

        return ret;
    }

    fn method_noreturn<A: AppendAll>(&self, member: &str, args: A) {
        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
        })
        .unwrap();
    }
}

#[allow(dead_code)]
struct IBluetoothCallbackDBus {}

impl 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 {
        String::from("")
    }
}

#[generate_dbus_exporter(
    export_bluetooth_callback_dbus_obj,
    "org.chromium.bluetooth.BluetoothCallback"
)]
impl IBluetoothCallback for IBluetoothCallbackDBus {
    #[dbus_method("OnBluetoothStateChanged")]
    fn on_bluetooth_state_changed(&self, prev_state: u32, new_state: u32) {}

    #[dbus_method("OnBluetoothAddressChanged")]
    fn on_bluetooth_address_changed(&self, addr: String) {}

    #[dbus_method("OnDeviceFound")]
    fn on_device_found(&self, remote_device: BluetoothDevice) {}

    #[dbus_method("OnDiscoveringChanged")]
    fn on_discovering_changed(&self, discovering: bool) {}
}

// 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>) {
        // TODO: Implement callback object export.
    fn register_callback(&mut self, callback: Box<dyn IBluetoothCallback + Send>) {
        let path_string = callback.get_object_id();
        let path = dbus::Path::new(path_string.clone()).unwrap();
        export_bluetooth_callback_dbus_obj(
            path_string,
            self.conn.clone(),
            &mut self.cr.lock().unwrap(),
            Arc::new(Mutex::new(callback)),
            Arc::new(Mutex::new(DisconnectWatcher::new())),
        );

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

    fn enable(&mut self) -> bool {
+43 −17
Original line number Diff line number Diff line
@@ -8,6 +8,10 @@ use btstack::bluetooth::{

use btstack::{RPCProxy, Stack};

use dbus::channel::MatchingReceiver;

use dbus::message::MatchRule;

use dbus::nonblock::SyncConnection;

use std::sync::{Arc, Mutex};
@@ -16,6 +20,8 @@ use crate::command_handler::CommandHandler;
use crate::dbus_iface::BluetoothDBus;
use crate::editor::AsyncEditor;

use dbus_crossroads::Crossroads;

mod command_handler;
mod console;
mod dbus_arg;
@@ -24,6 +30,7 @@ mod editor;

struct BtCallback {
    disconnect_callbacks: Arc<Mutex<Vec<Box<dyn Fn() + Send>>>>,
    objpath: String,
}

impl IBluetoothCallback for BtCallback {
@@ -48,18 +55,25 @@ impl RPCProxy for BtCallback {
    fn register_disconnect(&mut self, f: Box<dyn Fn() + Send>) {
        self.disconnect_callbacks.lock().unwrap().push(f);
    }

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

struct API {
    bluetooth: Arc<Mutex<dyn IBluetooth>>,
struct API<T: IBluetooth> {
    bluetooth: Arc<Mutex<Box<T>>>,
}

// This creates the API implementations directly embedded to this client.
fn create_api_embedded() -> API {
// TODO: Remove when D-Bus client is completed since this is only useful while D-Bus client is
// under development.
#[allow(dead_code)]
fn create_api_embedded() -> API<Bluetooth> {
    let (tx, rx) = Stack::create_channel();

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

    intf.lock().unwrap().initialize(get_bt_dispatcher(tx), vec![]);

@@ -71,8 +85,8 @@ fn create_api_embedded() -> API {
}

// This creates the API implementations over D-Bus.
fn create_api_dbus(conn: Arc<SyncConnection>) -> API {
    let bluetooth = Arc::new(Mutex::new(BluetoothDBus::new(conn.clone())));
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))));

    API { bluetooth }
}
@@ -92,20 +106,32 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
            panic!("Lost connection to D-Bus: {}", err);
        });

        // TODO: Separate the embedded mode into its own binary.
        let api = if std::env::var("EMBEDDED_STACK").is_ok() {
            create_api_embedded()
        } else {
            create_api_dbus(conn)
        };
        // Sets up Crossroads for receiving callbacks.
        let cr = Arc::new(Mutex::new(Crossroads::new()));
        cr.lock().unwrap().set_async_support(Some((
            conn.clone(),
            Box::new(|x| {
                topstack::get_runtime().spawn(x);
            }),
        )));
        let cr_clone = cr.clone();
        conn.start_receive(
            MatchRule::new_method_call(),
            Box::new(move |msg, conn| {
                cr_clone.lock().unwrap().handle_message(msg, conn).unwrap();
                true
            }),
        );

        let api = create_api_dbus(conn, cr);

        let dc_callbacks = Arc::new(Mutex::new(vec![]));
        api.bluetooth
            .lock()
            .unwrap()
            .register_callback(Box::new(BtCallback { disconnect_callbacks: dc_callbacks.clone() }));
        api.bluetooth.lock().unwrap().register_callback(Box::new(BtCallback {
            disconnect_callbacks: dc_callbacks.clone(),
            objpath: String::from("/org/chromium/bluetooth/client/bluetooth_callback"),
        }));

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

        let simulate_disconnect = move |_cmd| {
            for callback in &*dc_callbacks.lock().unwrap() {
+15 −8
Original line number Diff line number Diff line
@@ -54,6 +54,8 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre

    let mut register_methods = quote! {};

    let obj_type = quote! { std::sync::Arc<std::sync::Mutex<Box<T>>> };

    for item in ast.items {
        if let ImplItem::Method(method) = item {
            if method.attrs.len() != 1 {
@@ -151,7 +153,7 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre
                let conn_clone = conn.clone();
                let dc_watcher_clone = disconnect_watcher.clone();
                let handle_method = move |ctx: &mut dbus_crossroads::Context,
                                          obj: &mut ObjType,
                                          obj: &mut #obj_type,
                                          #dbus_input_args |
                      -> Result<(#output_type), dbus_crossroads::MethodErr> {
                    #make_args
@@ -171,20 +173,18 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre
    let gen = quote! {
        #ori_item

        type ObjType = std::sync::Arc<std::sync::Mutex<dyn #api_iface_ident + Send>>;

        pub fn #fn_ident(
            path: &'static str,
        pub fn #fn_ident<T: 'static + #api_iface_ident + Send + ?Sized>(
            path: String,
            conn: std::sync::Arc<SyncConnection>,
            cr: &mut dbus_crossroads::Crossroads,
            obj: ObjType,
            obj: #obj_type,
            disconnect_watcher: std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>,
        ) {
            fn get_iface_token(
            fn get_iface_token<T: #api_iface_ident + Send + ?Sized>(
                conn: std::sync::Arc<SyncConnection>,
                cr: &mut dbus_crossroads::Crossroads,
                disconnect_watcher: std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>,
            ) -> dbus_crossroads::IfaceToken<ObjType> {
            ) -> dbus_crossroads::IfaceToken<#obj_type> {
                cr.register(#dbus_iface_name, |ibuilder| {
                    #register_methods
                })
@@ -426,6 +426,9 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream {

        impl RPCProxy for #self_ty {
            fn register_disconnect(&mut self, _disconnect_callback: Box<dyn Fn() + Send>) {}
            fn get_object_id(&self) -> String {
                String::from("")
            }
        }

        struct #struct_ident {
@@ -443,6 +446,10 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream {
            fn register_disconnect(&mut self, disconnect_callback: Box<dyn Fn() + Send>) {
                self.disconnect_watcher.lock().unwrap().add(self.remote.clone(), disconnect_callback);
            }

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

        impl DBusArg for Box<dyn #trait_ + Send> {
+4 −4
Original line number Diff line number Diff line
@@ -33,8 +33,8 @@ fn main() -> Result<(), Box<dyn Error>> {
    let (tx, rx) = Stack::create_channel();

    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())));
    let bluetooth = Arc::new(Mutex::new(Box::new(Bluetooth::new(tx.clone(), intf.clone()))));
    let bluetooth_gatt = Arc::new(Mutex::new(Box::new(BluetoothGatt::new(intf.clone()))));

    // Args don't include arg[0] which is the binary name
    let all_args = std::env::args().collect::<Vec<String>>();
@@ -76,7 +76,7 @@ fn main() -> Result<(), Box<dyn Error>> {

        // Register D-Bus method handlers of IBluetooth.
        iface_bluetooth::export_bluetooth_dbus_obj(
            OBJECT_BLUETOOTH,
            String::from(OBJECT_BLUETOOTH),
            conn.clone(),
            &mut cr,
            bluetooth,
@@ -84,7 +84,7 @@ fn main() -> Result<(), Box<dyn Error>> {
        );
        // Register D-Bus method handlers of IBluetoothGatt.
        iface_bluetooth_gatt::export_bluetooth_gatt_dbus_obj(
            OBJECT_BLUETOOTH_GATT,
            String::from(OBJECT_BLUETOOTH_GATT),
            conn.clone(),
            &mut cr,
            bluetooth_gatt,
Loading