/* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "common/bind.h" #include "hci/acl_manager.h" #include "hci/address.h" #include "hci/controller.h" #include "hci/hci_layer.h" #include "hci/le_scanning_manager.h" #include "os/thread.h" #include "packet/raw_builder.h" namespace bluetooth { namespace hci { namespace { using packet::kLittleEndian; using packet::PacketView; using packet::RawBuilder; PacketView GetPacketView(std::unique_ptr packet) { auto bytes = std::make_shared>(); BitInserter i(*bytes); bytes->reserve(packet->size()); packet->Serialize(i); return packet::PacketView(bytes); } class TestController : public Controller { public: bool IsSupported(OpCode op_code) const override { return supported_opcodes_.count(op_code) == 1; } void AddSupported(OpCode op_code) { supported_opcodes_.insert(op_code); } protected: void Start() override {} void Stop() override {} void ListDependencies(ModuleList* list) override {} private: std::set supported_opcodes_{}; }; class TestHciLayer : public HciLayer { public: void EnqueueCommand( std::unique_ptr command, common::ContextualOnceCallback on_status) override { command_queue_.push(std::move(command)); command_status_callbacks.push_back(std::move(on_status)); if (command_promise_ != nullptr) { command_promise_->set_value(); command_promise_.reset(); } } void EnqueueCommand( std::unique_ptr command, common::ContextualOnceCallback on_complete) override { command_queue_.push(std::move(command)); command_complete_callbacks.push_back(std::move(on_complete)); if (command_promise_ != nullptr) { command_promise_->set_value(); command_promise_.reset(); } } std::future GetCommandFuture() { ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time"); command_promise_ = std::make_unique>(); return command_promise_->get_future(); } CommandView GetLastCommand() { if (command_queue_.empty()) { return CommandView::Create(GetPacketView(nullptr)); } else { auto last = std::move(command_queue_.front()); command_queue_.pop(); return CommandView::Create(GetPacketView(std::move(last))); } } ConnectionManagementCommandView GetCommand(OpCode op_code) { CommandView command_packet_view = GetLastCommand(); auto command = ConnectionManagementCommandView::Create(AclCommandView::Create(command_packet_view)); EXPECT_TRUE(command.IsValid()); EXPECT_EQ(command.GetOpCode(), op_code); return command; } void RegisterEventHandler(EventCode event_code, common::ContextualCallback event_handler) override { registered_events_[event_code] = event_handler; } void UnregisterEventHandler(EventCode event_code) override { registered_events_.erase(event_code); } void RegisterLeEventHandler(SubeventCode subevent_code, common::ContextualCallback event_handler) override { registered_le_events_[subevent_code] = event_handler; } void UnregisterLeEventHandler(SubeventCode subevent_code) override { registered_le_events_.erase(subevent_code); } void IncomingEvent(std::unique_ptr event_builder) { auto packet = GetPacketView(std::move(event_builder)); EventView event = EventView::Create(packet); ASSERT_TRUE(event.IsValid()); EventCode event_code = event.GetEventCode(); ASSERT_NE(registered_events_.find(event_code), registered_events_.end()) << EventCodeText(event_code); registered_events_[event_code].Invoke(event); } void IncomingLeMetaEvent(std::unique_ptr event_builder) { auto packet = GetPacketView(std::move(event_builder)); EventView event = EventView::Create(packet); LeMetaEventView meta_event_view = LeMetaEventView::Create(event); ASSERT_TRUE(meta_event_view.IsValid()); SubeventCode subevent_code = meta_event_view.GetSubeventCode(); ASSERT_NE(registered_le_events_.find(subevent_code), registered_le_events_.end()) << SubeventCodeText(subevent_code); registered_le_events_[subevent_code].Invoke(meta_event_view); } void CommandCompleteCallback(EventView event) { CommandCompleteView complete_view = CommandCompleteView::Create(event); ASSERT_TRUE(complete_view.IsValid()); ASSERT_NE(command_complete_callbacks.size(), 0); std::move(command_complete_callbacks.front()).Invoke(complete_view); command_complete_callbacks.pop_front(); } void CommandStatusCallback(EventView event) { CommandStatusView status_view = CommandStatusView::Create(event); ASSERT_TRUE(status_view.IsValid()); ASSERT_NE(command_status_callbacks.size(), 0); std::move(command_status_callbacks.front()).Invoke(status_view); command_status_callbacks.pop_front(); } void ListDependencies(ModuleList* list) override {} void Start() override { RegisterEventHandler(EventCode::COMMAND_COMPLETE, GetHandler()->BindOn(this, &TestHciLayer::CommandCompleteCallback)); RegisterEventHandler(EventCode::COMMAND_STATUS, GetHandler()->BindOn(this, &TestHciLayer::CommandStatusCallback)); } void Stop() override {} private: std::map> registered_events_; std::map> registered_le_events_; std::list> command_complete_callbacks; std::list> command_status_callbacks; std::queue> command_queue_; mutable std::mutex mutex_; std::unique_ptr> command_promise_{}; }; class TestLeAddressManager : public LeAddressManager { public: TestLeAddressManager( common::Callback)> enqueue_command, os::Handler* handler, Address public_address, uint8_t connect_list_size, uint8_t resolving_list_size) : LeAddressManager(enqueue_command, handler, public_address, connect_list_size, resolving_list_size) {} AddressPolicy Register(LeAddressManagerCallback* callback) override { return AddressPolicy::USE_STATIC_ADDRESS; } void Unregister(LeAddressManagerCallback* callback) override {} }; class TestAclManager : public AclManager { public: LeAddressManager* GetLeAddressManager() override { return test_le_address_manager_; } protected: void Start() override { thread_ = new os::Thread("thread", os::Thread::Priority::NORMAL); handler_ = new os::Handler(thread_); Address address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06}); test_le_address_manager_ = new TestLeAddressManager( common::Bind(&TestAclManager::enqueue_command, common::Unretained(this)), handler_, address, 0x3F, 0x3F); } void Stop() override { delete test_le_address_manager_; handler_->Clear(); delete handler_; delete thread_; } void ListDependencies(ModuleList* list) override {} void SetRandomAddress(Address address) {} void enqueue_command(std::unique_ptr command_packet){}; os::Thread* thread_; os::Handler* handler_; TestLeAddressManager* test_le_address_manager_; }; class LeScanningManagerTest : public ::testing::Test { protected: void SetUp() override { test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry test_controller_ = new TestController; test_controller_->AddSupported(param_opcode_); if (is_filter_support_) { test_controller_->AddSupported(OpCode::LE_ADV_FILTER); } if (is_batch_scan_support_) { test_controller_->AddSupported(OpCode::LE_BATCH_SCAN); } test_acl_manager_ = new TestAclManager; fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_); fake_registry_.InjectTestModule(&Controller::Factory, test_controller_); fake_registry_.InjectTestModule(&AclManager::Factory, test_acl_manager_); client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory); std::future config_future = test_hci_layer_->GetCommandFuture(); fake_registry_.Start(&thread_); le_scanning_manager = static_cast(fake_registry_.GetModuleUnderTest(&LeScanningManager::Factory)); auto result = config_future.wait_for(std::chrono::duration(std::chrono::milliseconds(1000))); ASSERT_EQ(std::future_status::ready, result); auto packet = test_hci_layer_->GetCommand(enable_opcode_); test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(1, ErrorCode::SUCCESS)); config_future.wait_for(std::chrono::duration(std::chrono::milliseconds(1000))); ASSERT_EQ(std::future_status::ready, result); HandleConfiguration(); le_scanning_manager->RegisterScanningCallback(&mock_callbacks_); } void TearDown() override { fake_registry_.SynchronizeModuleHandler(&LeScanningManager::Factory, std::chrono::milliseconds(20)); fake_registry_.StopAll(); } virtual void HandleConfiguration() { auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_SCAN_PARAMETERS); test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(1, ErrorCode::SUCCESS)); } void sync_client_handler() { std::promise promise; auto future = promise.get_future(); client_handler_->Call(common::BindOnce(&std::promise::set_value, common::Unretained(&promise))); auto future_status = future.wait_for(std::chrono::seconds(1)); ASSERT_EQ(future_status, std::future_status::ready); } TestModuleRegistry fake_registry_; TestHciLayer* test_hci_layer_ = nullptr; TestController* test_controller_ = nullptr; TestAclManager* test_acl_manager_ = nullptr; os::Thread& thread_ = fake_registry_.GetTestThread(); LeScanningManager* le_scanning_manager = nullptr; os::Handler* client_handler_ = nullptr; class MockCallbacks : public bluetooth::hci::ScanningCallback { public: MOCK_METHOD( void, OnScannerRegistered, (const bluetooth::hci::Uuid app_uuid, ScannerId scanner_id, ScanningStatus status), (override)); MOCK_METHOD( void, OnScanResult, (uint16_t event_type, uint8_t address_type, Address address, uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, int8_t tx_power, int8_t rssi, uint16_t periodic_advertising_interval, std::vector advertising_data), (override)); MOCK_METHOD( void, OnTrackAdvFoundLost, (bluetooth::hci::AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info), (override)); MOCK_METHOD( void, OnBatchScanReports, (int client_if, int status, int report_format, int num_records, std::vector data), (override)); MOCK_METHOD(void, OnBatchScanThresholdCrossed, (int client_if), (override)); MOCK_METHOD(void, OnTimeout, (), (override)); MOCK_METHOD(void, OnFilterEnable, (Enable enable, uint8_t status), (override)); MOCK_METHOD(void, OnFilterParamSetup, (uint8_t available_spaces, ApcfAction action, uint8_t status), (override)); MOCK_METHOD( void, OnFilterConfigCallback, (ApcfFilterType filter_type, uint8_t available_spaces, ApcfAction action, uint8_t status), (override)); } mock_callbacks_; OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS}; OpCode enable_opcode_{OpCode::LE_SET_SCAN_ENABLE}; bool is_filter_support_ = false; bool is_batch_scan_support_ = false; }; class LeAndroidHciScanningManagerTest : public LeScanningManagerTest { protected: void SetUp() override { param_opcode_ = OpCode::LE_EXTENDED_SCAN_PARAMS; is_filter_support_ = true; is_batch_scan_support_ = true; LeScanningManagerTest::SetUp(); test_controller_->AddSupported(OpCode::LE_ADV_FILTER); } void HandleConfiguration() override { auto packet = test_hci_layer_->GetCommand(OpCode::LE_EXTENDED_SCAN_PARAMS); test_hci_layer_->IncomingEvent(LeExtendedScanParamsCompleteBuilder::Create(1, ErrorCode::SUCCESS)); } }; class LeExtendedScanningManagerTest : public LeScanningManagerTest { protected: void SetUp() override { param_opcode_ = OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS; enable_opcode_ = OpCode::LE_SET_EXTENDED_SCAN_ENABLE; LeScanningManagerTest::SetUp(); } void HandleConfiguration() override { auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS); test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(1, ErrorCode::SUCCESS)); } }; TEST_F(LeScanningManagerTest, startup_teardown) {} TEST_F(LeScanningManagerTest, start_scan_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->Scan(true); auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); LeAdvertisingReport report{}; report.event_type_ = AdvertisingEventType::ADV_DIRECT_IND; report.address_type_ = AddressType::PUBLIC_DEVICE_ADDRESS; Address::FromString("12:34:56:78:9a:bc", report.address_); std::vector gap_data{}; GapData data_item{}; data_item.data_type_ = GapDataType::FLAGS; data_item.data_ = {0x34}; gap_data.push_back(data_item); data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME; data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}; gap_data.push_back(data_item); report.advertising_data_ = gap_data; EXPECT_CALL(mock_callbacks_, OnScanResult); test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); } TEST_F(LeAndroidHciScanningManagerTest, start_scan_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->Scan(true); auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); LeAdvertisingReport report{}; report.event_type_ = AdvertisingEventType::ADV_DIRECT_IND; report.address_type_ = AddressType::PUBLIC_DEVICE_ADDRESS; Address::FromString("12:34:56:78:9a:bc", report.address_); std::vector gap_data{}; GapData data_item{}; data_item.data_type_ = GapDataType::FLAGS; data_item.data_ = {0x34}; gap_data.push_back(data_item); data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME; data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}; gap_data.push_back(data_item); report.advertising_data_ = gap_data; EXPECT_CALL(mock_callbacks_, OnScanResult); test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); } TEST_F(LeAndroidHciScanningManagerTest, scan_filter_enable_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->ScanFilterEnable(true); auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); EXPECT_CALL(mock_callbacks_, OnFilterEnable); test_hci_layer_->IncomingEvent( LeAdvFilterEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, Enable::ENABLED)); sync_client_handler(); } TEST_F(LeAndroidHciScanningManagerTest, scan_filter_parameter_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); AdvertisingFilterParameter advertising_filter_parameter{}; advertising_filter_parameter.delivery_mode = DeliveryMode::IMMEDIATE; le_scanning_manager->ScanFilterParameterSetup(ApcfAction::ADD, 0x01, advertising_filter_parameter); auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); EXPECT_CALL(mock_callbacks_, OnFilterParamSetup); test_hci_layer_->IncomingEvent( LeAdvFilterSetFilteringParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a)); sync_client_handler(); } TEST_F(LeAndroidHciScanningManagerTest, scan_filter_add_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); std::vector filters = {}; AdvertisingPacketContentFilterCommand filter{}; filter.filter_type = ApcfFilterType::BROADCASTER_ADDRESS; filter.address = Address::kEmpty; filter.application_address_type = ApcfApplicationAddressType::RANDOM; filters.push_back(filter); le_scanning_manager->ScanFilterAdd(0x01, filters); EXPECT_CALL(mock_callbacks_, OnFilterConfigCallback); auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->IncomingEvent( LeAdvFilterBroadcasterAddressCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a)); sync_client_handler(); } TEST_F(LeAndroidHciScanningManagerTest, read_batch_scan_result) { // Enable batch scan feature auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->BatchScanConifgStorage(100, 0, 95, 0x00); auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->IncomingEvent(LeBatchScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); test_hci_layer_->IncomingEvent( LeBatchScanSetStorageParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); // Enable batch scan next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->BatchScanEnable(BatchScanMode::FULL, 2400, 2400, BatchScanDiscardRule::OLDEST); result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->IncomingEvent(LeBatchScanSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); // Read batch scan data next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->BatchScanReadReport(0x01, BatchScanMode::FULL); result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); EXPECT_CALL(mock_callbacks_, OnBatchScanReports); std::vector raw_data = {0x5c, 0x1f, 0xa2, 0xc3, 0x63, 0x5d, 0x01, 0xf5, 0xb3, 0x5e, 0x00, 0x0c, 0x02, 0x01, 0x02, 0x05, 0x09, 0x6d, 0x76, 0x38, 0x76, 0x02, 0x0a, 0xf5, 0x00}; next_command_future = test_hci_layer_->GetCommandFuture(); // We will send read command while num_of_record != 0 test_hci_layer_->IncomingEvent(LeBatchScanReadResultParametersCompleteRawBuilder::Create( uint8_t{1}, ErrorCode::SUCCESS, BatchScanDataRead::FULL_MODE_DATA, 1, raw_data)); result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); // OnBatchScanReports will be trigger when num_of_record == 0 test_hci_layer_->IncomingEvent(LeBatchScanReadResultParametersCompleteRawBuilder::Create( uint8_t{1}, ErrorCode::SUCCESS, BatchScanDataRead::FULL_MODE_DATA, 0, {})); } TEST_F(LeExtendedScanningManagerTest, start_scan_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->Scan(true); auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_SCAN_ENABLE); test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS); test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_SCAN_ENABLE); test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); LeExtendedAdvertisingReport report{}; report.connectable_ = 1; report.scannable_ = 0; report.address_type_ = DirectAdvertisingAddressType::PUBLIC_DEVICE_ADDRESS; Address::FromString("12:34:56:78:9a:bc", report.address_); std::vector gap_data{}; GapData data_item{}; data_item.data_type_ = GapDataType::FLAGS; data_item.data_ = {0x34}; gap_data.push_back(data_item); data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME; data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}; gap_data.push_back(data_item); std::vector advertising_data = {}; for (auto data : gap_data) { advertising_data.push_back((uint8_t)data.size() - 1); advertising_data.push_back((uint8_t)data.data_type_); advertising_data.insert(advertising_data.end(), data.data_.begin(), data.data_.end()); } report.advertising_data_ = advertising_data; EXPECT_CALL(mock_callbacks_, OnScanResult); test_hci_layer_->IncomingLeMetaEvent(LeExtendedAdvertisingReportBuilder::Create({report})); } } // namespace } // namespace hci } // namespace bluetooth