Loading system/gd/rust/linux/service/src/main.rs +4 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ use btstack::{ bluetooth_gatt::BluetoothGatt, bluetooth_logging::BluetoothLogging, bluetooth_media::BluetoothMedia, dis::DeviceInformation, socket_manager::BluetoothSocketManager, suspend::Suspend, Message, Stack, Loading Loading @@ -177,6 +178,8 @@ fn main() -> Result<(), Box<dyn Error>> { )))); let bt_sock_mgr = Arc::new(Mutex::new(Box::new(BluetoothSocketManager::new(tx.clone())))); let qa = Arc::new(Mutex::new(Box::new(BluetoothQA::new(tx.clone())))); let dis = Arc::new(Mutex::new(Box::new(DeviceInformation::new(bluetooth_gatt.clone(), tx.clone())))); topstack::get_runtime().block_on(async { // Connect to D-Bus system bus. Loading Loading @@ -219,6 +222,7 @@ fn main() -> Result<(), Box<dyn Error>> { suspend.clone(), bt_sock_mgr.clone(), bluetooth_admin.clone(), dis.clone(), )); // Set up the disconnect watcher to monitor client disconnects. Loading system/gd/rust/linux/stack/src/bluetooth.rs +6 −0 Original line number Diff line number Diff line Loading @@ -1135,6 +1135,12 @@ impl BtifBluetoothCallbacks for Bluetooth { Err(err) => warn!("create_pid_file() error: {}", err), _ => (), } // Inform the rest of the stack we're ready. let txl = self.tx.clone(); tokio::spawn(async move { let _ = txl.send(Message::AdapterReady).await; }); } } } Loading system/gd/rust/linux/stack/src/bluetooth_gatt.rs +40 −15 Original line number Diff line number Diff line Loading @@ -687,7 +687,11 @@ pub struct BluetoothGattDescriptor { } impl BluetoothGattDescriptor { fn new(uuid: Uuid128Bit, instance_id: i32, permissions: i32) -> BluetoothGattDescriptor { pub(crate) fn new( uuid: Uuid128Bit, instance_id: i32, permissions: i32, ) -> BluetoothGattDescriptor { BluetoothGattDescriptor { uuid, instance_id, permissions } } } Loading @@ -705,16 +709,27 @@ pub struct BluetoothGattCharacteristic { } impl BluetoothGattCharacteristic { pub const PROPERTY_BROADCAST: i32 = 0x01; pub const PROPERTY_READ: i32 = 0x02; pub const PROPERTY_WRITE_NO_RESPONSE: i32 = 0x04; pub const PROPERTY_WRITE: i32 = 0x08; pub const PROPERTY_NOTIFY: i32 = 0x10; pub const PROPERTY_INDICATE: i32 = 0x20; pub const PROPERTY_SIGNED_WRITE: i32 = 0x40; pub const PROPERTY_EXTENDED_PROPS: i32 = 0x80; fn new( // Properties are u8 but i32 in these apis. pub const PROPERTY_BROADCAST: i32 = 1 << 0; pub const PROPERTY_READ: i32 = 1 << 1; pub const PROPERTY_WRITE_NO_RESPONSE: i32 = 1 << 2; pub const PROPERTY_WRITE: i32 = 1 << 3; pub const PROPERTY_NOTIFY: i32 = 1 << 4; pub const PROPERTY_INDICATE: i32 = 1 << 5; pub const PROPERTY_SIGNED_WRITE: i32 = 1 << 6; pub const PROPERTY_EXTENDED_PROPS: i32 = 1 << 7; // Permissions are u16 but i32 in these apis. pub const PERMISSION_READ: i32 = 1 << 0; pub const PERMISSION_READ_ENCRYPTED: i32 = 1 << 1; pub const PERMISSION_READ_ENCRYPED_MITM: i32 = 1 << 2; pub const PERMISSION_WRITE: i32 = 1 << 4; pub const PERMISSION_WRITE_ENCRYPTED: i32 = 1 << 5; pub const PERMISSION_WRITE_ENCRYPTED_MITM: i32 = 1 << 6; pub const PERMISSION_WRITE_SIGNED: i32 = 1 << 7; pub const PERMISSION_WRITE_SIGNED_MITM: i32 = 1 << 8; pub(crate) fn new( uuid: Uuid128Bit, instance_id: i32, properties: i32, Loading Loading @@ -748,7 +763,11 @@ pub struct BluetoothGattService { } impl BluetoothGattService { fn new(uuid: Uuid128Bit, instance_id: i32, service_type: i32) -> BluetoothGattService { pub(crate) fn new( uuid: Uuid128Bit, instance_id: i32, service_type: i32, ) -> BluetoothGattService { BluetoothGattService { uuid, instance_id, Loading Loading @@ -1095,7 +1114,7 @@ pub trait IScannerCallback: RPCProxy { #[derive(Debug, FromPrimitive, ToPrimitive)] #[repr(u8)] /// GATT write type. enum GattDbElementType { pub(crate) enum GattDbElementType { PrimaryService = 0, SecondaryService = 1, IncludedService = 2, Loading @@ -1103,6 +1122,12 @@ enum GattDbElementType { Descriptor = 4, } impl Into<i32> for GattDbElementType { fn into(self) -> i32 { self.to_u8().unwrap_or(0).into() } } #[derive(Debug, FromPrimitive, ToPrimitive, Copy, Clone)] #[repr(u8)] /// GATT write type. Loading Loading @@ -1728,10 +1753,10 @@ impl BluetoothGatt { /// Start an active scan on given scanner id. This will look up and assign /// the correct ScanSettings for it as well. pub(crate) fn start_active_scan(&mut self, scanner_id: u8) -> BtStatus { let interval: u16 = sysprop::get_i32(sysprop::Property::LeInquiryScanInterval) let interval: u16 = sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanInterval) .try_into() .expect("Bad value configured for LeInquiryScanInterval"); let window: u16 = sysprop::get_i32(sysprop::Property::LeInquiryScanWindow) let window: u16 = sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanWindow) .try_into() .expect("Bad value configured for LeInquiryScanWindow"); Loading system/gd/rust/linux/stack/src/dis.rs 0 → 100644 +268 −0 Original line number Diff line number Diff line //! TODO(b/277818879) - Temporary DIS implementation use log; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc::Sender; use crate::bluetooth_gatt::{ BluetoothGatt, BluetoothGattCharacteristic, BluetoothGattService, GattDbElementType, IBluetoothGatt, IBluetoothGattServerCallback, }; use crate::uuid::{Profile, UuidHelper}; use crate::{Message, RPCProxy}; use bt_topshim::profiles::gatt::{GattStatus, LePhy}; use bt_topshim::sysprop; /// Random uuid generated for registering against gatt server. const DIS_APP_RANDOM_UUID: &str = "1b518948-fd77-4459-906f-4923104bb639"; /// UUID for PNP ID characteristic. const PNP_ID_CHAR_UUID: &str = "00002A50-0000-1000-8000-00805F9B34FB"; /// Handles exporting the Device Information Service (DIS). pub struct DeviceInformation { /// Reference to Gatt server implementation to export service. bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>, /// Server id (available once we are registered). gatt_server_id: Option<i32>, /// Handle for the PNP ID characteristic. pnp_id_handle: Option<i32>, /// Sender for stack mainloop. tx: Sender<Message>, } impl DeviceInformation { pub fn new(bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>, tx: Sender<Message>) -> Self { Self { bluetooth_gatt, gatt_server_id: None, pnp_id_handle: None, tx } } pub(crate) fn initialize(&mut self) { let callback = Box::new(DeviceInformationServerCallbacks::new(self.tx.clone())); // First register for callbacks with the server. self.bluetooth_gatt.lock().unwrap().register_server( DIS_APP_RANDOM_UUID.to_string(), callback, /*eatt_support=*/ true, ); } pub(crate) fn handle_callbacks(&mut self, callback: &ServiceCallbacks) { match callback { ServiceCallbacks::Registered(status, server_id) => { if status != &GattStatus::Success { log::error!("DIS failed to register callbacks. Status={:?}", status); return; } self.gatt_server_id = Some(*server_id); // Construct and add Device Information service. let mut service = BluetoothGattService::new( UuidHelper::get_profile_uuid(&Profile::Dis) .expect("DIS uuid mapping missing") .clone(), /*instance_id=*/ 0, GattDbElementType::PrimaryService.into(), ); service.characteristics.push(BluetoothGattCharacteristic::new( UuidHelper::from_string(PNP_ID_CHAR_UUID).expect("PNP ID uuid is malformed"), /*instance_id=*/ 0, BluetoothGattCharacteristic::PROPERTY_READ, BluetoothGattCharacteristic::PERMISSION_READ, )); self.bluetooth_gatt.lock().unwrap().add_service(*server_id, service); } ServiceCallbacks::ServiceAdded(status, service) => { if status != &GattStatus::Success { return; } let pnp_uuid = UuidHelper::from_string(PNP_ID_CHAR_UUID).expect("PNP ID uuid is malformed"); // Find the PNP ID characteristic we inserted before and store // the handle for it. for characteristic in &service.characteristics { if characteristic.uuid == pnp_uuid { self.pnp_id_handle = Some(characteristic.instance_id); } } } ServiceCallbacks::OnCharacteristicReadRequest( addr, trans_id, offset, _is_long, handle, ) => match (self.gatt_server_id, self.pnp_id_handle) { (Some(server_id), Some(pnp_handle)) => { if &pnp_handle == handle { let vendor_id = sysprop::get_i32(sysprop::PropertyI32::VendorId); let vendor_id_source = sysprop::get_i32(sysprop::PropertyI32::VendorIdSource); let product_id = sysprop::get_i32(sysprop::PropertyI32::ProductId); let product_version = sysprop::get_i32(sysprop::PropertyI32::ProductVersion); // PNP ID ordering (all values are in little endian): // - Vendor ID source (1 octet) // - Vendor ID (2 octet) // - Product ID (2 octet) // - Product Version (2 octet) let mut value: Vec<u8> = Vec::new(); value.push(vendor_id_source.to_le_bytes()[0]); value.extend_from_slice(&vendor_id.to_le_bytes()[0..2]); value.extend_from_slice(&product_id.to_le_bytes()[0..2]); value.extend_from_slice(&product_version.to_le_bytes()[0..2]); self.bluetooth_gatt.lock().unwrap().send_response( server_id, addr.clone(), *trans_id, GattStatus::Success, *offset, value, ); } } (_, _) => (), }, } } } // Callbacks we need to handle for DIS. pub enum ServiceCallbacks { Registered(GattStatus, i32), ServiceAdded(GattStatus, BluetoothGattService), OnCharacteristicReadRequest(String, i32, i32, bool, i32), } // Handle callbacks for DIS to register struct DeviceInformationServerCallbacks { // Sender to the main loop tx: Sender<Message>, } impl DeviceInformationServerCallbacks { fn new(tx: Sender<Message>) -> Self { Self { tx } } } impl IBluetoothGattServerCallback for DeviceInformationServerCallbacks { fn on_server_registered(&mut self, status: GattStatus, server_id: i32) { let txl = self.tx.clone(); tokio::spawn(async move { let _ = txl.send(Message::Dis(ServiceCallbacks::Registered(status, server_id))).await; }); } fn on_service_added(&mut self, status: GattStatus, service: BluetoothGattService) { let txl = self.tx.clone(); tokio::spawn(async move { let _ = txl.send(Message::Dis(ServiceCallbacks::ServiceAdded(status, service))).await; }); } fn on_characteristic_read_request( &mut self, addr: String, trans_id: i32, offset: i32, is_long: bool, handle: i32, ) { let txl = self.tx.clone(); tokio::spawn(async move { let _ = txl .send(Message::Dis(ServiceCallbacks::OnCharacteristicReadRequest( addr, trans_id, offset, is_long, handle, ))) .await; }); } // Remaining callbacks are unhandled fn on_service_removed(&mut self, _status: GattStatus, _handle: i32) {} fn on_server_connection_state(&mut self, _server_id: i32, _connected: bool, _addr: String) {} fn on_descriptor_read_request( &mut self, _addr: String, _trans_id: i32, _offset: i32, _is_long: bool, _handle: i32, ) { } fn on_characteristic_write_request( &mut self, _addr: String, _trans_id: i32, _offset: i32, _len: i32, _is_prep: bool, _need_rsp: bool, _handle: i32, _value: Vec<u8>, ) { } fn on_descriptor_write_request( &mut self, _addr: String, _trans_id: i32, _offset: i32, _len: i32, _is_prep: bool, _need_rsp: bool, _handle: i32, _value: Vec<u8>, ) { } fn on_execute_write(&mut self, _addr: String, _trans_id: i32, _exec_write: bool) {} fn on_notification_sent(&mut self, _addr: String, _status: GattStatus) {} fn on_mtu_changed(&mut self, _addr: String, _mtu: i32) {} fn on_phy_update( &mut self, _addr: String, _tx_phy: LePhy, _rx_phy: LePhy, _status: GattStatus, ) { } fn on_phy_read(&mut self, _addr: String, _tx_phy: LePhy, _rx_phy: LePhy, _status: GattStatus) {} fn on_connection_updated( &mut self, _addr: String, _interval: i32, _latency: i32, _timeout: i32, _status: GattStatus, ) { } fn on_subrate_change( &mut self, _addr: String, _subrate_factor: i32, _latency: i32, _cont_num: i32, _timeout: i32, _status: GattStatus, ) { } } impl RPCProxy for DeviceInformationServerCallbacks { fn get_object_id(&self) -> String { "DIS Gatt Server Callback".to_string() } } system/gd/rust/linux/stack/src/lib.rs +20 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ pub mod bluetooth_logging; pub mod bluetooth_media; pub mod bluetooth_qa; pub mod callbacks; pub mod dis; pub mod socket_manager; pub mod suspend; pub mod uuid; Loading @@ -38,6 +39,7 @@ use crate::bluetooth_gatt::{ dispatch_le_scanner_callbacks, dispatch_le_scanner_inband_callbacks, BluetoothGatt, }; use crate::bluetooth_media::{BluetoothMedia, MediaActions}; use crate::dis::{DeviceInformation, ServiceCallbacks}; use crate::socket_manager::{BluetoothSocketManager, SocketActions}; use crate::suspend::Suspend; use bt_topshim::{ Loading @@ -55,6 +57,9 @@ pub enum Message { // Shuts down the stack. Shutdown, // Adapter is enabled and ready. AdapterReady, // Callbacks from libbluetooth A2dp(A2dpCallbacks), Avrcp(AvrcpCallbacks), Loading Loading @@ -115,6 +120,9 @@ pub enum Message { // Admin policy related AdminCallbackDisconnected(u32), HidHostEnable, // Dis callbacks Dis(ServiceCallbacks), } /// Represents suspend mode of a module. Loading Loading @@ -150,6 +158,7 @@ impl Stack { suspend: Arc<Mutex<Box<Suspend>>>, bluetooth_socketmgr: Arc<Mutex<Box<BluetoothSocketManager>>>, bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>, bluetooth_dis: Arc<Mutex<Box<DeviceInformation>>>, ) { loop { let m = rx.recv().await; Loading @@ -164,6 +173,14 @@ impl Stack { bluetooth.lock().unwrap().disable(); } Message::AdapterReady => { // Initialize objects that need the adapter to be fully // enabled before running. // Register device information service. bluetooth_dis.lock().unwrap().initialize(); } Message::A2dp(a) => { bluetooth_media.lock().unwrap().dispatch_a2dp_callbacks(a); } Loading Loading @@ -322,6 +339,9 @@ impl Stack { Message::HidHostEnable => { bluetooth.lock().unwrap().enable_hidhost(); } Message::Dis(callback) => { bluetooth_dis.lock().unwrap().handle_callbacks(&callback); } } } } Loading Loading
system/gd/rust/linux/service/src/main.rs +4 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ use btstack::{ bluetooth_gatt::BluetoothGatt, bluetooth_logging::BluetoothLogging, bluetooth_media::BluetoothMedia, dis::DeviceInformation, socket_manager::BluetoothSocketManager, suspend::Suspend, Message, Stack, Loading Loading @@ -177,6 +178,8 @@ fn main() -> Result<(), Box<dyn Error>> { )))); let bt_sock_mgr = Arc::new(Mutex::new(Box::new(BluetoothSocketManager::new(tx.clone())))); let qa = Arc::new(Mutex::new(Box::new(BluetoothQA::new(tx.clone())))); let dis = Arc::new(Mutex::new(Box::new(DeviceInformation::new(bluetooth_gatt.clone(), tx.clone())))); topstack::get_runtime().block_on(async { // Connect to D-Bus system bus. Loading Loading @@ -219,6 +222,7 @@ fn main() -> Result<(), Box<dyn Error>> { suspend.clone(), bt_sock_mgr.clone(), bluetooth_admin.clone(), dis.clone(), )); // Set up the disconnect watcher to monitor client disconnects. Loading
system/gd/rust/linux/stack/src/bluetooth.rs +6 −0 Original line number Diff line number Diff line Loading @@ -1135,6 +1135,12 @@ impl BtifBluetoothCallbacks for Bluetooth { Err(err) => warn!("create_pid_file() error: {}", err), _ => (), } // Inform the rest of the stack we're ready. let txl = self.tx.clone(); tokio::spawn(async move { let _ = txl.send(Message::AdapterReady).await; }); } } } Loading
system/gd/rust/linux/stack/src/bluetooth_gatt.rs +40 −15 Original line number Diff line number Diff line Loading @@ -687,7 +687,11 @@ pub struct BluetoothGattDescriptor { } impl BluetoothGattDescriptor { fn new(uuid: Uuid128Bit, instance_id: i32, permissions: i32) -> BluetoothGattDescriptor { pub(crate) fn new( uuid: Uuid128Bit, instance_id: i32, permissions: i32, ) -> BluetoothGattDescriptor { BluetoothGattDescriptor { uuid, instance_id, permissions } } } Loading @@ -705,16 +709,27 @@ pub struct BluetoothGattCharacteristic { } impl BluetoothGattCharacteristic { pub const PROPERTY_BROADCAST: i32 = 0x01; pub const PROPERTY_READ: i32 = 0x02; pub const PROPERTY_WRITE_NO_RESPONSE: i32 = 0x04; pub const PROPERTY_WRITE: i32 = 0x08; pub const PROPERTY_NOTIFY: i32 = 0x10; pub const PROPERTY_INDICATE: i32 = 0x20; pub const PROPERTY_SIGNED_WRITE: i32 = 0x40; pub const PROPERTY_EXTENDED_PROPS: i32 = 0x80; fn new( // Properties are u8 but i32 in these apis. pub const PROPERTY_BROADCAST: i32 = 1 << 0; pub const PROPERTY_READ: i32 = 1 << 1; pub const PROPERTY_WRITE_NO_RESPONSE: i32 = 1 << 2; pub const PROPERTY_WRITE: i32 = 1 << 3; pub const PROPERTY_NOTIFY: i32 = 1 << 4; pub const PROPERTY_INDICATE: i32 = 1 << 5; pub const PROPERTY_SIGNED_WRITE: i32 = 1 << 6; pub const PROPERTY_EXTENDED_PROPS: i32 = 1 << 7; // Permissions are u16 but i32 in these apis. pub const PERMISSION_READ: i32 = 1 << 0; pub const PERMISSION_READ_ENCRYPTED: i32 = 1 << 1; pub const PERMISSION_READ_ENCRYPED_MITM: i32 = 1 << 2; pub const PERMISSION_WRITE: i32 = 1 << 4; pub const PERMISSION_WRITE_ENCRYPTED: i32 = 1 << 5; pub const PERMISSION_WRITE_ENCRYPTED_MITM: i32 = 1 << 6; pub const PERMISSION_WRITE_SIGNED: i32 = 1 << 7; pub const PERMISSION_WRITE_SIGNED_MITM: i32 = 1 << 8; pub(crate) fn new( uuid: Uuid128Bit, instance_id: i32, properties: i32, Loading Loading @@ -748,7 +763,11 @@ pub struct BluetoothGattService { } impl BluetoothGattService { fn new(uuid: Uuid128Bit, instance_id: i32, service_type: i32) -> BluetoothGattService { pub(crate) fn new( uuid: Uuid128Bit, instance_id: i32, service_type: i32, ) -> BluetoothGattService { BluetoothGattService { uuid, instance_id, Loading Loading @@ -1095,7 +1114,7 @@ pub trait IScannerCallback: RPCProxy { #[derive(Debug, FromPrimitive, ToPrimitive)] #[repr(u8)] /// GATT write type. enum GattDbElementType { pub(crate) enum GattDbElementType { PrimaryService = 0, SecondaryService = 1, IncludedService = 2, Loading @@ -1103,6 +1122,12 @@ enum GattDbElementType { Descriptor = 4, } impl Into<i32> for GattDbElementType { fn into(self) -> i32 { self.to_u8().unwrap_or(0).into() } } #[derive(Debug, FromPrimitive, ToPrimitive, Copy, Clone)] #[repr(u8)] /// GATT write type. Loading Loading @@ -1728,10 +1753,10 @@ impl BluetoothGatt { /// Start an active scan on given scanner id. This will look up and assign /// the correct ScanSettings for it as well. pub(crate) fn start_active_scan(&mut self, scanner_id: u8) -> BtStatus { let interval: u16 = sysprop::get_i32(sysprop::Property::LeInquiryScanInterval) let interval: u16 = sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanInterval) .try_into() .expect("Bad value configured for LeInquiryScanInterval"); let window: u16 = sysprop::get_i32(sysprop::Property::LeInquiryScanWindow) let window: u16 = sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanWindow) .try_into() .expect("Bad value configured for LeInquiryScanWindow"); Loading
system/gd/rust/linux/stack/src/dis.rs 0 → 100644 +268 −0 Original line number Diff line number Diff line //! TODO(b/277818879) - Temporary DIS implementation use log; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc::Sender; use crate::bluetooth_gatt::{ BluetoothGatt, BluetoothGattCharacteristic, BluetoothGattService, GattDbElementType, IBluetoothGatt, IBluetoothGattServerCallback, }; use crate::uuid::{Profile, UuidHelper}; use crate::{Message, RPCProxy}; use bt_topshim::profiles::gatt::{GattStatus, LePhy}; use bt_topshim::sysprop; /// Random uuid generated for registering against gatt server. const DIS_APP_RANDOM_UUID: &str = "1b518948-fd77-4459-906f-4923104bb639"; /// UUID for PNP ID characteristic. const PNP_ID_CHAR_UUID: &str = "00002A50-0000-1000-8000-00805F9B34FB"; /// Handles exporting the Device Information Service (DIS). pub struct DeviceInformation { /// Reference to Gatt server implementation to export service. bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>, /// Server id (available once we are registered). gatt_server_id: Option<i32>, /// Handle for the PNP ID characteristic. pnp_id_handle: Option<i32>, /// Sender for stack mainloop. tx: Sender<Message>, } impl DeviceInformation { pub fn new(bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>, tx: Sender<Message>) -> Self { Self { bluetooth_gatt, gatt_server_id: None, pnp_id_handle: None, tx } } pub(crate) fn initialize(&mut self) { let callback = Box::new(DeviceInformationServerCallbacks::new(self.tx.clone())); // First register for callbacks with the server. self.bluetooth_gatt.lock().unwrap().register_server( DIS_APP_RANDOM_UUID.to_string(), callback, /*eatt_support=*/ true, ); } pub(crate) fn handle_callbacks(&mut self, callback: &ServiceCallbacks) { match callback { ServiceCallbacks::Registered(status, server_id) => { if status != &GattStatus::Success { log::error!("DIS failed to register callbacks. Status={:?}", status); return; } self.gatt_server_id = Some(*server_id); // Construct and add Device Information service. let mut service = BluetoothGattService::new( UuidHelper::get_profile_uuid(&Profile::Dis) .expect("DIS uuid mapping missing") .clone(), /*instance_id=*/ 0, GattDbElementType::PrimaryService.into(), ); service.characteristics.push(BluetoothGattCharacteristic::new( UuidHelper::from_string(PNP_ID_CHAR_UUID).expect("PNP ID uuid is malformed"), /*instance_id=*/ 0, BluetoothGattCharacteristic::PROPERTY_READ, BluetoothGattCharacteristic::PERMISSION_READ, )); self.bluetooth_gatt.lock().unwrap().add_service(*server_id, service); } ServiceCallbacks::ServiceAdded(status, service) => { if status != &GattStatus::Success { return; } let pnp_uuid = UuidHelper::from_string(PNP_ID_CHAR_UUID).expect("PNP ID uuid is malformed"); // Find the PNP ID characteristic we inserted before and store // the handle for it. for characteristic in &service.characteristics { if characteristic.uuid == pnp_uuid { self.pnp_id_handle = Some(characteristic.instance_id); } } } ServiceCallbacks::OnCharacteristicReadRequest( addr, trans_id, offset, _is_long, handle, ) => match (self.gatt_server_id, self.pnp_id_handle) { (Some(server_id), Some(pnp_handle)) => { if &pnp_handle == handle { let vendor_id = sysprop::get_i32(sysprop::PropertyI32::VendorId); let vendor_id_source = sysprop::get_i32(sysprop::PropertyI32::VendorIdSource); let product_id = sysprop::get_i32(sysprop::PropertyI32::ProductId); let product_version = sysprop::get_i32(sysprop::PropertyI32::ProductVersion); // PNP ID ordering (all values are in little endian): // - Vendor ID source (1 octet) // - Vendor ID (2 octet) // - Product ID (2 octet) // - Product Version (2 octet) let mut value: Vec<u8> = Vec::new(); value.push(vendor_id_source.to_le_bytes()[0]); value.extend_from_slice(&vendor_id.to_le_bytes()[0..2]); value.extend_from_slice(&product_id.to_le_bytes()[0..2]); value.extend_from_slice(&product_version.to_le_bytes()[0..2]); self.bluetooth_gatt.lock().unwrap().send_response( server_id, addr.clone(), *trans_id, GattStatus::Success, *offset, value, ); } } (_, _) => (), }, } } } // Callbacks we need to handle for DIS. pub enum ServiceCallbacks { Registered(GattStatus, i32), ServiceAdded(GattStatus, BluetoothGattService), OnCharacteristicReadRequest(String, i32, i32, bool, i32), } // Handle callbacks for DIS to register struct DeviceInformationServerCallbacks { // Sender to the main loop tx: Sender<Message>, } impl DeviceInformationServerCallbacks { fn new(tx: Sender<Message>) -> Self { Self { tx } } } impl IBluetoothGattServerCallback for DeviceInformationServerCallbacks { fn on_server_registered(&mut self, status: GattStatus, server_id: i32) { let txl = self.tx.clone(); tokio::spawn(async move { let _ = txl.send(Message::Dis(ServiceCallbacks::Registered(status, server_id))).await; }); } fn on_service_added(&mut self, status: GattStatus, service: BluetoothGattService) { let txl = self.tx.clone(); tokio::spawn(async move { let _ = txl.send(Message::Dis(ServiceCallbacks::ServiceAdded(status, service))).await; }); } fn on_characteristic_read_request( &mut self, addr: String, trans_id: i32, offset: i32, is_long: bool, handle: i32, ) { let txl = self.tx.clone(); tokio::spawn(async move { let _ = txl .send(Message::Dis(ServiceCallbacks::OnCharacteristicReadRequest( addr, trans_id, offset, is_long, handle, ))) .await; }); } // Remaining callbacks are unhandled fn on_service_removed(&mut self, _status: GattStatus, _handle: i32) {} fn on_server_connection_state(&mut self, _server_id: i32, _connected: bool, _addr: String) {} fn on_descriptor_read_request( &mut self, _addr: String, _trans_id: i32, _offset: i32, _is_long: bool, _handle: i32, ) { } fn on_characteristic_write_request( &mut self, _addr: String, _trans_id: i32, _offset: i32, _len: i32, _is_prep: bool, _need_rsp: bool, _handle: i32, _value: Vec<u8>, ) { } fn on_descriptor_write_request( &mut self, _addr: String, _trans_id: i32, _offset: i32, _len: i32, _is_prep: bool, _need_rsp: bool, _handle: i32, _value: Vec<u8>, ) { } fn on_execute_write(&mut self, _addr: String, _trans_id: i32, _exec_write: bool) {} fn on_notification_sent(&mut self, _addr: String, _status: GattStatus) {} fn on_mtu_changed(&mut self, _addr: String, _mtu: i32) {} fn on_phy_update( &mut self, _addr: String, _tx_phy: LePhy, _rx_phy: LePhy, _status: GattStatus, ) { } fn on_phy_read(&mut self, _addr: String, _tx_phy: LePhy, _rx_phy: LePhy, _status: GattStatus) {} fn on_connection_updated( &mut self, _addr: String, _interval: i32, _latency: i32, _timeout: i32, _status: GattStatus, ) { } fn on_subrate_change( &mut self, _addr: String, _subrate_factor: i32, _latency: i32, _cont_num: i32, _timeout: i32, _status: GattStatus, ) { } } impl RPCProxy for DeviceInformationServerCallbacks { fn get_object_id(&self) -> String { "DIS Gatt Server Callback".to_string() } }
system/gd/rust/linux/stack/src/lib.rs +20 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ pub mod bluetooth_logging; pub mod bluetooth_media; pub mod bluetooth_qa; pub mod callbacks; pub mod dis; pub mod socket_manager; pub mod suspend; pub mod uuid; Loading @@ -38,6 +39,7 @@ use crate::bluetooth_gatt::{ dispatch_le_scanner_callbacks, dispatch_le_scanner_inband_callbacks, BluetoothGatt, }; use crate::bluetooth_media::{BluetoothMedia, MediaActions}; use crate::dis::{DeviceInformation, ServiceCallbacks}; use crate::socket_manager::{BluetoothSocketManager, SocketActions}; use crate::suspend::Suspend; use bt_topshim::{ Loading @@ -55,6 +57,9 @@ pub enum Message { // Shuts down the stack. Shutdown, // Adapter is enabled and ready. AdapterReady, // Callbacks from libbluetooth A2dp(A2dpCallbacks), Avrcp(AvrcpCallbacks), Loading Loading @@ -115,6 +120,9 @@ pub enum Message { // Admin policy related AdminCallbackDisconnected(u32), HidHostEnable, // Dis callbacks Dis(ServiceCallbacks), } /// Represents suspend mode of a module. Loading Loading @@ -150,6 +158,7 @@ impl Stack { suspend: Arc<Mutex<Box<Suspend>>>, bluetooth_socketmgr: Arc<Mutex<Box<BluetoothSocketManager>>>, bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>, bluetooth_dis: Arc<Mutex<Box<DeviceInformation>>>, ) { loop { let m = rx.recv().await; Loading @@ -164,6 +173,14 @@ impl Stack { bluetooth.lock().unwrap().disable(); } Message::AdapterReady => { // Initialize objects that need the adapter to be fully // enabled before running. // Register device information service. bluetooth_dis.lock().unwrap().initialize(); } Message::A2dp(a) => { bluetooth_media.lock().unwrap().dispatch_a2dp_callbacks(a); } Loading Loading @@ -322,6 +339,9 @@ impl Stack { Message::HidHostEnable => { bluetooth.lock().unwrap().enable_hidhost(); } Message::Dis(callback) => { bluetooth_dis.lock().unwrap().handle_callbacks(&callback); } } } } Loading