• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "neighbor/inquiry.h"
18 
19 #include <gtest/gtest.h>
20 #include <unistd.h>
21 
22 #include <algorithm>
23 #include <chrono>
24 #include <future>
25 #include <map>
26 #include <memory>
27 
28 #include "common/bind.h"
29 #include "common/callback.h"
30 #include "hci/address.h"
31 #include "hci/class_of_device.h"
32 #include "hci/hci_layer.h"
33 #include "hci/hci_packets.h"
34 #include "os/thread.h"
35 #include "packet/raw_builder.h"
36 
37 namespace bluetooth {
38 namespace neighbor {
39 namespace {
40 
41 static const uint8_t kNumberPacketsReadyToReceive = 1;
42 
43 /**
44  * This structure reflects the current state of the bluetooth chip
45  * at any given time.
46  */
47 static const int8_t kInitialInquiryResponseTransmitPowerLevel = 123;
48 static const uint16_t kInitialInquiryScanInterval = 1111;
49 static const uint16_t kInitialInquiryScanWindow = 2222;
50 
51 struct HciRegister {
52   bool one_shot_inquiry_active;
53   bool periodic_inquiry_active;
54   int8_t inquiry_response_transmit_power_level;
55   uint16_t inquiry_scan_interval;
56   uint16_t inquiry_scan_window;
57   hci::InquiryScanType inquiry_scan_type;
58   hci::InquiryMode inquiry_mode;
59   uint8_t inquiry_length;
60   uint8_t num_responses;
61   uint16_t min_period_length;
62   uint16_t max_period_length;
63 } hci_register_{
64     .one_shot_inquiry_active = false,
65     .periodic_inquiry_active = false,
66     .inquiry_response_transmit_power_level = kInitialInquiryResponseTransmitPowerLevel,
67     .inquiry_scan_interval = kInitialInquiryScanInterval,
68     .inquiry_scan_window = kInitialInquiryScanWindow,
69     .inquiry_scan_type = hci::InquiryScanType::STANDARD,
70     .inquiry_mode = hci::InquiryMode::STANDARD,
71     .inquiry_length = 0,
72     .num_responses = 0,
73     .min_period_length = 0,
74     .max_period_length = 0,
75 };
76 
GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet)77 hci::PacketView<hci::kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
78   auto bytes = std::make_shared<std::vector<uint8_t>>();
79   hci::BitInserter i(*bytes);
80   bytes->reserve(packet->size());
81   packet->Serialize(i);
82   return packet::PacketView<packet::kLittleEndian>(bytes);
83 }
84 
85 class TestHciLayer : public hci::HciLayer {
86  public:
EnqueueCommand(std::unique_ptr<hci::CommandBuilder> command,common::ContextualOnceCallback<void (hci::CommandCompleteView)> on_complete)87   void EnqueueCommand(
88       std::unique_ptr<hci::CommandBuilder> command,
89       common::ContextualOnceCallback<void(hci::CommandCompleteView)> on_complete) override {
90     GetHandler()->Post(common::BindOnce(
91         &TestHciLayer::HandleCommand, common::Unretained(this), std::move(command), std::move(on_complete)));
92   }
93 
EnqueueCommand(std::unique_ptr<hci::CommandBuilder> command,common::ContextualOnceCallback<void (hci::CommandStatusView)> on_status)94   void EnqueueCommand(
95       std::unique_ptr<hci::CommandBuilder> command,
96       common::ContextualOnceCallback<void(hci::CommandStatusView)> on_status) override {
97     GetHandler()->Post(common::BindOnce(
98         &TestHciLayer::HandleStatus, common::Unretained(this), std::move(command), std::move(on_status)));
99   }
100 
HandleCommand(std::unique_ptr<hci::CommandBuilder> command_builder,common::ContextualOnceCallback<void (hci::CommandCompleteView)> on_complete)101   void HandleCommand(
102       std::unique_ptr<hci::CommandBuilder> command_builder,
103       common::ContextualOnceCallback<void(hci::CommandCompleteView)> on_complete) {
104     hci::CommandView command = hci::CommandView::Create(GetPacketView(std::move(command_builder)));
105     ASSERT_TRUE(command.IsValid());
106 
107     std::unique_ptr<packet::BasePacketBuilder> event_builder;
108     switch (command.GetOpCode()) {
109       case hci::OpCode::INQUIRY_CANCEL:
110         event_builder =
111             hci::InquiryCancelCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
112         hci_register_.one_shot_inquiry_active = false;
113         break;
114 
115       case hci::OpCode::PERIODIC_INQUIRY_MODE: {
116         auto inquiry = hci::PeriodicInquiryModeView::Create(hci::DiscoveryCommandView::Create(command));
117         ASSERT_TRUE(inquiry.IsValid());
118         event_builder =
119             hci::PeriodicInquiryModeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
120         hci_register_.periodic_inquiry_active = true;
121         hci_register_.inquiry_length = inquiry.GetInquiryLength();
122         hci_register_.num_responses = inquiry.GetNumResponses();
123         hci_register_.max_period_length = inquiry.GetMaxPeriodLength();
124         hci_register_.min_period_length = inquiry.GetMinPeriodLength();
125       } break;
126 
127       case hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE:
128         event_builder =
129             hci::ExitPeriodicInquiryModeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
130         hci_register_.periodic_inquiry_active = false;
131         break;
132 
133       case hci::OpCode::WRITE_INQUIRY_MODE:
134         event_builder =
135             hci::WriteInquiryModeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
136         {
137           auto view = hci::WriteInquiryModeView::Create(hci::DiscoveryCommandView::Create(command));
138           ASSERT_TRUE(view.IsValid());
139           hci_register_.inquiry_mode = view.GetInquiryMode();
140         }
141         break;
142 
143       case hci::OpCode::READ_INQUIRY_MODE:
144         event_builder = hci::ReadInquiryModeCompleteBuilder::Create(
145             kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS, hci_register_.inquiry_mode);
146         break;
147 
148       case hci::OpCode::WRITE_INQUIRY_SCAN_ACTIVITY:
149         event_builder =
150             hci::WriteInquiryScanActivityCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
151         {
152           auto view = hci::WriteInquiryScanActivityView::Create(hci::DiscoveryCommandView::Create(command));
153           ASSERT_TRUE(view.IsValid());
154           hci_register_.inquiry_scan_interval = view.GetInquiryScanInterval();
155           hci_register_.inquiry_scan_window = view.GetInquiryScanWindow();
156         }
157         break;
158 
159       case hci::OpCode::READ_INQUIRY_SCAN_ACTIVITY:
160         event_builder = hci::ReadInquiryScanActivityCompleteBuilder::Create(
161             kNumberPacketsReadyToReceive,
162             hci::ErrorCode::SUCCESS,
163             hci_register_.inquiry_scan_interval,
164             hci_register_.inquiry_scan_window);
165         break;
166 
167       case hci::OpCode::WRITE_INQUIRY_SCAN_TYPE:
168         event_builder =
169             hci::WriteInquiryScanTypeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
170         {
171           auto view = hci::WriteInquiryScanTypeView::Create(hci::DiscoveryCommandView::Create(command));
172           ASSERT_TRUE(view.IsValid());
173           hci_register_.inquiry_scan_type = view.GetInquiryScanType();
174         }
175         break;
176 
177       case hci::OpCode::READ_INQUIRY_SCAN_TYPE:
178         event_builder = hci::ReadInquiryScanTypeCompleteBuilder::Create(
179             kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS, hci_register_.inquiry_scan_type);
180         break;
181 
182       case hci::OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL:
183         event_builder = hci::ReadInquiryResponseTransmitPowerLevelCompleteBuilder::Create(
184             kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS, hci_register_.inquiry_response_transmit_power_level);
185         break;
186 
187       default:
188         LOG_INFO("Dropping unhandled command:%s", hci::OpCodeText(command.GetOpCode()).c_str());
189         return;
190     }
191     hci::EventView event = hci::EventView::Create(GetPacketView(std::move(event_builder)));
192     ASSERT_TRUE(event.IsValid());
193     hci::CommandCompleteView command_complete = hci::CommandCompleteView::Create(event);
194     ASSERT_TRUE(command_complete.IsValid());
195     on_complete.Invoke(std::move(command_complete));
196 
197     if (promise_sync_complete_ != nullptr) {
198       promise_sync_complete_->set_value(command.GetOpCode());
199     }
200   }
201 
HandleStatus(std::unique_ptr<hci::CommandBuilder> command_builder,common::ContextualOnceCallback<void (hci::CommandStatusView)> on_status)202   void HandleStatus(
203       std::unique_ptr<hci::CommandBuilder> command_builder,
204       common::ContextualOnceCallback<void(hci::CommandStatusView)> on_status) {
205     hci::CommandView command = hci::CommandView::Create(GetPacketView(std::move(command_builder)));
206     ASSERT_TRUE(command.IsValid());
207 
208     std::unique_ptr<packet::BasePacketBuilder> event_builder;
209     switch (command.GetOpCode()) {
210       case hci::OpCode::INQUIRY: {
211         auto inquiry = hci::InquiryView::Create(hci::DiscoveryCommandView::Create(command));
212         ASSERT_TRUE(inquiry.IsValid());
213         event_builder = hci::InquiryStatusBuilder::Create(hci::ErrorCode::SUCCESS, kNumberPacketsReadyToReceive);
214         hci_register_.one_shot_inquiry_active = true;
215         hci_register_.num_responses = inquiry.GetNumResponses();
216         hci_register_.inquiry_length = inquiry.GetInquiryLength();
217       } break;
218       default:
219         LOG_INFO("Dropping unhandled status expecting command:%s", hci::OpCodeText(command.GetOpCode()).c_str());
220         return;
221     }
222     hci::EventView event = hci::EventView::Create(GetPacketView(std::move(event_builder)));
223     ASSERT_TRUE(event.IsValid());
224     hci::CommandStatusView command_status = hci::CommandStatusView::Create(event);
225     ASSERT_TRUE(command_status.IsValid());
226     on_status.Invoke(std::move(command_status));
227 
228     if (promise_sync_complete_ != nullptr) {
229       promise_sync_complete_->set_value(command.GetOpCode());
230     }
231   }
232 
RegisterEventHandler(hci::EventCode event_code,common::ContextualCallback<void (hci::EventView)> event_handler)233   void RegisterEventHandler(
234       hci::EventCode event_code, common::ContextualCallback<void(hci::EventView)> event_handler) override {
235     switch (event_code) {
236       case hci::EventCode::INQUIRY_RESULT:
237         inquiry_result_callback_ = event_handler;
238         break;
239       case hci::EventCode::INQUIRY_RESULT_WITH_RSSI:
240         inquiry_result_with_rssi_callback_ = event_handler;
241         break;
242       case hci::EventCode::EXTENDED_INQUIRY_RESULT:
243         extended_inquiry_result_callback_ = event_handler;
244         break;
245       case hci::EventCode::INQUIRY_COMPLETE:
246         inquiry_complete_callback_ = event_handler;
247         break;
248       default:
249         ASSERT_TRUE(false) << "Unexpected event handler being registered";
250         break;
251     }
252   }
253 
UnregisterEventHandler(hci::EventCode event_code)254   void UnregisterEventHandler(hci::EventCode event_code) override {
255     if (hci_register_.one_shot_inquiry_active || hci_register_.periodic_inquiry_active) {
256       LOG_ERROR("Event handlers may not be unregistered until inquiry is stopped");
257       return;
258     }
259 
260     switch (event_code) {
261       case hci::EventCode::INQUIRY_RESULT:
262         inquiry_result_callback_ = {};
263         break;
264       case hci::EventCode::INQUIRY_RESULT_WITH_RSSI:
265         inquiry_result_with_rssi_callback_ = {};
266         break;
267       case hci::EventCode::EXTENDED_INQUIRY_RESULT:
268         extended_inquiry_result_callback_ = {};
269         break;
270       case hci::EventCode::INQUIRY_COMPLETE:
271         inquiry_complete_callback_ = {};
272         break;
273       default:
274         ASSERT_TRUE(false) << "Unexpected event handler being unregistered";
275         break;
276     }
277   }
278 
Synchronize(std::function<void ()> func,hci::OpCode op_code)279   void Synchronize(std::function<void()> func, hci::OpCode op_code) {
280     ASSERT_EQ(promise_sync_complete_, nullptr);
281     promise_sync_complete_ = new std::promise<hci::OpCode>();
282     auto future = promise_sync_complete_->get_future();
283     func();
284     auto result = future.wait_for(std::chrono::milliseconds(100));
285     ASSERT_EQ(std::future_status::ready, result);
286     ASSERT_EQ(op_code, future.get());
287     delete promise_sync_complete_;
288     promise_sync_complete_ = nullptr;
289   }
290 
InjectInquiryResult(std::unique_ptr<hci::InquiryResultBuilder> result)291   void InjectInquiryResult(std::unique_ptr<hci::InquiryResultBuilder> result) {
292     hci::EventView view = hci::EventView::Create(GetPacketView(std::move(result)));
293     ASSERT_TRUE(view.IsValid());
294     inquiry_result_callback_.Invoke(std::move(view));
295   }
296 
ListDependencies(ModuleList * list) const297   void ListDependencies(ModuleList* list) const {}
Start()298   void Start() override {}
Stop()299   void Stop() override {}
300 
301  private:
302   std::promise<hci::OpCode>* promise_sync_complete_{nullptr};
303 
304   common::ContextualCallback<void(hci::EventView)> inquiry_result_callback_;
305   common::ContextualCallback<void(hci::EventView)> inquiry_result_with_rssi_callback_;
306   common::ContextualCallback<void(hci::EventView)> extended_inquiry_result_callback_;
307   common::ContextualCallback<void(hci::EventView)> inquiry_complete_callback_;
308 };
309 
310 class InquiryTest : public ::testing::Test {
311  public:
Result(hci::InquiryResultView view)312   void Result(hci::InquiryResultView view) {
313     ASSERT_TRUE(view.size() >= sizeof(uint16_t));
314     promise_result_complete_->set_value(true);
315   }
316 
WaitForInquiryResult(std::function<void ()> func)317   void WaitForInquiryResult(std::function<void()> func) {
318     ASSERT_EQ(promise_result_complete_, nullptr);
319     promise_result_complete_ = new std::promise<bool>();
320     auto future = promise_result_complete_->get_future();
321     func();
322     future.wait();
323     delete promise_result_complete_;
324     promise_result_complete_ = nullptr;
325   }
326 
ResultWithRssi(hci::InquiryResultWithRssiView view)327   void ResultWithRssi(hci::InquiryResultWithRssiView view) {
328     ASSERT_TRUE(view.size() >= sizeof(uint16_t));
329   }
330 
ExtendedResult(hci::ExtendedInquiryResultView view)331   void ExtendedResult(hci::ExtendedInquiryResultView view) {
332     ASSERT_TRUE(view.size() >= sizeof(uint16_t));
333   }
334 
Complete(hci::ErrorCode status)335   void Complete(hci::ErrorCode status) {}
336 
337  protected:
SetUp()338   void SetUp() override {
339     test_hci_layer_ = new TestHciLayer;
340     fake_registry_.InjectTestModule(&hci::HciLayer::Factory, test_hci_layer_);
341     client_handler_ = fake_registry_.GetTestModuleHandler(&hci::HciLayer::Factory);
342     fake_registry_.Start<InquiryModule>(&thread_);
343 
344     inquiry_module_ = static_cast<InquiryModule*>(fake_registry_.GetModuleUnderTest(&InquiryModule::Factory));
345 
346     InquiryCallbacks inquiry_callbacks;
347     inquiry_callbacks.result = std::bind(&InquiryTest::Result, this, std::placeholders::_1);
348     inquiry_callbacks.result_with_rssi = std::bind(&InquiryTest::ResultWithRssi, this, std::placeholders::_1);
349     inquiry_callbacks.extended_result = std::bind(&InquiryTest::ExtendedResult, this, std::placeholders::_1);
350     inquiry_callbacks.complete = std::bind(&InquiryTest::Complete, this, std::placeholders::_1);
351     inquiry_module_->RegisterCallbacks(inquiry_callbacks);
352   }
353 
TearDown()354   void TearDown() override {
355     inquiry_module_->UnregisterCallbacks();
356     fake_registry_.StopAll();
357   }
358 
359   TestModuleRegistry fake_registry_;
360   TestHciLayer* test_hci_layer_ = nullptr;
361   os::Thread& thread_ = fake_registry_.GetTestThread();
362   InquiryModule* inquiry_module_ = nullptr;
363   os::Handler* client_handler_ = nullptr;
364 
365   std::promise<bool>* promise_result_complete_{nullptr};
366 };
367 
TEST_F(InquiryTest,Module)368 TEST_F(InquiryTest, Module) {}
369 
TEST_F(InquiryTest,SetInquiryModes)370 TEST_F(InquiryTest, SetInquiryModes) {
371   test_hci_layer_->Synchronize(
372       [this] { inquiry_module_->SetInquiryWithRssiResultMode(); }, hci::OpCode::WRITE_INQUIRY_MODE);
373   ASSERT_EQ(hci_register_.inquiry_mode, hci::InquiryMode::RSSI);
374 
375   test_hci_layer_->Synchronize(
376       [this] { inquiry_module_->SetExtendedInquiryResultMode(); }, hci::OpCode::WRITE_INQUIRY_MODE);
377   ASSERT_EQ(hci_register_.inquiry_mode, hci::InquiryMode::RSSI_OR_EXTENDED);
378 
379   test_hci_layer_->Synchronize(
380       [this] { inquiry_module_->SetStandardInquiryResultMode(); }, hci::OpCode::WRITE_INQUIRY_MODE);
381   ASSERT_EQ(hci_register_.inquiry_mode, hci::InquiryMode::STANDARD);
382 }
383 
TEST_F(InquiryTest,SetScanType)384 TEST_F(InquiryTest, SetScanType) {
385   test_hci_layer_->Synchronize([this] { inquiry_module_->SetInterlacedScan(); }, hci::OpCode::WRITE_INQUIRY_SCAN_TYPE);
386   ASSERT_EQ(hci_register_.inquiry_scan_type, hci::InquiryScanType::INTERLACED);
387 
388   test_hci_layer_->Synchronize([this] { inquiry_module_->SetStandardScan(); }, hci::OpCode::WRITE_INQUIRY_SCAN_TYPE);
389   ASSERT_EQ(hci_register_.inquiry_scan_type, hci::InquiryScanType::STANDARD);
390 }
391 
TEST_F(InquiryTest,ScanActivity)392 TEST_F(InquiryTest, ScanActivity) {
393   ScanParameters params{
394       .interval = 0x1234,
395       .window = 0x5678,
396   };
397 
398   test_hci_layer_->Synchronize(
399       [this, params] { inquiry_module_->SetScanActivity(params); }, hci::OpCode::WRITE_INQUIRY_SCAN_ACTIVITY);
400   ASSERT_EQ(params.interval, hci_register_.inquiry_scan_interval);
401   ASSERT_EQ(params.window, hci_register_.inquiry_scan_window);
402 }
403 
TEST_F(InquiryTest,OneShotGeneralInquiry)404 TEST_F(InquiryTest, OneShotGeneralInquiry) {
405   uint8_t inquiry_length = 128;
406   uint8_t num_responses = 100;
407   test_hci_layer_->Synchronize(
408       [this, inquiry_length, num_responses] { inquiry_module_->StartGeneralInquiry(inquiry_length, num_responses); },
409       hci::OpCode::INQUIRY);
410   ASSERT_EQ(inquiry_length, hci_register_.inquiry_length);
411   ASSERT_EQ(num_responses, hci_register_.num_responses);
412 
413   test_hci_layer_->Synchronize([this] { inquiry_module_->StopInquiry(); }, hci::OpCode::INQUIRY_CANCEL);
414 }
415 
TEST_F(InquiryTest,OneShotLimitedInquiry)416 TEST_F(InquiryTest, OneShotLimitedInquiry) {
417   test_hci_layer_->Synchronize([this] { inquiry_module_->StartLimitedInquiry(128, 100); }, hci::OpCode::INQUIRY);
418 
419   test_hci_layer_->Synchronize([this] { inquiry_module_->StopInquiry(); }, hci::OpCode::INQUIRY_CANCEL);
420 }
421 
TEST_F(InquiryTest,GeneralPeriodicInquiry)422 TEST_F(InquiryTest, GeneralPeriodicInquiry) {
423   uint8_t inquiry_length = 128;
424   uint8_t num_responses = 100;
425   uint16_t max_delay = 1100;
426   uint16_t min_delay = 200;
427   test_hci_layer_->Synchronize(
428       [this, inquiry_length, num_responses, max_delay, min_delay] {
429         inquiry_module_->StartGeneralPeriodicInquiry(inquiry_length, num_responses, max_delay, min_delay);
430       },
431       hci::OpCode::PERIODIC_INQUIRY_MODE);
432   ASSERT_EQ(inquiry_length, hci_register_.inquiry_length);
433   ASSERT_EQ(num_responses, hci_register_.num_responses);
434   ASSERT_EQ(max_delay, hci_register_.max_period_length);
435   ASSERT_EQ(min_delay, hci_register_.min_period_length);
436 
437   test_hci_layer_->Synchronize(
438       [this] { inquiry_module_->StopPeriodicInquiry(); }, hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE);
439 }
440 
TEST_F(InquiryTest,LimitedPeriodicInquiry)441 TEST_F(InquiryTest, LimitedPeriodicInquiry) {
442   test_hci_layer_->Synchronize(
443       [this] { inquiry_module_->StartLimitedPeriodicInquiry(128, 100, 1100, 200); },
444       hci::OpCode::PERIODIC_INQUIRY_MODE);
445 
446   test_hci_layer_->Synchronize(
447       [this] { inquiry_module_->StopPeriodicInquiry(); }, hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE);
448 }
449 
TEST_F(InquiryTest,InjectInquiryResult)450 TEST_F(InquiryTest, InjectInquiryResult) {
451   test_hci_layer_->Synchronize([this] { inquiry_module_->StartGeneralInquiry(128, 100); }, hci::OpCode::INQUIRY);
452 
453   WaitForInquiryResult([this] {
454     const std::vector<hci::InquiryResult> inquiry_results;
455     auto packet = hci::InquiryResultBuilder::Create(inquiry_results);
456     test_hci_layer_->InjectInquiryResult(std::move(packet));
457   });
458   test_hci_layer_->Synchronize([this] { inquiry_module_->StopInquiry(); }, hci::OpCode::INQUIRY_CANCEL);
459 }
460 
461 }  // namespace
462 }  // namespace neighbor
463 }  // namespace bluetooth
464