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

Commit e1692b8f authored by Sonny Sasaka's avatar Sonny Sasaka
Browse files

Floss: Add suspend API

This defines the suspend API at btadapterd level. The Suspend API is
supposed to be used in conjunction with another entity that actually
detects suspend/resume. In Chrome OS `btmanagerd` will communicate with
`powerd`, and in systemd-based Linux distros `btmanagerd` will
communicate with systemd using Inhibitor interface. In other Linux
systems suspend/resume script hooks can use this API as well.

Follow ups:
* Implementation of suspend() and resume()
* btclient command handler for debugging purposes.

Bug: 224606285
Tag: #floss
Test: Manual - Build floss with `build.py`

Change-Id: I5e9d3d37445aceded1224a7eaa6dfb564c25a3a6
parent f250e23f
Loading
Loading
Loading
Loading
+52 −0
Original line number Original line Diff line number Diff line
use crate::dbus_iface::{
use crate::dbus_iface::{
    export_bluetooth_callback_dbus_obj, export_bluetooth_connection_callback_dbus_obj,
    export_bluetooth_callback_dbus_obj, export_bluetooth_connection_callback_dbus_obj,
    export_bluetooth_gatt_callback_dbus_obj, export_bluetooth_manager_callback_dbus_obj,
    export_bluetooth_gatt_callback_dbus_obj, export_bluetooth_manager_callback_dbus_obj,
    export_suspend_callback_dbus_obj,
};
};
use crate::ClientContext;
use crate::ClientContext;
use crate::{console_yellow, print_info};
use crate::{console_yellow, print_info};
@@ -10,6 +11,7 @@ use btstack::bluetooth::{
    BluetoothDevice, IBluetooth, IBluetoothCallback, IBluetoothConnectionCallback,
    BluetoothDevice, IBluetooth, IBluetoothCallback, IBluetoothConnectionCallback,
};
};
use btstack::bluetooth_gatt::{BluetoothGattService, IBluetoothGattCallback, LePhy};
use btstack::bluetooth_gatt::{BluetoothGattService, IBluetoothGattCallback, LePhy};
use btstack::suspend::ISuspendCallback;
use btstack::RPCProxy;
use btstack::RPCProxy;
use dbus::nonblock::SyncConnection;
use dbus::nonblock::SyncConnection;
use dbus_crossroads::Crossroads;
use dbus_crossroads::Crossroads;
@@ -451,3 +453,53 @@ impl RPCProxy for BtGattCallback {
        );
        );
    }
    }
}
}

/// Callback container for suspend interface callbacks.
pub(crate) struct SuspendCallback {
    objpath: String,

    dbus_connection: Arc<SyncConnection>,
    dbus_crossroads: Arc<Mutex<Crossroads>>,
}

impl SuspendCallback {
    pub(crate) fn new(
        objpath: String,
        dbus_connection: Arc<SyncConnection>,
        dbus_crossroads: Arc<Mutex<Crossroads>>,
    ) -> Self {
        Self { objpath, dbus_connection, dbus_crossroads }
    }
}

impl ISuspendCallback for SuspendCallback {
    // TODO(b/224606285): Implement suspend utils in btclient.
    fn on_callback_registered(&self, _callback_id: u32) {}
    fn on_suspend_ready(&self, _suspend_id: u32) {}
    fn on_resumed(&self, _suspend_id: u32) {}
}

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

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

    fn unregister(&mut self, _id: u32) -> bool {
        false
    }

    fn export_for_rpc(self: Box<Self>) {
        let cr = self.dbus_crossroads.clone();
        export_suspend_callback_dbus_obj(
            self.get_object_id(),
            self.dbus_connection.clone(),
            &mut cr.lock().unwrap(),
            Arc::new(Mutex::new(self)),
            Arc::new(Mutex::new(DisconnectWatcher::new())),
        );
    }
}
+73 −0
Original line number Original line Diff line number Diff line
@@ -12,6 +12,8 @@ use btstack::bluetooth_gatt::{
    IScannerCallback, LePhy, ScanFilter, ScanSettings,
    IScannerCallback, LePhy, ScanFilter, ScanSettings,
};
};


use btstack::suspend::{ISuspend, ISuspendCallback, SuspendType};

use btstack::uuid::Profile;
use btstack::uuid::Profile;
use dbus::arg::{AppendAll, RefArg};
use dbus::arg::{AppendAll, RefArg};
use dbus::nonblock::SyncConnection;
use dbus::nonblock::SyncConnection;
@@ -45,6 +47,7 @@ impl_dbus_arg_enum!(GattWriteRequestStatus);
impl_dbus_arg_enum!(GattWriteType);
impl_dbus_arg_enum!(GattWriteType);
impl_dbus_arg_enum!(LePhy);
impl_dbus_arg_enum!(LePhy);
impl_dbus_arg_enum!(Profile);
impl_dbus_arg_enum!(Profile);
impl_dbus_arg_enum!(SuspendType);


// Represents Uuid128Bit as an array in D-Bus.
// Represents Uuid128Bit as an array in D-Bus.
impl DBusArg for Uuid128Bit {
impl DBusArg for Uuid128Bit {
@@ -804,3 +807,73 @@ impl IBluetoothGattCallback for IBluetoothGattCallbackDBus {
    #[dbus_method("OnServiceChanged")]
    #[dbus_method("OnServiceChanged")]
    fn on_service_changed(&self, addr: String) {}
    fn on_service_changed(&self, addr: String) {}
}
}

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

impl SuspendDBus {
    pub(crate) fn new(conn: Arc<SyncConnection>, index: i32) -> SuspendDBus {
        SuspendDBus {
            client_proxy: ClientDBusProxy {
                conn: conn.clone(),
                bus_name: String::from("org.chromium.bluetooth"),
                objpath: make_object_path(index, "suspend"),
                interface: String::from("org.chromium.bluetooth.Suspend"),
            },
        }
    }
}

#[generate_dbus_interface_client]
impl ISuspend for SuspendDBus {
    #[dbus_method("RegisterCallback")]
    fn register_callback(&mut self, _callback: Box<dyn ISuspendCallback + Send>) -> bool {
        dbus_generated!()
    }

    #[dbus_method("UnregisterCallback")]
    fn unregister_callback(&mut self, _callback_id: u32) -> bool {
        dbus_generated!()
    }

    #[dbus_method("Suspend")]
    fn suspend(&self, _suspend_type: SuspendType) -> u32 {
        dbus_generated!()
    }

    #[dbus_method("Resume")]
    fn resume(&self) -> bool {
        dbus_generated!()
    }
}

#[allow(dead_code)]
struct ISuspendCallbackDBus {}

impl btstack::RPCProxy for ISuspendCallbackDBus {
    // Placeholder implementations just to satisfy impl RPCProxy requirements.
    fn register_disconnect(&mut self, _f: Box<dyn Fn(u32) + Send>) -> u32 {
        0
    }
    fn get_object_id(&self) -> String {
        String::from("")
    }
    fn unregister(&mut self, _id: u32) -> bool {
        false
    }
    fn export_for_rpc(self: Box<Self>) {}
}

#[generate_dbus_exporter(
    export_suspend_callback_dbus_obj,
    "org.chromium.bluetooth.SuspendCallback"
)]
impl ISuspendCallback for ISuspendCallbackDBus {
    #[dbus_method("OnCallbackRegistered")]
    fn on_callback_registered(&self, callback_id: u32) {}
    #[dbus_method("OnSuspendReady")]
    fn on_suspend_ready(&self, suspend_id: u32) {}
    #[dbus_method("OnResumed")]
    fn on_resumed(&self, suspend_id: u32) {}
}
+21 −3
Original line number Original line Diff line number Diff line
@@ -7,12 +7,13 @@ use dbus::nonblock::SyncConnection;
use dbus_crossroads::Crossroads;
use dbus_crossroads::Crossroads;
use tokio::sync::mpsc;
use tokio::sync::mpsc;


use crate::callbacks::{BtCallback, BtConnectionCallback, BtManagerCallback};
use crate::callbacks::{BtCallback, BtConnectionCallback, BtManagerCallback, SuspendCallback};
use crate::command_handler::CommandHandler;
use crate::command_handler::CommandHandler;
use crate::dbus_iface::{BluetoothDBus, BluetoothGattDBus, BluetoothManagerDBus};
use crate::dbus_iface::{BluetoothDBus, BluetoothGattDBus, BluetoothManagerDBus, SuspendDBus};
use crate::editor::AsyncEditor;
use crate::editor::AsyncEditor;
use bt_topshim::topstack;
use bt_topshim::topstack;
use btstack::bluetooth::{BluetoothDevice, IBluetooth};
use btstack::bluetooth::{BluetoothDevice, IBluetooth};
use btstack::suspend::ISuspend;
use manager_service::iface_bluetooth_manager::IBluetoothManager;
use manager_service::iface_bluetooth_manager::IBluetoothManager;


mod callbacks;
mod callbacks;
@@ -64,6 +65,9 @@ pub(crate) struct ClientContext {
    /// Proxy for GATT interface.
    /// Proxy for GATT interface.
    pub(crate) gatt_dbus: Option<BluetoothGattDBus>,
    pub(crate) gatt_dbus: Option<BluetoothGattDBus>,


    /// Proxy for suspend interface.
    pub(crate) suspend_dbus: Option<SuspendDBus>,

    /// Channel to send actions to take in the foreground
    /// Channel to send actions to take in the foreground
    fg: mpsc::Sender<ForegroundActions>,
    fg: mpsc::Sender<ForegroundActions>,


@@ -97,6 +101,7 @@ impl ClientContext {
            manager_dbus,
            manager_dbus,
            adapter_dbus: None,
            adapter_dbus: None,
            gatt_dbus: None,
            gatt_dbus: None,
            suspend_dbus: None,
            fg: tx,
            fg: tx,
            dbus_connection,
            dbus_connection,
            dbus_crossroads,
            dbus_crossroads,
@@ -134,6 +139,8 @@ impl ClientContext {
        let gatt_dbus = BluetoothGattDBus::new(conn.clone(), idx);
        let gatt_dbus = BluetoothGattDBus::new(conn.clone(), idx);
        self.gatt_dbus = Some(gatt_dbus);
        self.gatt_dbus = Some(gatt_dbus);


        self.suspend_dbus = Some(SuspendDBus::new(conn.clone(), idx));

        // Trigger callback registration in the foreground
        // Trigger callback registration in the foreground
        let fg = self.fg.clone();
        let fg = self.fg.clone();
        tokio::spawn(async move {
        tokio::spawn(async move {
@@ -318,7 +325,7 @@ async fn start_interactive_shell(


                context.lock().unwrap().adapter_dbus.as_mut().unwrap().register_callback(Box::new(
                context.lock().unwrap().adapter_dbus.as_mut().unwrap().register_callback(Box::new(
                    BtCallback::new(
                    BtCallback::new(
                        cb_objpath,
                        cb_objpath.clone(),
                        context.clone(),
                        context.clone(),
                        dbus_connection.clone(),
                        dbus_connection.clone(),
                        dbus_crossroads.clone(),
                        dbus_crossroads.clone(),
@@ -336,6 +343,17 @@ async fn start_interactive_shell(
                        dbus_connection.clone(),
                        dbus_connection.clone(),
                        dbus_crossroads.clone(),
                        dbus_crossroads.clone(),
                    )));
                    )));

                // When adapter is ready, Suspend API is also ready. Register as an observer.
                // TODO(b/224606285): Implement suspend debug utils in btclient.
                context.lock().unwrap().suspend_dbus.as_mut().unwrap().register_callback(Box::new(
                    SuspendCallback::new(
                        cb_objpath,
                        dbus_connection.clone(),
                        dbus_crossroads.clone(),
                    ),
                ));

                context.lock().unwrap().adapter_ready = true;
                context.lock().unwrap().adapter_ready = true;
                let adapter_address = context.lock().unwrap().update_adapter_address();
                let adapter_address = context.lock().unwrap().update_adapter_address();
                print_info!("Adapter {} is ready", adapter_address);
                print_info!("Adapter {} is ready", adapter_address);
+62 −0
Original line number Original line Diff line number Diff line
use btstack::suspend::{ISuspend, ISuspendCallback, SuspendType};
use btstack::RPCProxy;

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

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

use dbus_projection::{dbus_generated, impl_dbus_arg_enum, DisconnectWatcher};

use dbus::nonblock::SyncConnection;
use dbus::strings::Path;

use num_traits::cast::{FromPrimitive, ToPrimitive};

use std::sync::Arc;

impl_dbus_arg_enum!(SuspendType);

#[allow(dead_code)]
struct ISuspendDBus {}

#[generate_dbus_exporter(export_suspend_dbus_obj, "org.chromium.bluetooth.Suspend")]
impl ISuspend for ISuspendDBus {
    #[dbus_method("RegisterCallback")]
    fn register_callback(&mut self, callback: Box<dyn ISuspendCallback + Send>) -> bool {
        dbus_generated!()
    }

    #[dbus_method("UnregisterCallback")]
    fn unregister_callback(&mut self, callback_id: u32) -> bool {
        dbus_generated!()
    }

    #[dbus_method("Suspend")]
    fn suspend(&self, suspend_type: SuspendType) -> u32 {
        dbus_generated!()
    }

    #[dbus_method("Resume")]
    fn resume(&self) -> bool {
        dbus_generated!()
    }
}

#[allow(dead_code)]
struct SuspendCallbackDBus {}

#[dbus_proxy_obj(SuspendCallback, "org.chromium.bluetooth.SuspendCallback")]
impl ISuspendCallback for SuspendCallbackDBus {
    #[dbus_method("OnCallbackRegistered")]
    fn on_callback_registered(&self, callback_id: u32) {
        dbus_generated!()
    }
    #[dbus_method("OnSuspendReady")]
    fn on_suspend_ready(&self, suspend_id: u32) {
        dbus_generated!()
    }
    #[dbus_method("OnResumed")]
    fn on_resumed(&self, suspend_id: u32) {
        dbus_generated!()
    }
}
+12 −0
Original line number Original line Diff line number Diff line
@@ -12,6 +12,7 @@ use btstack::{
    bluetooth::{get_bt_dispatcher, Bluetooth, IBluetooth},
    bluetooth::{get_bt_dispatcher, Bluetooth, IBluetooth},
    bluetooth_gatt::BluetoothGatt,
    bluetooth_gatt::BluetoothGatt,
    bluetooth_media::BluetoothMedia,
    bluetooth_media::BluetoothMedia,
    suspend::Suspend,
    Stack,
    Stack,
};
};
use dbus_projection::DisconnectWatcher;
use dbus_projection::DisconnectWatcher;
@@ -20,6 +21,7 @@ mod dbus_arg;
mod iface_bluetooth;
mod iface_bluetooth;
mod iface_bluetooth_gatt;
mod iface_bluetooth_gatt;
mod iface_bluetooth_media;
mod iface_bluetooth_media;
mod iface_suspend;


const DBUS_SERVICE_NAME: &str = "org.chromium.bluetooth";
const DBUS_SERVICE_NAME: &str = "org.chromium.bluetooth";


@@ -58,6 +60,7 @@ fn main() -> Result<(), Box<dyn Error>> {
    let (tx, rx) = Stack::create_channel();
    let (tx, rx) = Stack::create_channel();


    let intf = Arc::new(Mutex::new(get_btinterface().unwrap()));
    let intf = Arc::new(Mutex::new(get_btinterface().unwrap()));
    let suspend = Arc::new(Mutex::new(Box::new(Suspend::new(tx.clone()))));
    let bluetooth_gatt = Arc::new(Mutex::new(Box::new(BluetoothGatt::new(intf.clone()))));
    let bluetooth_gatt = Arc::new(Mutex::new(Box::new(BluetoothGatt::new(intf.clone()))));
    let bluetooth_media =
    let bluetooth_media =
        Arc::new(Mutex::new(Box::new(BluetoothMedia::new(tx.clone(), intf.clone()))));
        Arc::new(Mutex::new(Box::new(BluetoothMedia::new(tx.clone(), intf.clone()))));
@@ -113,6 +116,7 @@ fn main() -> Result<(), Box<dyn Error>> {
            bluetooth.clone(),
            bluetooth.clone(),
            bluetooth_gatt.clone(),
            bluetooth_gatt.clone(),
            bluetooth_media.clone(),
            bluetooth_media.clone(),
            suspend.clone(),
        ));
        ));


        // Set up the disconnect watcher to monitor client disconnects.
        // Set up the disconnect watcher to monitor client disconnects.
@@ -144,6 +148,14 @@ fn main() -> Result<(), Box<dyn Error>> {
            disconnect_watcher.clone(),
            disconnect_watcher.clone(),
        );
        );


        iface_suspend::export_suspend_dbus_obj(
            make_object_name(adapter_index, "suspend"),
            conn.clone(),
            &mut cr,
            suspend,
            disconnect_watcher.clone(),
        );

        conn.start_receive(
        conn.start_receive(
            MatchRule::new_method_call(),
            MatchRule::new_method_call(),
            Box::new(move |msg, conn| {
            Box::new(move |msg, conn| {
Loading