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

Commit f877f45b authored by Katherine Lai's avatar Katherine Lai
Browse files

Floss: Implement Register/Unregister Server

This implements IBluetoothGatt's RegisterServer and
UnregisterServer as well as IBluetoothGattServerCallback
OnServerRegistered. Also adds these to btclient.

Bug: 193685149
Tag: #floss
Test: emerge-dedede floss and btclient
Change-Id: I54962d453d25716a29029d3ba7f27faab680a746
parent 3b190fb0
Loading
Loading
Loading
Loading
+46 −3
Original line number Diff line number Diff line
@@ -2,8 +2,8 @@ use crate::dbus_iface::{
    export_admin_policy_callback_dbus_intf, 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_socket_callback_dbus_intf,
    export_suspend_callback_dbus_intf,
    export_gatt_server_callback_dbus_intf, export_scanner_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};
@@ -15,7 +15,8 @@ use btstack::bluetooth::{
use btstack::bluetooth_admin::{IBluetoothAdminPolicyCallback, PolicyEffect};
use btstack::bluetooth_adv::IAdvertisingSetCallback;
use btstack::bluetooth_gatt::{
    BluetoothGattService, IBluetoothGattCallback, IScannerCallback, ScanResult,
    BluetoothGattService, IBluetoothGattCallback, IBluetoothGattServerCallback, IScannerCallback,
    ScanResult,
};
use btstack::socket_manager::{
    BluetoothServerSocket, BluetoothSocket, IBluetoothSocketManager,
@@ -738,6 +739,48 @@ impl RPCProxy for BtGattCallback {
    }
}

pub(crate) struct BtGattServerCallback {
    objpath: String,
    _context: Arc<Mutex<ClientContext>>,

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

impl BtGattServerCallback {
    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 IBluetoothGattServerCallback for BtGattServerCallback {
    fn on_server_registered(&self, status: GattStatus, server_id: i32) {
        print_info!("GATT Server registered status = {}, server_id = {}", status, server_id);
    }
}

impl RPCProxy for BtGattServerCallback {
    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_gatt_server_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)));
    }
}

pub(crate) struct BtSocketManagerCallback {
    objpath: String,
    context: Arc<Mutex<ClientContext>>,
+20 −1
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ use std::sync::{Arc, Mutex};

use crate::bt_adv::AdvSet;
use crate::bt_gatt::AuthReq;
use crate::callbacks::BtGattCallback;
use crate::callbacks::{BtGattCallback, BtGattServerCallback};
use crate::ClientContext;
use crate::{console_red, console_yellow, print_error, print_info};
use bt_topshim::btif::{BtConnectionState, BtStatus, BtTransport};
@@ -21,6 +21,7 @@ const BAR1_CHAR: &str = "=";
const BAR2_CHAR: &str = "-";
const MAX_MENU_CHAR_WIDTH: usize = 72;
const GATT_CLIENT_APP_UUID: &str = "12345678123456781234567812345678";
const GATT_SERVER_APP_UUID: &str = "12345678123456781234567812345679";

enum CommandError {
    // Command not handled due to invalid arguments.
@@ -169,6 +170,7 @@ fn build_commands() -> HashMap<String, CommandOption> {
                    "gatt write-characteristic <address> <handle> <NoRsp|Write|Prepare> <value>",
                ),
                String::from("gatt read-characteristic <address> <handle>"),
                String::from("gatt register-server"),
            ],
            description: String::from("GATT tools"),
            function_pointer: CommandHandler::cmd_gatt,
@@ -1076,6 +1078,23 @@ impl CommandHandler {
                    .unwrap()
                    .read_characteristic(client_id, addr, handle, auth_req);
            }
            "register-server" => {
                let dbus_connection = self.context.lock().unwrap().dbus_connection.clone();
                let dbus_crossroads = self.context.lock().unwrap().dbus_crossroads.clone();

                self.context.lock().unwrap().gatt_dbus.as_mut().unwrap().register_server(
                    String::from(GATT_SERVER_APP_UUID),
                    Box::new(BtGattServerCallback::new(
                        String::from(
                            "/org/chromium/bluetooth/client/bluetooth_gatt_server_callback",
                        ),
                        self.context.clone(),
                        dbus_connection,
                        dbus_crossroads,
                    )),
                    false,
                );
            }
            _ => return Err(CommandError::InvalidArgs),
        }
        Ok(())
+28 −2
Original line number Diff line number Diff line
@@ -18,8 +18,8 @@ use btstack::bluetooth_adv::{
use btstack::bluetooth_gatt::{
    BluetoothGattCharacteristic, BluetoothGattDescriptor, BluetoothGattService,
    GattWriteRequestStatus, GattWriteType, IBluetoothGatt, IBluetoothGattCallback,
    IScannerCallback, ScanFilter, ScanFilterCondition, ScanFilterPattern, ScanResult, ScanSettings,
    ScanType,
    IBluetoothGattServerCallback, IScannerCallback, ScanFilter, ScanFilterCondition,
    ScanFilterPattern, ScanResult, ScanSettings, ScanType,
};
use btstack::socket_manager::{
    BluetoothServerSocket, BluetoothSocket, CallbackId, IBluetoothSocketManager,
@@ -1264,6 +1264,23 @@ impl IBluetoothGatt for BluetoothGattDBus {
    ) {
        dbus_generated!()
    }

    // GATT Server

    #[dbus_method("RegisterServer")]
    fn register_server(
        &mut self,
        app_uuid: String,
        callback: Box<dyn IBluetoothGattServerCallback + Send>,
        eatt_support: bool,
    ) {
        dbus_generated!()
    }

    #[dbus_method("UnregisterServer")]
    fn unregister_server(&mut self, server_id: i32) {
        dbus_generated!()
    }
}

struct IBluetoothGattCallbackDBus {}
@@ -1349,6 +1366,15 @@ impl IBluetoothGattCallback for IBluetoothGattCallbackDBus {
    fn on_service_changed(&self, addr: String) {}
}

#[generate_dbus_exporter(
    export_gatt_server_callback_dbus_intf,
    "org.chromium.bluetooth.BluetoothGattServerCallback"
)]
impl IBluetoothGattServerCallback for IBluetoothGattCallbackDBus {
    #[dbus_method("OnServerRegistered")]
    fn on_server_registered(&self, status: GattStatus, client_id: i32) {}
}

#[dbus_propmap(BluetoothServerSocket)]
pub struct BluetoothServerSocketDBus {
    id: SocketId,
+30 −2
Original line number Diff line number Diff line
@@ -8,8 +8,8 @@ use btstack::bluetooth_adv::{
use btstack::bluetooth_gatt::{
    BluetoothGattCharacteristic, BluetoothGattDescriptor, BluetoothGattService,
    GattWriteRequestStatus, GattWriteType, IBluetoothGatt, IBluetoothGattCallback,
    IScannerCallback, ScanFilter, ScanFilterCondition, ScanFilterPattern, ScanResult, ScanSettings,
    ScanType,
    IBluetoothGattServerCallback, IScannerCallback, ScanFilter, ScanFilterCondition,
    ScanFilterPattern, ScanResult, ScanSettings, ScanType,
};
use btstack::{RPCProxy, SuspendMode};

@@ -136,6 +136,17 @@ impl IBluetoothGattCallback for BluetoothGattCallbackDBus {
    }
}

#[allow(dead_code)]
struct BluetoothGattServerCallbackDBus {}

#[dbus_proxy_obj(BluetoothGattServerCallback, "org.chromium.bluetooth.BluetoothGattServerCallback")]
impl IBluetoothGattServerCallback for BluetoothGattServerCallbackDBus {
    #[dbus_method("OnServerRegistered")]
    fn on_server_registered(&self, status: GattStatus, server_id: i32) {
        dbus_generated!()
    }
}

// Represents Uuid128Bit as an array in D-Bus.
impl DBusArg for Uuid128Bit {
    type DBusType = Vec<u8>;
@@ -747,4 +758,21 @@ impl IBluetoothGatt for IBluetoothGattDBus {
    fn client_read_phy(&mut self, client_id: i32, addr: String) {
        dbus_generated!()
    }

    // GATT Server

    #[dbus_method("RegisterServer")]
    fn register_server(
        &mut self,
        app_uuid: String,
        callback: Box<dyn IBluetoothGattServerCallback + Send>,
        eatt_support: bool,
    ) {
        dbus_generated!()
    }

    #[dbus_method("UnregisterServer")]
    fn unregister_server(&mut self, server_id: i32) {
        dbus_generated!()
    }
}
+169 −4
Original line number Diff line number Diff line
@@ -9,8 +9,8 @@ use bt_topshim::profiles::gatt::{
    BtGattReadParams, Gatt, GattAdvCallbacks, GattAdvCallbacksDispatcher,
    GattAdvInbandCallbacksDispatcher, GattClientCallbacks, GattClientCallbacksDispatcher,
    GattScannerCallbacks, GattScannerCallbacksDispatcher, GattScannerInbandCallbacks,
    GattScannerInbandCallbacksDispatcher, GattServerCallbacksDispatcher, GattStatus, LePhy,
    MsftAdvMonitor, MsftAdvMonitorPattern,
    GattScannerInbandCallbacksDispatcher, GattServerCallbacks, GattServerCallbacksDispatcher,
    GattStatus, LePhy, MsftAdvMonitor, MsftAdvMonitorPattern,
};
use bt_topshim::topstack;
use bt_utils::adv_parser;
@@ -180,6 +180,79 @@ impl ContextMap {
    }
}

struct Server {
    id: Option<i32>,
    cbid: u32,
    uuid: Uuid128Bit,
}

struct ServerContextMap {
    // TODO(b/196635530): Consider using `multimap` for a more efficient implementation of get by
    // multiple keys.
    callbacks: Callbacks<dyn IBluetoothGattServerCallback + Send>,
    servers: Vec<Server>,
}

type GattServerCallback = Box<dyn IBluetoothGattServerCallback + Send>;

impl ServerContextMap {
    fn new(tx: Sender<Message>) -> ServerContextMap {
        ServerContextMap {
            callbacks: Callbacks::new(tx, Message::GattServerCallbackDisconnected),
            servers: vec![],
        }
    }

    fn get_by_uuid(&self, uuid: &Uuid128Bit) -> Option<&Server> {
        self.servers.iter().find(|server| server.uuid == *uuid)
    }

    fn get_by_server_id(&self, server_id: i32) -> Option<&Server> {
        self.servers.iter().find(|server| server.id.map_or(false, |id| id == server_id))
    }

    fn get_by_callback_id(&self, callback_id: u32) -> Option<&Server> {
        self.servers.iter().find(|server| server.cbid == callback_id)
    }

    fn add(&mut self, uuid: &Uuid128Bit, callback: GattServerCallback) {
        if self.get_by_uuid(uuid).is_some() {
            return;
        }

        let cbid = self.callbacks.add_callback(callback);

        self.servers.push(Server { id: None, cbid, uuid: uuid.clone() });
    }

    fn remove(&mut self, id: i32) {
        // Remove any callbacks
        if let Some(cbid) = self.get_by_server_id(id).map(|server| server.cbid) {
            self.remove_callback(cbid);
        }

        self.servers.retain(|server| !(server.id.is_some() && server.id.unwrap() == id));
    }

    fn remove_callback(&mut self, callback_id: u32) {
        self.callbacks.remove_callback(callback_id);
    }

    fn set_server_id(&mut self, uuid: &Uuid128Bit, id: i32) {
        let server = self.servers.iter_mut().find(|server| server.uuid == *uuid);
        if let Some(s) = server {
            s.id = Some(id);
        }
    }

    fn get_callback_from_callback_id(
        &mut self,
        callback_id: u32,
    ) -> Option<&mut GattServerCallback> {
        self.callbacks.get_by_id(callback_id)
    }
}

/// Defines the GATT API.
// TODO(242083290): Split out interfaces.
pub trait IBluetoothGatt {
@@ -425,6 +498,19 @@ pub trait IBluetoothGatt {

    /// Reads the PHY used by a peer.
    fn client_read_phy(&mut self, client_id: i32, addr: String);

    // GATT Server

    /// Registers a GATT Server.
    fn register_server(
        &mut self,
        app_uuid: String,
        callback: Box<dyn IBluetoothGattServerCallback + Send>,
        eatt_support: bool,
    );

    /// Unregisters a GATT Server.
    fn unregister_server(&mut self, server_id: i32);
}

#[derive(Debug, Default)]
@@ -580,6 +666,12 @@ pub trait IBluetoothGattCallback: RPCProxy {
    fn on_service_changed(&self, _addr: String);
}

/// Callback for GATT Server API.
pub trait IBluetoothGattServerCallback: RPCProxy {
    /// When the `register_server` request is done.
    fn on_server_registered(&self, _status: GattStatus, _server_id: i32);
}

/// Interface for scanner callbacks to clients, passed to
/// `IBluetoothGatt::register_scanner_callback`.
pub trait IScannerCallback: RPCProxy {
@@ -813,6 +905,7 @@ pub struct BluetoothGatt {
    adapter: Option<Arc<Mutex<Box<Bluetooth>>>>,

    context_map: ContextMap,
    server_context_map: ServerContextMap,
    reliable_queue: HashSet<String>,
    scanner_callbacks: Callbacks<dyn IScannerCallback + Send>,
    scanners: Arc<Mutex<ScannersMap>>,
@@ -842,6 +935,7 @@ impl BluetoothGatt {
            gatt: None,
            adapter: None,
            context_map: ContextMap::new(tx.clone()),
            server_context_map: ServerContextMap::new(tx.clone()),
            reliable_queue: HashSet::new(),
            scanner_callbacks: Callbacks::new(tx.clone(), Message::ScannerCallbackDisconnected),
            scanners: scanners.clone(),
@@ -874,10 +968,13 @@ impl BluetoothGatt {
            }),
        };

        let tx_clone = tx.clone();
        let gatt_server_callbacks_dispatcher = GattServerCallbacksDispatcher {
            dispatch: Box::new(move |cb| {
                // TODO(b/193685149): Implement the callbacks
                debug!("received Gatt server callback: {:?}", cb);
                let tx_clone = tx_clone.clone();
                topstack::get_runtime().spawn(async move {
                    let _ = tx_clone.send(Message::GattServer(cb)).await;
                });
            }),
        };

@@ -1015,6 +1112,18 @@ impl BluetoothGatt {
        self.context_map.remove_callback(callback_id);
    }

    pub fn remove_server_callback(&mut self, callback_id: u32) {
        // Unregister server if server id exists.
        if let Some(server) = self.server_context_map.get_by_callback_id(callback_id) {
            if let Some(id) = server.id {
                self.unregister_server(id);
            }
        }

        // Always remove callback.
        self.context_map.remove_callback(callback_id);
    }

    /// Enters suspend mode for LE advertising.
    pub fn advertising_enter_suspend(&mut self) {
        self.advertisers.set_suspend_mode(SuspendMode::Suspending);
@@ -1501,6 +1610,8 @@ impl IBluetoothGatt for BluetoothGatt {
        }
    }

    // GATT Client

    fn register_client(
        &mut self,
        app_uuid: String,
@@ -1829,6 +1940,36 @@ impl IBluetoothGatt for BluetoothGatt {

        self.gatt.as_ref().unwrap().lock().unwrap().client.read_phy(client_id, &address);
    }

    // GATT Server

    fn register_server(
        &mut self,
        app_uuid: String,
        callback: Box<dyn IBluetoothGattServerCallback + Send>,
        eatt_support: bool,
    ) {
        let uuid = match UuidHelper::parse_string(&app_uuid) {
            Some(id) => id,
            None => {
                log::info!("Uuid is malformed: {}", app_uuid);
                return;
            }
        };
        self.server_context_map.add(&uuid.uu, callback);
        self.gatt
            .as_ref()
            .expect("GATT has not been initialized")
            .lock()
            .unwrap()
            .server
            .register_server(&uuid, eatt_support);
    }

    fn unregister_server(&mut self, server_id: i32) {
        self.server_context_map.remove(server_id);
        self.gatt.as_ref().unwrap().lock().unwrap().server.unregister_server(server_id);
    }
}

#[btif_callbacks_dispatcher(dispatch_gatt_client_callbacks, GattClientCallbacks)]
@@ -2430,6 +2571,30 @@ impl BtifGattClientCallbacks for BluetoothGatt {
    }
}

#[btif_callbacks_dispatcher(dispatch_gatt_server_callbacks, GattServerCallbacks)]
pub(crate) trait BtifGattServerCallbacks {
    #[btif_callback(RegisterServer)]
    fn register_server_cb(&mut self, status: GattStatus, server_id: i32, app_uuid: Uuid);
}

impl BtifGattServerCallbacks for BluetoothGatt {
    fn register_server_cb(&mut self, status: GattStatus, server_id: i32, app_uuid: Uuid) {
        self.server_context_map.set_server_id(&app_uuid.uu, server_id);

        let cbid = self.server_context_map.get_by_uuid(&app_uuid.uu).map(|server| server.cbid);
        match cbid {
            Some(cbid) => {
                if let Some(cb) = self.server_context_map.get_callback_from_callback_id(cbid) {
                    cb.on_server_registered(status, server_id)
                }
            }
            None => {
                warn!("Warning: No callback found for UUID {}", app_uuid);
            }
        }
    }
}

#[btif_callbacks_dispatcher(dispatch_le_scanner_callbacks, GattScannerCallbacks)]
pub(crate) trait BtifGattScannerCallbacks {
    #[btif_callback(OnScannerRegistered)]
Loading