| /* |
| * 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 "hci/le_scanning_manager.h" |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include <algorithm> |
| #include <chrono> |
| #include <future> |
| #include <list> |
| #include <map> |
| #include <memory> |
| #include <mutex> |
| #include <queue> |
| #include <vector> |
| |
| #include "hci/hci_layer_fake.h" |
| #include "common/bind.h" |
| #include "hci/acl_manager.h" |
| #include "hci/address.h" |
| #include "hci/controller.h" |
| #include "hci/hci_layer.h" |
| #include "hci/uuid.h" |
| #include "os/thread.h" |
| #include "packet/raw_builder.h" |
| |
| using ::testing::_; |
| using ::testing::Eq; |
| |
| using namespace bluetooth; |
| using namespace std::chrono_literals; |
| |
| using packet::kLittleEndian; |
| using packet::PacketView; |
| using packet::RawBuilder; |
| |
| namespace { |
| |
| hci::AdvertisingPacketContentFilterCommand make_filter(const hci::ApcfFilterType& filter_type) { |
| hci::AdvertisingPacketContentFilterCommand filter{}; |
| filter.filter_type = filter_type; |
| |
| switch (filter_type) { |
| case hci::ApcfFilterType::AD_TYPE: |
| case hci::ApcfFilterType::SERVICE_DATA: |
| filter.ad_type = 0x09; |
| filter.data = {0x12, 0x34, 0x56, 0x78}; |
| filter.data_mask = {0xff, 0xff, 0xff, 0xff}; |
| break; |
| case hci::ApcfFilterType::BROADCASTER_ADDRESS: |
| filter.address = hci::Address::kEmpty; |
| filter.application_address_type = hci::ApcfApplicationAddressType::RANDOM; |
| break; |
| case hci::ApcfFilterType::SERVICE_UUID: |
| filter.uuid = hci::Uuid::From32Bit(0x12345678); |
| filter.uuid_mask = hci::Uuid::From32Bit(0xffffffff); |
| break; |
| case hci::ApcfFilterType::LOCAL_NAME: |
| filter.name = {0x01, 0x02, 0x03}; |
| break; |
| case hci::ApcfFilterType::MANUFACTURER_DATA: |
| filter.company = 0x12; |
| filter.company_mask = 0xff; |
| filter.data = {0x12, 0x34, 0x56, 0x78}; |
| filter.data_mask = {0xff, 0xff, 0xff, 0xff}; |
| break; |
| default: |
| break; |
| } |
| return filter; |
| } |
| |
| hci::LeAdvertisingResponse make_advertising_report() { |
| hci::LeAdvertisingResponse report{}; |
| report.event_type_ = hci::AdvertisingEventType::ADV_DIRECT_IND; |
| report.address_type_ = hci::AddressType::PUBLIC_DEVICE_ADDRESS; |
| hci::Address::FromString("12:34:56:78:9a:bc", report.address_); |
| std::vector<hci::LengthAndData> adv_data{}; |
| hci::LengthAndData data_item{}; |
| data_item.data_.push_back(static_cast<uint8_t>(hci::GapDataType::FLAGS)); |
| data_item.data_.push_back(0x34); |
| adv_data.push_back(data_item); |
| data_item.data_.push_back(static_cast<uint8_t>(hci::GapDataType::COMPLETE_LOCAL_NAME)); |
| for (auto octet : {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}) { |
| data_item.data_.push_back(octet); |
| } |
| adv_data.push_back(data_item); |
| report.advertising_data_ = adv_data; |
| return report; |
| } |
| |
| } // namespace |
| |
| namespace bluetooth { |
| namespace hci { |
| namespace { |
| |
| 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); |
| } |
| |
| bool SupportsBleExtendedAdvertising() const override { |
| return support_ble_extended_advertising_; |
| } |
| |
| void SetBleExtendedAdvertisingSupport(bool support) { |
| support_ble_extended_advertising_ = support; |
| } |
| |
| protected: |
| void Start() override {} |
| void Stop() override {} |
| void ListDependencies(ModuleList* list) const {} |
| |
| private: |
| std::set<OpCode> supported_opcodes_{}; |
| bool support_ble_extended_advertising_ = false; |
| }; |
| |
| class TestLeAddressManager : public LeAddressManager { |
| public: |
| TestLeAddressManager( |
| common::Callback<void(std::unique_ptr<CommandBuilder>)> 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 { |
| client_ = callback; |
| test_client_state_ = RESUMED; |
| return AddressPolicy::USE_STATIC_ADDRESS; |
| } |
| |
| void Unregister(LeAddressManagerCallback* callback) override { |
| if (!ignore_unregister_for_testing) { |
| client_ = nullptr; |
| } |
| test_client_state_ = UNREGISTERED; |
| } |
| |
| void AckPause(LeAddressManagerCallback* callback) override { |
| test_client_state_ = PAUSED; |
| } |
| |
| void AckResume(LeAddressManagerCallback* callback) override { |
| test_client_state_ = RESUMED; |
| } |
| |
| LeAddressManagerCallback* client_; |
| bool ignore_unregister_for_testing = false; |
| enum TestClientState { |
| UNREGISTERED, |
| PAUSED, |
| RESUMED, |
| }; |
| TestClientState test_client_state_ = UNREGISTERED; |
| }; |
| |
| 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) const {} |
| |
| void SetRandomAddress(Address address) {} |
| |
| void enqueue_command(std::unique_ptr<CommandBuilder> command_packet){}; |
| |
| private: |
| os::Thread* thread_; |
| os::Handler* handler_; |
| TestLeAddressManager* test_le_address_manager_; |
| }; |
| |
| 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, OnSetScannerParameterComplete, (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<uint8_t> 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<uint8_t> 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_METHOD(void, OnPeriodicSyncStarted, (int, uint8_t, uint16_t, uint8_t, AddressWithType, uint8_t, uint16_t)); |
| MOCK_METHOD(void, OnPeriodicSyncReport, (uint16_t, int8_t, int8_t, uint8_t, std::vector<uint8_t>)); |
| MOCK_METHOD(void, OnPeriodicSyncLost, (uint16_t)); |
| MOCK_METHOD(void, OnPeriodicSyncTransferred, (int, uint8_t, Address)); |
| } mock_callbacks_; |
| |
| class LeScanningManagerTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry |
| test_controller_ = new TestController; |
| 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); |
| ASSERT_TRUE(client_handler_ != nullptr); |
| } |
| |
| void TearDown() override { |
| sync_client_handler(); |
| if (fake_registry_.IsStarted<LeScanningManager>()) { |
| fake_registry_.SynchronizeModuleHandler(&LeScanningManager::Factory, std::chrono::milliseconds(20)); |
| } |
| fake_registry_.StopAll(); |
| } |
| |
| void start_le_scanning_manager() { |
| fake_registry_.Start<LeScanningManager>(&thread_); |
| le_scanning_manager = |
| static_cast<LeScanningManager*>(fake_registry_.GetModuleUnderTest(&LeScanningManager::Factory)); |
| le_scanning_manager->RegisterScanningCallback(&mock_callbacks_); |
| sync_client_handler(); |
| } |
| |
| void sync_client_handler() { |
| ASSERT(thread_.GetReactor()->WaitForIdle(std::chrono::seconds(2))); |
| } |
| |
| 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; |
| |
| MockCallbacks mock_callbacks_; |
| }; |
| |
| class LeScanningManagerAndroidHciTest : public LeScanningManagerTest { |
| protected: |
| void SetUp() override { |
| LeScanningManagerTest::SetUp(); |
| test_controller_->AddSupported(OpCode::LE_EXTENDED_SCAN_PARAMS); |
| test_controller_->AddSupported(OpCode::LE_ADV_FILTER); |
| test_controller_->AddSupported(OpCode::LE_BATCH_SCAN); |
| start_le_scanning_manager(); |
| ASSERT_TRUE(fake_registry_.IsStarted(&HciLayer::Factory)); |
| |
| ASSERT_EQ(OpCode::LE_ADV_FILTER, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeAdvFilterReadExtendedFeaturesCompleteBuilder::Create(1, ErrorCode::SUCCESS, 0x01)); |
| |
| // Get the command a second time as the configure_scan is called twice in le_scanning_manager.cc |
| // Fixed on aosp/2242078 but not present on older branches |
| EXPECT_EQ(OpCode::LE_EXTENDED_SCAN_PARAMS, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeExtendedScanParamsCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| } |
| |
| void TearDown() override { |
| LeScanningManagerTest::TearDown(); |
| } |
| }; |
| |
| class LeScanningManagerExtendedTest : public LeScanningManagerTest { |
| protected: |
| void SetUp() override { |
| LeScanningManagerTest::SetUp(); |
| test_controller_->AddSupported(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS); |
| test_controller_->AddSupported(OpCode::LE_SET_EXTENDED_SCAN_ENABLE); |
| test_controller_->SetBleExtendedAdvertisingSupport(true); |
| start_le_scanning_manager(); |
| // Get the command a second time as the configure_scan is called twice in le_scanning_manager.cc |
| // Fixed on aosp/2242078 but not present on older branches |
| EXPECT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| } |
| }; |
| |
| TEST_F(LeScanningManagerTest, startup_teardown) {} |
| |
| TEST_F(LeScanningManagerTest, start_scan_test) { |
| start_le_scanning_manager(); |
| |
| // Get the command a second time as the configure_scan is called twice in le_scanning_manager.cc |
| // Fixed on aosp/2242078 but not present on older branches |
| EXPECT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| |
| // Enable scan |
| le_scanning_manager->Scan(true); |
| EXPECT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| |
| EXPECT_EQ(OpCode::LE_SET_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| |
| LeAdvertisingResponse report = make_advertising_report(); |
| EXPECT_CALL(mock_callbacks_, OnScanResult); |
| |
| test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); |
| } |
| |
| TEST_F(LeScanningManagerTest, is_ad_type_filter_supported_false_test) { |
| start_le_scanning_manager(); |
| ASSERT_TRUE(fake_registry_.IsStarted(&HciLayer::Factory)); |
| ASSERT_FALSE(le_scanning_manager->IsAdTypeFilterSupported()); |
| } |
| |
| TEST_F(LeScanningManagerTest, scan_filter_add_ad_type_not_supported_test) { |
| start_le_scanning_manager(); |
| ASSERT_TRUE(fake_registry_.IsStarted(&HciLayer::Factory)); |
| |
| std::vector<AdvertisingPacketContentFilterCommand> filters = {}; |
| filters.push_back(make_filter(hci::ApcfFilterType::AD_TYPE)); |
| le_scanning_manager->ScanFilterAdd(0x01, filters); |
| } |
| |
| TEST_F(LeScanningManagerAndroidHciTest, startup_teardown) {} |
| |
| TEST_F(LeScanningManagerAndroidHciTest, start_scan_test) { |
| // Enable scan |
| le_scanning_manager->Scan(true); |
| ASSERT_EQ(OpCode::LE_EXTENDED_SCAN_PARAMS, test_hci_layer_->GetCommand().GetOpCode()); |
| |
| LeAdvertisingResponse report = make_advertising_report(); |
| |
| EXPECT_CALL(mock_callbacks_, OnScanResult); |
| |
| test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); |
| } |
| |
| TEST_F(LeScanningManagerAndroidHciTest, is_ad_type_filter_supported_true_test) { |
| sync_client_handler(); |
| client_handler_->Post(common::BindOnce( |
| [](LeScanningManager* le_scanning_manager) { ASSERT_TRUE(le_scanning_manager->IsAdTypeFilterSupported()); }, |
| le_scanning_manager)); |
| } |
| |
| TEST_F(LeScanningManagerAndroidHciTest, scan_filter_enable_test) { |
| le_scanning_manager->ScanFilterEnable(true); |
| sync_client_handler(); |
| |
| EXPECT_CALL(mock_callbacks_, OnFilterEnable); |
| test_hci_layer_->IncomingEvent( |
| LeAdvFilterEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, Enable::ENABLED)); |
| sync_client_handler(); |
| } |
| |
| TEST_F(LeScanningManagerAndroidHciTest, scan_filter_parameter_test) { |
| |
| AdvertisingFilterParameter advertising_filter_parameter{}; |
| advertising_filter_parameter.delivery_mode = DeliveryMode::IMMEDIATE; |
| le_scanning_manager->ScanFilterParameterSetup(ApcfAction::ADD, 0x01, advertising_filter_parameter); |
| auto commandView = test_hci_layer_->GetCommand(); |
| ASSERT_EQ(OpCode::LE_ADV_FILTER, commandView.GetOpCode()); |
| auto filter_command_view = LeAdvFilterSetFilteringParametersView::Create( |
| LeAdvFilterView::Create(LeScanningCommandView::Create(commandView))); |
| ASSERT_TRUE(filter_command_view.IsValid()); |
| ASSERT_EQ(filter_command_view.GetApcfOpcode(), ApcfOpcode::SET_FILTERING_PARAMETERS); |
| |
| EXPECT_CALL(mock_callbacks_, OnFilterParamSetup); |
| test_hci_layer_->IncomingEvent( |
| LeAdvFilterSetFilteringParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a)); |
| sync_client_handler(); |
| } |
| |
| TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_broadcaster_address_test) { |
| |
| std::vector<AdvertisingPacketContentFilterCommand> filters = {}; |
| filters.push_back(make_filter(ApcfFilterType::BROADCASTER_ADDRESS)); |
| le_scanning_manager->ScanFilterAdd(0x01, filters); |
| auto commandView = test_hci_layer_->GetCommand(); |
| ASSERT_EQ(OpCode::LE_ADV_FILTER, commandView.GetOpCode()); |
| auto filter_command_view = |
| LeAdvFilterBroadcasterAddressView::Create(LeAdvFilterView::Create(LeScanningCommandView::Create(commandView))); |
| ASSERT_TRUE(filter_command_view.IsValid()); |
| ASSERT_EQ(filter_command_view.GetApcfOpcode(), ApcfOpcode::BROADCASTER_ADDRESS); |
| |
| EXPECT_CALL(mock_callbacks_, OnFilterConfigCallback); |
| test_hci_layer_->IncomingEvent( |
| LeAdvFilterBroadcasterAddressCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a)); |
| } |
| |
| TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_service_uuid_test) { |
| |
| std::vector<AdvertisingPacketContentFilterCommand> filters = {}; |
| filters.push_back(make_filter(ApcfFilterType::SERVICE_UUID)); |
| le_scanning_manager->ScanFilterAdd(0x01, filters); |
| auto commandView = test_hci_layer_->GetCommand(); |
| ASSERT_EQ(OpCode::LE_ADV_FILTER, commandView.GetOpCode()); |
| auto filter_command_view = |
| LeAdvFilterServiceUuidView::Create(LeAdvFilterView::Create(LeScanningCommandView::Create(commandView))); |
| ASSERT_TRUE(filter_command_view.IsValid()); |
| ASSERT_EQ(filter_command_view.GetApcfOpcode(), ApcfOpcode::SERVICE_UUID); |
| |
| EXPECT_CALL(mock_callbacks_, OnFilterConfigCallback); |
| test_hci_layer_->IncomingEvent( |
| LeAdvFilterServiceUuidCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a)); |
| } |
| |
| TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_local_name_test) { |
| |
| std::vector<AdvertisingPacketContentFilterCommand> filters = {}; |
| filters.push_back(make_filter(ApcfFilterType::LOCAL_NAME)); |
| le_scanning_manager->ScanFilterAdd(0x01, filters); |
| auto commandView = test_hci_layer_->GetCommand(); |
| ASSERT_EQ(OpCode::LE_ADV_FILTER, commandView.GetOpCode()); |
| auto filter_command_view = |
| LeAdvFilterLocalNameView::Create(LeAdvFilterView::Create(LeScanningCommandView::Create(commandView))); |
| ASSERT_TRUE(filter_command_view.IsValid()); |
| ASSERT_EQ(filter_command_view.GetApcfOpcode(), ApcfOpcode::LOCAL_NAME); |
| |
| EXPECT_CALL(mock_callbacks_, OnFilterConfigCallback); |
| test_hci_layer_->IncomingEvent( |
| LeAdvFilterLocalNameCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a)); |
| } |
| |
| TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_manufacturer_data_test) { |
| |
| std::vector<AdvertisingPacketContentFilterCommand> filters = {}; |
| filters.push_back(make_filter(ApcfFilterType::MANUFACTURER_DATA)); |
| le_scanning_manager->ScanFilterAdd(0x01, filters); |
| auto commandView = test_hci_layer_->GetCommand(); |
| ASSERT_EQ(OpCode::LE_ADV_FILTER, commandView.GetOpCode()); |
| auto filter_command_view = |
| LeAdvFilterManufacturerDataView::Create(LeAdvFilterView::Create(LeScanningCommandView::Create(commandView))); |
| ASSERT_TRUE(filter_command_view.IsValid()); |
| ASSERT_EQ(filter_command_view.GetApcfOpcode(), ApcfOpcode::MANUFACTURER_DATA); |
| |
| EXPECT_CALL(mock_callbacks_, OnFilterConfigCallback); |
| test_hci_layer_->IncomingEvent( |
| LeAdvFilterManufacturerDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a)); |
| } |
| |
| TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_service_data_test) { |
| |
| std::vector<AdvertisingPacketContentFilterCommand> filters = {}; |
| filters.push_back(make_filter(hci::ApcfFilterType::SERVICE_DATA)); |
| le_scanning_manager->ScanFilterAdd(0x01, filters); |
| auto commandView = test_hci_layer_->GetCommand(); |
| ASSERT_EQ(OpCode::LE_ADV_FILTER, commandView.GetOpCode()); |
| auto filter_command_view = |
| LeAdvFilterServiceDataView::Create(LeAdvFilterView::Create(LeScanningCommandView::Create(commandView))); |
| ASSERT_TRUE(filter_command_view.IsValid()); |
| ASSERT_EQ(filter_command_view.GetApcfOpcode(), ApcfOpcode::SERVICE_DATA); |
| |
| EXPECT_CALL(mock_callbacks_, OnFilterConfigCallback); |
| test_hci_layer_->IncomingEvent( |
| LeAdvFilterServiceDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a)); |
| } |
| |
| TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_ad_type_test) { |
| sync_client_handler(); |
| client_handler_->Post(common::BindOnce( |
| [](LeScanningManager* le_scanning_manager) { ASSERT_TRUE(le_scanning_manager->IsAdTypeFilterSupported()); }, |
| le_scanning_manager)); |
| |
| std::vector<AdvertisingPacketContentFilterCommand> filters = {}; |
| hci::AdvertisingPacketContentFilterCommand filter = make_filter(hci::ApcfFilterType::AD_TYPE); |
| filters.push_back(filter); |
| le_scanning_manager->ScanFilterAdd(0x01, filters); |
| sync_client_handler(); |
| |
| EXPECT_CALL(mock_callbacks_, OnFilterConfigCallback); |
| test_hci_layer_->IncomingEvent( |
| LeAdvFilterADTypeCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a)); |
| } |
| |
| TEST_F(LeScanningManagerAndroidHciTest, read_batch_scan_result) { |
| le_scanning_manager->BatchScanConifgStorage(100, 0, 95, 0x00); |
| sync_client_handler(); |
| ASSERT_EQ(OpCode::LE_BATCH_SCAN, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeBatchScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| ASSERT_EQ(OpCode::LE_BATCH_SCAN, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent( |
| LeBatchScanSetStorageParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| |
| // Enable batch scan |
| |
| le_scanning_manager->BatchScanEnable(BatchScanMode::FULL, 2400, 2400, BatchScanDiscardRule::OLDEST); |
| ASSERT_EQ(OpCode::LE_BATCH_SCAN, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeBatchScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| |
| // Read batch scan data |
| |
| le_scanning_manager->BatchScanReadReport(0x01, BatchScanMode::FULL); |
| ASSERT_EQ(OpCode::LE_BATCH_SCAN, test_hci_layer_->GetCommand().GetOpCode()); |
| |
| // We will send read command while num_of_record != 0 |
| std::vector<uint8_t> 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}; |
| |
| test_hci_layer_->IncomingEvent(LeBatchScanReadResultParametersCompleteRawBuilder::Create( |
| uint8_t{1}, ErrorCode::SUCCESS, BatchScanDataRead::FULL_MODE_DATA, 1, raw_data)); |
| ASSERT_EQ(OpCode::LE_BATCH_SCAN, test_hci_layer_->GetCommand().GetOpCode()); |
| |
| // OnBatchScanReports will be trigger when num_of_record == 0 |
| EXPECT_CALL(mock_callbacks_, OnBatchScanReports); |
| test_hci_layer_->IncomingEvent(LeBatchScanReadResultParametersCompleteRawBuilder::Create( |
| uint8_t{1}, ErrorCode::SUCCESS, BatchScanDataRead::FULL_MODE_DATA, 0, {})); |
| } |
| |
| TEST_F(LeScanningManagerExtendedTest, startup_teardown) {} |
| |
| TEST_F(LeScanningManagerExtendedTest, start_scan_test) { |
| // Enable scan |
| le_scanning_manager->Scan(true); |
| ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| LeExtendedAdvertisingResponse 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<LengthAndData> adv_data{}; |
| LengthAndData data_item{}; |
| data_item.data_.push_back(static_cast<uint8_t>(GapDataType::FLAGS)); |
| data_item.data_.push_back(0x34); |
| adv_data.push_back(data_item); |
| data_item.data_.push_back(static_cast<uint8_t>(GapDataType::COMPLETE_LOCAL_NAME)); |
| for (auto octet : {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}) { |
| data_item.data_.push_back(octet); |
| } |
| adv_data.push_back(data_item); |
| |
| report.advertising_data_ = adv_data; |
| |
| EXPECT_CALL(mock_callbacks_, OnScanResult); |
| |
| test_hci_layer_->IncomingLeMetaEvent(LeExtendedAdvertisingReportBuilder::Create({report})); |
| } |
| |
| TEST_F(LeScanningManagerExtendedTest, ignore_on_pause_on_resume_after_unregistered) { |
| TestLeAddressManager* test_le_address_manager = (TestLeAddressManager*)test_acl_manager_->GetLeAddressManager(); |
| test_le_address_manager->ignore_unregister_for_testing = true; |
| |
| // Register LeAddressManager |
| le_scanning_manager->Scan(true); |
| ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| sync_client_handler(); |
| |
| // Unregister LeAddressManager |
| le_scanning_manager->Scan(false); |
| ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| sync_client_handler(); |
| |
| // Unregistered client should ignore OnPause/OnResume |
| ASSERT_NE(test_le_address_manager->client_, nullptr); |
| ASSERT_EQ(test_le_address_manager->test_client_state_, TestLeAddressManager::TestClientState::UNREGISTERED); |
| test_le_address_manager->client_->OnPause(); |
| ASSERT_EQ(test_le_address_manager->test_client_state_, TestLeAddressManager::TestClientState::UNREGISTERED); |
| test_le_address_manager->client_->OnResume(); |
| ASSERT_EQ(test_le_address_manager->test_client_state_, TestLeAddressManager::TestClientState::UNREGISTERED); |
| } |
| |
| TEST_F(LeScanningManagerExtendedTest, drop_insignificant_bytes_test) { |
| // Enable scan |
| le_scanning_manager->Scan(true); |
| ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); |
| test_hci_layer_->IncomingEvent(LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); |
| |
| // Prepare advertisement report |
| LeExtendedAdvertisingResponse advertisement_report{}; |
| advertisement_report.connectable_ = 1; |
| advertisement_report.scannable_ = 1; |
| advertisement_report.address_type_ = DirectAdvertisingAddressType::PUBLIC_DEVICE_ADDRESS; |
| Address::FromString("12:34:56:78:9a:bc", advertisement_report.address_); |
| std::vector<LengthAndData> adv_data{}; |
| LengthAndData flags_data{}; |
| flags_data.data_.push_back(static_cast<uint8_t>(GapDataType::FLAGS)); |
| flags_data.data_.push_back(0x34); |
| adv_data.push_back(flags_data); |
| LengthAndData name_data{}; |
| name_data.data_.push_back(static_cast<uint8_t>(GapDataType::COMPLETE_LOCAL_NAME)); |
| for (auto octet : "random device") { |
| name_data.data_.push_back(octet); |
| } |
| adv_data.push_back(name_data); |
| for (int i = 0; i != 5; ++i) { |
| adv_data.push_back({}); // pad with a few insigificant zeros |
| } |
| advertisement_report.advertising_data_ = adv_data; |
| |
| // Prepare scan response report |
| auto scan_response_report = advertisement_report; |
| scan_response_report.scan_response_ = true; |
| LengthAndData extra_data{}; |
| extra_data.data_.push_back(static_cast<uint8_t>(GapDataType::MANUFACTURER_SPECIFIC_DATA)); |
| for (auto octet : "manufacturer specific") { |
| extra_data.data_.push_back(octet); |
| } |
| adv_data = {extra_data}; |
| for (int i = 0; i != 5; ++i) { |
| adv_data.push_back({}); // pad with a few insigificant zeros |
| } |
| scan_response_report.advertising_data_ = adv_data; |
| |
| // We expect the two reports to be concatenated, excluding the zero-padding |
| auto result = std::vector<uint8_t>(); |
| packet::BitInserter it(result); |
| flags_data.Serialize(it); |
| name_data.Serialize(it); |
| extra_data.Serialize(it); |
| EXPECT_CALL(mock_callbacks_, OnScanResult(_, _, _, _, _, _, _, _, _, result)); |
| |
| // Send both reports |
| test_hci_layer_->IncomingLeMetaEvent(LeExtendedAdvertisingReportBuilder::Create({advertisement_report})); |
| test_hci_layer_->IncomingLeMetaEvent(LeExtendedAdvertisingReportBuilder::Create({scan_response_report})); |
| } |
| |
| } // namespace |
| } // namespace hci |
| } // namespace bluetooth |