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