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