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

Commit 786a42c2 authored by Katherine Lai's avatar Katherine Lai
Browse files

Floss: Implement read/write request CBs for GATT Server

This implements IBluetoothGattServerCallback
onCharacteristicReadRequest, onDescriptorReadRequest,
onCharacteristicWriteRequest, onDescriptorWriteRequest, and
onExecuteWrite as well as corresponding IBluetoothGatt's
sendResponse.

Bug: 193685791
Tag: #floss
Test: emerge-dedede floss and manual testing
Change-Id: I11e7d4cc790efd088d42e5ca44d422cf4e602c44
parent 6a44c3e3
Loading
Loading
Loading
Loading
+95 −0
Original line number Diff line number Diff line
@@ -775,6 +775,101 @@ impl IBluetoothGattServerCallback for BtGattServerCallback {
    fn on_service_added(&self, status: GattStatus, service: BluetoothGattService) {
        print_info!("GATT service added with status = {}, service = {:?}", status, service)
    }

    fn on_characteristic_read_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        is_long: bool,
        handle: i32,
    ) {
        print_info!(
            "GATT characteristic read request for addr = {}, trans_id = {}, offset = {}, is_long = {}, handle = {}",
            addr,
            trans_id,
            offset,
            is_long,
            handle
        );
    }

    fn on_descriptor_read_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        is_long: bool,
        handle: i32,
    ) {
        print_info!(
            "GATT descriptor read request for addr = {}, trans_id = {}, offset = {}, is_long = {}, handle = {}",
            addr,
            trans_id,
            offset,
            is_long,
            handle
        );
    }

    fn on_characteristic_write_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        len: i32,
        is_prep: bool,
        need_rsp: bool,
        handle: i32,
        value: Vec<u8>,
    ) {
        print_info!(
            "GATT characteristic write request for \
                addr = {}, trans_id = {}, offset = {}, len = {}, is_prep = {}, need_rsp = {}, handle = {}, value = {:?}",
            addr,
            trans_id,
            offset,
            len,
            is_prep,
            need_rsp,
            handle,
            value
        );
    }

    fn on_descriptor_write_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        len: i32,
        is_prep: bool,
        need_rsp: bool,
        handle: i32,
        value: Vec<u8>,
    ) {
        print_info!(
            "GATT descriptor write request for \
                addr = {}, trans_id = {}, offset = {}, len = {}, is_prep = {}, need_rsp = {}, handle = {}, value = {:?}",
            addr,
            trans_id,
            offset,
            len,
            is_prep,
            need_rsp,
            handle,
            value
        );
    }

    fn on_execute_write(&self, addr: String, trans_id: i32, exec_write: bool) {
        print_info!(
            "GATT executed write for addr = {}, trans_id = {}, exec_write = {}",
            addr,
            trans_id,
            exec_write
        );
    }
}

impl RPCProxy for BtGattServerCallback {
+66 −0
Original line number Diff line number Diff line
@@ -1342,6 +1342,19 @@ impl IBluetoothGatt for BluetoothGattDBus {
    fn clear_services(&self, server_id: i32) {
        dbus_generated!()
    }

    #[dbus_method("SendResponse")]
    fn send_response(
        &self,
        server_id: i32,
        addr: String,
        request_id: i32,
        status: GattStatus,
        offset: i32,
        value: Vec<u8>,
    ) -> bool {
        dbus_generated!()
    }
}

struct IBluetoothGattCallbackDBus {}
@@ -1440,6 +1453,59 @@ impl IBluetoothGattServerCallback for IBluetoothGattCallbackDBus {

    #[dbus_method("OnServiceAdded")]
    fn on_service_added(&self, status: GattStatus, service: BluetoothGattService) {}

    #[dbus_method("OnCharacteristicReadRequest")]
    fn on_characteristic_read_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        is_long: bool,
        handle: i32,
    ) {
    }

    #[dbus_method("OnDescriptorReadRequest")]
    fn on_descriptor_read_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        is_long: bool,
        handle: i32,
    ) {
    }

    #[dbus_method("OnCharacteristicWriteRequest")]
    fn on_characteristic_write_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        len: i32,
        is_prep: bool,
        need_rsp: bool,
        handle: i32,
        value: Vec<u8>,
    ) {
    }

    #[dbus_method("OnDescriptorWriteRequest")]
    fn on_descriptor_write_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        len: i32,
        is_prep: bool,
        need_rsp: bool,
        handle: i32,
        value: Vec<u8>,
    ) {
    }

    #[dbus_method("OnExecuteWrite")]
    fn on_execute_write(&self, addr: String, trans_id: i32, exec_write: bool) {}
}

#[dbus_propmap(BluetoothServerSocket)]
+72 −0
Original line number Diff line number Diff line
@@ -155,6 +155,65 @@ impl IBluetoothGattServerCallback for BluetoothGattServerCallbackDBus {
    fn on_service_added(&self, status: GattStatus, service: BluetoothGattService) {
        dbus_generated!()
    }

    #[dbus_method("OnCharacteristicReadRequest")]
    fn on_characteristic_read_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        is_long: bool,
        handle: i32,
    ) {
        dbus_generated!()
    }

    #[dbus_method("OnDescriptorReadRequest")]
    fn on_descriptor_read_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        is_long: bool,
        handle: i32,
    ) {
        dbus_generated!()
    }

    #[dbus_method("OnCharacteristicWriteRequest")]
    fn on_characteristic_write_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        len: i32,
        is_prep: bool,
        need_rsp: bool,
        handle: i32,
        value: Vec<u8>,
    ) {
        dbus_generated!()
    }

    #[dbus_method("OnDescriptorWriteRequest")]
    fn on_descriptor_write_request(
        &self,
        addr: String,
        trans_id: i32,
        offset: i32,
        len: i32,
        is_prep: bool,
        need_rsp: bool,
        handle: i32,
        value: Vec<u8>,
    ) {
        dbus_generated!()
    }

    #[dbus_method("OnExecuteWrite")]
    fn on_execute_write(&self, addr: String, trans_id: i32, exec_write: bool) {
        dbus_generated!()
    }
}

// Represents Uuid128Bit as an array in D-Bus.
@@ -821,4 +880,17 @@ impl IBluetoothGatt for IBluetoothGattDBus {
    fn clear_services(&self, server_id: i32) {
        dbus_generated!()
    }

    #[dbus_method("SendResponse")]
    fn send_response(
        &self,
        server_id: i32,
        addr: String,
        request_id: i32,
        status: GattStatus,
        offset: i32,
        value: Vec<u8>,
    ) -> bool {
        dbus_generated!()
    }
}
+311 −5
Original line number Diff line number Diff line
@@ -6,11 +6,11 @@ use bt_topshim::bindings::root::bluetooth::Uuid;
use bt_topshim::btif::{BluetoothInterface, BtStatus, BtTransport, RawAddress, Uuid128Bit};
use bt_topshim::profiles::gatt::{
    ffi::RustAdvertisingTrackInfo, AdvertisingStatus, BtGattDbElement, BtGattNotifyParams,
    BtGattReadParams, Gatt, GattAdvCallbacks, GattAdvCallbacksDispatcher,
    GattAdvInbandCallbacksDispatcher, GattClientCallbacks, GattClientCallbacksDispatcher,
    GattScannerCallbacks, GattScannerCallbacksDispatcher, GattScannerInbandCallbacks,
    GattScannerInbandCallbacksDispatcher, GattServerCallbacks, GattServerCallbacksDispatcher,
    GattStatus, LePhy, MsftAdvMonitor, MsftAdvMonitorPattern,
    BtGattReadParams, BtGattResponse, BtGattValue, Gatt, GattAdvCallbacks,
    GattAdvCallbacksDispatcher, GattAdvInbandCallbacksDispatcher, GattClientCallbacks,
    GattClientCallbacksDispatcher, GattScannerCallbacks, GattScannerCallbacksDispatcher,
    GattScannerInbandCallbacks, GattScannerInbandCallbacksDispatcher, GattServerCallbacks,
    GattServerCallbacksDispatcher, GattStatus, LePhy, MsftAdvMonitor, MsftAdvMonitorPattern,
};
use bt_topshim::topstack;
use bt_utils::adv_parser;
@@ -196,12 +196,18 @@ struct Server {
    services: Vec<BluetoothGattService>,
}

struct Request {
    id: i32,
    handle: i32,
}

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>,
    connections: Vec<Connection>,
    requests: Vec<Request>,
}

type GattServerCallback = Box<dyn IBluetoothGattServerCallback + Send>;
@@ -212,6 +218,7 @@ impl ServerContextMap {
            callbacks: Callbacks::new(tx, Message::GattServerCallbackDisconnected),
            servers: vec![],
            connections: vec![],
            requests: vec![],
        }
    }

@@ -231,6 +238,13 @@ impl ServerContextMap {
        self.servers.iter().find(|server| server.cbid == callback_id)
    }

    fn get_by_conn_id(&self, conn_id: i32) -> Option<&Server> {
        self.connections
            .iter()
            .find(|conn| conn.conn_id == conn_id)
            .and_then(|conn| self.get_by_server_id(conn.server_id))
    }

    fn add(&mut self, uuid: &Uuid128Bit, callback: GattServerCallback) {
        if self.get_by_uuid(uuid).is_some() {
            return;
@@ -303,6 +317,18 @@ impl ServerContextMap {
        self.get_mut_by_server_id(server_id)
            .map(|s: &mut Server| s.services.retain(|service| service.instance_id != handle));
    }

    fn add_request(&mut self, request_id: i32, handle: i32) {
        self.requests.push(Request { id: request_id, handle: handle });
    }

    fn delete_request(&mut self, request_id: i32) {
        self.requests.retain(|request| request.id != request_id);
    }

    fn get_request_handle_from_id(&self, request_id: i32) -> Option<i32> {
        self.requests.iter().find_map(|request| (request.id == request_id).then(|| request.handle))
    }
}

/// Defines the GATT API.
@@ -587,6 +613,17 @@ pub trait IBluetoothGatt {

    /// Clears all services from the GATT server.
    fn clear_services(&self, server_id: i32);

    /// Sends a response to a read/write operation.
    fn send_response(
        &self,
        server_id: i32,
        addr: String,
        request_id: i32,
        status: GattStatus,
        offset: i32,
        value: Vec<u8>,
    ) -> bool;
}

#[derive(Debug, Default, Clone)]
@@ -884,6 +921,55 @@ pub trait IBluetoothGattServerCallback: RPCProxy {

    /// When there is a service added to the GATT server.
    fn on_service_added(&self, _status: GattStatus, _service: BluetoothGattService);

    /// When a remote device has requested to read a characteristic.
    fn on_characteristic_read_request(
        &self,
        _addr: String,
        _trans_id: i32,
        _offset: i32,
        _is_long: bool,
        _handle: i32,
    );

    /// When a remote device has requested to read a descriptor.
    fn on_descriptor_read_request(
        &self,
        _addr: String,
        _trans_id: i32,
        _offset: i32,
        _is_long: bool,
        _handle: i32,
    );

    /// When a remote device has requested to write to a characteristic.
    fn on_characteristic_write_request(
        &self,
        _addr: String,
        _trans_id: i32,
        _offset: i32,
        _len: i32,
        _is_prep: bool,
        _need_rsp: bool,
        _handle: i32,
        _value: Vec<u8>,
    );

    /// When a remote device has requested to write to a descriptor.
    fn on_descriptor_write_request(
        &self,
        _addr: String,
        _trans_id: i32,
        _offset: i32,
        _len: i32,
        _is_prep: bool,
        _need_rsp: bool,
        _handle: i32,
        _value: Vec<u8>,
    );

    /// When a previously prepared write is to be executed.
    fn on_execute_write(&self, _addr: String, _trans_id: i32, _exec_write: bool);
}

/// Interface for scanner callbacks to clients, passed to
@@ -2272,6 +2358,41 @@ impl IBluetoothGatt for BluetoothGatt {
            }
        }
    }

    fn send_response(
        &self,
        server_id: i32,
        addr: String,
        request_id: i32,
        status: GattStatus,
        offset: i32,
        value: Vec<u8>,
    ) -> bool {
        (|| {
            let conn_id = self.server_context_map.get_conn_id_from_address(server_id, &addr)?;
            let handle = self.server_context_map.get_request_handle_from_id(request_id)?;
            let len = value.len() as u16;
            let data: [u8; 600] = value.try_into().ok()?;

            self.gatt.as_ref().unwrap().lock().unwrap().server.send_response(
                conn_id,
                request_id,
                status as i32,
                &BtGattResponse {
                    attr_value: BtGattValue {
                        value: data,
                        handle: handle as u16,
                        offset: offset as u16,
                        len: len,
                        auth_req: 0 as u8,
                    },
                },
            );

            Some(())
        })()
        .is_some()
    }
}

#[btif_callbacks_dispatcher(dispatch_gatt_client_callbacks, GattClientCallbacks)]
@@ -2832,6 +2953,65 @@ pub(crate) trait BtifGattServerCallbacks {

    #[btif_callback(ServiceDeleted)]
    fn service_deleted_cb(&mut self, status: GattStatus, server_id: i32, handle: i32);

    #[btif_callback(RequestReadCharacteristic)]
    fn request_read_characteristic_cb(
        &mut self,
        conn_id: i32,
        trans_id: i32,
        addr: RawAddress,
        handle: i32,
        offset: i32,
        is_long: bool,
    );

    #[btif_callback(RequestReadDescriptor)]
    fn request_read_descriptor_cb(
        &mut self,
        conn_id: i32,
        trans_id: i32,
        addr: RawAddress,
        handle: i32,
        offset: i32,
        is_long: bool,
    );

    #[btif_callback(RequestWriteCharacteristic)]
    fn request_write_characteristic_cb(
        &mut self,
        conn_id: i32,
        trans_id: i32,
        addr: RawAddress,
        handle: i32,
        offset: i32,
        need_rsp: bool,
        is_prep: bool,
        data: Vec<u8>,
        len: usize,
    );

    #[btif_callback(RequestWriteDescriptor)]
    fn request_write_descriptor_cb(
        &mut self,
        conn_id: i32,
        trans_id: i32,
        addr: RawAddress,
        handle: i32,
        offset: i32,
        need_rsp: bool,
        is_prep: bool,
        data: Vec<u8>,
        len: usize,
    );

    #[btif_callback(RequestExecWrite)]
    fn request_exec_write_cb(
        &mut self,
        conn_id: i32,
        trans_id: i32,
        addr: RawAddress,
        exec_write: i32,
    );
}

impl BtifGattServerCallbacks for BluetoothGatt {
@@ -2904,6 +3084,132 @@ impl BtifGattServerCallbacks for BluetoothGatt {
            self.server_context_map.delete_service(server_id, handle);
        }
    }

    fn request_read_characteristic_cb(
        &mut self,
        conn_id: i32,
        trans_id: i32,
        addr: RawAddress,
        handle: i32,
        offset: i32,
        is_long: bool,
    ) {
        self.server_context_map.add_request(trans_id, handle);

        if let Some(cbid) =
            self.server_context_map.get_by_conn_id(conn_id).map(|server| server.cbid)
        {
            if let Some(cb) = self.server_context_map.get_callback_from_callback_id(cbid) {
                cb.on_characteristic_read_request(
                    addr.to_string(),
                    trans_id,
                    offset,
                    is_long,
                    handle,
                );
            }
        }
    }

    fn request_read_descriptor_cb(
        &mut self,
        conn_id: i32,
        trans_id: i32,
        addr: RawAddress,
        handle: i32,
        offset: i32,
        is_long: bool,
    ) {
        self.server_context_map.add_request(trans_id, handle);

        if let Some(cbid) =
            self.server_context_map.get_by_conn_id(conn_id).map(|server| server.cbid)
        {
            if let Some(cb) = self.server_context_map.get_callback_from_callback_id(cbid) {
                cb.on_descriptor_read_request(addr.to_string(), trans_id, offset, is_long, handle);
            }
        }
    }

    fn request_write_characteristic_cb(
        &mut self,
        conn_id: i32,
        trans_id: i32,
        addr: RawAddress,
        handle: i32,
        offset: i32,
        need_rsp: bool,
        is_prep: bool,
        data: Vec<u8>,
        len: usize,
    ) {
        self.server_context_map.add_request(trans_id, handle);

        if let Some(cbid) =
            self.server_context_map.get_by_conn_id(conn_id).map(|server| server.cbid)
        {
            if let Some(cb) = self.server_context_map.get_callback_from_callback_id(cbid) {
                cb.on_characteristic_write_request(
                    addr.to_string(),
                    trans_id,
                    offset,
                    len as i32,
                    is_prep,
                    need_rsp,
                    handle,
                    data,
                );
            }
        }
    }

    fn request_write_descriptor_cb(
        &mut self,
        conn_id: i32,
        trans_id: i32,
        addr: RawAddress,
        handle: i32,
        offset: i32,
        need_rsp: bool,
        is_prep: bool,
        data: Vec<u8>,
        len: usize,
    ) {
        self.server_context_map.add_request(trans_id, handle);

        if let Some(cbid) =
            self.server_context_map.get_by_conn_id(conn_id).map(|server| server.cbid)
        {
            if let Some(cb) = self.server_context_map.get_callback_from_callback_id(cbid) {
                cb.on_descriptor_write_request(
                    addr.to_string(),
                    trans_id,
                    offset,
                    len as i32,
                    is_prep,
                    need_rsp,
                    handle,
                    data,
                );
            }
        }
    }

    fn request_exec_write_cb(
        &mut self,
        conn_id: i32,
        trans_id: i32,
        addr: RawAddress,
        exec_write: i32,
    ) {
        if let Some(cbid) =
            self.server_context_map.get_by_conn_id(conn_id).map(|server| server.cbid)
        {
            if let Some(cb) = self.server_context_map.get_callback_from_callback_id(cbid) {
                cb.on_execute_write(addr.to_string(), trans_id, exec_write != 0);
            }
        }
    }
}

#[btif_callbacks_dispatcher(dispatch_le_scanner_callbacks, GattScannerCallbacks)]
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ pub type BtGattNotifyParams = bindings::btgatt_notify_params_t;
pub type BtGattReadParams = bindings::btgatt_read_params_t;
pub type BtGattDbElement = bindings::btgatt_db_element_t;
pub type BtGattResponse = bindings::btgatt_response_t;
pub type BtGattValue = bindings::btgatt_value_t;
pub type BtGattTestParams = bindings::btgatt_test_params_t;

#[cxx::bridge(namespace = bluetooth::topshim::rust)]