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 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 {
on_advertising_set_started( &mut self, reg_id: i32, advertiser_id: u8, tx_power: i8, status: AdvertisingStatus, )1206 fn on_advertising_set_started(
1207 &mut self,
1208 reg_id: i32,
1209 advertiser_id: u8,
1210 tx_power: i8,
1211 status: AdvertisingStatus,
1212 ) {
1213 debug!(
1214 "on_advertising_set_started(): reg_id = {}, advertiser_id = {}, tx_power = {}, status = {:?}",
1215 reg_id, advertiser_id, tx_power, status
1216 );
1217
1218 let s = if let Some(s) = self.sets.get_mut(®_id) {
1219 s
1220 } else {
1221 error!("AdvertisingSetInfo not found");
1222 // An unknown advertising set has started. Unregister it anyway.
1223 self.gatt.lock().unwrap().advertiser.unregister(advertiser_id);
1224 return;
1225 };
1226
1227 if s.is_stopped() {
1228 // The advertising set needs to be stopped. This could happen when |unregister_callback|
1229 // is called before an advertising becomes ready.
1230 self.gatt.lock().unwrap().advertiser.unregister(advertiser_id);
1231 self.sets.remove(®_id);
1232 return;
1233 }
1234
1235 s.set_adv_id(Some(advertiser_id.into()));
1236 s.set_enabled(status == AdvertisingStatus::Success);
1237
1238 if let Some(cb) = self.callbacks.get_by_id_mut(s.callback_id()) {
1239 cb.on_advertising_set_started(reg_id, advertiser_id.into(), tx_power.into(), status);
1240 }
1241
1242 if status != AdvertisingStatus::Success {
1243 warn!(
1244 "on_advertising_set_started(): failed! reg_id = {}, status = {:?}",
1245 reg_id, status
1246 );
1247 self.sets.remove(®_id);
1248 }
1249 }
1250
on_advertising_enabled(&mut self, adv_id: u8, enabled: bool, status: AdvertisingStatus)1251 fn on_advertising_enabled(&mut self, adv_id: u8, enabled: bool, status: AdvertisingStatus) {
1252 debug!(
1253 "on_advertising_enabled(): adv_id = {}, enabled = {}, status = {:?}",
1254 adv_id, enabled, status
1255 );
1256
1257 let advertiser_id: i32 = adv_id.into();
1258
1259 if let Some(s) = self.get_mut_by_advertiser_id(advertiser_id) {
1260 s.set_enabled(enabled);
1261 } else {
1262 return;
1263 }
1264
1265 let s = *self.get_by_advertiser_id(advertiser_id).unwrap();
1266 if let Some(cb) = self.get_callback(&s) {
1267 cb.on_advertising_enabled(advertiser_id, enabled, status);
1268 }
1269
1270 if self.suspend_mode() == SuspendMode::Suspending && self.enabled_sets().count() == 0 {
1271 self.set_suspend_mode(SuspendMode::Suspended);
1272 }
1273 }
1274
on_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus)1275 fn on_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus) {
1276 debug!("on_advertising_data_set(): adv_id = {}, status = {:?}", adv_id, status);
1277
1278 let advertiser_id: i32 = adv_id.into();
1279 if self.get_by_advertiser_id(advertiser_id).is_none() {
1280 return;
1281 }
1282 let s = *self.get_by_advertiser_id(advertiser_id).unwrap();
1283
1284 if let Some(cb) = self.get_callback(&s) {
1285 cb.on_advertising_data_set(advertiser_id, status);
1286 }
1287 }
1288
on_scan_response_data_set(&mut self, adv_id: u8, status: AdvertisingStatus)1289 fn on_scan_response_data_set(&mut self, adv_id: u8, status: AdvertisingStatus) {
1290 debug!("on_scan_response_data_set(): adv_id = {}, status = {:?}", adv_id, status);
1291
1292 let advertiser_id: i32 = adv_id.into();
1293 if self.get_by_advertiser_id(advertiser_id).is_none() {
1294 return;
1295 }
1296 let s = *self.get_by_advertiser_id(advertiser_id).unwrap();
1297
1298 if let Some(cb) = self.get_callback(&s) {
1299 cb.on_scan_response_data_set(advertiser_id, status);
1300 }
1301 }
1302
on_advertising_parameters_updated( &mut self, adv_id: u8, tx_power: i8, status: AdvertisingStatus, )1303 fn on_advertising_parameters_updated(
1304 &mut self,
1305 adv_id: u8,
1306 tx_power: i8,
1307 status: AdvertisingStatus,
1308 ) {
1309 debug!(
1310 "on_advertising_parameters_updated(): adv_id = {}, tx_power = {}, status = {:?}",
1311 adv_id, tx_power, status
1312 );
1313
1314 let advertiser_id: i32 = adv_id.into();
1315 if self.get_by_advertiser_id(advertiser_id).is_none() {
1316 return;
1317 }
1318 let s = *self.get_by_advertiser_id(advertiser_id).unwrap();
1319
1320 if let Some(cb) = self.get_callback(&s) {
1321 cb.on_advertising_parameters_updated(advertiser_id, tx_power.into(), status);
1322 }
1323 }
1324
on_periodic_advertising_parameters_updated( &mut self, adv_id: u8, status: AdvertisingStatus, )1325 fn on_periodic_advertising_parameters_updated(
1326 &mut self,
1327 adv_id: u8,
1328 status: AdvertisingStatus,
1329 ) {
1330 debug!(
1331 "on_periodic_advertising_parameters_updated(): adv_id = {}, status = {:?}",
1332 adv_id, status
1333 );
1334
1335 let advertiser_id: i32 = adv_id.into();
1336 if self.get_by_advertiser_id(advertiser_id).is_none() {
1337 return;
1338 }
1339 let s = *self.get_by_advertiser_id(advertiser_id).unwrap();
1340
1341 if let Some(cb) = self.get_callback(&s) {
1342 cb.on_periodic_advertising_parameters_updated(advertiser_id, status);
1343 }
1344 }
1345
on_periodic_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus)1346 fn on_periodic_advertising_data_set(&mut self, adv_id: u8, status: AdvertisingStatus) {
1347 debug!("on_periodic_advertising_data_set(): adv_id = {}, status = {:?}", adv_id, status);
1348
1349 let advertiser_id: i32 = adv_id.into();
1350 if self.get_by_advertiser_id(advertiser_id).is_none() {
1351 return;
1352 }
1353 let s = *self.get_by_advertiser_id(advertiser_id).unwrap();
1354
1355 if let Some(cb) = self.get_callback(&s) {
1356 cb.on_periodic_advertising_data_set(advertiser_id, status);
1357 }
1358 }
1359
on_periodic_advertising_enabled( &mut self, adv_id: u8, enabled: bool, status: AdvertisingStatus, )1360 fn on_periodic_advertising_enabled(
1361 &mut self,
1362 adv_id: u8,
1363 enabled: bool,
1364 status: AdvertisingStatus,
1365 ) {
1366 debug!(
1367 "on_periodic_advertising_enabled(): adv_id = {}, enabled = {}, status = {:?}",
1368 adv_id, enabled, status
1369 );
1370
1371 let advertiser_id: i32 = adv_id.into();
1372 if self.get_by_advertiser_id(advertiser_id).is_none() {
1373 return;
1374 }
1375 let s = *self.get_by_advertiser_id(advertiser_id).unwrap();
1376
1377 if let Some(cb) = self.get_callback(&s) {
1378 cb.on_periodic_advertising_enabled(advertiser_id, enabled, status);
1379 }
1380 }
1381
on_own_address_read(&mut self, adv_id: u8, addr_type: u8, address: RawAddress)1382 fn on_own_address_read(&mut self, adv_id: u8, addr_type: u8, address: RawAddress) {
1383 debug!(
1384 "on_own_address_read(): adv_id = {}, addr_type = {}, address = {}",
1385 adv_id,
1386 addr_type,
1387 DisplayAddress(&address)
1388 );
1389
1390 let advertiser_id: i32 = adv_id.into();
1391 if self.get_by_advertiser_id(advertiser_id).is_none() {
1392 return;
1393 }
1394 let s = *self.get_by_advertiser_id(advertiser_id).unwrap();
1395
1396 if let Some(cb) = self.get_callback(&s) {
1397 cb.on_own_address_read(advertiser_id, addr_type.into(), address);
1398 }
1399 }
1400 }
1401
1402 /// The underlying legacy advertising rotates every SOFTWARE_ROTATION_INTERVAL seconds.
1403 const SOFTWARE_ROTATION_INTERVAL: Duration = Duration::from_secs(2);
1404
1405 /// The ID of a software rotation advertising.
1406 ///
1407 /// From DBus API's perspective this is used as both Advertiser ID and Register ID.
1408 /// Unlike the extended advertising stack we can't propagate the LibBluetooth Advertiser ID to
1409 /// DBus clients because there can be at most 1 advertiser in LibBluetooth layer at the same time.
1410 pub type SoftwareRotationAdvertierId = i32;
1411
1412 struct SoftwareRotationAdvertiseInfo {
1413 id: SoftwareRotationAdvertierId,
1414 callback_id: u32,
1415
1416 advertising_params: AdvertisingSetParameters,
1417 advertising_data: Vec<u8>,
1418 scan_response_data: Vec<u8>,
1419
1420 /// Filled in on the first time the advertiser started.
1421 tx_power: Option<i32>,
1422
1423 /// True if it's advertising (from DBus client's perspective), false otherwise.
1424 enabled: bool,
1425 duration: i32,
1426 /// None means no timeout
1427 expire_time: Option<Instant>,
1428 }
1429
1430 enum SoftwareRotationAdvertiseState {
1431 /// No advertiser is running in LibBluetooth.
1432 Stopped,
1433 /// A StartAdvertisingSet call to LibBluetooth is pending.
1434 Pending(SoftwareRotationAdvertierId),
1435 /// An advertiser is running in LibBluetooth, i.e., an OnAdvertisingSetStarted is received.
1436 /// Parameters: ID, LibBluetooth BLE Advertiser ID, rotation timer handle
1437 Advertising(SoftwareRotationAdvertierId, u8, JoinHandle<()>),
1438 }
1439
1440 struct SoftwareRotationAdvertiseManagerImpl {
1441 callbacks: Callbacks<dyn IAdvertisingSetCallback + Send>,
1442 suspend_mode: SuspendMode,
1443 gatt: Arc<Mutex<Gatt>>,
1444 adapter: Arc<Mutex<Box<Bluetooth>>>,
1445 tx: Sender<Message>,
1446
1447 state: SoftwareRotationAdvertiseState,
1448 adv_info: HashMap<SoftwareRotationAdvertierId, SoftwareRotationAdvertiseInfo>,
1449 /// The enabled advertising sets to be rotate.
1450 /// When they are removed from the queue, OnAdvertisingEnabled needs to be sent.
1451 /// Note that the current advertiser running in LibBluetooth must *NOT* be in the queue.
1452 adv_queue: VecDeque<SoftwareRotationAdvertierId>,
1453 }
1454
1455 impl SoftwareRotationAdvertiseManagerImpl {
new( tx: Sender<Message>, gatt: Arc<Mutex<Gatt>>, adapter: Arc<Mutex<Box<Bluetooth>>>, ) -> Self1456 fn new(
1457 tx: Sender<Message>,
1458 gatt: Arc<Mutex<Gatt>>,
1459 adapter: Arc<Mutex<Box<Bluetooth>>>,
1460 ) -> Self {
1461 Self {
1462 callbacks: Callbacks::new(tx.clone(), Message::AdvertiserCallbackDisconnected),
1463 suspend_mode: SuspendMode::Normal,
1464 gatt,
1465 adapter,
1466 tx,
1467 state: SoftwareRotationAdvertiseState::Stopped,
1468 adv_info: HashMap::new(),
1469 adv_queue: VecDeque::new(),
1470 }
1471 }
1472 }
1473
1474 impl SoftwareRotationAdvertiseManagerImpl {
1475 /// Updates suspend mode.
set_suspend_mode(&mut self, suspend_mode: SuspendMode)1476 fn set_suspend_mode(&mut self, suspend_mode: SuspendMode) {
1477 if suspend_mode != self.suspend_mode {
1478 self.suspend_mode = suspend_mode.clone();
1479 self.callbacks.for_all_callbacks(|cb| {
1480 cb.on_suspend_mode_change(suspend_mode.clone());
1481 });
1482 }
1483 }
1484
get_adapter_name(&self) -> String1485 fn get_adapter_name(&self) -> String {
1486 self.adapter.lock().unwrap().get_name()
1487 }
1488
1489 /// Returns the ID of the advertiser running in LibBluetooth.
current_id(&self) -> Option<SoftwareRotationAdvertierId>1490 fn current_id(&self) -> Option<SoftwareRotationAdvertierId> {
1491 match &self.state {
1492 SoftwareRotationAdvertiseState::Pending(id) => Some(*id),
1493 SoftwareRotationAdvertiseState::Advertising(id, _, _) => Some(*id),
1494 SoftwareRotationAdvertiseState::Stopped => None,
1495 }
1496 }
1497
1498 /// Returns the minimum unoccupied ID from 0.
new_id(&mut self) -> SoftwareRotationAdvertierId1499 fn new_id(&mut self) -> SoftwareRotationAdvertierId {
1500 // The advertiser running in LibBluetooth may have been removed in this layer.
1501 // Avoid conflicting with it.
1502 let current_id = self.current_id();
1503 (0..)
1504 .find(|id| !self.adv_info.contains_key(id) && Some(*id) != current_id)
1505 .expect("There must be an unoccupied register ID")
1506 }
1507
is_pending(&self) -> bool1508 fn is_pending(&self) -> bool {
1509 matches!(&self.state, SoftwareRotationAdvertiseState::Pending(_))
1510 }
1511
is_stopped(&self) -> bool1512 fn is_stopped(&self) -> bool {
1513 matches!(&self.state, SoftwareRotationAdvertiseState::Stopped)
1514 }
1515
1516 /// Clears the removed or disabled advertisers from the queue and invokes callback.
refresh_queue(&mut self)1517 fn refresh_queue(&mut self) {
1518 let now = Instant::now();
1519 let adv_info = &mut self.adv_info;
1520 let callbacks = &mut self.callbacks;
1521 self.adv_queue.retain(|id| {
1522 let Some(info) = adv_info.get_mut(id) else {
1523 // This advertiser has been removed.
1524 return false;
1525 };
1526 if info.expire_time.map_or(false, |t| t < now) {
1527 // This advertiser has expired.
1528 info.enabled = false;
1529 if let Some(cb) = callbacks.get_by_id_mut(info.callback_id) {
1530 cb.on_advertising_enabled(info.id, false, AdvertisingStatus::Success);
1531 }
1532 }
1533 info.enabled
1534 });
1535 }
1536
stop_current_advertising(&mut self)1537 fn stop_current_advertising(&mut self) {
1538 match &self.state {
1539 SoftwareRotationAdvertiseState::Advertising(id, adv_id, handle) => {
1540 handle.abort();
1541 self.gatt.lock().unwrap().advertiser.unregister(*adv_id);
1542 self.adv_queue.push_back(*id);
1543 self.state = SoftwareRotationAdvertiseState::Stopped;
1544 }
1545 SoftwareRotationAdvertiseState::Pending(_) => {
1546 error!("stop_current_advertising: Unexpected Pending state");
1547 }
1548 SoftwareRotationAdvertiseState::Stopped => {}
1549 };
1550 }
1551
start_next_advertising(&mut self)1552 fn start_next_advertising(&mut self) {
1553 match &self.state {
1554 SoftwareRotationAdvertiseState::Stopped => {
1555 self.state = loop {
1556 let Some(id) = self.adv_queue.pop_front() else {
1557 break SoftwareRotationAdvertiseState::Stopped;
1558 };
1559 let Some(info) = self.adv_info.get(&id) else {
1560 error!("start_next_advertising: Unknown ID, which means queue is not refreshed!");
1561 continue;
1562 };
1563 self.gatt.lock().unwrap().advertiser.start_advertising_set(
1564 id,
1565 info.advertising_params.clone().into(),
1566 info.advertising_data.clone(),
1567 info.scan_response_data.clone(),
1568 Default::default(), // Unsupported periodic_parameters
1569 vec![], // Unsupported periodic_data
1570 0, // Set no timeout. Timeout is controlled in this layer.
1571 0, // Unsupported max_ext_adv_events
1572 );
1573 break SoftwareRotationAdvertiseState::Pending(id);
1574 }
1575 }
1576 SoftwareRotationAdvertiseState::Pending(_) => {
1577 error!("start_next_advertising: Unexpected Pending state");
1578 }
1579 SoftwareRotationAdvertiseState::Advertising(_, _, _) => {
1580 error!("start_next_advertising: Unexpected Advertising state");
1581 }
1582 };
1583 }
1584
run_rotate(&mut self)1585 fn run_rotate(&mut self) {
1586 if self.is_pending() {
1587 return;
1588 }
1589 let Some(current_id) = self.current_id() else {
1590 // State is Stopped. Try to start next one.
1591 self.refresh_queue();
1592 self.start_next_advertising();
1593 return;
1594 };
1595 // We are Advertising. Checks if the current advertiser is still allowed
1596 // to advertise, or if we should schedule the next one in the queue.
1597 let current_is_enabled = {
1598 let now = Instant::now();
1599 if let Some(info) = self.adv_info.get(¤t_id) {
1600 if info.enabled {
1601 info.expire_time.map_or(true, |t| t >= now)
1602 } else {
1603 false
1604 }
1605 } else {
1606 false
1607 }
1608 };
1609 if !current_is_enabled {
1610 // If current advertiser is not allowed to advertise,
1611 // stop it and then let |refresh_queue| handle the callback.
1612 self.stop_current_advertising();
1613 self.refresh_queue();
1614 self.start_next_advertising();
1615 } else {
1616 // Current advertiser is still enabled, refresh the other advertisers in the queue.
1617 self.refresh_queue();
1618 if self.adv_queue.is_empty() {
1619 // No need to rotate.
1620 } else {
1621 self.stop_current_advertising();
1622 self.start_next_advertising();
1623 }
1624 }
1625 }
1626 }
1627
1628 impl AdvertiseManagerOps for SoftwareRotationAdvertiseManagerImpl {
enter_suspend(&mut self)1629 fn enter_suspend(&mut self) {
1630 if self.suspend_mode != SuspendMode::Normal {
1631 return;
1632 }
1633
1634 self.set_suspend_mode(SuspendMode::Suspending);
1635 if self.is_pending() {
1636 // We will unregister it on_advertising_set_started and then set mode to suspended.
1637 return;
1638 }
1639 self.stop_current_advertising();
1640 self.set_suspend_mode(SuspendMode::Suspended);
1641 }
1642
exit_suspend(&mut self)1643 fn exit_suspend(&mut self) {
1644 if self.suspend_mode != SuspendMode::Suspended {
1645 return;
1646 }
1647 self.refresh_queue();
1648 self.start_next_advertising();
1649 self.set_suspend_mode(SuspendMode::Normal);
1650 }
1651
handle_action(&mut self, action: AdvertiserActions)1652 fn handle_action(&mut self, action: AdvertiserActions) {
1653 match action {
1654 AdvertiserActions::RunRotate => {
1655 if self.suspend_mode == SuspendMode::Normal {
1656 self.run_rotate();
1657 }
1658 }
1659 }
1660 }
1661 }
1662
1663 /// Generates expire time from now per the definition in IBluetoothAdvertiseManager
1664 ///
1665 /// None means never timeout.
gen_expire_time_from_now(duration: i32) -> Option<Instant>1666 fn gen_expire_time_from_now(duration: i32) -> Option<Instant> {
1667 let duration = clamp(duration, 0, 0xffff) as u64;
1668 if duration != 0 {
1669 Some(Instant::now() + Duration::from_millis(duration * 10))
1670 } else {
1671 None
1672 }
1673 }
1674
1675 impl IBluetoothAdvertiseManager for SoftwareRotationAdvertiseManagerImpl {
register_callback(&mut self, callback: Box<dyn IAdvertisingSetCallback + Send>) -> u321676 fn register_callback(&mut self, callback: Box<dyn IAdvertisingSetCallback + Send>) -> u32 {
1677 self.callbacks.add_callback(callback)
1678 }
1679
unregister_callback(&mut self, callback_id: u32) -> bool1680 fn unregister_callback(&mut self, callback_id: u32) -> bool {
1681 self.adv_info.retain(|_, info| info.callback_id != callback_id);
1682 let ret = self.callbacks.remove_callback(callback_id);
1683 if let Some(current_id) = self.current_id() {
1684 if !self.adv_info.contains_key(¤t_id) {
1685 self.run_rotate();
1686 }
1687 }
1688 ret
1689 }
1690
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, ) -> i321691 fn start_advertising_set(
1692 &mut self,
1693 advertising_params: AdvertisingSetParameters,
1694 advertising_data: AdvertiseData,
1695 scan_response_data: Option<AdvertiseData>,
1696 periodic_parameters: Option<PeriodicAdvertisingParameters>,
1697 periodic_data: Option<AdvertiseData>,
1698 duration: i32,
1699 max_ext_adv_events: i32,
1700 callback_id: u32,
1701 ) -> i32 {
1702 if self.suspend_mode != SuspendMode::Normal {
1703 return INVALID_REG_ID;
1704 }
1705
1706 let is_legacy = advertising_params.is_legacy;
1707 let device_name = self.get_adapter_name();
1708
1709 let advertising_data = advertising_data.make_with(&device_name);
1710 if !AdvertiseData::validate_raw_data(is_legacy, &advertising_data) {
1711 warn!("Failed to start advertising set with invalid advertising data");
1712 return INVALID_REG_ID;
1713 }
1714
1715 let scan_response_data =
1716 scan_response_data.map_or(vec![], |data| data.make_with(&device_name));
1717 if !AdvertiseData::validate_raw_data(is_legacy, &scan_response_data) {
1718 warn!("Failed to start advertising set with invalid scan response data");
1719 return INVALID_REG_ID;
1720 }
1721
1722 if periodic_parameters.is_some() {
1723 warn!("Periodic parameters is not supported in software rotation stack, ignored");
1724 }
1725 if periodic_data.is_some() {
1726 warn!("Periodic data is not supported in software rotation stack, ignored");
1727 }
1728 if max_ext_adv_events != 0 {
1729 warn!("max_ext_adv_events is not supported in software rotation stack, ignored");
1730 }
1731
1732 let id = self.new_id();
1733
1734 // expire_time will be determined on this advertiser is started at the first time.
1735 self.adv_info.insert(
1736 id,
1737 SoftwareRotationAdvertiseInfo {
1738 id,
1739 callback_id,
1740 advertising_params,
1741 advertising_data,
1742 scan_response_data,
1743 tx_power: None,
1744 enabled: true,
1745 duration,
1746 expire_time: None,
1747 },
1748 );
1749 // Schedule it as the next one and rotate.
1750 self.adv_queue.push_front(id);
1751 self.run_rotate();
1752
1753 id
1754 }
1755
stop_advertising_set(&mut self, adv_id: i32)1756 fn stop_advertising_set(&mut self, adv_id: i32) {
1757 let current_id = self.current_id();
1758 let Some(info) = self.adv_info.remove(&adv_id) else {
1759 warn!("stop_advertising_set: Unknown adv_id {}", adv_id);
1760 return;
1761 };
1762 if let Some(cb) = self.callbacks.get_by_id_mut(info.callback_id) {
1763 cb.on_advertising_set_stopped(info.id);
1764 }
1765 if current_id == Some(info.id) {
1766 self.run_rotate();
1767 }
1768 }
1769
get_own_address(&mut self, _adv_id: i32)1770 fn get_own_address(&mut self, _adv_id: i32) {
1771 error!("get_own_address is not supported in software rotation stack");
1772 }
1773
enable_advertising_set( &mut self, adv_id: i32, enable: bool, duration: i32, max_ext_adv_events: i32, )1774 fn enable_advertising_set(
1775 &mut self,
1776 adv_id: i32,
1777 enable: bool,
1778 duration: i32,
1779 max_ext_adv_events: i32,
1780 ) {
1781 if self.suspend_mode != SuspendMode::Normal {
1782 return;
1783 }
1784
1785 let current_id = self.current_id();
1786 let Some(info) = self.adv_info.get_mut(&adv_id) else {
1787 warn!("enable_advertising_set: Unknown adv_id {}", adv_id);
1788 return;
1789 };
1790
1791 if max_ext_adv_events != 0 {
1792 warn!("max_ext_adv_events is not supported in software rotation stack, ignored");
1793 }
1794
1795 info.enabled = enable;
1796 // We won't really call enable() to LibBluetooth so calculate the expire time right now.
1797 info.expire_time = gen_expire_time_from_now(duration);
1798 // This actually won't be used as the expire_time is already determined.
1799 // Still fill it in to keep the data updated.
1800 info.duration = duration;
1801
1802 if enable && !self.adv_queue.contains(&info.id) && current_id != Some(info.id) {
1803 // The adv was not enabled and not in the queue. Invoke callback and queue it.
1804 if let Some(cb) = self.callbacks.get_by_id_mut(info.callback_id) {
1805 cb.on_advertising_enabled(info.id, false, AdvertisingStatus::Success);
1806 }
1807 self.adv_queue.push_back(info.id);
1808 if self.is_stopped() {
1809 self.start_next_advertising();
1810 }
1811 } else if !enable && current_id == Some(info.id) {
1812 self.run_rotate();
1813 }
1814 }
1815
set_advertising_data(&mut self, adv_id: i32, data: AdvertiseData)1816 fn set_advertising_data(&mut self, adv_id: i32, data: AdvertiseData) {
1817 if self.suspend_mode != SuspendMode::Normal {
1818 return;
1819 }
1820
1821 let current_id = self.current_id();
1822 let device_name = self.get_adapter_name();
1823 let Some(info) = self.adv_info.get_mut(&adv_id) else {
1824 warn!("set_advertising_data: Unknown adv_id {}", adv_id);
1825 return;
1826 };
1827 let data = data.make_with(&device_name);
1828 if !AdvertiseData::validate_raw_data(info.advertising_params.is_legacy, &data) {
1829 warn!("set_advertising_data {}: invalid advertise data to update", adv_id);
1830 return;
1831 }
1832 info.advertising_data = data;
1833 if let Some(cb) = self.callbacks.get_by_id_mut(info.callback_id) {
1834 cb.on_advertising_data_set(info.id, AdvertisingStatus::Success);
1835 }
1836
1837 if current_id == Some(info.id) {
1838 self.run_rotate();
1839 }
1840 }
1841
set_raw_adv_data(&mut self, adv_id: i32, data: Vec<u8>)1842 fn set_raw_adv_data(&mut self, adv_id: i32, data: Vec<u8>) {
1843 if self.suspend_mode != SuspendMode::Normal {
1844 return;
1845 }
1846
1847 let current_id = self.current_id();
1848 let Some(info) = self.adv_info.get_mut(&adv_id) else {
1849 warn!("set_raw_adv_data: Unknown adv_id {}", adv_id);
1850 return;
1851 };
1852 if !AdvertiseData::validate_raw_data(info.advertising_params.is_legacy, &data) {
1853 warn!("set_raw_adv_data {}: invalid raw advertise data to update", adv_id);
1854 return;
1855 }
1856 info.advertising_data = data;
1857 if let Some(cb) = self.callbacks.get_by_id_mut(info.callback_id) {
1858 cb.on_advertising_data_set(info.id, AdvertisingStatus::Success);
1859 }
1860
1861 if current_id == Some(info.id) {
1862 self.run_rotate();
1863 }
1864 }
1865
set_scan_response_data(&mut self, adv_id: i32, data: AdvertiseData)1866 fn set_scan_response_data(&mut self, adv_id: i32, data: AdvertiseData) {
1867 if self.suspend_mode != SuspendMode::Normal {
1868 return;
1869 }
1870
1871 let current_id = self.current_id();
1872 let device_name = self.get_adapter_name();
1873 let Some(info) = self.adv_info.get_mut(&adv_id) else {
1874 warn!("set_scan_response_data: Unknown adv_id {}", adv_id);
1875 return;
1876 };
1877 let data = data.make_with(&device_name);
1878 if !AdvertiseData::validate_raw_data(info.advertising_params.is_legacy, &data) {
1879 warn!("set_scan_response_data {}: invalid scan response to update", adv_id);
1880 return;
1881 }
1882 info.scan_response_data = data;
1883 if let Some(cb) = self.callbacks.get_by_id_mut(info.callback_id) {
1884 cb.on_scan_response_data_set(info.id, AdvertisingStatus::Success);
1885 }
1886
1887 if current_id == Some(info.id) {
1888 self.run_rotate();
1889 }
1890 }
1891
set_advertising_parameters(&mut self, adv_id: i32, params: AdvertisingSetParameters)1892 fn set_advertising_parameters(&mut self, adv_id: i32, params: AdvertisingSetParameters) {
1893 if self.suspend_mode != SuspendMode::Normal {
1894 return;
1895 }
1896
1897 let current_id = self.current_id();
1898 let Some(info) = self.adv_info.get_mut(&adv_id) else {
1899 warn!("set_advertising_parameters: Unknown adv_id {}", adv_id);
1900 return;
1901 };
1902 info.advertising_params = params;
1903 let Some(tx_power) = info.tx_power else {
1904 error!("set_advertising_parameters: tx_power is None! Is this called before adv has started?");
1905 return;
1906 };
1907 if let Some(cb) = self.callbacks.get_by_id_mut(info.callback_id) {
1908 cb.on_advertising_parameters_updated(info.id, tx_power, AdvertisingStatus::Success);
1909 }
1910
1911 if current_id == Some(info.id) {
1912 self.run_rotate();
1913 }
1914 }
1915
set_periodic_advertising_parameters( &mut self, _adv_id: i32, _parameters: PeriodicAdvertisingParameters, )1916 fn set_periodic_advertising_parameters(
1917 &mut self,
1918 _adv_id: i32,
1919 _parameters: PeriodicAdvertisingParameters,
1920 ) {
1921 error!("set_periodic_advertising_parameters is not supported in software rotation stack");
1922 }
1923
set_periodic_advertising_data(&mut self, _adv_id: i32, _data: AdvertiseData)1924 fn set_periodic_advertising_data(&mut self, _adv_id: i32, _data: AdvertiseData) {
1925 error!("set_periodic_advertising_data is not supported in software rotation stack");
1926 }
1927
set_periodic_advertising_enable(&mut self, _adv_id: i32, _enable: bool, _include_adi: bool)1928 fn set_periodic_advertising_enable(&mut self, _adv_id: i32, _enable: bool, _include_adi: bool) {
1929 error!("set_periodic_advertising_enable is not supported in software rotation stack");
1930 }
1931 }
1932
1933 impl BtifGattAdvCallbacks for SoftwareRotationAdvertiseManagerImpl {
on_advertising_set_started( &mut self, reg_id: i32, adv_id: u8, tx_power: i8, status: AdvertisingStatus, )1934 fn on_advertising_set_started(
1935 &mut self,
1936 reg_id: i32,
1937 adv_id: u8,
1938 tx_power: i8,
1939 status: AdvertisingStatus,
1940 ) {
1941 debug!(
1942 "on_advertising_set_started(): reg_id = {}, advertiser_id = {}, tx_power = {}, status = {:?}",
1943 reg_id, adv_id, tx_power, status
1944 );
1945
1946 // Unregister if it's unexpected.
1947 match &self.state {
1948 SoftwareRotationAdvertiseState::Pending(pending_id) if pending_id == ®_id => {}
1949 _ => {
1950 error!(
1951 "Unexpected on_advertising_set_started reg_id = {}, adv_id = {}, status = {:?}",
1952 reg_id, adv_id, status
1953 );
1954 if status == AdvertisingStatus::Success {
1955 self.gatt.lock().unwrap().advertiser.unregister(adv_id);
1956 }
1957 return;
1958 }
1959 }
1960 // Switch out from the pending state.
1961 self.state = if status != AdvertisingStatus::Success {
1962 warn!("on_advertising_set_started failed: reg_id = {}, status = {:?}", reg_id, status);
1963 SoftwareRotationAdvertiseState::Stopped
1964 } else {
1965 let txl = self.tx.clone();
1966 SoftwareRotationAdvertiseState::Advertising(
1967 reg_id,
1968 adv_id,
1969 tokio::spawn(async move {
1970 loop {
1971 time::sleep(SOFTWARE_ROTATION_INTERVAL).await;
1972 let _ = txl
1973 .send(Message::AdvertiserActions(AdvertiserActions::RunRotate))
1974 .await;
1975 }
1976 }),
1977 )
1978 };
1979
1980 // 1. Handle on_advertising_set_started callback if it's the first time it started
1981 // 2. Stop advertising if it's removed or disabled
1982 // 3. Disable or remove the advertiser if it failed
1983 if let Some(info) = self.adv_info.get_mut(®_id) {
1984 if info.tx_power.is_none() {
1985 // tx_power is none means it's the first time this advertiser started.
1986 if status != AdvertisingStatus::Success {
1987 if let Some(cb) = self.callbacks.get_by_id_mut(info.callback_id) {
1988 cb.on_advertising_set_started(info.id, INVALID_ADV_ID, 0, status);
1989 }
1990 self.adv_info.remove(®_id);
1991 } else {
1992 info.tx_power = Some(tx_power.into());
1993 info.expire_time = gen_expire_time_from_now(info.duration);
1994 if let Some(cb) = self.callbacks.get_by_id_mut(info.callback_id) {
1995 cb.on_advertising_set_started(info.id, info.id, tx_power.into(), status);
1996 }
1997 }
1998 } else {
1999 // Not the first time. This means we are not able to report the failure through
2000 // on_advertising_set_started if it failed. Disable it instead in that case.
2001 if status != AdvertisingStatus::Success {
2002 info.enabled = false;
2003 // Push to the queue and let refresh_queue handle the disabled callback.
2004 self.adv_queue.push_back(reg_id);
2005 } else if !info.enabled {
2006 self.stop_current_advertising();
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_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_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];
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];
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];
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_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