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

Commit f4ad2c84 authored by Sonny Sasaka's avatar Sonny Sasaka Committed by Abhishek Pandit-Subedi
Browse files

Floss: Fix deadlock between btmanagerd and btadapterd

With Suspend API, btmanagerd calls RegisterCallback to btadapterd and
may be deadlocked waiting for this return. This patch changes the call
to async call so that btmanagerd does not have to block waiting for the
return.

Bug: 232547719
Tag: #floss
Test: Build and run on Chrome OS

Change-Id: I4d245f54dc0684d51c12b7e1698a180eef9b8c58
parent 7a30c68e
Loading
Loading
Loading
Loading
+7 −8
Original line number Diff line number Diff line
@@ -373,22 +373,21 @@ pub fn generate_dbus_interface_client(attr: TokenStream, item: TokenStream) -> T
                                        path
                                    };
                            };

                            input_list = quote! {
                                #input_list
                                #ident,
                            };
                        } else {
                            // Convert every parameter to its corresponding type recognized by
                            // the D-Bus library.
                            object_conversions = quote! {
                                #object_conversions
                                    let #ident = <#arg_type as DBusArg>::to_dbus(#ident).unwrap();
                            };
                        }
                        input_list = quote! {
                            #input_list
                                <#arg_type as DBusArg>::to_dbus(#ident).unwrap(),
                            #ident,
                        };
                    }
                }
            }
            }

            let mut output_as_dbus_arg = quote! {};
            if let ReturnType::Type(_, t) = &method.sig.output {
+1 −0
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ impl DisconnectWatcher {

/// A client proxy to conveniently call API methods generated with the
/// [`generate_dbus_interface_client`](dbus_macros::generate_dbus_interface_client) macro.
#[derive(Clone)]
pub struct ClientDBusProxy {
    conn: Arc<SyncConnection>,
    bus_name: String,
+20 −7
Original line number Diff line number Diff line
@@ -12,24 +12,37 @@ use crate::dbus_arg::{DBusArg, DBusArgError};

impl_dbus_arg_enum!(SuspendType);

#[derive(Clone)]
pub struct SuspendDBusRPC {
    client_proxy: ClientDBusProxy,
}

pub struct SuspendDBus {
    client_proxy: ClientDBusProxy,
    pub rpc: SuspendDBusRPC,
}

impl SuspendDBus {
    pub(crate) fn new(conn: Arc<SyncConnection>, path: dbus::Path<'static>) -> SuspendDBus {
        SuspendDBus {
            client_proxy: ClientDBusProxy::new(
    fn make_client_proxy(conn: Arc<SyncConnection>, path: dbus::Path<'static>) -> ClientDBusProxy {
        ClientDBusProxy::new(
            conn.clone(),
            String::from("org.chromium.bluetooth"),
            path,
            String::from("org.chromium.bluetooth.Suspend"),
            ),
        )
    }

    pub(crate) fn new(conn: Arc<SyncConnection>, path: dbus::Path<'static>) -> SuspendDBus {
        SuspendDBus {
            client_proxy: Self::make_client_proxy(conn.clone(), path.clone()),
            rpc: SuspendDBusRPC {
                client_proxy: Self::make_client_proxy(conn.clone(), path.clone()),
            },
        }
    }
}

#[generate_dbus_interface_client]
#[generate_dbus_interface_client(SuspendDBusRPC)]
impl ISuspend for SuspendDBus {
    #[dbus_method("RegisterCallback")]
    fn register_callback(&mut self, callback: Box<dyn ISuspendCallback + Send>) -> bool {
+32 −15
Original line number Diff line number Diff line
use btstack::suspend::{ISuspend, ISuspendCallback, SuspendType};
use btstack::suspend::{ISuspendCallback, SuspendType};
use btstack::RPCProxy;
use dbus::channel::MatchingReceiver;
use dbus::message::MatchRule;
@@ -443,10 +443,17 @@ impl PowerdSuspendManager {
            // times in the `if let` block below. Prevent deadlock by locking only once.
            let mut context_locked = self.context.lock().unwrap();
            if let Some(adapter_suspend_dbus) = &mut context_locked.adapter_suspend_dbus {
                adapter_suspend_dbus.suspend(match suspend_imminent.get_reason() {
                let mut suspend_dbus_rpc = adapter_suspend_dbus.rpc.clone();
                tokio::spawn(async move {
                    let result = suspend_dbus_rpc
                        .suspend(match suspend_imminent.get_reason() {
                            SuspendImminent_Reason::IDLE => SuspendType::AllowWakeFromHid,
                            SuspendImminent_Reason::LID_CLOSED => SuspendType::NoWakesAllowed,
                            SuspendImminent_Reason::OTHER => SuspendType::Other,
                        })
                        .await;

                    log::debug!("Adapter suspend call, success = {}", result.is_ok());
                });
            } else {
                // If there is no adapter, that means Bluetooth is not active and we should always
@@ -478,8 +485,11 @@ impl PowerdSuspendManager {
        self.context.lock().unwrap().pending_suspend_imminent = None;

        if let Some(adapter_suspend_dbus) = &self.context.lock().unwrap().adapter_suspend_dbus {
            let success = adapter_suspend_dbus.resume();
            log::debug!("Adapter resume is successful = {}", success);
            let suspend_dbus_rpc = adapter_suspend_dbus.rpc.clone();
            tokio::spawn(async move {
                let result = suspend_dbus_rpc.resume().await;
                log::debug!("Adapter resume call, success = {}", result.unwrap_or(false));
            });
        } else {
            log::debug!("Adapter is not available, nothing to resume.");
        }
@@ -495,14 +505,21 @@ impl PowerdSuspendManager {
        let crossroads = self.context.lock().unwrap().dbus_crossroads.clone();

        if let Some(adapter_suspend_dbus) = &mut self.context.lock().unwrap().adapter_suspend_dbus {
            let mut suspend_dbus_rpc = adapter_suspend_dbus.rpc.clone();
            let context = self.context.clone();
            tokio::spawn(async move {
                let suspend_cb_objpath: String =
                    format!("/org/chromium/bluetooth/Manager/suspend_callback");
            adapter_suspend_dbus.register_callback(Box::new(SuspendCallback::new(
                let status = suspend_dbus_rpc
                    .register_callback(Box::new(SuspendCallback::new(
                        suspend_cb_objpath,
                        conn,
                        crossroads,
                self.context.clone(),
            )));
                        context.clone(),
                    )))
                    .await;
                log::debug!("Suspend::RegisterCallback success = {}", status.unwrap_or(false));
            });
        }
    }