• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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