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

Commit de31b5a2 authored by Hsin-chen Chuang's avatar Hsin-chen Chuang Committed by Gerrit Code Review
Browse files

Merge "floss: client: Add basic socket manager example."

parents 80e9ec8e 398383b3
Loading
Loading
Loading
Loading
+105 −2
Original line number Diff line number Diff line
@@ -2,11 +2,11 @@ use crate::dbus_iface::{
    export_advertising_set_callback_dbus_intf, export_bluetooth_callback_dbus_intf,
    export_bluetooth_connection_callback_dbus_intf, export_bluetooth_gatt_callback_dbus_intf,
    export_bluetooth_manager_callback_dbus_intf, export_scanner_callback_dbus_intf,
    export_suspend_callback_dbus_intf,
    export_socket_callback_dbus_intf, export_suspend_callback_dbus_intf,
};
use crate::ClientContext;
use crate::{console_red, console_yellow, print_error, print_info};
use bt_topshim::btif::{BtBondState, BtPropertyType, BtSspVariant, Uuid128Bit};
use bt_topshim::btif::{BtBondState, BtPropertyType, BtSspVariant, BtStatus, Uuid128Bit};
use bt_topshim::profiles::gatt::GattStatus;
use btstack::bluetooth::{
    BluetoothDevice, IBluetooth, IBluetoothCallback, IBluetoothConnectionCallback,
@@ -15,6 +15,10 @@ use btstack::bluetooth_adv::IAdvertisingSetCallback;
use btstack::bluetooth_gatt::{
    BluetoothGattService, IBluetoothGattCallback, IScannerCallback, LePhy, ScanResult,
};
use btstack::socket_manager::{
    BluetoothServerSocket, BluetoothSocket, IBluetoothSocketManager,
    IBluetoothSocketManagerCallbacks, SocketId,
};
use btstack::suspend::ISuspendCallback;
use btstack::uuid::UuidWrapper;
use btstack::RPCProxy;
@@ -665,6 +669,105 @@ impl RPCProxy for BtGattCallback {
    }
}

pub(crate) struct BtSocketManagerCallback {
    objpath: String,
    context: Arc<Mutex<ClientContext>>,

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

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

impl IBluetoothSocketManagerCallbacks for BtSocketManagerCallback {
    fn on_incoming_socket_ready(&mut self, socket: BluetoothServerSocket, status: BtStatus) {
        if status != BtStatus::Success {
            print_error!(
                "Incoming socket {} failed to be ready, type = {:?}, flags = {}, status = {:?}",
                socket.id,
                socket.sock_type,
                socket.flags,
                status,
            );
            return;
        }

        print_info!(
            "Socket {} ready, details: {:?}, flags = {}, psm = {:?}, channel = {:?}, name = {:?}, uuid = {:?}",
            socket.id,
            socket.sock_type,
            socket.flags,
            socket.psm,
            socket.channel,
            socket.name,
            socket.uuid,
        );

        let callback_id = self.context.lock().unwrap().socket_manager_callback_id.clone().unwrap();

        self.context.lock().unwrap().run_callback(Box::new(move |context| {
            let status = context
                .lock()
                .unwrap()
                .socket_manager_dbus
                .as_mut()
                .unwrap()
                .close(callback_id, socket.id);
            if status != BtStatus::Success {
                print_error!("Failed to close socket {}, status = {:?}", socket.id, status);
                return;
            }
            print_info!("Requested for closing socket {}", socket.id);
        }));
    }

    fn on_incoming_socket_closed(&mut self, listener_id: SocketId, reason: BtStatus) {
        print_info!("Socket {} closed, reason = {:?}", listener_id, reason);
    }

    fn on_handle_incoming_connection(
        &mut self,
        listener_id: SocketId,
        connection: BluetoothSocket,
    ) {
        todo!();
    }

    fn on_outgoing_connection_result(
        &mut self,
        connecting_id: SocketId,
        result: BtStatus,
        socket: Option<BluetoothSocket>,
    ) {
        todo!();
    }
}

impl RPCProxy for BtSocketManagerCallback {
    fn get_object_id(&self) -> String {
        self.objpath.clone()
    }

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

/// Callback container for suspend interface callbacks.
pub(crate) struct SuspendCallback {
    objpath: String,
+48 −1
Original line number Diff line number Diff line
@@ -5,10 +5,11 @@ use std::sync::{Arc, Mutex};
use crate::callbacks::BtGattCallback;
use crate::ClientContext;
use crate::{console_red, console_yellow, print_error, print_info};
use bt_topshim::btif::{BtConnectionState, BtTransport};
use bt_topshim::btif::{BtConnectionState, BtStatus, BtTransport};
use btstack::bluetooth::{BluetoothDevice, IBluetooth, IBluetoothQA};
use btstack::bluetooth_adv::{AdvertiseData, AdvertisingSetParameters};
use btstack::bluetooth_gatt::{IBluetoothGatt, RSSISettings, ScanSettings, ScanType};
use btstack::socket_manager::{IBluetoothSocketManager, SocketResult};
use btstack::uuid::{Profile, UuidHelper, UuidWrapper};
use manager_service::iface_bluetooth_manager::IBluetoothManager;

@@ -165,6 +166,14 @@ fn build_commands() -> HashMap<String, CommandOption> {
            function_pointer: CommandHandler::cmd_advertise,
        },
    );
    command_options.insert(
        String::from("socket"),
        CommandOption {
            rules: vec![String::from("socket test")],
            description: String::from("Socket manager utilities."),
            function_pointer: CommandHandler::cmd_socket,
        },
    );
    command_options.insert(
        String::from("get-address"),
        CommandOption {
@@ -964,6 +973,44 @@ impl CommandHandler {
        });
    }

    fn cmd_socket(&mut self, args: &Vec<String>) {
        if !self.context.lock().unwrap().adapter_ready {
            self.adapter_not_ready();
            return;
        }
        let callback_id = match self.context.lock().unwrap().socket_manager_callback_id.clone() {
            Some(id) => id,
            None => {
                return;
            }
        };

        enforce_arg_len(args, 1, "socket <test>", || match &args[0][0..] {
            "test" => {
                let SocketResult { status, id } = self
                    .context
                    .lock()
                    .unwrap()
                    .socket_manager_dbus
                    .as_mut()
                    .unwrap()
                    .listen_using_l2cap_channel(callback_id);

                if status != BtStatus::Success {
                    print_error!(
                        "Failed to request for listening using l2cap channel, status = {:?}",
                        status,
                    );
                    return;
                }
                print_info!("Requested for listening using l2cap channel on socket {}", id);
            }
            _ => {
                println!("Invalid argument '{}'", args[0]);
            }
        });
    }

    /// Get the list of rules of supported commands
    pub fn get_command_rule_list(&self) -> Vec<String> {
        self.command_options.values().flat_map(|cmd| cmd.rules.clone()).collect()
+20 −8
Original line number Diff line number Diff line
@@ -1285,24 +1285,36 @@ pub struct SocketResultDBus {
    id: u64,
}

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

pub(crate) struct BluetoothSocketManagerDBus {
    client_proxy: ClientDBusProxy,
    pub rpc: BluetoothSocketManagerDBusRPC,
}

impl BluetoothSocketManagerDBus {
    pub(crate) fn _new(conn: Arc<SyncConnection>, index: i32) -> Self {
        BluetoothSocketManagerDBus {
            client_proxy: ClientDBusProxy::new(
                conn.clone(),
    fn make_client_proxy(conn: Arc<SyncConnection>, index: i32) -> ClientDBusProxy {
        ClientDBusProxy::new(
            conn,
            String::from("org.chromium.bluetooth"),
            make_object_path(index, "adapter"),
            String::from("org.chromium.bluetooth.SocketManager"),
            ),
        )
    }

    pub(crate) fn new(conn: Arc<SyncConnection>, index: i32) -> Self {
        BluetoothSocketManagerDBus {
            client_proxy: Self::make_client_proxy(conn.clone(), index),
            rpc: BluetoothSocketManagerDBusRPC {
                client_proxy: Self::make_client_proxy(conn.clone(), index),
            },
        }
    }
}

#[generate_dbus_interface_client]
#[generate_dbus_interface_client(BluetoothSocketManagerDBusRPC)]
impl IBluetoothSocketManager for BluetoothSocketManagerDBus {
    #[dbus_method("RegisterCallback")]
    fn register_callback(
+35 −3
Original line number Diff line number Diff line
@@ -8,12 +8,13 @@ use dbus_crossroads::Crossroads;
use tokio::sync::mpsc;

use crate::callbacks::{
    AdvertisingSetCallback, BtCallback, BtConnectionCallback, BtManagerCallback, ScannerCallback,
    SuspendCallback,
    AdvertisingSetCallback, BtCallback, BtConnectionCallback, BtManagerCallback,
    BtSocketManagerCallback, ScannerCallback, SuspendCallback,
};
use crate::command_handler::CommandHandler;
use crate::dbus_iface::{
    BluetoothDBus, BluetoothGattDBus, BluetoothManagerDBus, BluetoothQADBus, SuspendDBus,
    BluetoothDBus, BluetoothGattDBus, BluetoothManagerDBus, BluetoothQADBus,
    BluetoothSocketManagerDBus, SuspendDBus,
};
use crate::editor::AsyncEditor;
use bt_topshim::topstack;
@@ -79,6 +80,9 @@ pub(crate) struct ClientContext {
    /// Proxy for suspend interface.
    pub(crate) suspend_dbus: Option<SuspendDBus>,

    /// Proxy for socket manager interface.
    pub(crate) socket_manager_dbus: Option<BluetoothSocketManagerDBus>,

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

@@ -99,6 +103,9 @@ pub(crate) struct ClientContext {

    /// Advertising sets started/registered. Map from reg_id to advertiser_id.
    adv_sets: HashMap<i32, Option<i32>>,

    /// Identifies the callback to receive IBluetoothSocketManagerCallback method calls.
    socket_manager_callback_id: Option<u32>,
}

impl ClientContext {
@@ -127,6 +134,7 @@ impl ClientContext {
            qa_dbus: None,
            gatt_dbus: None,
            suspend_dbus: None,
            socket_manager_dbus: None,
            fg: tx,
            dbus_connection,
            dbus_crossroads,
@@ -134,6 +142,7 @@ impl ClientContext {
            advertiser_callback_id: None,
            active_scanner_ids: HashSet::new(),
            adv_sets: HashMap::new(),
            socket_manager_callback_id: None,
        }
    }

@@ -169,6 +178,9 @@ impl ClientContext {
        let gatt_dbus = BluetoothGattDBus::new(conn.clone(), idx);
        self.gatt_dbus = Some(gatt_dbus);

        let socket_manager_dbus = BluetoothSocketManagerDBus::new(conn.clone(), idx);
        self.socket_manager_dbus = Some(socket_manager_dbus);

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

        // Trigger callback registration in the foreground
@@ -393,6 +405,8 @@ async fn start_interactive_shell(
                    format!("/org/chromium/bluetooth/client/{}/scanner_callback", adapter);
                let advertiser_cb_objpath: String =
                    format!("/org/chromium/bluetooth/client/{}/advertising_set_callback", adapter);
                let socket_manager_cb_objpath: String =
                    format!("/org/chromium/bluetooth/client/{}/socket_manager_callback", adapter);

                let dbus_connection = context.lock().unwrap().dbus_connection.clone();
                let dbus_crossroads = context.lock().unwrap().dbus_crossroads.clone();
@@ -463,6 +477,24 @@ async fn start_interactive_shell(
                    .expect("D-Bus error on IBluetoothGatt::RegisterAdvertiserCallback");
                context.lock().unwrap().advertiser_callback_id = Some(advertiser_callback_id);

                let socket_manager_callback_id = context
                    .lock()
                    .unwrap()
                    .socket_manager_dbus
                    .as_mut()
                    .unwrap()
                    .rpc
                    .register_callback(Box::new(BtSocketManagerCallback::new(
                        socket_manager_cb_objpath.clone(),
                        context.clone(),
                        dbus_connection.clone(),
                        dbus_crossroads.clone(),
                    )))
                    .await
                    .expect("D-Bus error on IBluetoothSocketManager::RegisterCallback");
                context.lock().unwrap().socket_manager_callback_id =
                    Some(socket_manager_callback_id);

                // 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(