• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! TODO(b/277818879) - Temporary DIS implementation
2 
3 use log;
4 use std::sync::{Arc, Mutex};
5 use tokio::sync::mpsc::Sender;
6 
7 use crate::bluetooth_gatt::{
8     BluetoothGatt, BluetoothGattCharacteristic, BluetoothGattService, GattDbElementType,
9     IBluetoothGatt, IBluetoothGattServerCallback,
10 };
11 use crate::uuid::{Profile, UuidHelper};
12 use crate::{Message, RPCProxy};
13 use bt_topshim::profiles::gatt::{GattStatus, LePhy};
14 use bt_topshim::sysprop;
15 
16 /// Random uuid generated for registering against gatt server.
17 const DIS_APP_RANDOM_UUID: &str = "1b518948-fd77-4459-906f-4923104bb639";
18 
19 /// UUID for PNP ID characteristic.
20 const PNP_ID_CHAR_UUID: &str = "00002A50-0000-1000-8000-00805F9B34FB";
21 
22 /// Handles exporting the Device Information Service (DIS).
23 pub struct DeviceInformation {
24     /// Reference to Gatt server implementation to export service.
25     bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>,
26 
27     /// Server id (available once we are registered).
28     gatt_server_id: Option<i32>,
29 
30     /// Handle for the PNP ID characteristic.
31     pnp_id_handle: Option<i32>,
32 
33     /// Sender for stack mainloop.
34     tx: Sender<Message>,
35 }
36 
37 impl DeviceInformation {
new(bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>, tx: Sender<Message>) -> Self38     pub fn new(bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>, tx: Sender<Message>) -> Self {
39         Self { bluetooth_gatt, gatt_server_id: None, pnp_id_handle: None, tx }
40     }
41 
initialize(&mut self)42     pub(crate) fn initialize(&mut self) {
43         let callback = Box::new(DeviceInformationServerCallbacks::new(self.tx.clone()));
44 
45         // First register for callbacks with the server.
46         self.bluetooth_gatt.lock().unwrap().register_server(
47             DIS_APP_RANDOM_UUID.to_string(),
48             callback,
49             /*eatt_support=*/ true,
50         );
51     }
52 
handle_callbacks(&mut self, callback: &ServiceCallbacks)53     pub(crate) fn handle_callbacks(&mut self, callback: &ServiceCallbacks) {
54         match callback {
55             ServiceCallbacks::Registered(status, server_id) => {
56                 if status != &GattStatus::Success {
57                     log::error!("DIS failed to register callbacks. Status={:?}", status);
58                     return;
59                 }
60 
61                 self.gatt_server_id = Some(*server_id);
62 
63                 // Construct and add Device Information service.
64                 let mut service = BluetoothGattService::new(
65                     UuidHelper::get_profile_uuid(&Profile::Dis)
66                         .expect("DIS uuid mapping missing")
67                         .clone(),
68                     /*instance_id=*/ 0,
69                     GattDbElementType::PrimaryService.into(),
70                 );
71 
72                 service.characteristics.push(BluetoothGattCharacteristic::new(
73                     UuidHelper::from_string(PNP_ID_CHAR_UUID).expect("PNP ID uuid is malformed"),
74                     /*instance_id=*/ 0,
75                     BluetoothGattCharacteristic::PROPERTY_READ,
76                     BluetoothGattCharacteristic::PERMISSION_READ,
77                 ));
78 
79                 self.bluetooth_gatt.lock().unwrap().add_service(*server_id, service);
80             }
81 
82             ServiceCallbacks::ServiceAdded(status, service) => {
83                 if status != &GattStatus::Success {
84                     return;
85                 }
86 
87                 let pnp_uuid =
88                     UuidHelper::from_string(PNP_ID_CHAR_UUID).expect("PNP ID uuid is malformed");
89 
90                 // Find the PNP ID characteristic we inserted before and store
91                 // the handle for it.
92                 for characteristic in &service.characteristics {
93                     if characteristic.uuid == pnp_uuid {
94                         self.pnp_id_handle = Some(characteristic.instance_id);
95                     }
96                 }
97             }
98             ServiceCallbacks::OnCharacteristicReadRequest(
99                 addr,
100                 trans_id,
101                 offset,
102                 _is_long,
103                 handle,
104             ) => match (self.gatt_server_id, self.pnp_id_handle) {
105                 (Some(server_id), Some(pnp_handle)) => {
106                     if &pnp_handle == handle {
107                         let vendor_id = sysprop::get_i32(sysprop::PropertyI32::VendorId);
108                         let vendor_id_source =
109                             sysprop::get_i32(sysprop::PropertyI32::VendorIdSource);
110                         let product_id = sysprop::get_i32(sysprop::PropertyI32::ProductId);
111                         let product_version =
112                             sysprop::get_i32(sysprop::PropertyI32::ProductVersion);
113 
114                         // PNP ID ordering (all values are in little endian):
115                         // - Vendor ID source (1 octet)
116                         // - Vendor ID (2 octet)
117                         // - Product ID (2 octet)
118                         // - Product Version (2 octet)
119                         let mut value: Vec<u8> = Vec::new();
120                         value.push(vendor_id_source.to_le_bytes()[0]);
121                         value.extend_from_slice(&vendor_id.to_le_bytes()[0..2]);
122                         value.extend_from_slice(&product_id.to_le_bytes()[0..2]);
123                         value.extend_from_slice(&product_version.to_le_bytes()[0..2]);
124 
125                         self.bluetooth_gatt.lock().unwrap().send_response(
126                             server_id,
127                             addr.clone(),
128                             *trans_id,
129                             GattStatus::Success,
130                             *offset,
131                             value,
132                         );
133                     }
134                 }
135 
136                 (_, _) => (),
137             },
138         }
139     }
140 }
141 
142 // Callbacks we need to handle for DIS.
143 pub enum ServiceCallbacks {
144     Registered(GattStatus, i32),
145     ServiceAdded(GattStatus, BluetoothGattService),
146     OnCharacteristicReadRequest(String, i32, i32, bool, i32),
147 }
148 
149 // Handle callbacks for DIS to register
150 struct DeviceInformationServerCallbacks {
151     // Sender to the main loop
152     tx: Sender<Message>,
153 }
154 
155 impl DeviceInformationServerCallbacks {
new(tx: Sender<Message>) -> Self156     fn new(tx: Sender<Message>) -> Self {
157         Self { tx }
158     }
159 }
160 
161 impl IBluetoothGattServerCallback for DeviceInformationServerCallbacks {
on_server_registered(&mut self, status: GattStatus, server_id: i32)162     fn on_server_registered(&mut self, status: GattStatus, server_id: i32) {
163         let txl = self.tx.clone();
164         tokio::spawn(async move {
165             let _ = txl.send(Message::Dis(ServiceCallbacks::Registered(status, server_id))).await;
166         });
167     }
168 
on_service_added(&mut self, status: GattStatus, service: BluetoothGattService)169     fn on_service_added(&mut self, status: GattStatus, service: BluetoothGattService) {
170         let txl = self.tx.clone();
171         tokio::spawn(async move {
172             let _ = txl.send(Message::Dis(ServiceCallbacks::ServiceAdded(status, service))).await;
173         });
174     }
175 
on_characteristic_read_request( &mut self, addr: String, trans_id: i32, offset: i32, is_long: bool, handle: i32, )176     fn on_characteristic_read_request(
177         &mut self,
178         addr: String,
179         trans_id: i32,
180         offset: i32,
181         is_long: bool,
182         handle: i32,
183     ) {
184         let txl = self.tx.clone();
185         tokio::spawn(async move {
186             let _ = txl
187                 .send(Message::Dis(ServiceCallbacks::OnCharacteristicReadRequest(
188                     addr, trans_id, offset, is_long, handle,
189                 )))
190                 .await;
191         });
192     }
193 
194     // Remaining callbacks are unhandled
195 
on_service_removed(&mut self, _status: GattStatus, _handle: i32)196     fn on_service_removed(&mut self, _status: GattStatus, _handle: i32) {}
on_server_connection_state(&mut self, _server_id: i32, _connected: bool, _addr: String)197     fn on_server_connection_state(&mut self, _server_id: i32, _connected: bool, _addr: String) {}
on_descriptor_read_request( &mut self, _addr: String, _trans_id: i32, _offset: i32, _is_long: bool, _handle: i32, )198     fn on_descriptor_read_request(
199         &mut self,
200         _addr: String,
201         _trans_id: i32,
202         _offset: i32,
203         _is_long: bool,
204         _handle: i32,
205     ) {
206     }
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>, )207     fn on_characteristic_write_request(
208         &mut self,
209         _addr: String,
210         _trans_id: i32,
211         _offset: i32,
212         _len: i32,
213         _is_prep: bool,
214         _need_rsp: bool,
215         _handle: i32,
216         _value: Vec<u8>,
217     ) {
218     }
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>, )219     fn on_descriptor_write_request(
220         &mut self,
221         _addr: String,
222         _trans_id: i32,
223         _offset: i32,
224         _len: i32,
225         _is_prep: bool,
226         _need_rsp: bool,
227         _handle: i32,
228         _value: Vec<u8>,
229     ) {
230     }
on_execute_write(&mut self, _addr: String, _trans_id: i32, _exec_write: bool)231     fn on_execute_write(&mut self, _addr: String, _trans_id: i32, _exec_write: bool) {}
on_notification_sent(&mut self, _addr: String, _status: GattStatus)232     fn on_notification_sent(&mut self, _addr: String, _status: GattStatus) {}
on_mtu_changed(&mut self, _addr: String, _mtu: i32)233     fn on_mtu_changed(&mut self, _addr: String, _mtu: i32) {}
on_phy_update( &mut self, _addr: String, _tx_phy: LePhy, _rx_phy: LePhy, _status: GattStatus, )234     fn on_phy_update(
235         &mut self,
236         _addr: String,
237         _tx_phy: LePhy,
238         _rx_phy: LePhy,
239         _status: GattStatus,
240     ) {
241     }
on_phy_read(&mut self, _addr: String, _tx_phy: LePhy, _rx_phy: LePhy, _status: GattStatus)242     fn on_phy_read(&mut self, _addr: String, _tx_phy: LePhy, _rx_phy: LePhy, _status: GattStatus) {}
on_connection_updated( &mut self, _addr: String, _interval: i32, _latency: i32, _timeout: i32, _status: GattStatus, )243     fn on_connection_updated(
244         &mut self,
245         _addr: String,
246         _interval: i32,
247         _latency: i32,
248         _timeout: i32,
249         _status: GattStatus,
250     ) {
251     }
on_subrate_change( &mut self, _addr: String, _subrate_factor: i32, _latency: i32, _cont_num: i32, _timeout: i32, _status: GattStatus, )252     fn on_subrate_change(
253         &mut self,
254         _addr: String,
255         _subrate_factor: i32,
256         _latency: i32,
257         _cont_num: i32,
258         _timeout: i32,
259         _status: GattStatus,
260     ) {
261     }
262 }
263 
264 impl RPCProxy for DeviceInformationServerCallbacks {
get_object_id(&self) -> String265     fn get_object_id(&self) -> String {
266         "DIS Gatt Server Callback".to_string()
267     }
268 }
269