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

Commit 852a59cb authored by Abhishek Pandit-Subedi's avatar Abhishek Pandit-Subedi
Browse files

floss: Refactor insertion via dbus projection

Dbus projection currently requires that a single dbus object path only
has a single interface associated with it. This results in multiple
objects being created for several interfaces.

This change refactors generate_dbus_exporter to provide an Interface
token which must be separately inserted with the object path. It also
provides a mechanism to have Mixins, a single object that contains
multiple interface implementations.

Bug: 233123489
Tag: #floss
Test: ./build.py and manual test on ChromeOS
Change-Id: I82f2cd18d02276bf26f77541ba3592a73ca558fa
parent f263f853
Loading
Loading
Loading
Loading
+14 −18
Original line number Diff line number Diff line
use crate::dbus_iface::{
    export_bluetooth_callback_dbus_obj, export_bluetooth_connection_callback_dbus_obj,
    export_bluetooth_gatt_callback_dbus_obj, export_bluetooth_manager_callback_dbus_obj,
    export_suspend_callback_dbus_obj,
    export_bluetooth_callback_dbus_intf, export_bluetooth_connection_callback_dbus_intf,
    export_bluetooth_gatt_callback_dbus_intf, export_bluetooth_manager_callback_dbus_intf,
    export_suspend_callback_dbus_intf,
};
use crate::ClientContext;
use crate::{console_yellow, print_info};
@@ -70,13 +70,12 @@ impl RPCProxy for BtManagerCallback {

    fn export_for_rpc(self: Box<Self>) {
        let cr = self.dbus_crossroads.clone();
        export_bluetooth_manager_callback_dbus_obj(
            self.get_object_id(),
        let iface = export_bluetooth_manager_callback_dbus_intf(
            self.dbus_connection.clone(),
            &mut cr.lock().unwrap(),
            Arc::new(Mutex::new(self)),
            Arc::new(Mutex::new(DisconnectWatcher::new())),
        );
        cr.lock().unwrap().insert(self.get_object_id(), &[iface], Arc::new(Mutex::new(self)));
    }
}

@@ -232,13 +231,12 @@ impl RPCProxy for BtCallback {

    fn export_for_rpc(self: Box<Self>) {
        let cr = self.dbus_crossroads.clone();
        export_bluetooth_callback_dbus_obj(
            self.get_object_id(),
        let iface = export_bluetooth_callback_dbus_intf(
            self.dbus_connection.clone(),
            &mut cr.lock().unwrap(),
            Arc::new(Mutex::new(self)),
            Arc::new(Mutex::new(DisconnectWatcher::new())),
        );
        cr.lock().unwrap().insert(self.get_object_id(), &[iface], Arc::new(Mutex::new(self)));
    }
}

@@ -286,13 +284,12 @@ impl RPCProxy for BtConnectionCallback {

    fn export_for_rpc(self: Box<Self>) {
        let cr = self.dbus_crossroads.clone();
        export_bluetooth_connection_callback_dbus_obj(
            self.get_object_id(),
        let iface = export_bluetooth_connection_callback_dbus_intf(
            self.dbus_connection.clone(),
            &mut cr.lock().unwrap(),
            Arc::new(Mutex::new(self)),
            Arc::new(Mutex::new(DisconnectWatcher::new())),
        );
        cr.lock().unwrap().insert(self.get_object_id(), &[iface], Arc::new(Mutex::new(self)));
    }
}

@@ -458,13 +455,13 @@ impl RPCProxy for BtGattCallback {

    fn export_for_rpc(self: Box<Self>) {
        let cr = self.dbus_crossroads.clone();
        export_bluetooth_gatt_callback_dbus_obj(
            self.get_object_id(),
        let iface = export_bluetooth_gatt_callback_dbus_intf(
            self.dbus_connection.clone(),
            &mut cr.lock().unwrap(),
            Arc::new(Mutex::new(self)),
            Arc::new(Mutex::new(DisconnectWatcher::new())),
        );

        cr.lock().unwrap().insert(self.get_object_id(), &[iface], Arc::new(Mutex::new(self)));
    }
}

@@ -508,12 +505,11 @@ impl RPCProxy for SuspendCallback {

    fn export_for_rpc(self: Box<Self>) {
        let cr = self.dbus_crossroads.clone();
        export_suspend_callback_dbus_obj(
            self.get_object_id(),
        let iface = export_suspend_callback_dbus_intf(
            self.dbus_connection.clone(),
            &mut cr.lock().unwrap(),
            Arc::new(Mutex::new(self)),
            Arc::new(Mutex::new(DisconnectWatcher::new())),
        );
        cr.lock().unwrap().insert(self.get_object_id(), &[iface], Arc::new(Mutex::new(self)));
    }
}
+6 −6
Original line number Diff line number Diff line
@@ -120,7 +120,7 @@ impl RPCProxy for IBluetoothCallbackDBus {
}

#[generate_dbus_exporter(
    export_bluetooth_callback_dbus_obj,
    export_bluetooth_callback_dbus_intf,
    "org.chromium.bluetooth.BluetoothCallback"
)]
impl IBluetoothCallback for IBluetoothCallbackDBus {
@@ -177,7 +177,7 @@ impl RPCProxy for IBluetoothConnectionCallbackDBus {
}

#[generate_dbus_exporter(
    export_bluetooth_connection_callback_dbus_obj,
    export_bluetooth_connection_callback_dbus_intf,
    "org.chromium.bluetooth.BluetoothConnectionCallback"
)]
impl IBluetoothConnectionCallback for IBluetoothConnectionCallbackDBus {
@@ -519,7 +519,7 @@ impl RPCProxy for IBluetoothManagerCallbackDBus {
}

#[generate_dbus_exporter(
    export_bluetooth_manager_callback_dbus_obj,
    export_bluetooth_manager_callback_dbus_intf,
    "org.chromium.bluetooth.ManagerCallback"
)]
impl IBluetoothManagerCallback for IBluetoothManagerCallbackDBus {
@@ -737,7 +737,7 @@ impl RPCProxy for IBluetoothGattCallbackDBus {
}

#[generate_dbus_exporter(
    export_bluetooth_gatt_callback_dbus_obj,
    export_bluetooth_gatt_callback_dbus_intf,
    "org.chromium.bluetooth.BluetoothGattCallback"
)]
impl IBluetoothGattCallback for IBluetoothGattCallbackDBus {
@@ -812,7 +812,7 @@ impl SuspendDBus {
            client_proxy: ClientDBusProxy::new(
                conn.clone(),
                String::from("org.chromium.bluetooth"),
                make_object_path(index, "suspend"),
                make_object_path(index, "adapter"),
                String::from("org.chromium.bluetooth.Suspend"),
            ),
        }
@@ -860,7 +860,7 @@ impl RPCProxy for ISuspendCallbackDBus {
}

#[generate_dbus_exporter(
    export_suspend_callback_dbus_obj,
    export_suspend_callback_dbus_intf,
    "org.chromium.bluetooth.SuspendCallback"
)]
impl ISuspendCallback for ISuspendCallbackDBus {
+61 −22
Original line number Diff line number Diff line
@@ -42,13 +42,28 @@ pub fn dbus_method(_attr: TokenStream, item: TokenStream) -> TokenStream {
    gen.into()
}

/// Generates a function to export a Rust object to D-Bus.
/// Generates a function to export a Rust object to D-Bus. The result will provide an IFaceToken
/// that must then be registered to an object.
///
/// Example:
///   `#[generate_dbus_exporter(export_foo_dbus_obj, "org.example.FooInterface")]`
///   `#[generate_dbus_exporter(export_foo_dbus_intf, "org.example.FooInterface")]`
///   `#[generate_dbus_exporter(export_foo_dbus_intf, "org.example.FooInterface", FooMixin, foo]`
///
/// This generates a method called `export_foo_dbus_obj` that will export a Rust object into a
/// D-Bus object having interface `org.example.FooInterface`.
/// This generates a method called `export_foo_dbus_intf` that will export a Rust object type into a
/// interface token for `org.example.FooInterface`. This interface must then be inserted to an
/// object in order to be exported.
///
/// If the mixin parameter is provided, you must provide the mixin class when registering with
/// crossroads (and that's the one that should be Arc<Mutex<...>>.
///
/// # Args
///
/// `exporter`: Function name for outputted interface exporter.
/// `interface`: Name of the interface where this object should be exported.
/// `mixin_type`: The name of the Mixin struct. Mixins should be used when
///               exporting multiple interfaces and objects under a single object
///               path.
/// `mixin`: Name of this object in the mixin where it's implemented.
#[proc_macro_attribute]
pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStream {
    let ori_item: proc_macro2::TokenStream = item.clone().into();
@@ -67,12 +82,28 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre
        panic!("D-Bus interface name must be specified");
    };

    // Must provide both a mixin type and name.
    let (mixin_type, mixin_name) = if args.len() > 3 {
        match (&args[2], &args[3]) {
            (Expr::Path(t), Expr::Path(n)) => (Some(t), Some(n)),
            (_, _) => (None, None),
        }
    } else {
        (None, None)
    };

    let ast: ItemImpl = syn::parse(item.clone()).unwrap();
    let api_iface_ident = ast.trait_.unwrap().1.to_token_stream();

    let mut register_methods = quote! {};

    let obj_type = quote! { std::sync::Arc<std::sync::Mutex<Box<T>>> };
    // If the object isn't expected to be part of a mixin, expect the object
    // type to be Arc<Mutex<Box<T>>>. Otherwise, we accept any type T and depend
    // on the field name lookup to throw an error.
    let obj_type = match mixin_type {
        None => quote! { std::sync::Arc<std::sync::Mutex<Box<T>>> },
        Some(t) => quote! { Box<#t> },
    };

    for item in ast.items {
        if let ImplItem::Method(method) = item {
@@ -165,6 +196,19 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre
                output_names = quote! { "out", };
            }

            let method_call = match mixin_name {
                Some(name) => {
                    quote! {
                        let ret = obj.#name.lock().unwrap().#method_name(#method_args);
                    }
                }
                None => {
                    quote! {
                        let ret = obj.lock().unwrap().#method_name(#method_args);
                    }
                }
            };

            register_methods = quote! {
                #register_methods

@@ -175,7 +219,7 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre
                                          #dbus_input_args |
                      -> Result<(#output_type), dbus_crossroads::MethodErr> {
                    #make_args
                    let ret = obj.lock().unwrap().#method_name(#method_args);
                    #method_call
                    #ret
                };
                ibuilder.method(
@@ -188,17 +232,16 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre
        }
    }

    // If mixin is not given, we enforce the API trait is implemented when exporting.
    let type_t = match mixin_type {
        None => quote! { <T: 'static + #api_iface_ident + Send + ?Sized> },
        Some(_) => quote! {},
    };

    let gen = quote! {
        #ori_item

        pub fn #fn_ident<T: 'static + #api_iface_ident + Send + ?Sized, P: Into<dbus::Path<'static>>>(
            path: P,
            conn: std::sync::Arc<dbus::nonblock::SyncConnection>,
            cr: &mut dbus_crossroads::Crossroads,
            obj: #obj_type,
            disconnect_watcher: std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>,
        ) {
            fn get_iface_token<T: #api_iface_ident + Send + ?Sized>(
        pub fn #fn_ident #type_t(
            conn: std::sync::Arc<dbus::nonblock::SyncConnection>,
            cr: &mut dbus_crossroads::Crossroads,
            disconnect_watcher: std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>,
@@ -207,10 +250,6 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre
                #register_methods
            })
        }

            let iface_token = get_iface_token(conn, cr, disconnect_watcher);
            cr.insert(path, &[iface_token], obj);
        }
    };

    debug_output_to_file(&gen, format!("out-{}.rs", fn_ident.to_string()));
+6 −3
Original line number Diff line number Diff line
@@ -117,13 +117,16 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {

    // Let's add the "/org/chromium/bluetooth/Manager" path, which implements
    // the org.chromium.bluetooth.Manager interface, to the crossroads instance.
    bluetooth_manager_dbus::export_bluetooth_manager_dbus_obj(
        "/org/chromium/bluetooth/Manager",
    let iface = bluetooth_manager_dbus::export_bluetooth_manager_dbus_intf(
        conn.clone(),
        &mut cr.lock().unwrap(),
        bluetooth_manager.clone(),
        disconnect_watcher.clone(),
    );
    cr.lock().unwrap().insert(
        "/org/chromium/bluetooth/Manager",
        &[iface],
        bluetooth_manager.clone(),
    );

    // We add the Crossroads instance to the connection so that incoming method calls will be handled.
    let cr_clone = cr.clone();
+2 −1
Original line number Diff line number Diff line
use dbus::arg::RefArg;
use dbus::strings::Path;
use dbus_crossroads;
use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter};
use dbus_projection::{dbus_generated, DisconnectWatcher};

@@ -19,7 +20,7 @@ pub struct AdapterWithEnabledDbus {
/// D-Bus projection of IBluetoothManager.
struct BluetoothManagerDBus {}

#[generate_dbus_exporter(export_bluetooth_manager_dbus_obj, "org.chromium.bluetooth.Manager")]
#[generate_dbus_exporter(export_bluetooth_manager_dbus_intf, "org.chromium.bluetooth.Manager")]
impl IBluetoothManager for BluetoothManagerDBus {
    #[dbus_method("Start")]
    fn start(&mut self, hci_interface: i32) {
Loading