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