1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_advertising_manager.h"
16
17 #include <map>
18
19 #include "pw_bluetooth_sapphire/internal/host/common/advertising_data.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
23 #include "pw_bluetooth_sapphire/internal/host/hci/connection.h"
24 #include "pw_bluetooth_sapphire/internal/host/hci/fake_local_address_delegate.h"
25 #include "pw_bluetooth_sapphire/internal/host/hci/fake_low_energy_connection.h"
26 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
27 #include "pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"
28 #include "pw_bluetooth_sapphire/internal/host/transport/control_packets.h"
29 #include "pw_bluetooth_sapphire/internal/host/transport/error.h"
30
31 namespace bt {
32 using testing::FakeController;
33
34 namespace gap {
35 namespace {
36 namespace pwemb = pw::bluetooth::emboss;
37 using TestingBase = bt::testing::FakeDispatcherControllerTest<FakeController>;
38
39 constexpr size_t kDefaultMaxAdSize = 23;
40 constexpr size_t kDefaultFakeAdSize = 20;
41 constexpr AdvertisingInterval kTestInterval = AdvertisingInterval::FAST1;
42
43 const DeviceAddress kPublicAddress(DeviceAddress::Type::kLEPublic,
44 {0x01, 0, 0, 0, 0, 0});
45 const DeviceAddress kRandomAddress(DeviceAddress::Type::kLERandom,
46 {0x55, 0x44, 0x33, 0x22, 0x11, 0x00});
47
NopConnectCallback(AdvertisementId,std::unique_ptr<hci::Connection>)48 void NopConnectCallback(AdvertisementId, std::unique_ptr<hci::Connection>) {}
49
50 struct AdvertisementStatus {
51 AdvertisingData data;
52 AdvertisingData scan_rsp;
53 bool anonymous;
54 uint16_t interval_min;
55 uint16_t interval_max;
56 bool extended_pdu;
57 hci::LowEnergyAdvertiser::ConnectionCallback connect_cb;
58 };
59
60 // LowEnergyAdvertiser for testing purposes:
61 // - Reports mas_ad_size supported
62 // - Actually just accepts all ads and stores them in ad_store
63 class FakeLowEnergyAdvertiser final : public hci::LowEnergyAdvertiser {
64 public:
FakeLowEnergyAdvertiser(const hci::Transport::WeakPtr & hci,std::unordered_map<DeviceAddress,AdvertisementStatus> * ad_store)65 FakeLowEnergyAdvertiser(
66 const hci::Transport::WeakPtr& hci,
67 std::unordered_map<DeviceAddress, AdvertisementStatus>* ad_store)
68 : hci::LowEnergyAdvertiser(hci, kDefaultMaxAdSize),
69 ads_(ad_store),
70 hci_(hci) {
71 PW_CHECK(ads_);
72 }
73
74 ~FakeLowEnergyAdvertiser() override = default;
75
MaxAdvertisements() const76 size_t MaxAdvertisements() const override { return 1; }
77
AllowsRandomAddressChange() const78 bool AllowsRandomAddressChange() const override { return true; }
79
StartAdvertising(const DeviceAddress & address,const AdvertisingData & data,const AdvertisingData & scan_rsp,const AdvertisingOptions & options,ConnectionCallback connect_callback,hci::ResultFunction<> result_callback)80 void StartAdvertising(const DeviceAddress& address,
81 const AdvertisingData& data,
82 const AdvertisingData& scan_rsp,
83 const AdvertisingOptions& options,
84 ConnectionCallback connect_callback,
85 hci::ResultFunction<> result_callback) override {
86 if (pending_error_.is_error()) {
87 result_callback(pending_error_);
88 pending_error_ = fit::ok();
89 return;
90 }
91
92 fit::result<HostError> result =
93 CanStartAdvertising(address, data, scan_rsp, options, connect_callback);
94 if (result.is_error()) {
95 result_callback(ToResult(result.error_value()));
96 return;
97 }
98
99 AdvertisementStatus new_status;
100 data.Copy(&new_status.data);
101 scan_rsp.Copy(&new_status.scan_rsp);
102 new_status.connect_cb = std::move(connect_callback);
103 new_status.interval_min = options.interval.min();
104 new_status.interval_max = options.interval.max();
105 new_status.anonymous = options.anonymous;
106 new_status.extended_pdu = options.extended_pdu;
107 ads_->emplace(address, std::move(new_status));
108 result_callback(fit::ok());
109 }
110
StopAdvertising(const DeviceAddress & address,bool)111 void StopAdvertising(const DeviceAddress& address, bool) override {
112 ads_->erase(address);
113 }
114
OnIncomingConnection(hci_spec::ConnectionHandle handle,pwemb::ConnectionRole role,const DeviceAddress & peer_address,const hci_spec::LEConnectionParameters &)115 void OnIncomingConnection(hci_spec::ConnectionHandle handle,
116 pwemb::ConnectionRole role,
117 const DeviceAddress& peer_address,
118 const hci_spec::LEConnectionParameters&) override {
119 // Right now, we call the first callback, because we can't call any other
120 // ones.
121 // TODO(jamuraa): make this send it to the correct callback once we can
122 // determine which one that is.
123 const auto& cb = ads_->begin()->second.connect_cb;
124 if (cb) {
125 cb(std::make_unique<hci::testing::FakeLowEnergyConnection>(
126 handle, ads_->begin()->first, peer_address, role, hci_));
127 }
128 }
129
130 // Sets this faker up to send an error back from the next StartAdvertising
131 // call. Set to success to disable a previously called error.
ErrorOnNext(hci::Result<> error_status)132 void ErrorOnNext(hci::Result<> error_status) {
133 pending_error_ = error_status;
134 }
135
136 private:
BuildEnablePacket(const DeviceAddress &,pw::bluetooth::emboss::GenericEnableParam,bool)137 hci::CommandPacket BuildEnablePacket(
138 const DeviceAddress&,
139 pw::bluetooth::emboss::GenericEnableParam,
140 bool) override {
141 return hci::CommandPacket::New<
142 pwemb::LESetExtendedAdvertisingEnableDataWriter>(
143 hci_spec::kLESetExtendedAdvertisingEnable);
144 }
145
BuildSetAdvertisingParams(const DeviceAddress &,const AdvertisingEventProperties &,pwemb::LEOwnAddressType,const hci::AdvertisingIntervalRange &,bool)146 std::optional<hci::CommandPacket> BuildSetAdvertisingParams(
147 const DeviceAddress&,
148 const AdvertisingEventProperties&,
149 pwemb::LEOwnAddressType,
150 const hci::AdvertisingIntervalRange&,
151 bool) override {
152 return std::nullopt;
153 }
154
BuildSetAdvertisingData(const DeviceAddress &,const AdvertisingData &,AdvFlags,bool)155 std::vector<hci::CommandPacket> BuildSetAdvertisingData(
156 const DeviceAddress&, const AdvertisingData&, AdvFlags, bool) override {
157 hci::CommandPacket packet =
158 hci::CommandPacket::New<pwemb::LESetAdvertisingDataCommandWriter>(
159 hci_spec::kLESetAdvertisingData);
160
161 std::vector<hci::CommandPacket> packets;
162 packets.push_back(std::move(packet));
163 return packets;
164 }
165
BuildUnsetAdvertisingData(const DeviceAddress &,bool)166 hci::CommandPacket BuildUnsetAdvertisingData(const DeviceAddress&,
167 bool) override {
168 return hci::CommandPacket::New<pwemb::LESetAdvertisingDataCommandWriter>(
169 hci_spec::kLESetAdvertisingData);
170 }
171
BuildSetScanResponse(const DeviceAddress &,const AdvertisingData &,bool)172 std::vector<hci::CommandPacket> BuildSetScanResponse(const DeviceAddress&,
173 const AdvertisingData&,
174 bool) override {
175 hci::CommandPacket packet =
176 hci::CommandPacket::New<pwemb::LESetScanResponseDataCommandWriter>(
177 hci_spec::kLESetScanResponseData);
178
179 std::vector<hci::CommandPacket> packets;
180 packets.push_back(std::move(packet));
181 return packets;
182 }
183
BuildUnsetScanResponse(const DeviceAddress &,bool)184 hci::CommandPacket BuildUnsetScanResponse(const DeviceAddress&,
185 bool) override {
186 return hci::CommandPacket::New<pwemb::LESetScanResponseDataCommandWriter>(
187 hci_spec::kLESetScanResponseData);
188 }
189
BuildRemoveAdvertisingSet(const DeviceAddress &,bool)190 hci::CommandPacket BuildRemoveAdvertisingSet(const DeviceAddress&,
191 bool) override {
192 return hci::CommandPacket::New<pwemb::LERemoveAdvertisingSetCommandWriter>(
193 hci_spec::kLERemoveAdvertisingSet);
194 }
195
196 std::unordered_map<DeviceAddress, AdvertisementStatus>* ads_;
197 hci::Result<> pending_error_ = fit::ok();
198 hci::Transport::WeakPtr hci_;
199
200 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(FakeLowEnergyAdvertiser);
201 };
202
203 class LowEnergyAdvertisingManagerTest : public TestingBase {
204 public:
205 LowEnergyAdvertisingManagerTest() = default;
206 ~LowEnergyAdvertisingManagerTest() override = default;
207
208 protected:
SetUp()209 void SetUp() override {
210 TestingBase::SetUp();
211 InitializeACLDataChannel();
212
213 fake_address_delegate_.EnablePrivacy(true);
214 fake_address_delegate_.set_identity_address(kPublicAddress);
215 fake_address_delegate_.set_local_address(kRandomAddress);
216 MakeFakeAdvertiser();
217 MakeAdvertisingManager();
218 }
219
TearDown()220 void TearDown() override {
221 adv_mgr_ = nullptr;
222 advertiser_ = nullptr;
223 TestingBase::TearDown();
224 }
225
226 // Makes some fake advertising data of a specific |packed_size|
CreateFakeAdvertisingData(size_t packed_size=kDefaultFakeAdSize)227 AdvertisingData CreateFakeAdvertisingData(
228 size_t packed_size = kDefaultFakeAdSize) {
229 AdvertisingData result;
230 StaticByteBuffer buffer(
231 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08);
232 size_t bytes_left = packed_size;
233 while (bytes_left > 0) {
234 // Each field to take 10 bytes total, unless the next header (4 bytes)
235 // won't fit. In which case we add enough bytes to finish up.
236 size_t data_bytes = bytes_left < 14 ? (bytes_left - 4) : 6;
237 EXPECT_TRUE(result.SetManufacturerData(0xb000 + bytes_left,
238 buffer.view(0, data_bytes)));
239 bytes_left = packed_size - result.CalculateBlockSize();
240 }
241 return result;
242 }
243
GetErrorCallback()244 LowEnergyAdvertisingManager::AdvertisingStatusCallback GetErrorCallback() {
245 return [this](AdvertisementInstance instance, hci::Result<> status) {
246 EXPECT_EQ(kInvalidAdvertisementId, instance.id());
247 EXPECT_TRUE(status.is_error());
248 last_status_ = status;
249 };
250 }
251
GetSuccessCallback()252 LowEnergyAdvertisingManager::AdvertisingStatusCallback GetSuccessCallback() {
253 return [this](AdvertisementInstance instance, hci::Result<> status) {
254 EXPECT_NE(kInvalidAdvertisementId, instance.id());
255 EXPECT_EQ(fit::ok(), status);
256 last_instance_ = std::move(instance);
257 last_status_ = status;
258 };
259 }
260
MakeFakeAdvertiser()261 void MakeFakeAdvertiser() {
262 advertiser_ = std::make_unique<FakeLowEnergyAdvertiser>(
263 transport()->GetWeakPtr(), &ad_store_);
264 }
265
MakeAdvertisingManager()266 void MakeAdvertisingManager() {
267 adv_mgr_ = std::make_unique<LowEnergyAdvertisingManager>(
268 advertiser(), &fake_address_delegate_);
269 }
270
adv_mgr() const271 LowEnergyAdvertisingManager* adv_mgr() const { return adv_mgr_.get(); }
ad_store()272 const std::unordered_map<DeviceAddress, AdvertisementStatus>& ad_store() {
273 return ad_store_;
274 }
last_ad_id() const275 AdvertisementId last_ad_id() const { return last_instance_.id(); }
276
277 // Returns the currently active advertising state. This is useful for tests
278 // that want to verify advertising parameters when there is a single known
279 // advertisement. Returns nullptr if the number of advertisements are not
280 // equal to one.
current_adv() const281 const AdvertisementStatus* current_adv() const {
282 if (ad_store_.size() != 1u) {
283 return nullptr;
284 }
285 return &ad_store_.begin()->second;
286 }
287
288 // Returns and clears the last callback status. This resets the state to
289 // detect another callback.
last_status()290 std::optional<hci::Result<>> last_status() { return last_status_; }
291
advertiser() const292 FakeLowEnergyAdvertiser* advertiser() const { return advertiser_.get(); }
293
294 private:
295 hci::FakeLocalAddressDelegate fake_address_delegate_{dispatcher()};
296
297 // TODO(armansito): The address mapping is currently broken since the
298 // gap::LEAM always assigns the controller random address. Make this track
299 // each instance by instance ID instead once the layering issues have been
300 // fixed.
301 std::unordered_map<DeviceAddress, AdvertisementStatus> ad_store_;
302 AdvertisementInstance last_instance_;
303 std::optional<hci::Result<>> last_status_;
304 std::unique_ptr<FakeLowEnergyAdvertiser> advertiser_;
305 std::unique_ptr<LowEnergyAdvertisingManager> adv_mgr_;
306
307 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyAdvertisingManagerTest);
308 };
309
310 // Tests:
311 // - When the advertiser succeeds, the callback is called with the success
TEST_F(LowEnergyAdvertisingManagerTest,Success)312 TEST_F(LowEnergyAdvertisingManagerTest, Success) {
313 EXPECT_FALSE(adv_mgr()->advertising());
314 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
315 AdvertisingData(),
316 /*connect_callback=*/nullptr,
317 kTestInterval,
318 /*extended_pdu=*/false,
319 /*anonymous=*/false,
320 /*include_tx_power_level=*/false,
321 /*address_type=*/std::nullopt,
322 GetSuccessCallback());
323
324 RunUntilIdle();
325
326 EXPECT_TRUE(last_status());
327 ASSERT_EQ(1u, ad_store().size());
328 EXPECT_TRUE(adv_mgr()->advertising());
329
330 // Verify that the advertiser uses the requested local address.
331 EXPECT_EQ(kRandomAddress, ad_store().begin()->first);
332 }
333
TEST_F(LowEnergyAdvertisingManagerTest,DataSize)334 TEST_F(LowEnergyAdvertisingManagerTest, DataSize) {
335 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
336 AdvertisingData(),
337 /*connect_callback=*/nullptr,
338 kTestInterval,
339 /*extended_pdu=*/true,
340 /*anonymous=*/false,
341 /*include_tx_power_level=*/false,
342 /*address_type=*/std::nullopt,
343 GetSuccessCallback());
344
345 RunUntilIdle();
346
347 EXPECT_TRUE(last_status());
348 EXPECT_EQ(1u, ad_store().size());
349
350 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(kDefaultMaxAdSize + 1),
351 AdvertisingData(),
352 /*connect_callback=*/nullptr,
353 kTestInterval,
354 /*extended_pdu=*/true,
355 /*anonymous=*/false,
356 /*include_tx_power_level=*/false,
357 /*address_type=*/std::nullopt,
358 GetErrorCallback());
359
360 RunUntilIdle();
361
362 EXPECT_TRUE(last_status());
363 EXPECT_EQ(1u, ad_store().size());
364 }
365
366 // TODO: https://fxbug.dev/42083437 - Revise this test to use multiple
367 // advertising instances when multi-advertising is supported.
368 // - Stopping one that is registered stops it in the advertiser
369 // (and stops the right address)
370 // - Stopping an advertisement that isn't registered returns false
TEST_F(LowEnergyAdvertisingManagerTest,RegisterUnregister)371 TEST_F(LowEnergyAdvertisingManagerTest, RegisterUnregister) {
372 EXPECT_FALSE(adv_mgr()->StopAdvertising(kInvalidAdvertisementId));
373
374 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
375 AdvertisingData(),
376 /*connect_callback=*/nullptr,
377 kTestInterval,
378 /*extended_pdu=*/false,
379 /*anonymous=*/false,
380 /*include_tx_power_level=*/false,
381 /*address_type=*/std::nullopt,
382 GetSuccessCallback());
383
384 RunUntilIdle();
385
386 EXPECT_TRUE(last_status());
387 EXPECT_EQ(1u, ad_store().size());
388 EXPECT_TRUE(adv_mgr()->advertising());
389
390 EXPECT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
391 EXPECT_TRUE(ad_store().empty());
392 EXPECT_FALSE(adv_mgr()->advertising());
393
394 EXPECT_FALSE(adv_mgr()->StopAdvertising(last_ad_id()));
395 EXPECT_TRUE(ad_store().empty());
396 }
397
398 // - When the advertiser returns an error, we return an error
TEST_F(LowEnergyAdvertisingManagerTest,AdvertiserError)399 TEST_F(LowEnergyAdvertisingManagerTest, AdvertiserError) {
400 advertiser()->ErrorOnNext(
401 ToResult(pwemb::StatusCode::INVALID_HCI_COMMAND_PARAMETERS));
402
403 EXPECT_FALSE(adv_mgr()->advertising());
404 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
405 AdvertisingData(),
406 /*connect_callback=*/nullptr,
407 kTestInterval,
408 /*extended_pdu=*/false,
409 /*anonymous=*/false,
410 /*include_tx_power_level=*/false,
411 /*address_type=*/std::nullopt,
412 GetErrorCallback());
413 RunUntilIdle();
414
415 EXPECT_TRUE(last_status());
416 EXPECT_FALSE(adv_mgr()->advertising());
417 }
418
419 // - It calls the connectable callback correctly when connected to
TEST_F(LowEnergyAdvertisingManagerTest,ConnectCallback)420 TEST_F(LowEnergyAdvertisingManagerTest, ConnectCallback) {
421 std::unique_ptr<hci::LowEnergyConnection> link;
422 AdvertisementId advertised_id = kInvalidAdvertisementId;
423
424 auto connect_cb = [&](AdvertisementId connected_id,
425 std::unique_ptr<hci::LowEnergyConnection> cb_link) {
426 link = std::move(cb_link);
427 EXPECT_EQ(advertised_id, connected_id);
428 };
429 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
430 AdvertisingData(),
431 connect_cb,
432 kTestInterval,
433 /*extended_pdu=*/false,
434 /*anonymous=*/false,
435 /*include_tx_power_level=*/false,
436 /*address_type=*/std::nullopt,
437 GetSuccessCallback());
438
439 RunUntilIdle();
440
441 EXPECT_TRUE(last_status());
442 advertised_id = last_ad_id();
443
444 DeviceAddress peer_address(DeviceAddress::Type::kLEPublic,
445 {3, 2, 1, 1, 2, 3});
446 advertiser()->OnIncomingConnection(1,
447 pwemb::ConnectionRole::PERIPHERAL,
448 peer_address,
449 hci_spec::LEConnectionParameters());
450 RunUntilIdle();
451 ASSERT_TRUE(link);
452
453 // Make sure that the link has the correct local and peer addresses
454 // assigned.
455 EXPECT_EQ(kRandomAddress, link->local_address());
456 EXPECT_EQ(peer_address, link->peer_address());
457 }
458
459 // - Error: Connectable and Anonymous at the same time
TEST_F(LowEnergyAdvertisingManagerTest,ConnectAdvertiseError)460 TEST_F(LowEnergyAdvertisingManagerTest, ConnectAdvertiseError) {
461 auto connect_cb = [](AdvertisementId,
462 std::unique_ptr<hci::LowEnergyConnection>) {};
463
464 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
465 AdvertisingData(),
466 connect_cb,
467 kTestInterval,
468 /*extended_pdu=*/false,
469 /*anonymous=*/true,
470 /*include_tx_power_level=*/false,
471 /*address_type=*/std::nullopt,
472 GetErrorCallback());
473
474 EXPECT_TRUE(last_status());
475 }
476
477 // Passes the values for the data on. (anonymous, data, scan_rsp)
TEST_F(LowEnergyAdvertisingManagerTest,SendsCorrectData)478 TEST_F(LowEnergyAdvertisingManagerTest, SendsCorrectData) {
479 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
480 CreateFakeAdvertisingData(/*packed_size=*/21),
481 /*connect_callback=*/nullptr,
482 kTestInterval,
483 /*extended_pdu=*/false,
484 /*anonymous=*/false,
485 /*include_tx_power_level=*/false,
486 /*address_type=*/std::nullopt,
487 GetSuccessCallback());
488
489 RunUntilIdle();
490
491 EXPECT_TRUE(last_status());
492 EXPECT_EQ(1u, ad_store().size());
493
494 auto ad_status = &ad_store().begin()->second;
495
496 AdvertisingData expected_ad = CreateFakeAdvertisingData();
497 AdvertisingData expected_scan_rsp =
498 CreateFakeAdvertisingData(/*packed_size=*/21);
499 EXPECT_EQ(expected_ad, ad_status->data);
500 EXPECT_EQ(expected_scan_rsp, ad_status->scan_rsp);
501 EXPECT_EQ(false, ad_status->anonymous);
502 EXPECT_EQ(nullptr, ad_status->connect_cb);
503 }
504
505 // Test that the AdvertisingInterval values map to the spec defined constants
506 // (NOTE: this might change in the future in favor of a more advanced policy
507 // for managing the intervals; for now they get mapped to recommended values
508 // from Vol 3, Part C, Appendix A).
TEST_F(LowEnergyAdvertisingManagerTest,ConnectableAdvertisingIntervals)509 TEST_F(LowEnergyAdvertisingManagerTest, ConnectableAdvertisingIntervals) {
510 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
511 CreateFakeAdvertisingData(/*packed_size=*/21),
512 NopConnectCallback,
513 AdvertisingInterval::FAST1,
514 /*extended_pdu=*/false,
515 /*anonymous=*/false,
516 /*include_tx_power_level=*/false,
517 /*address_type=*/std::nullopt,
518 GetSuccessCallback());
519 RunUntilIdle();
520 ASSERT_TRUE(last_status());
521 ASSERT_TRUE(current_adv());
522 EXPECT_EQ(kLEAdvertisingFastIntervalMin1, current_adv()->interval_min);
523 EXPECT_EQ(kLEAdvertisingFastIntervalMax1, current_adv()->interval_max);
524 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
525
526 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
527 CreateFakeAdvertisingData(/*packed_size=*/21),
528 NopConnectCallback,
529 AdvertisingInterval::FAST2,
530 /*extended_pdu=*/false,
531 /*anonymous=*/false,
532 /*include_tx_power_level=*/false,
533 /*address_type=*/std::nullopt,
534 GetSuccessCallback());
535 RunUntilIdle();
536 ASSERT_TRUE(last_status());
537 ASSERT_TRUE(current_adv());
538 EXPECT_EQ(kLEAdvertisingFastIntervalMin2, current_adv()->interval_min);
539 EXPECT_EQ(kLEAdvertisingFastIntervalMax2, current_adv()->interval_max);
540 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
541
542 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
543 CreateFakeAdvertisingData(/*packed_size=*/21),
544 NopConnectCallback,
545 AdvertisingInterval::SLOW,
546 /*extended_pdu=*/false,
547 /*anonymous=*/false,
548 /*include_tx_power_level=*/false,
549 /*address_type=*/std::nullopt,
550 GetSuccessCallback());
551 RunUntilIdle();
552 ASSERT_TRUE(last_status());
553 ASSERT_TRUE(current_adv());
554 EXPECT_EQ(kLEAdvertisingSlowIntervalMin, current_adv()->interval_min);
555 EXPECT_EQ(kLEAdvertisingSlowIntervalMax, current_adv()->interval_max);
556 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
557 }
558
TEST_F(LowEnergyAdvertisingManagerTest,NonConnectableAdvertisingIntervals)559 TEST_F(LowEnergyAdvertisingManagerTest, NonConnectableAdvertisingIntervals) {
560 AdvertisingData fake_ad = CreateFakeAdvertisingData();
561 AdvertisingData scan_rsp = CreateFakeAdvertisingData(21 /* size of ad */);
562
563 // We expect FAST1 to fall back to FAST2 due to specification recommendation
564 // (Vol 3, Part C, Appendix A) and lack of support for non-connectable
565 // advertising with FAST1 parameters on certain controllers.
566 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
567 CreateFakeAdvertisingData(/*packed_size=*/21),
568 /*connect_callback=*/nullptr,
569 AdvertisingInterval::FAST1,
570 /*extended_pdu=*/false,
571 /*anonymous=*/false,
572 /*include_tx_power_level=*/false,
573 /*address_type=*/std::nullopt,
574 GetSuccessCallback());
575 RunUntilIdle();
576 ASSERT_TRUE(last_status());
577 ASSERT_TRUE(current_adv());
578 EXPECT_EQ(kLEAdvertisingFastIntervalMin2, current_adv()->interval_min);
579 EXPECT_EQ(kLEAdvertisingFastIntervalMax2, current_adv()->interval_max);
580 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
581
582 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
583 CreateFakeAdvertisingData(/*packed_size=*/21),
584 /*connect_callback=*/nullptr,
585 AdvertisingInterval::FAST2,
586 /*extended_pdu=*/false,
587 /*anonymous=*/false,
588 /*include_tx_power_level=*/false,
589 /*address_type=*/std::nullopt,
590 GetSuccessCallback());
591 RunUntilIdle();
592 ASSERT_TRUE(last_status());
593 ASSERT_TRUE(current_adv());
594 EXPECT_EQ(kLEAdvertisingFastIntervalMin2, current_adv()->interval_min);
595 EXPECT_EQ(kLEAdvertisingFastIntervalMax2, current_adv()->interval_max);
596 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
597
598 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
599 CreateFakeAdvertisingData(/*packed_size=*/21),
600 /*connect_callback=*/nullptr,
601 AdvertisingInterval::SLOW,
602 /*extended_pdu=*/false,
603 /*anonymous=*/false,
604 /*include_tx_power_level=*/false,
605 /*address_type=*/std::nullopt,
606 GetSuccessCallback());
607 RunUntilIdle();
608 ASSERT_TRUE(last_status());
609 ASSERT_TRUE(current_adv());
610 EXPECT_EQ(kLEAdvertisingSlowIntervalMin, current_adv()->interval_min);
611 EXPECT_EQ(kLEAdvertisingSlowIntervalMax, current_adv()->interval_max);
612 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
613 }
614
TEST_F(LowEnergyAdvertisingManagerTest,AdvertisePublicAddress)615 TEST_F(LowEnergyAdvertisingManagerTest, AdvertisePublicAddress) {
616 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
617 CreateFakeAdvertisingData(/*packed_size=*/21),
618 NopConnectCallback,
619 AdvertisingInterval::FAST1,
620 /*extended_pdu=*/false,
621 /*anonymous=*/false,
622 /*include_tx_power_level=*/false,
623 DeviceAddress::Type::kLEPublic,
624 GetSuccessCallback());
625 RunUntilIdle();
626 ASSERT_TRUE(last_status());
627 ASSERT_EQ(1u, ad_store().size());
628 EXPECT_TRUE(adv_mgr()->advertising());
629
630 // Verify that the advertiser uses the requested local address.
631 EXPECT_EQ(kPublicAddress, ad_store().begin()->first);
632 }
633
TEST_F(LowEnergyAdvertisingManagerTest,AdvertiseRandomAddress)634 TEST_F(LowEnergyAdvertisingManagerTest, AdvertiseRandomAddress) {
635 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
636 CreateFakeAdvertisingData(/*packed_size=*/21),
637 NopConnectCallback,
638 AdvertisingInterval::FAST1,
639 /*extended_pdu=*/false,
640 /*anonymous=*/false,
641 /*include_tx_power_level=*/false,
642 /*address_type=*/std::nullopt,
643 GetSuccessCallback());
644 RunUntilIdle();
645 ASSERT_TRUE(last_status());
646 ASSERT_EQ(1u, ad_store().size());
647 EXPECT_TRUE(adv_mgr()->advertising());
648
649 // Verify that the advertiser uses the requested local address.
650 EXPECT_EQ(kRandomAddress, ad_store().begin()->first);
651 }
652
TEST_F(LowEnergyAdvertisingManagerTest,DestroyingInstanceStopsAdvertisement)653 TEST_F(LowEnergyAdvertisingManagerTest, DestroyingInstanceStopsAdvertisement) {
654 {
655 AdvertisementInstance instance;
656 adv_mgr()->StartAdvertising(AdvertisingData(),
657 AdvertisingData(),
658 /*connect_callback=*/nullptr,
659 AdvertisingInterval::FAST1,
660 /*extended_pdu=*/false,
661 /*anonymous=*/false,
662 /*include_tx_power_level=*/false,
663 /*address_type=*/std::nullopt,
664 [&](AdvertisementInstance i, auto status) {
665 ASSERT_EQ(fit::ok(), status);
666 instance = std::move(i);
667 });
668 RunUntilIdle();
669 EXPECT_TRUE(adv_mgr()->advertising());
670
671 // Destroying |instance| should stop the advertisement.
672 }
673
674 RunUntilIdle();
675 EXPECT_FALSE(adv_mgr()->advertising());
676 }
677
TEST_F(LowEnergyAdvertisingManagerTest,MovingIntoInstanceStopsAdvertisement)678 TEST_F(LowEnergyAdvertisingManagerTest, MovingIntoInstanceStopsAdvertisement) {
679 AdvertisementInstance instance;
680 adv_mgr()->StartAdvertising(AdvertisingData(),
681 AdvertisingData(),
682 /*connect_callback=*/nullptr,
683 AdvertisingInterval::FAST1,
684 /*extended_pdu=*/false,
685 /*anonymous=*/false,
686 /*include_tx_power_level=*/false,
687 /*address_type=*/std::nullopt,
688 [&](AdvertisementInstance i, auto status) {
689 ASSERT_EQ(fit::ok(), status);
690 instance = std::move(i);
691 });
692 RunUntilIdle();
693 EXPECT_TRUE(adv_mgr()->advertising());
694
695 // Destroying |instance| by invoking the move assignment operator should
696 // stop the advertisement.
697 instance = {};
698 RunUntilIdle();
699 EXPECT_FALSE(adv_mgr()->advertising());
700 }
701
TEST_F(LowEnergyAdvertisingManagerTest,MovingInstanceTransfersOwnershipOfAdvertisement)702 TEST_F(LowEnergyAdvertisingManagerTest,
703 MovingInstanceTransfersOwnershipOfAdvertisement) {
704 auto instance = std::make_unique<AdvertisementInstance>();
705 adv_mgr()->StartAdvertising(AdvertisingData(),
706 AdvertisingData(),
707 /*connect_callback=*/nullptr,
708 AdvertisingInterval::FAST1,
709 /*extended_pdu=*/false,
710 /*anonymous=*/false,
711 /*include_tx_power_level=*/false,
712 /*address_type=*/std::nullopt,
713 [&](AdvertisementInstance i, auto status) {
714 ASSERT_EQ(fit::ok(), status);
715 *instance = std::move(i);
716 });
717 RunUntilIdle();
718 EXPECT_TRUE(adv_mgr()->advertising());
719
720 // Moving |instance| should transfer the ownership of the advertisement
721 // (assignment).
722 {
723 AdvertisementInstance move_assigned_instance = std::move(*instance);
724
725 // Explicitly clearing the old instance should have no effect.
726 *instance = {};
727 RunUntilIdle();
728 EXPECT_TRUE(adv_mgr()->advertising());
729
730 *instance = std::move(move_assigned_instance);
731 }
732
733 // Advertisement should not stop when |move_assigned_instance| goes out of
734 // scope as it no longer owns the advertisement.
735 RunUntilIdle();
736 EXPECT_TRUE(adv_mgr()->advertising());
737
738 // Moving |instance| should transfer the ownership of the advertisement
739 // (move-constructor).
740 {
741 AdvertisementInstance move_constructed_instance(std::move(*instance));
742
743 // Explicitly destroying the old instance should have no effect.
744 instance.reset();
745 RunUntilIdle();
746 EXPECT_TRUE(adv_mgr()->advertising());
747 }
748
749 // Advertisement should stop when |move_constructed_instance| goes out of
750 // scope.
751 RunUntilIdle();
752 EXPECT_FALSE(adv_mgr()->advertising());
753 }
754
755 } // namespace
756 } // namespace gap
757 } // namespace bt
758