1 //! BLE Advertising types and utilities
2
3 use btif_macros::{btif_callback, btif_callbacks_dispatcher};
4
5 use bt_topshim::btif::{DisplayAddress, RawAddress, Uuid};
6 use bt_topshim::profiles::gatt::{AdvertisingStatus, Gatt, GattAdvCallbacks, LeDiscMode, LePhy};
7
8 use itertools::Itertools;
9 use log::{debug, error, info, warn};
10 use num_traits::clamp;
11 use std::collections::{HashMap, VecDeque};
12 use std::sync::{Arc, Mutex};
13 use std::time::{Duration, Instant};
14 use tokio::sync::mpsc::Sender;
15 use tokio::task::JoinHandle;
16 use tokio::time;
17
18 use crate::bluetooth::{Bluetooth, IBluetooth};
19 use crate::callbacks::Callbacks;
20 use crate::{Message, RPCProxy, SuspendMode};
21
22 pub type AdvertiserId = i32;
23 pub type CallbackId = u32;
24 pub type RegId = i32;
25 pub type ManfId = u16;
26
27 /// Advertising parameters for each BLE advertising set.
28 #[derive(Debug, Default, Clone)]
29 pub struct AdvertisingSetParameters {
30 /// Discoverable modes.
31 pub discoverable: LeDiscMode,
32 /// Whether the advertisement will be connectable.
33 pub connectable: bool,
34 /// Whether the advertisement will be scannable.
35 pub scannable: bool,
36 /// Whether the legacy advertisement will be used.
37 pub is_legacy: bool,
38 /// Whether the advertisement will be anonymous.
39 pub is_anonymous: bool,
40 /// Whether the TX Power will be included.
41 pub include_tx_power: bool,
42 /// Primary advertising phy. Valid values are: 1 (1M), 2 (2M), 3 (Coded).
43 pub primary_phy: LePhy,
44 /// Secondary advertising phy. Valid values are: 1 (1M), 2 (2M), 3 (Coded).
45 pub secondary_phy: LePhy,
46 /// The advertising interval. Bluetooth LE Advertising interval, in 0.625 ms unit.
47 /// The valid range is from 160 (100 ms) to 16777215 (10485.759375 sec).
48 /// Recommended values are: 160 (100 ms), 400 (250 ms), 1600 (1 sec).
49 pub interval: i32,
50 /// Transmission power of Bluetooth LE Advertising, in dBm. The valid range is [-127, 1].
51 /// Recommended values are: -21, -15, 7, 1.
52 pub tx_power_level: i32,
53 /// Own address type for advertising to control public or privacy mode.
54 /// The valid types are: -1 (default), 0 (public), 1 (random).
55 pub own_address_type: i32,
56 }
57
58 /// Represents the data to be advertised and the scan response data for active scans.
59 #[derive(Debug, Default, Clone)]
60 pub struct AdvertiseData {
61 /// A list of service UUIDs within the advertisement that are used to identify
62 /// the Bluetooth GATT services.
63 pub service_uuids: Vec<Uuid>,
64 /// A list of service solicitation UUIDs within the advertisement that we invite to connect.
65 pub solicit_uuids: Vec<Uuid>,
66 /// A list of transport discovery data.
67 pub transport_discovery_data: Vec<Vec<u8>>,
68 /// A collection of manufacturer Id and the corresponding manufacturer specific data.
69 pub manufacturer_data: HashMap<ManfId, Vec<u8>>,
70 /// A map of 128-bit UUID and its corresponding service data.
71 pub service_data: HashMap<String, Vec<u8>>,
72 /// Whether TX Power level will be included in the advertising packet.
73 pub include_tx_power_level: bool,
74 /// Whether the device name will be included in the advertisement packet.
75 pub include_device_name: bool,
76 }
77
78 /// Parameters of the periodic advertising packet for BLE advertising set.
79 #[derive(Debug, Default)]
80 pub struct PeriodicAdvertisingParameters {
81 /// Whether TX Power level will be included.
82 pub include_tx_power: bool,
83 /// Periodic advertising interval in 1.25 ms unit. Valid values are from 80 (100 ms) to
84 /// 65519 (81.89875 sec). Value from range [interval, interval+20ms] will be picked as
85 /// the actual value.
86 pub interval: i32,
87 }
88
89 /// Interface for advertiser callbacks to clients, passed to
90 /// `IBluetoothGatt::start_advertising_set`.
91 pub trait IAdvertisingSetCallback: RPCProxy {
92 /// Callback triggered in response to `start_advertising_set` indicating result of
93 /// the operation.
94 ///
95 /// * `reg_id` - Identifies the advertising set registered by `start_advertising_set`.
96 /// * `advertiser_id` - ID for the advertising set. It will be used in other advertising methods
97 /// and callbacks.
98 /// * `tx_power` - Transmit power that will be used for this advertising set.
99 /// * `status` - Status of this operation.
on_advertising_set_started( &mut self, reg_id: i32, advertiser_id: i32, tx_power: i32, status: AdvertisingStatus, )100 fn on_advertising_set_started(
101 &mut self,
102 reg_id: i32,
103 advertiser_id: i32,
104 tx_power: i32,
105 status: AdvertisingStatus,
106 );
107
108 /// Callback triggered in response to `get_own_address` indicating result of the operation.
on_own_address_read(&mut self, advertiser_id: i32, address_type: i32, address: RawAddress)109 fn on_own_address_read(&mut self, advertiser_id: i32, address_type: i32, address: RawAddress);
110
111 /// Callback triggered in response to `stop_advertising_set` indicating the advertising set
112 /// is stopped.
on_advertising_set_stopped(&mut self, advertiser_id: i32)113 fn on_advertising_set_stopped(&mut self, advertiser_id: i32);
114
115 /// Callback triggered in response to `enable_advertising_set` indicating result of
116 /// the operation.
on_advertising_enabled( &mut self, advertiser_id: i32, enable: bool, status: AdvertisingStatus, )117 fn on_advertising_enabled(
118 &mut self,
119 advertiser_id: i32,
120 enable: bool,
121 status: AdvertisingStatus,
122 );
123
124 /// Callback triggered in response to `set_advertising_data` indicating result of the operation.
on_advertising_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus)125 fn on_advertising_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus);
126
127 /// Callback triggered in response to `set_scan_response_data` indicating result of
128 /// the operation.
on_scan_response_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus)129 fn on_scan_response_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus);
130
131 /// Callback triggered in response to `set_advertising_parameters` indicating result of
132 /// the operation.
on_advertising_parameters_updated( &mut self, advertiser_id: i32, tx_power: i32, status: AdvertisingStatus, )133 fn on_advertising_parameters_updated(
134 &mut self,
135 advertiser_id: i32,
136 tx_power: i32,
137 status: AdvertisingStatus,
138 );
139
140 /// Callback triggered in response to `set_periodic_advertising_parameters` indicating result of
141 /// the operation.
on_periodic_advertising_parameters_updated( &mut self, advertiser_id: i32, status: AdvertisingStatus, )142 fn on_periodic_advertising_parameters_updated(
143 &mut self,
144 advertiser_id: i32,
145 status: AdvertisingStatus,
146 );
147
148 /// Callback triggered in response to `set_periodic_advertising_data` indicating result of
149 /// the operation.
on_periodic_advertising_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus)150 fn on_periodic_advertising_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus);
151
152 /// Callback triggered in response to `set_periodic_advertising_enable` indicating result of
153 /// the operation.
on_periodic_advertising_enabled( &mut self, advertiser_id: i32, enable: bool, status: AdvertisingStatus, )154 fn on_periodic_advertising_enabled(
155 &mut self,
156 advertiser_id: i32,
157 enable: bool,
158 status: AdvertisingStatus,
159 );
160
161 /// When advertising module changes its suspend mode due to system suspend/resume.
on_suspend_mode_change(&mut self, suspend_mode: SuspendMode)162 fn on_suspend_mode_change(&mut self, suspend_mode: SuspendMode);
163 }
164
165 // Advertising interval range.
166 const INTERVAL_MAX: i32 = 0xff_ffff; // 10485.759375 sec
167 const INTERVAL_MIN: i32 = 160; // 100 ms
168 const INTERVAL_DELTA: i32 = 50; // 31.25 ms gap between min and max
169
170 // Periodic advertising interval range.
171 const PERIODIC_INTERVAL_MAX: i32 = 65519; // 81.89875 sec
172 const PERIODIC_INTERVAL_MIN: i32 = 80; // 100 ms
173 const PERIODIC_INTERVAL_DELTA: i32 = 16; // 20 ms gap between min and max
174
175 // Device name length.
176 const DEVICE_NAME_MAX: usize = 26;
177
178 // Advertising data types.
179 const COMPLETE_LIST_16_BIT_SERVICE_UUIDS: u8 = 0x03;
180 const COMPLETE_LIST_32_BIT_SERVICE_UUIDS: u8 = 0x05;
181 const COMPLETE_LIST_128_BIT_SERVICE_UUIDS: u8 = 0x07;
182 const SHORTENED_LOCAL_NAME: u8 = 0x08;
183 const COMPLETE_LOCAL_NAME: u8 = 0x09;
184 const TX_POWER_LEVEL: u8 = 0x0a;
185 const LIST_16_BIT_SERVICE_SOLICITATION_UUIDS: u8 = 0x14;
186 const LIST_128_BIT_SERVICE_SOLICITATION_UUIDS: u8 = 0x15;
187 const SERVICE_DATA_16_BIT_UUID: u8 = 0x16;
188 const LIST_32_BIT_SERVICE_SOLICITATION_UUIDS: u8 = 0x1f;
189 const SERVICE_DATA_32_BIT_UUID: u8 = 0x20;
190 const SERVICE_DATA_128_BIT_UUID: u8 = 0x21;
191 const TRANSPORT_DISCOVERY_DATA: u8 = 0x26;
192 const MANUFACTURER_SPECIFIC_DATA: u8 = 0xff;
193 const SERVICE_AD_TYPES: [u8; 3] = [
194 COMPLETE_LIST_16_BIT_SERVICE_UUIDS,
195 COMPLETE_LIST_32_BIT_SERVICE_UUIDS,
196 COMPLETE_LIST_128_BIT_SERVICE_UUIDS,
197 ];
198 const SOLICIT_AD_TYPES: [u8; 3] = [
199 LIST_16_BIT_SERVICE_SOLICITATION_UUIDS,
200 LIST_32_BIT_SERVICE_SOLICITATION_UUIDS,
201 LIST_128_BIT_SERVICE_SOLICITATION_UUIDS,
202 ];
203
204 const LEGACY_ADV_DATA_LEN_MAX: usize = 31;
205 const EXT_ADV_DATA_LEN_MAX: usize = 254;
206
207 // Invalid advertising set id.
208 const INVALID_ADV_ID: i32 = 0xff;
209
210 // Invalid advertising set id.
211 pub const INVALID_REG_ID: i32 = -1;
212
213 impl Into<bt_topshim::profiles::gatt::AdvertiseParameters> for AdvertisingSetParameters {
into(self) -> bt_topshim::profiles::gatt::AdvertiseParameters214 fn into(self) -> bt_topshim::profiles::gatt::AdvertiseParameters {
215 let mut props: u16 = 0;
216 if self.connectable {
217 props |= 0x01;
218 }
219 if self.scannable {
220 props |= 0x02;
221 }
222 if self.is_legacy {
223 props |= 0x10;
224 }
225 if self.is_anonymous {
226 props |= 0x20;
227 }
228 if self.include_tx_power {
229 props |= 0x40;
230 }
231
232 match self.discoverable {
233 LeDiscMode::GeneralDiscoverable => {
234 props |= 0x04;
235 }
236 _ => {}
237 }
238
239 let interval = clamp(self.interval, INTERVAL_MIN, INTERVAL_MAX - INTERVAL_DELTA);
240
241 bt_topshim::profiles::gatt::AdvertiseParameters {
242 advertising_event_properties: props,
243 min_interval: interval as u32,
244 max_interval: (interval + INTERVAL_DELTA) as u32,
245 channel_map: 0x07 as u8, // all channels
246 tx_power: self.tx_power_level as i8,
247 primary_advertising_phy: self.primary_phy.into(),
248 secondary_advertising_phy: self.secondary_phy.into(),
249 scan_request_notification_enable: 0 as u8, // false
250 own_address_type: self.own_address_type as i8,
251 }
252 }
253 }
254
255 impl AdvertiseData {
append_adv_data(dest: &mut Vec<u8>, ad_type: u8, ad_payload: &[u8])256 fn append_adv_data(dest: &mut Vec<u8>, ad_type: u8, ad_payload: &[u8]) {
257 let len = clamp(ad_payload.len(), 0, 254);
258 dest.push((len + 1) as u8);
259 dest.push(ad_type);
260 dest.extend(&ad_payload[..len]);
261 }
262
append_uuids(dest: &mut Vec<u8>, ad_types: &[u8; 3], uuids: &Vec<Uuid>)263 fn append_uuids(dest: &mut Vec<u8>, ad_types: &[u8; 3], uuids: &Vec<Uuid>) {
264 let mut uuid16_bytes = Vec::<u8>::new();
265 let mut uuid32_bytes = Vec::<u8>::new();
266 let mut uuid128_bytes = Vec::<u8>::new();
267
268 // For better transmission efficiency, we generate a compact
269 // advertisement data by converting UUIDs into shorter binary forms
270 // and then group them by their length in order.
271 // The data generated for UUIDs looks like:
272 // [16-bit_UUID_LIST, 32-bit_UUID_LIST, 128-bit_UUID_LIST].
273 for uuid in uuids {
274 let uuid_slice = uuid.get_shortest_slice();
275 let id: Vec<u8> = uuid_slice.iter().rev().cloned().collect();
276 match id.len() {
277 2 => uuid16_bytes.extend(id),
278 4 => uuid32_bytes.extend(id),
279 16 => uuid128_bytes.extend(id),
280 _ => (),
281 }
282 }
283
284 let bytes_list = vec![uuid16_bytes, uuid32_bytes, uuid128_bytes];
285 for (ad_type, bytes) in
286 ad_types.iter().zip(bytes_list.iter()).filter(|(_, bytes)| bytes.len() > 0)
287 {
288 AdvertiseData::append_adv_data(dest, *ad_type, bytes);
289 }
290 }
291
append_service_uuids(dest: &mut Vec<u8>, uuids: &Vec<Uuid>)292 fn append_service_uuids(dest: &mut Vec<u8>, uuids: &Vec<Uuid>) {
293 AdvertiseData::append_uuids(dest, &SERVICE_AD_TYPES, uuids);
294 }
295
append_solicit_uuids(dest: &mut Vec<u8>, uuids: &Vec<Uuid>)296 fn append_solicit_uuids(dest: &mut Vec<u8>, uuids: &Vec<Uuid>) {
297 AdvertiseData::append_uuids(dest, &SOLICIT_AD_TYPES, uuids);
298 }
299
append_service_data(dest: &mut Vec<u8>, service_data: &HashMap<String, Vec<u8>>)300 fn append_service_data(dest: &mut Vec<u8>, service_data: &HashMap<String, Vec<u8>>) {
301 for (uuid, data) in
302 service_data.iter().filter_map(|(s, d)| Uuid::from_string(s).map(|s| (s, d)))
303 {
304 let uuid_slice = uuid.get_shortest_slice();
305 let concated: Vec<u8> = uuid_slice.iter().rev().chain(data).cloned().collect();
306 match uuid_slice.len() {
307 2 => AdvertiseData::append_adv_data(dest, SERVICE_DATA_16_BIT_UUID, &concated),
308 4 => AdvertiseData::append_adv_data(dest, SERVICE_DATA_32_BIT_UUID, &concated),
309 16 => AdvertiseData::append_adv_data(dest, SERVICE_DATA_128_BIT_UUID, &concated),
310 _ => (),
311 }
312 }
313 }
314
append_device_name(dest: &mut Vec<u8>, device_name: &String)315 fn append_device_name(dest: &mut Vec<u8>, device_name: &String) {
316 if device_name.len() == 0 {
317 return;
318 }
319
320 let (ad_type, name) = if device_name.len() > DEVICE_NAME_MAX {
321 (SHORTENED_LOCAL_NAME, [&device_name.as_bytes()[..DEVICE_NAME_MAX], &[0]].concat())
322 } else {
323 (COMPLETE_LOCAL_NAME, [device_name.as_bytes(), &[0]].concat())
324 };
325 AdvertiseData::append_adv_data(dest, ad_type, &name);
326 }
327
append_manufacturer_data(dest: &mut Vec<u8>, manufacturer_data: &HashMap<ManfId, Vec<u8>>)328 fn append_manufacturer_data(dest: &mut Vec<u8>, manufacturer_data: &HashMap<ManfId, Vec<u8>>) {
329 for (m, data) in manufacturer_data.iter().sorted() {
330 let concated = [&m.to_le_bytes()[..], data].concat();
331 AdvertiseData::append_adv_data(dest, MANUFACTURER_SPECIFIC_DATA, &concated);
332 }
333 }
334
append_transport_discovery_data( dest: &mut Vec<u8>, transport_discovery_data: &Vec<Vec<u8>>, )335 fn append_transport_discovery_data(
336 dest: &mut Vec<u8>,
337 transport_discovery_data: &Vec<Vec<u8>>,
338 ) {
339 for tdd in transport_discovery_data.iter().filter(|tdd| tdd.len() > 0) {
340 AdvertiseData::append_adv_data(dest, TRANSPORT_DISCOVERY_DATA, &tdd);
341 }
342 }
343
344 /// Creates raw data from the AdvertiseData.
make_with(&self, device_name: &String) -> Vec<u8>345 pub fn make_with(&self, device_name: &String) -> Vec<u8> {
346 let mut bytes = Vec::<u8>::new();
347 if self.include_device_name {
348 AdvertiseData::append_device_name(&mut bytes, device_name);
349 }
350 if self.include_tx_power_level {
351 // Lower layers will fill tx power level.
352 AdvertiseData::append_adv_data(&mut bytes, TX_POWER_LEVEL, &[0]);
353 }
354 AdvertiseData::append_manufacturer_data(&mut bytes, &self.manufacturer_data);
355 AdvertiseData::append_service_uuids(&mut bytes, &self.service_uuids);
356 AdvertiseData::append_service_data(&mut bytes, &self.service_data);
357 AdvertiseData::append_solicit_uuids(&mut bytes, &self.solicit_uuids);
358 AdvertiseData::append_transport_discovery_data(&mut bytes, &self.transport_discovery_data);
359 bytes
360 }
361
362 /// Validates the raw data as advertisement data.
validate_raw_data(is_legacy: bool, bytes: &Vec<u8>) -> bool363 pub fn validate_raw_data(is_legacy: bool, bytes: &Vec<u8>) -> bool {
364 bytes.len() <= if is_legacy { LEGACY_ADV_DATA_LEN_MAX } else { EXT_ADV_DATA_LEN_MAX }
365 }
366
367 /// Checks if the advertisement can be upgraded to extended.
can_upgrade(parameters: &mut AdvertisingSetParameters, adv_bytes: &Vec<u8>) -> bool368 pub fn can_upgrade(parameters: &mut AdvertisingSetParameters, adv_bytes: &Vec<u8>) -> bool {
369 if parameters.is_legacy && !AdvertiseData::validate_raw_data(true, adv_bytes) {
370 info!("Auto upgrading advertisement to extended");
371 parameters.is_legacy = false;
372 return true;
373 }
374
375 false
376 }
377 }
378
379 impl Into<bt_topshim::profiles::gatt::PeriodicAdvertisingParameters>
380 for PeriodicAdvertisingParameters
381 {
into(self) -> bt_topshim::profiles::gatt::PeriodicAdvertisingParameters382 fn into(self) -> bt_topshim::profiles::gatt::PeriodicAdvertisingParameters {
383 let mut p = bt_topshim::profiles::gatt::PeriodicAdvertisingParameters::default();
384
385 let interval = clamp(
386 self.interval,
387 PERIODIC_INTERVAL_MIN,
388 PERIODIC_INTERVAL_MAX - PERIODIC_INTERVAL_DELTA,
389 );
390
391 p.enable = true;
392 p.include_adi = false;
393 p.min_interval = interval as u16;
394 p.max_interval = p.min_interval + (PERIODIC_INTERVAL_DELTA as u16);
395 if self.include_tx_power {
396 p.periodic_advertising_properties |= 0x40;
397 }
398
399 p
400 }
401 }
402
403 // Keeps information of an advertising set.
404 #[derive(Debug, PartialEq, Copy, Clone)]
405 struct AdvertisingSetInfo {
406 /// Identifies the advertising set when it's started successfully.
407 adv_id: Option<AdvertiserId>,
408
409 /// Identifies callback associated.
410 callback_id: CallbackId,
411
412 /// Identifies the advertising set when it's registered.
413 reg_id: RegId,
414
415 /// Whether the advertising set has been enabled.
416 enabled: bool,
417
418 /// Whether the advertising set has been paused.
419 paused: bool,
420
421 /// Whether the stop of advertising set is held.
422 /// This flag is set when an advertising set is stopped while we're not able to do it, such as:
423 /// - The system is suspending / suspended
424 /// - The advertising set is not yet valid (started)
425 ///
426 /// The advertising set will be stopped on system resumed / advertising set becomes ready.
427 stopped: bool,
428
429 /// Advertising duration, in 10 ms unit.
430 adv_timeout: u16,
431
432 /// Maximum number of extended advertising events the controller
433 /// shall attempt to send before terminating the extended advertising.
434 adv_events: u8,
435
436 /// Whether the legacy advertisement will be used.
437 legacy: bool,
438 }
439
440 impl AdvertisingSetInfo {
new( callback_id: CallbackId, adv_timeout: u16, adv_events: u8, legacy: bool, reg_id: RegId, ) -> Self441 fn new(
442 callback_id: CallbackId,
443 adv_timeout: u16,
444 adv_events: u8,
445 legacy: bool,
446 reg_id: RegId,
447 ) -> Self {
448 AdvertisingSetInfo {
449 adv_id: None,
450 callback_id,
451 reg_id,
452 enabled: false,
453 paused: false,
454 stopped: false,
455 adv_timeout,
456 adv_events,
457 legacy,
458 }
459 }
460
461 /// Gets advertising set registration ID.
reg_id(&self) -> RegId462 fn reg_id(&self) -> RegId {
463 self.reg_id
464 }
465
466 /// Gets associated callback ID.
callback_id(&self) -> CallbackId467 fn callback_id(&self) -> CallbackId {
468 self.callback_id
469 }
470
471 /// Updates advertiser ID.
set_adv_id(&mut self, id: Option<AdvertiserId>)472 fn set_adv_id(&mut self, id: Option<AdvertiserId>) {
473 self.adv_id = id;
474 }
475
476 /// Gets advertiser ID, which is required for advertising |BleAdvertiserInterface|.
adv_id(&self) -> u8477 fn adv_id(&self) -> u8 {
478 // As advertiser ID was from topshim originally, type casting is safe.
479 self.adv_id.unwrap_or(INVALID_ADV_ID) as u8
480 }
481
482 /// Updates advertising set status.
set_enabled(&mut self, enabled: bool)483 fn set_enabled(&mut self, enabled: bool) {
484 self.enabled = enabled;
485 }
486
487 /// Returns true if the advertising set has been enabled, false otherwise.
is_enabled(&self) -> bool488 fn is_enabled(&self) -> bool {
489 self.enabled
490 }
491
492 /// Marks the advertising set as paused or not.
set_paused(&mut self, paused: bool)493 fn set_paused(&mut self, paused: bool) {
494 self.paused = paused;
495 }
496
497 /// Returns true if the advertising set has been paused, false otherwise.
is_paused(&self) -> bool498 fn is_paused(&self) -> bool {
499 self.paused
500 }
501
502 /// Marks the advertising set as stopped.
set_stopped(&mut self)503 fn set_stopped(&mut self) {
504 self.stopped = true;
505 }
506
507 /// Returns true if the advertising set has been stopped, false otherwise.
is_stopped(&self) -> bool508 fn is_stopped(&self) -> bool {
509 self.stopped
510 }
511
512 /// Gets adv_timeout.
adv_timeout(&self) -> u16513 fn adv_timeout(&self) -> u16 {
514 self.adv_timeout
515 }
516
517 /// Gets adv_events.
adv_events(&self) -> u8518 fn adv_events(&self) -> u8 {
519 self.adv_events
520 }
521
522 /// Returns whether the legacy advertisement will be used.
is_legacy(&self) -> bool523 fn is_legacy(&self) -> bool {
524 self.legacy
525 }
526
527 /// Returns whether the advertising set is valid.
is_valid(&self) -> bool528 fn is_valid(&self) -> bool {
529 self.adv_id.is_some()
530 }
531 }
532
533 // Manages advertising sets and the callbacks.
534 pub(crate) struct AdvertiseManager {
535 tx: Sender<Message>,
536 adv_manager_impl: Option<Box<dyn AdvertiseManagerOps + Send>>,
537 }
538
539 impl AdvertiseManager {
new(tx: Sender<Message>) -> Self540 pub(crate) fn new(tx: Sender<Message>) -> Self {
541 AdvertiseManager { tx, adv_manager_impl: None }
542 }
543
544 /// Initializes the AdvertiseManager
545 /// This needs to be called after Bluetooth is ready because we need to query LE features.
initialize( &mut self, gatt: Arc<Mutex<Gatt>>, adapter: Arc<Mutex<Box<Bluetooth>>>, is_le_ext_adv_supported: bool, )546 pub(crate) fn initialize(
547 &mut self,
548 gatt: Arc<Mutex<Gatt>>,
549 adapter: Arc<Mutex<Box<Bluetooth>>>,
550 is_le_ext_adv_supported: bool,
551 ) {
552 self.adv_manager_impl = if is_le_ext_adv_supported {
553 info!("AdvertiseManager: Selected extended advertising stack");
554 Some(Box::new(AdvertiseManagerImpl::new(self.tx.clone(), gatt, adapter)))
555 } else {
556 info!("AdvertiseManager: Selected software rotation stack");
557 Some(Box::new(SoftwareRotationAdvertiseManagerImpl::new(
558 self.tx.clone(),
559 gatt,
560 adapter,
561 )))
562 }
563 }
564
get_impl(&mut self) -> &mut Box<dyn AdvertiseManagerOps + Send>565 pub fn get_impl(&mut self) -> &mut Box<dyn AdvertiseManagerOps + Send> {
566 self.adv_manager_impl.as_mut().unwrap()
567 }
568 }
569
570 struct AdvertiseManagerImpl {
571 callbacks: Callbacks<dyn IAdvertisingSetCallback + Send>,
572 sets: HashMap<RegId, AdvertisingSetInfo>,
573 suspend_mode: SuspendMode,
574 gatt: Arc<Mutex<Gatt>>,
575 adapter: Arc<Mutex<Box<Bluetooth>>>,
576 }
577
578 impl AdvertiseManagerImpl {
new( tx: Sender<Message>, gatt: Arc<Mutex<Gatt>>, adapter: Arc<Mutex<Box<Bluetooth>>>, ) -> Self579 fn new(
580 tx: Sender<Message>,
581 gatt: Arc<Mutex<Gatt>>,
582 adapter: Arc<Mutex<Box<Bluetooth>>>,
583 ) -> Self {
584 AdvertiseManagerImpl {
585 callbacks: Callbacks::new(tx, Message::AdvertiserCallbackDisconnected),
586 sets: HashMap::new(),
587 suspend_mode: SuspendMode::Normal,
588 gatt,
589 adapter,
590 }
591 }
592
593 // Returns the minimum unoccupied register ID from 0.
new_reg_id(&mut self) -> RegId594 fn new_reg_id(&mut self) -> RegId {
595 (0..)
596 .find(|id| !self.sets.contains_key(id))
597 .expect("There must be an unoccupied register ID")
598 }
599
600 /// Adds an advertising set.
add(&mut self, s: AdvertisingSetInfo)601 fn add(&mut self, s: AdvertisingSetInfo) {
602 if let Some(old) = self.sets.insert(s.reg_id(), s) {
603 warn!("An advertising set with the same reg_id ({}) exists. Drop it!", old.reg_id);
604 }
605 }
606
607 /// Returns an iterator of valid advertising sets.
valid_sets(&self) -> impl Iterator<Item = &AdvertisingSetInfo>608 fn valid_sets(&self) -> impl Iterator<Item = &AdvertisingSetInfo> {
609 self.sets.iter().filter_map(|(_, s)| s.adv_id.map(|_| s))
610 }
611
612 /// Returns an iterator of enabled advertising sets.
enabled_sets(&self) -> impl Iterator<Item = &AdvertisingSetInfo>613 fn enabled_sets(&self) -> impl Iterator<Item = &AdvertisingSetInfo> {
614 self.valid_sets().filter(|s| s.is_enabled())
615 }
616
617 /// Returns an iterator of stopped advertising sets.
stopped_sets(&self) -> impl Iterator<Item = &AdvertisingSetInfo>618 fn stopped_sets(&self) -> impl Iterator<Item = &AdvertisingSetInfo> {
619 self.valid_sets().filter(|s| s.is_stopped())
620 }
621
find_reg_id(&self, adv_id: AdvertiserId) -> Option<RegId>622 fn find_reg_id(&self, adv_id: AdvertiserId) -> Option<RegId> {
623 for (_, s) in &self.sets {
624 if s.adv_id == Some(adv_id) {
625 return Some(s.reg_id());
626 }
627 }
628 return None;
629 }
630
631 /// Returns a mutable reference to the advertising set with the reg_id specified.
get_mut_by_reg_id(&mut self, reg_id: RegId) -> Option<&mut AdvertisingSetInfo>632 fn get_mut_by_reg_id(&mut self, reg_id: RegId) -> Option<&mut AdvertisingSetInfo> {
633 self.sets.get_mut(®_id)
634 }
635
636 /// Returns a shared reference to the advertising set with the reg_id specified.
get_by_reg_id(&self, reg_id: RegId) -> Option<&AdvertisingSetInfo>637 fn get_by_reg_id(&self, reg_id: RegId) -> Option<&AdvertisingSetInfo> {
638 self.sets.get(®_id)
639 }
640
641 /// Returns a mutable reference to the advertising set with the advertiser ID specified.
get_mut_by_advertiser_id( &mut self, adv_id: AdvertiserId, ) -> Option<&mut AdvertisingSetInfo>642 fn get_mut_by_advertiser_id(
643 &mut self,
644 adv_id: AdvertiserId,
645 ) -> Option<&mut AdvertisingSetInfo> {
646 if let Some(reg_id) = self.find_reg_id(adv_id) {
647 return self.get_mut_by_reg_id(reg_id);
648 }
649 None
650 }
651
652 /// Returns a shared reference to the advertising set with the advertiser ID specified.
get_by_advertiser_id(&self, adv_id: AdvertiserId) -> Option<&AdvertisingSetInfo>653 fn get_by_advertiser_id(&self, adv_id: AdvertiserId) -> Option<&AdvertisingSetInfo> {
654 if let Some(reg_id) = self.find_reg_id(adv_id) {
655 return self.get_by_reg_id(reg_id);
656 }
657 None
658 }
659
660 /// Removes the advertising set with the reg_id specified.
661 ///
662 /// Returns the advertising set if found, None otherwise.
remove_by_reg_id(&mut self, reg_id: RegId) -> Option<AdvertisingSetInfo>663 fn remove_by_reg_id(&mut self, reg_id: RegId) -> Option<AdvertisingSetInfo> {
664 self.sets.remove(®_id)
665 }
666
667 /// Removes the advertising set with the specified advertiser ID.
668 ///
669 /// Returns the advertising set if found, None otherwise.
remove_by_advertiser_id(&mut self, adv_id: AdvertiserId) -> Option<AdvertisingSetInfo>670 fn remove_by_advertiser_id(&mut self, adv_id: AdvertiserId) -> Option<AdvertisingSetInfo> {
671 if let Some(reg_id) = self.find_reg_id(adv_id) {
672 return self.remove_by_reg_id(reg_id);
673 }
674 None
675 }
676
677 /// Returns callback of the advertising set.
get_callback( &mut self, s: &AdvertisingSetInfo, ) -> Option<&mut Box<dyn IAdvertisingSetCallback + Send>>678 fn get_callback(
679 &mut self,
680 s: &AdvertisingSetInfo,
681 ) -> Option<&mut Box<dyn IAdvertisingSetCallback + Send>> {
682 self.callbacks.get_by_id_mut(s.callback_id())
683 }
684
685 /// Update suspend mode.
set_suspend_mode(&mut self, suspend_mode: SuspendMode)686 fn set_suspend_mode(&mut self, suspend_mode: SuspendMode) {
687 if suspend_mode != self.suspend_mode {
688 self.suspend_mode = suspend_mode;
689 self.notify_suspend_mode();
690 }
691 }
692
693 /// Gets current suspend mode.
suspend_mode(&mut self) -> SuspendMode694 fn suspend_mode(&mut self) -> SuspendMode {
695 self.suspend_mode.clone()
696 }
697
698 /// Notify current suspend mode to all active callbacks.
notify_suspend_mode(&mut self)699 fn notify_suspend_mode(&mut self) {
700 let suspend_mode = &self.suspend_mode;
701 self.callbacks.for_all_callbacks(|callback| {
702 callback.on_suspend_mode_change(suspend_mode.clone());
703 });
704 }
705
get_adapter_name(&self) -> String706 fn get_adapter_name(&self) -> String {
707 self.adapter.lock().unwrap().get_name()
708 }
709 }
710
711 pub enum AdvertiserActions {
712 /// Triggers the rotation of the advertising set.
713 /// Should only be used in the software rotation stack.
714 RunRotate,
715 }
716
717 /// Defines all required ops for an AdvertiseManager to communicate with the upper/lower layers.
718 pub(crate) trait AdvertiseManagerOps:
719 IBluetoothAdvertiseManager + BtifGattAdvCallbacks
720 {
721 /// Prepares for suspend
enter_suspend(&mut self)722 fn enter_suspend(&mut self);
723
724 /// Undoes previous suspend preparation
exit_suspend(&mut self)725 fn exit_suspend(&mut self);
726
727 /// Handles advertise manager actions
handle_action(&mut self, action: AdvertiserActions)728 fn handle_action(&mut self, action: AdvertiserActions);
729 }
730
731 impl AdvertiseManagerOps for AdvertiseManagerImpl {
enter_suspend(&mut self)732 fn enter_suspend(&mut self) {
733 if self.suspend_mode() != SuspendMode::Normal {
734 return;
735 }
736 self.set_suspend_mode(SuspendMode::Suspending);
737
738 let mut pausing_cnt = 0;
739 for s in self.sets.values_mut().filter(|s| s.is_valid() && s.is_enabled()) {
740 s.set_paused(true);
741 self.gatt.lock().unwrap().advertiser.enable(
742 s.adv_id(),
743 false,
744 s.adv_timeout(),
745 s.adv_events(),
746 );
747 pausing_cnt += 1;
748 }
749
750 if pausing_cnt == 0 {
751 self.set_suspend_mode(SuspendMode::Suspended);
752 }
753 }
754
exit_suspend(&mut self)755 fn exit_suspend(&mut self) {
756 if self.suspend_mode() != SuspendMode::Suspended {
757 return;
758 }
759 for id in self.stopped_sets().map(|s| s.adv_id()).collect::<Vec<_>>() {
760 self.gatt.lock().unwrap().advertiser.unregister(id);
761 self.remove_by_advertiser_id(id as AdvertiserId);
762 }
763 for s in self.sets.values_mut().filter(|s| s.is_valid() && s.is_paused()) {
764 s.set_paused(false);
765 self.gatt.lock().unwrap().advertiser.enable(
766 s.adv_id(),
767 true,
768 s.adv_timeout(),
769 s.adv_events(),
770 );
771 }
772
773 self.set_suspend_mode(SuspendMode::Normal);
774 }
775
handle_action(&mut self, action: AdvertiserActions)776 fn handle_action(&mut self, action: AdvertiserActions) {
777 match action {
778 AdvertiserActions::RunRotate => {
779 error!("Unexpected RunRotate call in hardware offloaded stack");
780 }
781 }
782 }
783 }
784
785 pub trait IBluetoothAdvertiseManager {
786 /// Registers callback for BLE advertising.
register_callback(&mut self, callback: Box<dyn IAdvertisingSetCallback + Send>) -> u32787 fn register_callback(&mut self, callback: Box<dyn IAdvertisingSetCallback + Send>) -> u32;
788
789 /// Unregisters callback for BLE advertising.
unregister_callback(&mut self, callback_id: u32) -> bool790 fn unregister_callback(&mut self, callback_id: u32) -> bool;
791
792 /// Creates a new BLE advertising set and start advertising.
793 ///
794 /// Returns the reg_id for the advertising set, which is used in the callback
795 /// `on_advertising_set_started` to identify the advertising set started.
796 ///
797 /// * `parameters` - Advertising set parameters.
798 /// * `advertise_data` - Advertisement data to be broadcasted.
799 /// * `scan_response` - Scan response.
800 /// * `periodic_parameters` - Periodic advertising parameters. If None, periodic advertising
801 /// will not be started.
802 /// * `periodic_data` - Periodic advertising data.
803 /// * `duration` - Advertising duration, in 10 ms unit. Valid range is from 1 (10 ms) to
804 /// 65535 (655.35 sec). 0 means no advertising timeout.
805 /// * `max_ext_adv_events` - Maximum number of extended advertising events the controller
806 /// shall attempt to send before terminating the extended advertising, even if the
807 /// duration has not expired. Valid range is from 1 to 255. 0 means event count limitation.
808 /// * `callback_id` - Identifies callback registered in register_advertiser_callback.
start_advertising_set( &mut self, parameters: AdvertisingSetParameters, advertise_data: AdvertiseData, scan_response: Option<AdvertiseData>, periodic_parameters: Option<PeriodicAdvertisingParameters>, periodic_data: Option<AdvertiseData>, duration: i32, max_ext_adv_events: i32, callback_id: u32, ) -> i32809 fn start_advertising_set(
810 &mut self,
811 parameters: AdvertisingSetParameters,
812 advertise_data: AdvertiseData,
813 scan_response: Option<AdvertiseData>,
814 periodic_parameters: Option<PeriodicAdvertisingParameters>,
815 periodic_data: Option<AdvertiseData>,
816 duration: i32,
817 max_ext_adv_events: i32,
818 callback_id: u32,
819 ) -> i32;
820
821 /// Disposes a BLE advertising set.
stop_advertising_set(&mut self, advertiser_id: i32)822 fn stop_advertising_set(&mut self, advertiser_id: i32);
823
824 /// Queries address associated with the advertising set.
get_own_address(&mut self, advertiser_id: i32)825 fn get_own_address(&mut self, advertiser_id: i32);
826
827 /// Enables or disables an advertising set.
enable_advertising_set( &mut self, advertiser_id: i32, enable: bool, duration: i32, max_ext_adv_events: i32, )828 fn enable_advertising_set(
829 &mut self,
830 advertiser_id: i32,
831 enable: bool,
832 duration: i32,
833 max_ext_adv_events: i32,
834 );
835
836 /// Updates advertisement data of the advertising set.
set_advertising_data(&mut self, advertiser_id: i32, data: AdvertiseData)837 fn set_advertising_data(&mut self, advertiser_id: i32, data: AdvertiseData);
838
839 /// Set the advertisement data of the advertising set.
set_raw_adv_data(&mut self, advertiser_id: i32, data: Vec<u8>)840 fn set_raw_adv_data(&mut self, advertiser_id: i32, data: Vec<u8>);
841
842 /// Updates scan response of the advertising set.
set_scan_response_data(&mut self, advertiser_id: i32, data: AdvertiseData)843 fn set_scan_response_data(&mut self, advertiser_id: i32, data: AdvertiseData);
844
845 /// Updates advertising parameters of the advertising set.
846 ///
847 /// It must be called when advertising is not active.
set_advertising_parameters( &mut self, advertiser_id: i32, parameters: AdvertisingSetParameters, )848 fn set_advertising_parameters(
849 &mut self,
850 advertiser_id: i32,
851 parameters: AdvertisingSetParameters,
852 );
853
854 /// Updates periodic advertising parameters.
set_periodic_advertising_parameters( &mut self, advertiser_id: i32, parameters: PeriodicAdvertisingParameters, )855 fn set_periodic_advertising_parameters(
856 &mut self,
857 advertiser_id: i32,
858 parameters: PeriodicAdvertisingParameters,
859 );
860
861 /// Updates periodic advertisement data.
862 ///
863 /// It must be called after `set_periodic_advertising_parameters`, or after
864 /// advertising was started with periodic advertising data set.
set_periodic_advertising_data(&mut self, advertiser_id: i32, data: AdvertiseData)865 fn set_periodic_advertising_data(&mut self, advertiser_id: i32, data: AdvertiseData);
866
867 /// Enables or disables periodic advertising.
set_periodic_advertising_enable( &mut self, advertiser_id: i32, enable: bool, include_adi: bool, )868 fn set_periodic_advertising_enable(
869 &mut self,
870 advertiser_id: i32,
871 enable: bool,
872 include_adi: bool,
873 );
874 }
875
876 impl IBluetoothAdvertiseManager for AdvertiseManagerImpl {
register_callback(&mut self, callback: Box<dyn IAdvertisingSetCallback + Send>) -> u32877 fn register_callback(&mut self, callback: Box<dyn IAdvertisingSetCallback + Send>) -> u32 {
878 self.callbacks.add_callback(callback)
879 }
880
unregister_callback(&mut self, callback_id: u32) -> bool881 fn unregister_callback(&mut self, callback_id: u32) -> bool {
882 for s in self.sets.values_mut().filter(|s| s.callback_id() == callback_id) {
883 if s.is_valid() {
884 self.gatt.lock().unwrap().advertiser.unregister(s.adv_id());
885 } else {
886 s.set_stopped();
887 }
888 }
889 self.sets.retain(|_, s| s.callback_id() != callback_id || !s.is_valid());
890
891 self.callbacks.remove_callback(callback_id)
892 }
893
start_advertising_set( &mut self, mut parameters: AdvertisingSetParameters, advertise_data: AdvertiseData, scan_response: Option<AdvertiseData>, periodic_parameters: Option<PeriodicAdvertisingParameters>, periodic_data: Option<AdvertiseData>, duration: i32, max_ext_adv_events: i32, callback_id: u32, ) -> i32894 fn start_advertising_set(
895 &mut self,
896 mut parameters: AdvertisingSetParameters,
897 advertise_data: AdvertiseData,
898 scan_response: Option<AdvertiseData>,
899 periodic_parameters: Option<PeriodicAdvertisingParameters>,
900 periodic_data: Option<AdvertiseData>,
901 duration: i32,
902 max_ext_adv_events: i32,
903 callback_id: u32,
904 ) -> i32 {
905 if self.suspend_mode() != SuspendMode::Normal {
906 return INVALID_REG_ID;
907 }
908
909 let device_name = self.get_adapter_name();
910 let adv_bytes = advertise_data.make_with(&device_name);
911 // TODO(b/311417973): Remove this once we have more robust /device/bluetooth APIs to control extended advertising
912 let is_legacy =
913 parameters.is_legacy && !AdvertiseData::can_upgrade(&mut parameters, &adv_bytes);
914 let params = parameters.into();
915 if !AdvertiseData::validate_raw_data(is_legacy, &adv_bytes) {
916 warn!("Failed to start advertising set with invalid advertise data");
917 return INVALID_REG_ID;
918 }
919 let scan_bytes =
920 if let Some(d) = scan_response { d.make_with(&device_name) } else { Vec::<u8>::new() };
921 if !AdvertiseData::validate_raw_data(is_legacy, &scan_bytes) {
922 warn!("Failed to start advertising set with invalid scan response");
923 return INVALID_REG_ID;
924 }
925 let periodic_params = if let Some(p) = periodic_parameters {
926 p.into()
927 } else {
928 bt_topshim::profiles::gatt::PeriodicAdvertisingParameters::default()
929 };
930 let periodic_bytes =
931 if let Some(d) = periodic_data { d.make_with(&device_name) } else { Vec::<u8>::new() };
932 if !AdvertiseData::validate_raw_data(false, &periodic_bytes) {
933 warn!("Failed to start advertising set with invalid periodic data");
934 return INVALID_REG_ID;
935 }
936 let adv_timeout = clamp(duration, 0, 0xffff) as u16;
937 let adv_events = clamp(max_ext_adv_events, 0, 0xff) as u8;
938
939 let reg_id = self.new_reg_id();
940 let s = AdvertisingSetInfo::new(callback_id, adv_timeout, adv_events, is_legacy, reg_id);
941 self.add(s);
942
943 self.gatt.lock().unwrap().advertiser.start_advertising_set(
944 reg_id,
945 params,
946 adv_bytes,
947 scan_bytes,
948 periodic_params,
949 periodic_bytes,
950 adv_timeout,
951 adv_events,
952 );
953 reg_id
954 }
955
stop_advertising_set(&mut self, advertiser_id: i32)956 fn stop_advertising_set(&mut self, advertiser_id: i32) {
957 let s = if let Some(s) = self.get_by_advertiser_id(advertiser_id) {
958 s.clone()
959 } else {
960 return;
961 };
962
963 if self.suspend_mode() != SuspendMode::Normal {
964 if !s.is_stopped() {
965 info!("Deferred advertisement unregistering due to suspending");
966 self.get_mut_by_advertiser_id(advertiser_id).unwrap().set_stopped();
967 if let Some(cb) = self.get_callback(&s) {
968 cb.on_advertising_set_stopped(advertiser_id);
969 }
970 }
971 return;
972 }
973
974 self.gatt.lock().unwrap().advertiser.unregister(s.adv_id());
975 if let Some(cb) = self.get_callback(&s) {
976 cb.on_advertising_set_stopped(advertiser_id);
977 }
978 self.remove_by_advertiser_id(advertiser_id);
979 }
980
get_own_address(&mut self, advertiser_id: i32)981 fn get_own_address(&mut self, advertiser_id: i32) {
982 if self.suspend_mode() != SuspendMode::Normal {
983 return;
984 }
985
986 if let Some(s) = self.get_by_advertiser_id(advertiser_id) {
987 self.gatt.lock().unwrap().advertiser.get_own_address(s.adv_id());
988 }
989 }
990
enable_advertising_set( &mut self, advertiser_id: i32, enable: bool, duration: i32, max_ext_adv_events: i32, )991 fn enable_advertising_set(
992 &mut self,
993 advertiser_id: i32,
994 enable: bool,
995 duration: i32,
996 max_ext_adv_events: i32,
997 ) {
998 if self.suspend_mode() != SuspendMode::Normal {
999 return;
1000 }
1001
1002 let adv_timeout = clamp(duration, 0, 0xffff) as u16;
1003 let adv_events = clamp(max_ext_adv_events, 0, 0xff) as u8;
1004
1005 if let Some(s) = self.get_by_advertiser_id(advertiser_id) {
1006 self.gatt.lock().unwrap().advertiser.enable(
1007 s.adv_id(),
1008 enable,
1009 adv_timeout,
1010 adv_events,
1011 );
1012 }
1013 }
1014
set_advertising_data(&mut self, advertiser_id: i32, data: AdvertiseData)1015 fn set_advertising_data(&mut self, advertiser_id: i32, data: AdvertiseData) {
1016 if self.suspend_mode() != SuspendMode::Normal {
1017 return;
1018 }
1019
1020 let device_name = self.get_adapter_name();
1021 let bytes = data.make_with(&device_name);
1022
1023 if let Some(s) = self.get_by_advertiser_id(advertiser_id) {
1024 if !AdvertiseData::validate_raw_data(s.is_legacy(), &bytes) {
1025 warn!("AdvertiseManagerImpl {}: invalid advertise data to update", advertiser_id);
1026 return;
1027 }
1028 self.gatt.lock().unwrap().advertiser.set_data(s.adv_id(), false, bytes);
1029 }
1030 }
1031
set_raw_adv_data(&mut self, advertiser_id: i32, data: Vec<u8>)1032 fn set_raw_adv_data(&mut self, advertiser_id: i32, data: Vec<u8>) {
1033 if self.suspend_mode() != SuspendMode::Normal {
1034 return;
1035 }
1036
1037 if let Some(s) = self.get_by_advertiser_id(advertiser_id) {
1038 if !AdvertiseData::validate_raw_data(s.is_legacy(), &data) {
1039 warn!(
1040 "AdvertiseManagerImpl {}: invalid raw advertise data to update",
1041 advertiser_id
1042 );
1043 return;
1044 }
1045 self.gatt.lock().unwrap().advertiser.set_data(s.adv_id(), false, data);
1046 }
1047 }
1048
set_scan_response_data(&mut self, advertiser_id: i32, data: AdvertiseData)1049 fn set_scan_response_data(&mut self, advertiser_id: i32, data: AdvertiseData) {
1050 if self.suspend_mode() != SuspendMode::Normal {
1051 return;
1052 }
1053
1054 let device_name = self.get_adapter_name();
1055 let bytes = data.make_with(&device_name);
1056
1057 if let Some(s) = self.get_by_advertiser_id(advertiser_id) {
1058 if !AdvertiseData::validate_raw_data(s.is_legacy(), &bytes) {
1059 warn!("AdvertiseManagerImpl {}: invalid scan response to update", advertiser_id);
1060 return;
1061 }
1062 self.gatt.lock().unwrap().advertiser.set_data(s.adv_id(), true, bytes);
1063 }
1064 }
1065
set_advertising_parameters( &mut self, advertiser_id: i32, parameters: AdvertisingSetParameters, )1066 fn set_advertising_parameters(
1067 &mut self,
1068 advertiser_id: i32,
1069 parameters: AdvertisingSetParameters,
1070 ) {
1071 if self.suspend_mode() != SuspendMode::Normal {
1072 return;
1073 }
1074
1075 let params = parameters.into();
1076
1077 if let Some(s) = self.get_by_advertiser_id(advertiser_id) {
1078 let was_enabled = s.is_enabled();
1079 if was_enabled {
1080 self.gatt.lock().unwrap().advertiser.enable(
1081 s.adv_id(),
1082 false,
1083 s.adv_timeout(),
1084 s.adv_events(),
1085 );
1086 }
1087 self.gatt.lock().unwrap().advertiser.set_parameters(s.adv_id(), params);
1088 if was_enabled {
1089 self.gatt.lock().unwrap().advertiser.enable(
1090 s.adv_id(),
1091 true,
1092 s.adv_timeout(),
1093 s.adv_events(),
1094 );
1095 }
1096 }
1097 }
1098
set_periodic_advertising_parameters( &mut self, advertiser_id: i32, parameters: PeriodicAdvertisingParameters, )1099 fn set_periodic_advertising_parameters(
1100 &mut self,
1101 advertiser_id: i32,
1102 parameters: PeriodicAdvertisingParameters,
1103 ) {
1104 if self.suspend_mode() != SuspendMode::Normal {
1105 return;
1106 }
1107
1108 let params = parameters.into();
1109
1110 if let Some(s) = self.get_by_advertiser_id(advertiser_id) {
1111 self.gatt
1112 .lock()
1113 .unwrap()
1114 .advertiser
1115 .set_periodic_advertising_parameters(s.adv_id(), params);
1116 }
1117 }
1118
set_periodic_advertising_data(&mut self, advertiser_id: i32, data: AdvertiseData)1119 fn set_periodic_advertising_data(&mut self, advertiser_id: i32, data: AdvertiseData) {
1120 if self.suspend_mode() != SuspendMode::Normal {
1121 return;
1122 }
1123
1124 let device_name = self.get_adapter_name();
1125 let bytes = data.make_with(&device_name);
1126
1127 if let Some(s) = self.get_by_advertiser_id(advertiser_id) {
1128 if !AdvertiseData::validate_raw_data(false, &bytes) {
1129 warn!("AdvertiseManagerImpl {}: invalid periodic data to update", advertiser_id);
1130 return;
1131 }
1132 self.gatt.lock().unwrap().advertiser.set_periodic_advertising_data(s.adv_id(), bytes);
1133 }
1134 }
1135
set_periodic_advertising_enable( &mut self, advertiser_id: i32, enable: bool, include_adi: bool, )1136 fn set_periodic_advertising_enable(
1137 &mut self,
1138 advertiser_id: i32,
1139 enable: bool,
1140 include_adi: bool,
1141 ) {
1142 if self.suspend_mode() != SuspendMode::Normal {
1143 return;
1144 }
1145 if let Some(s) = self.get_by_advertiser_id(advertiser_id) {
1146 self.gatt.lock().unwrap().advertiser.set_periodic_advertising_enable(
1147 s.adv_id(),
1148 enable,
1149 include_adi,
1150 );
1151 }
1152 }
1153 }
1154
1155 #[btif_callbacks_dispatcher(dispatch_le_adv_callbacks, GattAdvCallbacks)]
1156 pub(crate) trait BtifGattAdvCallbacks {
1157 #[btif_callback(OnAdvertisingSetStarted)]
on_advertising_set_started( &mut self, reg_id: i32, advertiser_id: u8, tx_power: i8, status: AdvertisingStatus, )1158 fn on_advertising_set_started(
1159 &mut self,
1160 reg_id: i32,
1161 advertiser_id: u8,
1162 tx_power: i8,
1163 status: AdvertisingStatus,
1164 );
1165
1166 #[btif_callback(OnAdvertisingEnabled)]
on_advertising_enabled(&mut self, adv_id: u8, enabled: bool, status: AdvertisingStatus)1167 fn on_advertising_enabled(&mut self, adv_id: u8, enabled: bool, status: AdvertisingStatus);
1168
1169 #[btif_callback(OnAdvertisingDataSet)]
on_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus)1170 fn on_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus);
1171
1172 #[btif_callback(OnScanResponseDataSet)]
on_scan_response_data_set(&mut self, adv_id: u8, status: AdvertisingStatus)1173 fn on_scan_response_data_set(&mut self, adv_id: u8, status: AdvertisingStatus);
1174
1175 #[btif_callback(OnAdvertisingParametersUpdated)]
on_advertising_parameters_updated( &mut self, adv_id: u8, tx_power: i8, status: AdvertisingStatus, )1176 fn on_advertising_parameters_updated(
1177 &mut self,
1178 adv_id: u8,
1179 tx_power: i8,
1180 status: AdvertisingStatus,
1181 );
1182
1183 #[btif_callback(OnPeriodicAdvertisingParametersUpdated)]
on_periodic_advertising_parameters_updated(&mut self, adv_id: u8, status: AdvertisingStatus)1184 fn on_periodic_advertising_parameters_updated(&mut self, adv_id: u8, status: AdvertisingStatus);
1185
1186 #[btif_callback(OnPeriodicAdvertisingDataSet)]
on_periodic_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus)1187 fn on_periodic_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus);
1188
1189 #[btif_callback(OnPeriodicAdvertisingEnabled)]
on_periodic_advertising_enabled( &mut self, adv_id: u8, enabled: bool, status: AdvertisingStatus, )1190 fn on_periodic_advertising_enabled(
1191 &mut self,
1192 adv_id: u8,
1193 enabled: bool,
1194 status: AdvertisingStatus,
1195 );
1196
1197 #[btif_callback(OnOwnAddressRead)]
on_own_address_read(&mut self, adv_id: u8, addr_type: u8, address: RawAddress)1198 fn on_own_address_read(&mut self, adv_id: u8, addr_type: u8, address: RawAddress);
1199 }
1200
1201 impl BtifGattAdvCallbacks for AdvertiseManagerImpl {
on_advertising_set_started( &mut self, reg_id: i32, advertiser_id: u8, tx_power: i8, status: AdvertisingStatus, )1202 fn on_advertising_set_started(
1203 &mut self,
1204 reg_id: i32,
1205 advertiser_id: u8,
1206 tx_power: i8,
1207 status: AdvertisingStatus,
1208 ) {
1209 debug!(
1210 "on_advertising_set_started(): reg_id = {}, advertiser_id = {}, tx_power = {}, status = {:?}",
1211 reg_id, advertiser_id, tx_power, status
1212 );
1213
1214 let s = if let Some(s) = self.sets.get_mut(®_id) {
1215 s
1216 } else {
1217 error!("AdvertisingSetInfo not found");
1218 // An unknown advertising set has started. Unregister it anyway.
1219 self.gatt.lock().unwrap().advertiser.unregister(advertiser_id);
1220 return;
1221 };
1222
1223 if s.is_stopped() {
1224 // The advertising set needs to be stopped. This could happen when |unregister_callback|
1225 // is called before an advertising becomes ready.
1226 self.gatt.lock().unwrap().advertiser.unregister(advertiser_id);
1227 self.sets.remove(®_id);
1228 return;
1229 }
1230
1231 s.set_adv_id(Some(advertiser_id.into()));
1232 s.set_enabled(status == AdvertisingStatus::Success);
1233
1234 if let Some(cb) = self.callbacks.get_by_id_mut(s.callback_id()) {
1235 cb.on_advertising_set_started(reg_id, advertiser_id.into(), tx_power.into(), status);
1236 }
1237
1238 if status != AdvertisingStatus::Success {
1239 warn!(
1240 "on_advertising_set_started(): failed! reg_id = {}, status = {:?}",
1241 reg_id, status
1242 );
1243 self.sets.remove(®_id);
1244 }
1245 }
1246
on_advertising_enabled(&mut self, adv_id: u8, enabled: bool, status: AdvertisingStatus)1247 fn on_advertising_enabled(&mut self, adv_id: u8, enabled: bool, status: AdvertisingStatus) {
1248 debug!(
1249 "on_advertising_enabled(): adv_id = {}, enabled = {}, status = {:?}",
1250 adv_id, enabled, status
1251 );
1252
1253 let advertiser_id: i32 = adv_id.into();
1254
1255 if let Some(s) = self.get_mut_by_advertiser_id(advertiser_id) {
1256 s.set_enabled(enabled);
1257 } else {
1258 return;
1259 }
1260
1261 let s = self.get_by_advertiser_id(advertiser_id).unwrap().clone();
1262 if let Some(cb) = self.get_callback(&s) {
1263 cb.on_advertising_enabled(advertiser_id, enabled, status);
1264 }
1265
1266 if self.suspend_mode() == SuspendMode::Suspending {
1267 if self.enabled_sets().count() == 0 {
1268 self.set_suspend_mode(SuspendMode::Suspended);
1269 }
1270 }
1271 }
1272
on_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus)1273 fn on_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus) {
1274 debug!("on_advertising_data_set(): adv_id = {}, status = {:?}", adv_id, status);
1275
1276 let advertiser_id: i32 = adv_id.into();
1277 if None == self.get_by_advertiser_id(advertiser_id) {
1278 return;
1279 }
1280 let s = self.get_by_advertiser_id(advertiser_id).unwrap().clone();
1281
1282 if let Some(cb) = self.get_callback(&s) {
1283 cb.on_advertising_data_set(advertiser_id, status);
1284 }
1285 }
1286
on_scan_response_data_set(&mut self, adv_id: u8, status: AdvertisingStatus)1287 fn on_scan_response_data_set(&mut self, adv_id: u8, status: AdvertisingStatus) {
1288 debug!("on_scan_response_data_set(): adv_id = {}, status = {:?}", adv_id, status);
1289
1290 let advertiser_id: i32 = adv_id.into();
1291 if None == self.get_by_advertiser_id(advertiser_id) {
1292 return;
1293 }
1294 let s = self.get_by_advertiser_id(advertiser_id).unwrap().clone();
1295
1296 if let Some(cb) = self.get_callback(&s) {
1297 cb.on_scan_response_data_set(advertiser_id, status);
1298 }
1299 }
1300
on_advertising_parameters_updated( &mut self, adv_id: u8, tx_power: i8, status: AdvertisingStatus, )1301 fn on_advertising_parameters_updated(
1302 &mut self,
1303 adv_id: u8,
1304 tx_power: i8,
1305 status: AdvertisingStatus,
1306 ) {
1307 debug!(
1308 "on_advertising_parameters_updated(): adv_id = {}, tx_power = {}, status = {:?}",
1309 adv_id, tx_power, status
1310 );
1311
1312 let advertiser_id: i32 = adv_id.into();
1313 if None == self.get_by_advertiser_id(advertiser_id) {
1314 return;
1315 }
1316 let s = self.get_by_advertiser_id(advertiser_id).unwrap().clone();
1317
1318 if let Some(cb) = self.get_callback(&s) {
1319 cb.on_advertising_parameters_updated(advertiser_id, tx_power.into(), status);
1320 }
1321 }
1322
on_periodic_advertising_parameters_updated( &mut self, adv_id: u8, status: AdvertisingStatus, )1323 fn on_periodic_advertising_parameters_updated(
1324 &mut self,
1325 adv_id: u8,
1326 status: AdvertisingStatus,
1327 ) {
1328 debug!(
1329 "on_periodic_advertising_parameters_updated(): adv_id = {}, status = {:?}",
1330 adv_id, status
1331 );
1332
1333 let advertiser_id: i32 = adv_id.into();
1334 if None == self.get_by_advertiser_id(advertiser_id) {
1335 return;
1336 }
1337 let s = self.get_by_advertiser_id(advertiser_id).unwrap().clone();
1338
1339 if let Some(cb) = self.get_callback(&s) {
1340 cb.on_periodic_advertising_parameters_updated(advertiser_id, status);
1341 }
1342 }
1343
on_periodic_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus)1344 fn on_periodic_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus) {
1345 debug!("on_periodic_advertising_data_set(): adv_id = {}, status = {:?}", adv_id, status);
1346
1347 let advertiser_id: i32 = adv_id.into();
1348 if None == self.get_by_advertiser_id(advertiser_id) {
1349 return;
1350 }
1351 let s = self.get_by_advertiser_id(advertiser_id).unwrap().clone();
1352
1353 if let Some(cb) = self.get_callback(&s) {
1354 cb.on_periodic_advertising_data_set(advertiser_id, status);
1355 }
1356 }
1357
on_periodic_advertising_enabled( &mut self, adv_id: u8, enabled: bool, status: AdvertisingStatus, )1358 fn on_periodic_advertising_enabled(
1359 &mut self,
1360 adv_id: u8,
1361 enabled: bool,
1362 status: AdvertisingStatus,
1363 ) {
1364 debug!(
1365 "on_periodic_advertising_enabled(): adv_id = {}, enabled = {}, status = {:?}",
1366 adv_id, enabled, status
1367 );
1368
1369 let advertiser_id: i32 = adv_id.into();
1370 if None == self.get_by_advertiser_id(advertiser_id) {
1371 return;
1372 }
1373 let s = self.get_by_advertiser_id(advertiser_id).unwrap().clone();
1374
1375 if let Some(cb) = self.get_callback(&s) {
1376 cb.on_periodic_advertising_enabled(advertiser_id, enabled, status);
1377 }
1378 }
1379
on_own_address_read(&mut self, adv_id: u8, addr_type: u8, address: RawAddress)1380 fn on_own_address_read(&mut self, adv_id: u8, addr_type: u8, address: RawAddress) {
1381 debug!(
1382 "on_own_address_read(): adv_id = {}, addr_type = {}, address = {}",
1383 adv_id,
1384 addr_type,
1385 DisplayAddress(&address)
1386 );
1387
1388 let advertiser_id: i32 = adv_id.into();
1389 if None == self.get_by_advertiser_id(advertiser_id) {
1390 return;
1391 }
1392 let s = self.get_by_advertiser_id(advertiser_id).unwrap().clone();
1393
1394 if let Some(cb) = self.get_callback(&s) {
1395 cb.on_own_address_read(advertiser_id, addr_type.into(), address);
1396 }
1397 }
1398 }
1399
1400 /// The underlying legacy advertising rotates every SOFTWARE_ROTATION_INTERVAL seconds.
1401 const SOFTWARE_ROTATION_INTERVAL: Duration = Duration::from_secs(2);
1402
1403 /// The ID of a software rotation advertising.
1404 ///
1405 /// From DBus API's perspective this is used as both Advertiser ID and Register ID.
1406 /// Unlike the extended advertising stack we can't propagate the LibBluetooth Advertiser ID to
1407 /// DBus clients because there can be at most 1 advertiser in LibBluetooth layer at the same time.
1408 pub type SoftwareRotationAdvertierId = i32;
1409
1410 struct SoftwareRotationAdvertiseInfo {
1411 id: SoftwareRotationAdvertierId,
1412 callback_id: u32,
1413
1414 advertising_params: AdvertisingSetParameters,
1415 advertising_data: Vec<u8>,
1416 scan_response_data: Vec<u8>,
1417
1418 /// Filled in on the first time the advertiser started.
1419 tx_power: Option<i32>,
1420
1421 /// True if it's advertising (from DBus client's perspective), false otherwise.
1422 enabled: bool,
1423 duration: i32,
1424 /// None means no timeout
1425 expire_time: Option<Instant>,
1426 }
1427
1428 enum SoftwareRotationAdvertiseState {
1429 /// No advertiser is running in LibBluetooth.
1430 Stopped,
1431 /// A StartAdvertisingSet call to LibBluetooth is pending.
1432 Pending(SoftwareRotationAdvertierId),
1433 /// An advertiser is running in LibBluetooth, i.e., an OnAdvertisingSetStarted is received.
1434 /// Parameters: ID, LibBluetooth BLE Advertiser ID, rotation timer handle
1435 Advertising(SoftwareRotationAdvertierId, u8, JoinHandle<()>),
1436 }
1437
1438 struct SoftwareRotationAdvertiseManagerImpl {
1439 callbacks: Callbacks<dyn IAdvertisingSetCallback + Send>,
1440 suspend_mode: SuspendMode,
1441 gatt: Arc<Mutex<Gatt>>,
1442 adapter: Arc<Mutex<Box<Bluetooth>>>,
1443 tx: Sender<Message>,
1444
1445 state: SoftwareRotationAdvertiseState,
1446 adv_info: HashMap<SoftwareRotationAdvertierId, SoftwareRotationAdvertiseInfo>,
1447 /// The enabled advertising sets to be rotate.
1448 /// When they are removed from the queue, OnAdvertisingEnabled needs to be sent.
1449 /// Note that the current advertiser running in LibBluetooth must *NOT* be in the queue.
1450 adv_queue: VecDeque<SoftwareRotationAdvertierId>,
1451 }
1452
1453 impl SoftwareRotationAdvertiseManagerImpl {
new( tx: Sender<Message>, gatt: Arc<Mutex<Gatt>>, adapter: Arc<Mutex<Box<Bluetooth>>>, ) -> Self1454 fn new(
1455 tx: Sender<Message>,
1456 gatt: Arc<Mutex<Gatt>>,
1457 adapter: Arc<Mutex<Box<Bluetooth>>>,
1458 ) -> Self {
1459 Self {
1460 callbacks: Callbacks::new(tx.clone(), Message::AdvertiserCallbackDisconnected),
1461 suspend_mode: SuspendMode::Normal,
1462 gatt,
1463 adapter,
1464 tx,
1465 state: SoftwareRotationAdvertiseState::Stopped,
1466 adv_info: HashMap::new(),
1467 adv_queue: VecDeque::new(),
1468 }
1469 }
1470 }
1471
1472 impl SoftwareRotationAdvertiseManagerImpl {
1473 /// Updates suspend mode.
set_suspend_mode(&mut self, suspend_mode: SuspendMode)1474 fn set_suspend_mode(&mut self, suspend_mode: SuspendMode) {
1475 if suspend_mode != self.suspend_mode {
1476 self.suspend_mode = suspend_mode.clone();
1477 self.callbacks.for_all_callbacks(|cb| {
1478 cb.on_suspend_mode_change(suspend_mode.clone());
1479 });
1480 }
1481 }
1482
get_adapter_name(&self) -> String1483 fn get_adapter_name(&self) -> String {
1484 self.adapter.lock().unwrap().get_name()
1485 }
1486
1487 /// Returns the ID of the advertiser running in LibBluetooth.
current_id(&self) -> Option<SoftwareRotationAdvertierId>1488 fn current_id(&self) -> Option<SoftwareRotationAdvertierId> {
1489 match &self.state {
1490 SoftwareRotationAdvertiseState::Pending(id) => Some(*id),
1491 SoftwareRotationAdvertiseState::Advertising(id, _, _) => Some(*id),
1492 SoftwareRotationAdvertiseState::Stopped => None,
1493 }
1494 }
1495
1496 /// Returns the minimum unoccupied ID from 0.
new_id(&mut self) -> SoftwareRotationAdvertierId1497 fn new_id(&mut self) -> SoftwareRotationAdvertierId {
1498 // The advertiser running in LibBluetooth may have been removed in this layer.
1499 // Avoid conflicting with it.
1500 let current_id = self.current_id();
1501 (0..)
1502 .find(|id| !self.adv_info.contains_key(id) && Some(*id) != current_id)
1503 .expect("There must be an unoccupied register ID")
1504 }
1505
is_pending(&self) -> bool1506 fn is_pending(&self) -> bool {
1507 matches!(&self.state, SoftwareRotationAdvertiseState::Pending(_))
1508 }
1509
is_stopped(&self) -> bool1510 fn is_stopped(&self) -> bool {
1511 matches!(&self.state, SoftwareRotationAdvertiseState::Stopped)
1512 }
1513
1514 /// Clears the removed or disabled advertisers from the queue and invokes callback.
refresh_queue(&mut self)1515 fn refresh_queue(&mut self) {
1516 let now = Instant::now();
1517 let adv_info = &mut self.adv_info;
1518 let callbacks = &mut self.callbacks;
1519 self.adv_queue.retain(|id| {
1520 let Some(info) = adv_info.get_mut(id) else {
1521 // This advertiser has been removed.
1522 return false;
1523 };
1524 if info.expire_time.map_or(false, |t| t < now) {
1525 // This advertiser has expired.
1526 info.enabled = false;
1527 callbacks.get_by_id_mut(info.callback_id).map(|cb| {
1528 cb.on_advertising_enabled(info.id, false, AdvertisingStatus::Success);
1529 });
1530 }
1531 info.enabled
1532 });
1533 }
1534
stop_current_advertising(&mut self)1535 fn stop_current_advertising(&mut self) {
1536 match &self.state {
1537 SoftwareRotationAdvertiseState::Advertising(id, adv_id, handle) => {
1538 handle.abort();
1539 self.gatt.lock().unwrap().advertiser.unregister(*adv_id);
1540 self.adv_queue.push_back(*id);
1541 self.state = SoftwareRotationAdvertiseState::Stopped;
1542 }
1543 SoftwareRotationAdvertiseState::Pending(_) => {
1544 error!("stop_current_advertising: Unexpected Pending state");
1545 }
1546 SoftwareRotationAdvertiseState::Stopped => {}
1547 };
1548 }
1549
start_next_advertising(&mut self)1550 fn start_next_advertising(&mut self) {
1551 match &self.state {
1552 SoftwareRotationAdvertiseState::Stopped => {
1553 self.state = loop {
1554 let Some(id) = self.adv_queue.pop_front() else {
1555 break SoftwareRotationAdvertiseState::Stopped;
1556 };
1557 let Some(info) = self.adv_info.get(&id) else {
1558 error!("start_next_advertising: Unknown ID, which means queue is not refreshed!");
1559 continue;
1560 };
1561 self.gatt.lock().unwrap().advertiser.start_advertising_set(
1562 id,
1563 info.advertising_params.clone().into(),
1564 info.advertising_data.clone(),
1565 info.scan_response_data.clone(),
1566 Default::default(), // Unsupported periodic_parameters
1567 vec![], // Unsupported periodic_data
1568 0, // Set no timeout. Timeout is controlled in this layer.
1569 0, // Unsupported max_ext_adv_events
1570 );
1571 break SoftwareRotationAdvertiseState::Pending(id);
1572 }
1573 }
1574 SoftwareRotationAdvertiseState::Pending(_) => {
1575 error!("start_next_advertising: Unexpected Pending state");
1576 }
1577 SoftwareRotationAdvertiseState::Advertising(_, _, _) => {
1578 error!("start_next_advertising: Unexpected Advertising state");
1579 }
1580 };
1581 }
1582
run_rotate(&mut self)1583 fn run_rotate(&mut self) {
1584 if self.is_pending() {
1585 return;
1586 }
1587 let Some(current_id) = self.current_id() else {
1588 // State is Stopped. Try to start next one.
1589 self.refresh_queue();
1590 self.start_next_advertising();
1591 return;
1592 };
1593 // We are Advertising. Checks if the current advertiser is still allowed
1594 // to advertise, or if we should schedule the next one in the queue.
1595 let current_is_enabled = {
1596 let now = Instant::now();
1597 if let Some(info) = self.adv_info.get(¤t_id) {
1598 if info.enabled {
1599 info.expire_time.map_or(true, |t| t >= now)
1600 } else {
1601 false
1602 }
1603 } else {
1604 false
1605 }
1606 };
1607 if !current_is_enabled {
1608 // If current advertiser is not allowed to advertise,
1609 // stop it and then let |refresh_queue| handle the callback.
1610 self.stop_current_advertising();
1611 self.refresh_queue();
1612 self.start_next_advertising();
1613 } else {
1614 // Current advertiser is still enabled, refresh the other advertisers in the queue.
1615 self.refresh_queue();
1616 if self.adv_queue.is_empty() {
1617 // No need to rotate.
1618 } else {
1619 self.stop_current_advertising();
1620 self.start_next_advertising();
1621 }
1622 }
1623 }
1624 }
1625
1626 impl AdvertiseManagerOps for SoftwareRotationAdvertiseManagerImpl {
enter_suspend(&mut self)1627 fn enter_suspend(&mut self) {
1628 if self.suspend_mode != SuspendMode::Normal {
1629 return;
1630 }
1631
1632 self.set_suspend_mode(SuspendMode::Suspending);
1633 if self.is_pending() {
1634 // We will unregister it on_advertising_set_started and then set mode to suspended.
1635 return;
1636 }
1637 self.stop_current_advertising();
1638 self.set_suspend_mode(SuspendMode::Suspended);
1639 }
1640
exit_suspend(&mut self)1641 fn exit_suspend(&mut self) {
1642 if self.suspend_mode != SuspendMode::Suspended {
1643 return;
1644 }
1645 self.refresh_queue();
1646 self.start_next_advertising();
1647 self.set_suspend_mode(SuspendMode::Normal);
1648 }
1649
handle_action(&mut self, action: AdvertiserActions)1650 fn handle_action(&mut self, action: AdvertiserActions) {
1651 match action {
1652 AdvertiserActions::RunRotate => {
1653 if self.suspend_mode == SuspendMode::Normal {
1654 self.run_rotate();
1655 }
1656 }
1657 }
1658 }
1659 }
1660
1661 /// Generates expire time from now per the definition in IBluetoothAdvertiseManager
1662 ///
1663 /// None means never timeout.
gen_expire_time_from_now(duration: i32) -> Option<Instant>1664 fn gen_expire_time_from_now(duration: i32) -> Option<Instant> {
1665 let duration = clamp(duration, 0, 0xffff) as u64;
1666 if duration != 0 {
1667 Some(Instant::now() + Duration::from_millis(duration * 10))
1668 } else {
1669 None
1670 }
1671 }
1672
1673 impl IBluetoothAdvertiseManager for SoftwareRotationAdvertiseManagerImpl {
register_callback(&mut self, callback: Box<dyn IAdvertisingSetCallback + Send>) -> u321674 fn register_callback(&mut self, callback: Box<dyn IAdvertisingSetCallback + Send>) -> u32 {
1675 self.callbacks.add_callback(callback)
1676 }
1677
unregister_callback(&mut self, callback_id: u32) -> bool1678 fn unregister_callback(&mut self, callback_id: u32) -> bool {
1679 self.adv_info.retain(|_, info| info.callback_id != callback_id);
1680 let ret = self.callbacks.remove_callback(callback_id);
1681 if let Some(current_id) = self.current_id() {
1682 if !self.adv_info.contains_key(¤t_id) {
1683 self.run_rotate();
1684 }
1685 }
1686 ret
1687 }
1688
start_advertising_set( &mut self, advertising_params: AdvertisingSetParameters, advertising_data: AdvertiseData, scan_response_data: Option<AdvertiseData>, periodic_parameters: Option<PeriodicAdvertisingParameters>, periodic_data: Option<AdvertiseData>, duration: i32, max_ext_adv_events: i32, callback_id: u32, ) -> i321689 fn start_advertising_set(
1690 &mut self,
1691 advertising_params: AdvertisingSetParameters,
1692 advertising_data: AdvertiseData,
1693 scan_response_data: Option<AdvertiseData>,
1694 periodic_parameters: Option<PeriodicAdvertisingParameters>,
1695 periodic_data: Option<AdvertiseData>,
1696 duration: i32,
1697 max_ext_adv_events: i32,
1698 callback_id: u32,
1699 ) -> i32 {
1700 if self.suspend_mode != SuspendMode::Normal {
1701 return INVALID_REG_ID;
1702 }
1703
1704 let is_legacy = advertising_params.is_legacy;
1705 let device_name = self.get_adapter_name();
1706
1707 let advertising_data = advertising_data.make_with(&device_name);
1708 if !AdvertiseData::validate_raw_data(is_legacy, &advertising_data) {
1709 warn!("Failed to start advertising set with invalid advertising data");
1710 return INVALID_REG_ID;
1711 }
1712
1713 let scan_response_data =
1714 scan_response_data.map_or(vec![], |data| data.make_with(&device_name));
1715 if !AdvertiseData::validate_raw_data(is_legacy, &scan_response_data) {
1716 warn!("Failed to start advertising set with invalid scan response data");
1717 return INVALID_REG_ID;
1718 }
1719
1720 if periodic_parameters.is_some() {
1721 warn!("Periodic parameters is not supported in software rotation stack, ignored");
1722 }
1723 if periodic_data.is_some() {
1724 warn!("Periodic data is not supported in software rotation stack, ignored");
1725 }
1726 if max_ext_adv_events != 0 {
1727 warn!("max_ext_adv_events is not supported in software rotation stack, ignored");
1728 }
1729
1730 let id = self.new_id();
1731
1732 // expire_time will be determined on this advertiser is started at the first time.
1733 self.adv_info.insert(
1734 id,
1735 SoftwareRotationAdvertiseInfo {
1736 id,
1737 callback_id,
1738 advertising_params,
1739 advertising_data,
1740 scan_response_data,
1741 tx_power: None,
1742 enabled: true,
1743 duration,
1744 expire_time: None,
1745 },
1746 );
1747 // Schedule it as the next one and rotate.
1748 self.adv_queue.push_front(id);
1749 self.run_rotate();
1750
1751 id
1752 }
1753
stop_advertising_set(&mut self, adv_id: i32)1754 fn stop_advertising_set(&mut self, adv_id: i32) {
1755 let current_id = self.current_id();
1756 let Some(info) = self.adv_info.remove(&adv_id) else {
1757 warn!("stop_advertising_set: Unknown adv_id {}", adv_id);
1758 return;
1759 };
1760 self.callbacks.get_by_id_mut(info.callback_id).map(|cb| {
1761 cb.on_advertising_set_stopped(info.id);
1762 });
1763 if current_id == Some(info.id) {
1764 self.run_rotate();
1765 }
1766 }
1767
get_own_address(&mut self, _adv_id: i32)1768 fn get_own_address(&mut self, _adv_id: i32) {
1769 error!("get_own_address is not supported in software rotation stack");
1770 }
1771
enable_advertising_set( &mut self, adv_id: i32, enable: bool, duration: i32, max_ext_adv_events: i32, )1772 fn enable_advertising_set(
1773 &mut self,
1774 adv_id: i32,
1775 enable: bool,
1776 duration: i32,
1777 max_ext_adv_events: i32,
1778 ) {
1779 if self.suspend_mode != SuspendMode::Normal {
1780 return;
1781 }
1782
1783 let current_id = self.current_id();
1784 let Some(info) = self.adv_info.get_mut(&adv_id) else {
1785 warn!("enable_advertising_set: Unknown adv_id {}", adv_id);
1786 return;
1787 };
1788
1789 if max_ext_adv_events != 0 {
1790 warn!("max_ext_adv_events is not supported in software rotation stack, ignored");
1791 }
1792
1793 info.enabled = enable;
1794 // We won't really call enable() to LibBluetooth so calculate the expire time right now.
1795 info.expire_time = gen_expire_time_from_now(duration);
1796 // This actually won't be used as the expire_time is already determined.
1797 // Still fill it in to keep the data updated.
1798 info.duration = duration;
1799
1800 if enable && !self.adv_queue.contains(&info.id) && current_id != Some(info.id) {
1801 // The adv was not enabled and not in the queue. Invoke callback and queue it.
1802 self.callbacks.get_by_id_mut(info.callback_id).map(|cb| {
1803 cb.on_advertising_enabled(info.id, false, AdvertisingStatus::Success);
1804 });
1805 self.adv_queue.push_back(info.id);
1806 if self.is_stopped() {
1807 self.start_next_advertising();
1808 }
1809 } else if !enable && current_id == Some(info.id) {
1810 self.run_rotate();
1811 }
1812 }
1813
set_advertising_data(&mut self, adv_id: i32, data: AdvertiseData)1814 fn set_advertising_data(&mut self, adv_id: i32, data: AdvertiseData) {
1815 if self.suspend_mode != SuspendMode::Normal {
1816 return;
1817 }
1818
1819 let current_id = self.current_id();
1820 let device_name = self.get_adapter_name();
1821 let Some(info) = self.adv_info.get_mut(&adv_id) else {
1822 warn!("set_advertising_data: Unknown adv_id {}", adv_id);
1823 return;
1824 };
1825 let data = data.make_with(&device_name);
1826 if !AdvertiseData::validate_raw_data(info.advertising_params.is_legacy, &data) {
1827 warn!("set_advertising_data {}: invalid advertise data to update", adv_id);
1828 return;
1829 }
1830 info.advertising_data = data;
1831 self.callbacks.get_by_id_mut(info.callback_id).map(|cb| {
1832 cb.on_advertising_data_set(info.id, AdvertisingStatus::Success);
1833 });
1834
1835 if current_id == Some(info.id) {
1836 self.run_rotate();
1837 }
1838 }
1839
set_raw_adv_data(&mut self, adv_id: i32, data: Vec<u8>)1840 fn set_raw_adv_data(&mut self, adv_id: i32, data: Vec<u8>) {
1841 if self.suspend_mode != SuspendMode::Normal {
1842 return;
1843 }
1844
1845 let current_id = self.current_id();
1846 let Some(info) = self.adv_info.get_mut(&adv_id) else {
1847 warn!("set_raw_adv_data: Unknown adv_id {}", adv_id);
1848 return;
1849 };
1850 if !AdvertiseData::validate_raw_data(info.advertising_params.is_legacy, &data) {
1851 warn!("set_raw_adv_data {}: invalid raw advertise data to update", adv_id);
1852 return;
1853 }
1854 info.advertising_data = data;
1855 self.callbacks.get_by_id_mut(info.callback_id).map(|cb| {
1856 cb.on_advertising_data_set(info.id, AdvertisingStatus::Success);
1857 });
1858
1859 if current_id == Some(info.id) {
1860 self.run_rotate();
1861 }
1862 }
1863
set_scan_response_data(&mut self, adv_id: i32, data: AdvertiseData)1864 fn set_scan_response_data(&mut self, adv_id: i32, data: AdvertiseData) {
1865 if self.suspend_mode != SuspendMode::Normal {
1866 return;
1867 }
1868
1869 let current_id = self.current_id();
1870 let device_name = self.get_adapter_name();
1871 let Some(info) = self.adv_info.get_mut(&adv_id) else {
1872 warn!("set_scan_response_data: Unknown adv_id {}", adv_id);
1873 return;
1874 };
1875 let data = data.make_with(&device_name);
1876 if !AdvertiseData::validate_raw_data(info.advertising_params.is_legacy, &data) {
1877 warn!("set_scan_response_data {}: invalid scan response to update", adv_id);
1878 return;
1879 }
1880 info.scan_response_data = data;
1881 self.callbacks.get_by_id_mut(info.callback_id).map(|cb| {
1882 cb.on_scan_response_data_set(info.id, AdvertisingStatus::Success);
1883 });
1884
1885 if current_id == Some(info.id) {
1886 self.run_rotate();
1887 }
1888 }
1889
set_advertising_parameters(&mut self, adv_id: i32, params: AdvertisingSetParameters)1890 fn set_advertising_parameters(&mut self, adv_id: i32, params: AdvertisingSetParameters) {
1891 if self.suspend_mode != SuspendMode::Normal {
1892 return;
1893 }
1894
1895 let current_id = self.current_id();
1896 let Some(info) = self.adv_info.get_mut(&adv_id) else {
1897 warn!("set_advertising_parameters: Unknown adv_id {}", adv_id);
1898 return;
1899 };
1900 info.advertising_params = params;
1901 let Some(tx_power) = info.tx_power else {
1902 error!("set_advertising_parameters: tx_power is None! Is this called before adv has started?");
1903 return;
1904 };
1905 self.callbacks.get_by_id_mut(info.callback_id).map(|cb| {
1906 cb.on_advertising_parameters_updated(info.id, tx_power, AdvertisingStatus::Success);
1907 });
1908
1909 if current_id == Some(info.id) {
1910 self.run_rotate();
1911 }
1912 }
1913
set_periodic_advertising_parameters( &mut self, _adv_id: i32, _parameters: PeriodicAdvertisingParameters, )1914 fn set_periodic_advertising_parameters(
1915 &mut self,
1916 _adv_id: i32,
1917 _parameters: PeriodicAdvertisingParameters,
1918 ) {
1919 error!("set_periodic_advertising_parameters is not supported in software rotation stack");
1920 }
1921
set_periodic_advertising_data(&mut self, _adv_id: i32, _data: AdvertiseData)1922 fn set_periodic_advertising_data(&mut self, _adv_id: i32, _data: AdvertiseData) {
1923 error!("set_periodic_advertising_data is not supported in software rotation stack");
1924 }
1925
set_periodic_advertising_enable(&mut self, _adv_id: i32, _enable: bool, _include_adi: bool)1926 fn set_periodic_advertising_enable(&mut self, _adv_id: i32, _enable: bool, _include_adi: bool) {
1927 error!("set_periodic_advertising_enable is not supported in software rotation stack");
1928 }
1929 }
1930
1931 impl BtifGattAdvCallbacks for SoftwareRotationAdvertiseManagerImpl {
on_advertising_set_started( &mut self, reg_id: i32, adv_id: u8, tx_power: i8, status: AdvertisingStatus, )1932 fn on_advertising_set_started(
1933 &mut self,
1934 reg_id: i32,
1935 adv_id: u8,
1936 tx_power: i8,
1937 status: AdvertisingStatus,
1938 ) {
1939 debug!(
1940 "on_advertising_set_started(): reg_id = {}, advertiser_id = {}, tx_power = {}, status = {:?}",
1941 reg_id, adv_id, tx_power, status
1942 );
1943
1944 // Unregister if it's unexpected.
1945 match &self.state {
1946 SoftwareRotationAdvertiseState::Pending(pending_id) if pending_id == ®_id => {}
1947 _ => {
1948 error!(
1949 "Unexpected on_advertising_set_started reg_id = {}, adv_id = {}, status = {:?}",
1950 reg_id, adv_id, status
1951 );
1952 if status == AdvertisingStatus::Success {
1953 self.gatt.lock().unwrap().advertiser.unregister(adv_id);
1954 }
1955 return;
1956 }
1957 }
1958 // Switch out from the pending state.
1959 self.state = if status != AdvertisingStatus::Success {
1960 warn!("on_advertising_set_started failed: reg_id = {}, status = {:?}", reg_id, status);
1961 SoftwareRotationAdvertiseState::Stopped
1962 } else {
1963 let txl = self.tx.clone();
1964 SoftwareRotationAdvertiseState::Advertising(
1965 reg_id,
1966 adv_id,
1967 tokio::spawn(async move {
1968 loop {
1969 time::sleep(SOFTWARE_ROTATION_INTERVAL).await;
1970 let _ = txl
1971 .send(Message::AdvertiserActions(AdvertiserActions::RunRotate))
1972 .await;
1973 }
1974 }),
1975 )
1976 };
1977
1978 // 1. Handle on_advertising_set_started callback if it's the first time it started
1979 // 2. Stop advertising if it's removed or disabled
1980 // 3. Disable or remove the advertiser if it failed
1981 if let Some(info) = self.adv_info.get_mut(®_id) {
1982 if info.tx_power.is_none() {
1983 // tx_power is none means it's the first time this advertiser started.
1984 if status != AdvertisingStatus::Success {
1985 self.callbacks.get_by_id_mut(info.callback_id).map(|cb| {
1986 cb.on_advertising_set_started(info.id, INVALID_ADV_ID, 0, status);
1987 });
1988 self.adv_info.remove(®_id);
1989 } else {
1990 info.tx_power = Some(tx_power.into());
1991 info.expire_time = gen_expire_time_from_now(info.duration);
1992 self.callbacks.get_by_id_mut(info.callback_id).map(|cb| {
1993 cb.on_advertising_set_started(info.id, info.id, tx_power.into(), status);
1994 });
1995 }
1996 } else {
1997 // Not the first time. This means we are not able to report the failure through
1998 // on_advertising_set_started if it failed. Disable it instead in that case.
1999 if status != AdvertisingStatus::Success {
2000 info.enabled = false;
2001 // Push to the queue and let refresh_queue handle the disabled callback.
2002 self.adv_queue.push_back(reg_id);
2003 } else {
2004 if !info.enabled {
2005 self.stop_current_advertising();
2006 }
2007 }
2008 }
2009 } else {
2010 self.stop_current_advertising();
2011 }
2012
2013 // Rotate again if the next advertiser is new. We need to consume all
2014 // "first time" advertiser before suspended to make sure callbacks are sent.
2015 if let Some(id) = self.adv_queue.front() {
2016 if let Some(info) = self.adv_info.get(id) {
2017 if info.tx_power.is_none() {
2018 self.run_rotate();
2019 return;
2020 }
2021 }
2022 }
2023
2024 // We're fine to suspend since there is no advertiser pending callback.
2025 if self.suspend_mode != SuspendMode::Normal {
2026 self.stop_current_advertising();
2027 self.set_suspend_mode(SuspendMode::Suspended);
2028 return;
2029 }
2030
2031 // If the current advertiser is stopped for some reason, schedule the next one.
2032 if self.is_stopped() {
2033 self.refresh_queue();
2034 self.start_next_advertising();
2035 }
2036 }
2037
on_advertising_enabled(&mut self, _adv_id: u8, _enabled: bool, _status: AdvertisingStatus)2038 fn on_advertising_enabled(&mut self, _adv_id: u8, _enabled: bool, _status: AdvertisingStatus) {
2039 error!("Unexpected on_advertising_enabled in software rotation stack");
2040 }
2041
on_advertising_data_set(&mut self, _adv_id: u8, _status: AdvertisingStatus)2042 fn on_advertising_data_set(&mut self, _adv_id: u8, _status: AdvertisingStatus) {
2043 error!("Unexpected on_advertising_data_set in software rotation stack");
2044 }
2045
on_scan_response_data_set(&mut self, _adv_id: u8, _status: AdvertisingStatus)2046 fn on_scan_response_data_set(&mut self, _adv_id: u8, _status: AdvertisingStatus) {
2047 error!("Unexpected on_scan_response_data_set in software rotation stack");
2048 }
2049
on_advertising_parameters_updated( &mut self, _adv_id: u8, _tx_power: i8, _status: AdvertisingStatus, )2050 fn on_advertising_parameters_updated(
2051 &mut self,
2052 _adv_id: u8,
2053 _tx_power: i8,
2054 _status: AdvertisingStatus,
2055 ) {
2056 error!("Unexpected on_advertising_parameters_updated in software rotation stack");
2057 }
2058
on_periodic_advertising_parameters_updated( &mut self, _adv_id: u8, _status: AdvertisingStatus, )2059 fn on_periodic_advertising_parameters_updated(
2060 &mut self,
2061 _adv_id: u8,
2062 _status: AdvertisingStatus,
2063 ) {
2064 error!("Unexpected on_periodic_advertising_parameters_updated in software rotation stack");
2065 }
2066
on_periodic_advertising_data_set(&mut self, _adv_id: u8, _status: AdvertisingStatus)2067 fn on_periodic_advertising_data_set(&mut self, _adv_id: u8, _status: AdvertisingStatus) {
2068 error!("Unexpected on_periodic_advertising_data_set in software rotation stack");
2069 }
2070
on_periodic_advertising_enabled( &mut self, _adv_id: u8, _enabled: bool, _status: AdvertisingStatus, )2071 fn on_periodic_advertising_enabled(
2072 &mut self,
2073 _adv_id: u8,
2074 _enabled: bool,
2075 _status: AdvertisingStatus,
2076 ) {
2077 error!("Unexpected on_periodic_advertising_enabled in software rotation stack");
2078 }
2079
on_own_address_read(&mut self, _adv_id: u8, _addr_type: u8, _address: RawAddress)2080 fn on_own_address_read(&mut self, _adv_id: u8, _addr_type: u8, _address: RawAddress) {
2081 error!("Unexpected on_own_address_read in software rotation stack");
2082 }
2083 }
2084
2085 #[cfg(test)]
2086 mod tests {
2087 use super::*;
2088 use std::iter::FromIterator;
2089
2090 #[test]
test_append_ad_data_clamped()2091 fn test_append_ad_data_clamped() {
2092 let mut bytes = Vec::<u8>::new();
2093 let mut ans = Vec::<u8>::new();
2094 ans.push(255);
2095 ans.push(102);
2096 ans.extend(Vec::<u8>::from_iter(0..254));
2097
2098 let payload = Vec::<u8>::from_iter(0..255);
2099 AdvertiseData::append_adv_data(&mut bytes, 102, &payload);
2100 assert_eq!(bytes, ans);
2101 }
2102
2103 #[test]
test_append_ad_data_multiple()2104 fn test_append_ad_data_multiple() {
2105 let mut bytes = Vec::<u8>::new();
2106
2107 let payload = vec![0 as u8, 1, 2, 3, 4];
2108 AdvertiseData::append_adv_data(&mut bytes, 100, &payload);
2109 AdvertiseData::append_adv_data(&mut bytes, 101, &[0]);
2110 assert_eq!(bytes, vec![6 as u8, 100, 0, 1, 2, 3, 4, 2, 101, 0]);
2111 }
2112
2113 #[test]
test_append_service_uuids()2114 fn test_append_service_uuids() {
2115 let mut bytes = Vec::<u8>::new();
2116 let uuid_16 = Uuid::from_string("0000fef3-0000-1000-8000-00805f9b34fb").unwrap();
2117 let uuids = vec![uuid_16.clone()];
2118 let exp_16: Vec<u8> = vec![3, 0x3, 0xf3, 0xfe];
2119 AdvertiseData::append_service_uuids(&mut bytes, &uuids);
2120 assert_eq!(bytes, exp_16);
2121
2122 let mut bytes = Vec::<u8>::new();
2123 let uuid_32 = Uuid::from_string("00112233-0000-1000-8000-00805f9b34fb").unwrap();
2124 let uuids = vec![uuid_32.clone()];
2125 let exp_32: Vec<u8> = vec![5, 0x5, 0x33, 0x22, 0x11, 0x0];
2126 AdvertiseData::append_service_uuids(&mut bytes, &uuids);
2127 assert_eq!(bytes, exp_32);
2128
2129 let mut bytes = Vec::<u8>::new();
2130 let uuid_128 = Uuid::from_string("00010203-0405-0607-0809-0a0b0c0d0e0f").unwrap();
2131 let uuids = vec![uuid_128.clone()];
2132 let exp_128: Vec<u8> = vec![
2133 17, 0x7, 0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0,
2134 ];
2135 AdvertiseData::append_service_uuids(&mut bytes, &uuids);
2136 assert_eq!(bytes, exp_128);
2137
2138 let mut bytes = Vec::<u8>::new();
2139 let uuids = vec![uuid_16, uuid_32, uuid_128];
2140 let exp_bytes: Vec<u8> =
2141 [exp_16.as_slice(), exp_32.as_slice(), exp_128.as_slice()].concat();
2142 AdvertiseData::append_service_uuids(&mut bytes, &uuids);
2143 assert_eq!(bytes, exp_bytes);
2144
2145 // Interleaved UUIDs.
2146 let mut bytes = Vec::<u8>::new();
2147 let uuid_16_2 = Uuid::from_string("0000aabb-0000-1000-8000-00805f9b34fb").unwrap();
2148 let uuids = vec![uuid_16, uuid_128, uuid_16_2, uuid_32];
2149 let exp_16: Vec<u8> = vec![5, 0x3, 0xf3, 0xfe, 0xbb, 0xaa];
2150 let exp_bytes: Vec<u8> =
2151 [exp_16.as_slice(), exp_32.as_slice(), exp_128.as_slice()].concat();
2152 AdvertiseData::append_service_uuids(&mut bytes, &uuids);
2153 assert_eq!(bytes, exp_bytes);
2154 }
2155
2156 #[test]
test_append_solicit_uuids()2157 fn test_append_solicit_uuids() {
2158 let mut bytes = Vec::<u8>::new();
2159 let uuid_16 = Uuid::from_string("0000fef3-0000-1000-8000-00805f9b34fb").unwrap();
2160 let uuid_32 = Uuid::from_string("00112233-0000-1000-8000-00805f9b34fb").unwrap();
2161 let uuid_128 = Uuid::from_string("00010203-0405-0607-0809-0a0b0c0d0e0f").unwrap();
2162 let uuids = vec![uuid_16, uuid_32, uuid_128];
2163 let exp_16: Vec<u8> = vec![3, 0x14, 0xf3, 0xfe];
2164 let exp_32: Vec<u8> = vec![5, 0x1f, 0x33, 0x22, 0x11, 0x0];
2165 let exp_128: Vec<u8> = vec![
2166 17, 0x15, 0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1,
2167 0x0,
2168 ];
2169 let exp_bytes: Vec<u8> =
2170 [exp_16.as_slice(), exp_32.as_slice(), exp_128.as_slice()].concat();
2171 AdvertiseData::append_solicit_uuids(&mut bytes, &uuids);
2172 assert_eq!(bytes, exp_bytes);
2173 }
2174
2175 #[test]
test_append_service_data_good_id()2176 fn test_append_service_data_good_id() {
2177 let mut bytes = Vec::<u8>::new();
2178 let uuid_str = "0000fef3-0000-1000-8000-00805f9b34fb".to_string();
2179 let mut service_data = HashMap::new();
2180 let data: Vec<u8> = vec![
2181 0x4A, 0x17, 0x23, 0x41, 0x39, 0x37, 0x45, 0x11, 0x16, 0x60, 0x1D, 0xB8, 0x27, 0xA2,
2182 0xEF, 0xAA, 0xFE, 0x58, 0x04, 0x9F, 0xE3, 0x8F, 0xD0, 0x04, 0x29, 0x4F, 0xC2,
2183 ];
2184 service_data.insert(uuid_str, data.clone());
2185 let mut exp_bytes: Vec<u8> = vec![30, 0x16, 0xf3, 0xfe];
2186 exp_bytes.extend(data);
2187 AdvertiseData::append_service_data(&mut bytes, &service_data);
2188 assert_eq!(bytes, exp_bytes);
2189 }
2190
2191 #[test]
test_append_service_data_bad_id()2192 fn test_append_service_data_bad_id() {
2193 let mut bytes = Vec::<u8>::new();
2194 let uuid_str = "fef3".to_string();
2195 let mut service_data = HashMap::new();
2196 let data: Vec<u8> = vec![
2197 0x4A, 0x17, 0x23, 0x41, 0x39, 0x37, 0x45, 0x11, 0x16, 0x60, 0x1D, 0xB8, 0x27, 0xA2,
2198 0xEF, 0xAA, 0xFE, 0x58, 0x04, 0x9F, 0xE3, 0x8F, 0xD0, 0x04, 0x29, 0x4F, 0xC2,
2199 ];
2200 service_data.insert(uuid_str, data.clone());
2201 let exp_bytes: Vec<u8> = Vec::new();
2202 AdvertiseData::append_service_data(&mut bytes, &service_data);
2203 assert_eq!(bytes, exp_bytes);
2204 }
2205
2206 #[test]
test_append_device_name()2207 fn test_append_device_name() {
2208 let mut bytes = Vec::<u8>::new();
2209 let complete_name = "abc".to_string();
2210 let exp_bytes: Vec<u8> = vec![5, 0x9, 0x61, 0x62, 0x63, 0x0];
2211 AdvertiseData::append_device_name(&mut bytes, &complete_name);
2212 assert_eq!(bytes, exp_bytes);
2213
2214 let mut bytes = Vec::<u8>::new();
2215 let shortened_name = "abcdefghijklmnopqrstuvwxyz7890".to_string();
2216 let exp_bytes: Vec<u8> = vec![
2217 28, 0x8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
2218 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x0,
2219 ];
2220 AdvertiseData::append_device_name(&mut bytes, &shortened_name);
2221 assert_eq!(bytes, exp_bytes);
2222 }
2223
2224 #[test]
test_append_manufacturer_data()2225 fn test_append_manufacturer_data() {
2226 let mut bytes = Vec::<u8>::new();
2227 let manufacturer_data = HashMap::from([(0x0123 as u16, vec![0, 1, 2])]);
2228 let exp_bytes: Vec<u8> = vec![6, 0xff, 0x23, 0x01, 0x0, 0x1, 0x2];
2229 AdvertiseData::append_manufacturer_data(&mut bytes, &manufacturer_data);
2230 assert_eq!(bytes, exp_bytes);
2231 }
2232
2233 #[test]
test_append_transport_discovery_data()2234 fn test_append_transport_discovery_data() {
2235 let mut bytes = Vec::<u8>::new();
2236 let transport_discovery_data = vec![vec![0, 1, 2]];
2237 let exp_bytes: Vec<u8> = vec![0x4, 0x26, 0x0, 0x1, 0x2];
2238 AdvertiseData::append_transport_discovery_data(&mut bytes, &transport_discovery_data);
2239 assert_eq!(bytes, exp_bytes);
2240
2241 let mut bytes = Vec::<u8>::new();
2242 let transport_discovery_data = vec![vec![1, 2, 4, 8], vec![0xa, 0xb]];
2243 let exp_bytes: Vec<u8> = vec![0x5, 0x26, 0x1, 0x2, 0x4, 0x8, 3, 0x26, 0xa, 0xb];
2244 AdvertiseData::append_transport_discovery_data(&mut bytes, &transport_discovery_data);
2245 assert_eq!(bytes, exp_bytes);
2246 }
2247 }
2248