Loading system/gd/hci/le_advertising_manager.cc +91 −12 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ struct LeAdvertisingManager::impl { le_advertising_interface_ = hci_layer_->GetLeAdvertisingInterface( common::Bind(&LeAdvertisingManager::impl::handle_event, common::Unretained(this)), module_handler_); num_instances_ = controller_->GetControllerLeNumberOfSupportedAdverisingSets(); enabled_sets_ = std::vector<EnabledSet>(num_instances_); if (controller_->IsSupported(hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS)) { advertising_api_type_ = AdvertisingApiType::LE_5_0; } else if (controller_->IsSupported(hci::OpCode::LE_MULTI_ADVT)) { Loading Loading @@ -112,6 +113,7 @@ struct LeAdvertisingManager::impl { } void remove_advertiser(AdvertiserId id) { stop_advertising(id); std::unique_lock lock(id_mutex_); if (advertising_sets_.count(id) == 0) { return; Loading Loading @@ -173,6 +175,7 @@ struct LeAdvertisingManager::impl { ExtendedAdvertisingConfig new_config; AdvertisingConfig* base_config_ptr = &new_config; *(base_config_ptr) = config; new_config.legacy_pdus = true; create_extended_advertiser(id, new_config, scan_callback, set_terminated_callback, handler); } break; } Loading @@ -186,14 +189,70 @@ struct LeAdvertisingManager::impl { create_advertiser(id, config, scan_callback, set_terminated_callback, handler); return; } LOG_ALWAYS_FATAL("LE_SET_EXTENDED_ADVERTISING_PARAMETERS isn't implemented."); /* le_advertising_interface_->EnqueueCommand(hci::LeSetExtendedAdvertisingParametersBuilder::Create(config.interval_min, config.interval_max, config.event_type, config.address_type, config.peer_address_type, config.peer_address, config.channel_map, config.filter_policy, id, config.tx_power), common::BindOnce(impl::check_status), module_handler_); */ if (config.legacy_pdus) { LegacyAdvertisingProperties legacy_properties = LegacyAdvertisingProperties::ADV_IND; if (config.connectable && config.directed) { if (config.high_duty_directed_connectable) { legacy_properties = LegacyAdvertisingProperties::ADV_DIRECT_IND_HIGH; } else { legacy_properties = LegacyAdvertisingProperties::ADV_DIRECT_IND_LOW; } } if (config.scannable && !config.connectable) { legacy_properties = LegacyAdvertisingProperties::ADV_SCAN_IND; } if (!config.scannable && !config.connectable) { legacy_properties = LegacyAdvertisingProperties::ADV_NONCONN_IND; } le_advertising_interface_->EnqueueCommand( LeSetExtendedAdvertisingLegacyParametersBuilder::Create( id, legacy_properties, config.interval_min, config.interval_max, config.channel_map, config.own_address_type, config.peer_address_type, config.peer_address, config.filter_policy, config.tx_power, (config.use_le_coded_phy ? PrimaryPhyType::LE_CODED : PrimaryPhyType::LE_1M), config.sid, config.enable_scan_request_notifications), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingParametersCompleteView>), module_handler_); } else { uint8_t legacy_properties = (config.connectable ? 0x1 : 0x00) | (config.scannable ? 0x2 : 0x00) | (config.directed ? 0x4 : 0x00) | (config.high_duty_directed_connectable ? 0x8 : 0x00); uint8_t extended_properties = (config.anonymous ? 0x20 : 0x00) | (config.include_tx_power ? 0x40 : 0x00); le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingParametersBuilder::Create( id, legacy_properties, extended_properties, config.interval_min, config.interval_max, config.channel_map, config.own_address_type, config.peer_address_type, config.peer_address, config.filter_policy, config.tx_power, (config.use_le_coded_phy ? PrimaryPhyType::LE_CODED : PrimaryPhyType::LE_1M), config.secondary_max_skip, config.secondary_advertising_phy, config.sid, config.enable_scan_request_notifications), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingParametersCompleteView>), module_handler_); } le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingRandomAddressBuilder::Create(id, config.random_address), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingRandomAddressCompleteView>), module_handler_); if (!config.scan_response.empty()) { le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingScanResponseBuilder::Create(id, config.operation, config.fragment_preference, config.scan_response), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingScanResponseCompleteView>), module_handler_); } le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingDataBuilder::Create(id, config.operation, config.fragment_preference, config.advertisement), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingDataCompleteView>), module_handler_); EnabledSet curr_set; curr_set.advertising_handle_ = id; curr_set.duration_ = 0; // TODO: 0 means until the host disables it curr_set.max_extended_advertising_events_ = 0; // TODO: 0 is no maximum std::vector<EnabledSet> enabled_sets = {curr_set}; enabled_sets_[id] = curr_set; le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::ENABLED, enabled_sets), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingEnableCompleteView>), module_handler_); advertising_sets_[id].scan_callback = scan_callback; advertising_sets_[id].set_terminated_callback = set_terminated_callback; advertising_sets_[id].handler = handler; Loading @@ -204,10 +263,29 @@ struct LeAdvertisingManager::impl { LOG_INFO("Unknown advertising set %u", advertising_set); return; } le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED), common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), module_handler_); switch (advertising_api_type_) { case (AdvertisingApiType::LE_4_0): le_advertising_interface_->EnqueueCommand( hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED), common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), module_handler_); break; case (AdvertisingApiType::ANDROID_HCI): le_advertising_interface_->EnqueueCommand( hci::LeMultiAdvtSetEnableBuilder::Create(Enable::DISABLED, advertising_set), common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_); break; case (AdvertisingApiType::LE_5_0): { EnabledSet curr_set; curr_set.advertising_handle_ = advertising_set; std::vector<EnabledSet> enabled_vector{curr_set}; le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::DISABLED, enabled_vector), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingEnableCompleteView>), module_handler_); } break; } std::unique_lock lock(id_mutex_); enabled_sets_[advertising_set].advertising_handle_ = -1; advertising_sets_.erase(advertising_set); } Loading @@ -223,6 +301,7 @@ struct LeAdvertisingManager::impl { std::mutex id_mutex_; size_t num_instances_; std::vector<hci::EnabledSet> enabled_sets_; AdvertisingApiType advertising_api_type_{0}; Loading Loading @@ -323,7 +402,7 @@ AdvertiserId LeAdvertisingManager::ExtendedCreateAdvertiser( } void LeAdvertisingManager::RemoveAdvertiser(AdvertiserId id) { pimpl_->remove_advertiser(id); GetHandler()->Post(common::BindOnce(&impl::remove_advertiser, common::Unretained(pimpl_.get()), id)); } } // namespace hci Loading system/gd/hci/le_advertising_manager.h +5 −2 Original line number Diff line number Diff line Loading @@ -50,9 +50,12 @@ class ExtendedAdvertisingConfig : public AdvertisingConfig { bool include_tx_power; bool use_le_coded_phy; // Primary advertisement PHY is LE Coded uint8_t secondary_max_skip; // maximum advertising events to be skipped, 0x0 send AUX_ADV_IND prior ot the next event uint8_t secondary_advertising_phy; // 1 = 1M, 2 = 2M, 3 = coded SecondaryPhyType secondary_advertising_phy; uint8_t sid; bool enable_scan_request_notifications; Enable enable_scan_request_notifications; OwnAddressType own_address_type; Operation operation; FragmentPreference fragment_preference; }; using AdvertiserId = int32_t; Loading system/gd/hci/le_advertising_manager_test.cc +107 −36 Original line number Diff line number Diff line Loading @@ -83,9 +83,15 @@ class TestHciLayer : public HciLayer { void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override { command_queue_.push_back(std::move(command)); auto packet_view = CommandPacketView::Create(GetPacketView(std::move(command))); ASSERT(packet_view.IsValid()); command_queue_.push_back(packet_view); command_status_callbacks.push_back(std::move(on_status)); if (command_promise_ != nullptr) { if (command_promise_ != nullptr && (command_op_code_ == OpCode::NONE || command_op_code_ == packet_view.GetOpCode())) { if (command_op_code_ == OpCode::LE_MULTI_ADVT && command_sub_ocf_ != SubOcf::SET_ENABLE) { return; } command_promise_->set_value(command_queue_.size()); command_promise_.reset(); } Loading @@ -93,30 +99,43 @@ class TestHciLayer : public HciLayer { void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override { command_queue_.push_back(std::move(command)); auto packet_view = CommandPacketView::Create(GetPacketView(std::move(command))); ASSERT(packet_view.IsValid()); command_queue_.push_back(packet_view); command_complete_callbacks.push_back(std::move(on_complete)); if (command_promise_ != nullptr) { if (command_promise_ != nullptr && (command_op_code_ == OpCode::NONE || command_op_code_ == packet_view.GetOpCode())) { if (command_op_code_ == OpCode::LE_MULTI_ADVT) { auto sub_view = LeMultiAdvtView::Create(LeAdvertisingCommandView::Create(packet_view)); ASSERT(sub_view.IsValid()); if (sub_view.GetSubCmd() != command_sub_ocf_) { return; } } command_promise_->set_value(command_queue_.size()); command_promise_.reset(); } } std::future<size_t> GetCommandFuture() { std::future<size_t> GetCommandFuture(OpCode op_code = OpCode::NONE) { ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time"); command_op_code_ = op_code; command_promise_ = std::make_unique<std::promise<size_t>>(); return command_promise_->get_future(); } std::unique_ptr<CommandPacketBuilder> GetLastCommand() { ASSERT(!command_queue_.empty()); auto last = std::move(command_queue_.front()); command_queue_.pop_front(); return last; std::future<size_t> GetSubCommandFuture(SubOcf sub_ocf) { ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time"); command_op_code_ = OpCode::LE_MULTI_ADVT; command_sub_ocf_ = sub_ocf; command_promise_ = std::make_unique<std::promise<size_t>>(); return command_promise_->get_future(); } ConnectionManagementCommandView GetCommandPacket(OpCode op_code) { auto packet_view = GetPacketView(GetLastCommand()); CommandPacketView command_packet_view = CommandPacketView::Create(packet_view); ASSERT(!command_queue_.empty()); CommandPacketView command_packet_view = CommandPacketView::Create(command_queue_.front()); command_queue_.pop_front(); ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view); ASSERT(command.IsValid()); EXPECT_EQ(command.GetOpCode(), op_code); Loading Loading @@ -178,9 +197,11 @@ class TestHciLayer : public HciLayer { std::list<base::OnceCallback<void(CommandCompleteView)>> command_complete_callbacks; std::list<base::OnceCallback<void(CommandStatusView)>> command_status_callbacks; std::list<std::unique_ptr<CommandPacketBuilder>> command_queue_; std::list<CommandPacketView> command_queue_; mutable std::mutex mutex_; std::unique_ptr<std::promise<size_t>> command_promise_{}; OpCode command_op_code_; SubOcf command_sub_ocf_; }; class LeAdvertisingManagerTest : public ::testing::Test { Loading Loading @@ -287,7 +308,7 @@ TEST_F(LeAdvertisingManagerTest, create_advertiser_test) { advertising_config.advertisement = gap_data; advertising_config.scan_response = gap_data; auto next_command_future = test_hci_layer_->GetCommandFuture(); auto last_command_future = test_hci_layer_->GetCommandFuture(OpCode::LE_SET_ADVERTISING_ENABLE); auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback, client_handler_); ASSERT_NE(LeAdvertisingManager::kInvalidId, id); Loading @@ -295,21 +316,22 @@ TEST_F(LeAdvertisingManagerTest, create_advertiser_test) { OpCode::LE_SET_ADVERTISING_PARAMETERS, OpCode::LE_SET_RANDOM_ADDRESS, OpCode::LE_SET_SCAN_RESPONSE_DATA, OpCode::LE_SET_ADVERTISING_DATA, OpCode::LE_SET_ADVERTISING_ENABLE, }; auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_NE(std::future_status::timeout, result); size_t num_commands = next_command_future.get(); for (size_t i = 0; i < adv_opcodes.size(); i++) { auto packet = test_hci_layer_->GetCommandPacket(adv_opcodes[i]); std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)}; auto result = last_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); for (size_t i = 0; i < adv_opcodes.size(); i++) { auto packet_view = test_hci_layer_->GetCommandPacket(adv_opcodes[i]); CommandPacketView command_packet_view = CommandPacketView::Create(packet_view); ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view); test_hci_layer_->IncomingEvent( CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector))); if (i < adv_opcodes.size() - 1 && --num_commands == 1) { next_command_future = test_hci_layer_->GetCommandFuture(); result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_NE(std::future_status::timeout, result); num_commands = next_command_future.get(); } } // Disable the advertiser last_command_future = test_hci_layer_->GetCommandFuture(OpCode::LE_SET_ADVERTISING_ENABLE); le_advertising_manager_->RemoveAdvertiser(id); result = last_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->IncomingEvent(LeSetAdvertisingEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); } TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) { Loading @@ -327,7 +349,7 @@ TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) { advertising_config.advertisement = gap_data; advertising_config.scan_response = gap_data; auto next_command_future = test_hci_layer_->GetCommandFuture(); auto next_command_future = test_hci_layer_->GetSubCommandFuture(SubOcf::SET_ENABLE); auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback, client_handler_); ASSERT_NE(LeAdvertisingManager::kInvalidId, id); Loading @@ -335,22 +357,71 @@ TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) { SubOcf::SET_PARAM, SubOcf::SET_DATA, SubOcf::SET_SCAN_RESP, SubOcf::SET_RANDOM_ADDR, SubOcf::SET_ENABLE, }; auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_NE(std::future_status::timeout, result); ASSERT_EQ(std::future_status::ready, result); size_t num_commands = next_command_future.get(); for (size_t i = 0; i < sub_ocf.size(); i++) { auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_MULTI_ADVT); std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS), static_cast<uint8_t>(sub_ocf[i])}; test_hci_layer_->IncomingEvent(CommandCompleteBuilder::Create(uint8_t{1}, OpCode::LE_MULTI_ADVT, std::make_unique<RawBuilder>(success_vector))); if (i < sub_ocf.size() - 1 && --num_commands == 1) { next_command_future = test_hci_layer_->GetCommandFuture(); auto sub_packet = LeMultiAdvtView::Create(LeAdvertisingCommandView::Create(packet)); ASSERT(sub_packet.IsValid()); test_hci_layer_->IncomingEvent(LeMultiAdvtCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, sub_ocf[i])); num_commands -= 1; } ASSERT_EQ(0, num_commands); // Disable the advertiser next_command_future = test_hci_layer_->GetSubCommandFuture(SubOcf::SET_ENABLE); le_advertising_manager_->RemoveAdvertiser(id); result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_NE(std::future_status::timeout, result); num_commands = next_command_future.get(); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->IncomingEvent(LeMultiAdvtSetEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); } TEST_F(LeExtendedAdvertisingManagerTest, create_advertiser_test) { ExtendedAdvertisingConfig advertising_config{}; advertising_config.event_type = AdvertisingEventType::ADV_IND; advertising_config.address_type = AddressType::PUBLIC_DEVICE_ADDRESS; std::vector<GapData> 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); advertising_config.advertisement = gap_data; advertising_config.scan_response = gap_data; advertising_config.channel_map = 1; auto last_command_future = test_hci_layer_->GetCommandFuture(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE); auto id = le_advertising_manager_->ExtendedCreateAdvertiser(advertising_config, scan_callback, set_terminated_callback, client_handler_); ASSERT_NE(LeAdvertisingManager::kInvalidId, id); std::vector<OpCode> adv_opcodes = { OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS, OpCode::LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS, OpCode::LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE, OpCode::LE_SET_EXTENDED_ADVERTISING_DATA, OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE, }; auto result = last_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)}; ASSERT_EQ(std::future_status::ready, result); for (size_t i = 0; i < adv_opcodes.size(); i++) { auto packet_view = test_hci_layer_->GetCommandPacket(adv_opcodes[i]); CommandPacketView command_packet_view = CommandPacketView::Create(packet_view); ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view); if (adv_opcodes[i] == OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS) { test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingParametersCompleteBuilder::Create( uint8_t{1}, ErrorCode::SUCCESS, static_cast<uint8_t>(-23))); } else { test_hci_layer_->IncomingEvent( CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector))); } } // Disable the advertiser last_command_future = test_hci_layer_->GetCommandFuture(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE); le_advertising_manager_->RemoveAdvertiser(id); result = last_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); } } // namespace } // namespace hci } // namespace bluetooth system/gd/hci/le_scanning_manager_test.cc +8 −4 Original line number Diff line number Diff line Loading @@ -191,7 +191,8 @@ class LeScanningManagerTest : public ::testing::Test { fake_registry_.Start<LeScanningManager>(&thread_); le_scanning_manager = static_cast<LeScanningManager*>(fake_registry_.GetModuleUnderTest(&LeScanningManager::Factory)); config_future.wait_for(std::chrono::duration(std::chrono::milliseconds(1000))); auto result = config_future.wait_for(std::chrono::duration(std::chrono::milliseconds(1000))); ASSERT_EQ(std::future_status::ready, result); HandleConfiguration(); } Loading Loading @@ -257,7 +258,8 @@ TEST_F(LeScanningManagerTest, start_scan_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->StartScan(&mock_callbacks_); next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); 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{}; Loading @@ -283,7 +285,8 @@ TEST_F(LeAndroidHciScanningManagerTest, start_scan_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->StartScan(&mock_callbacks_); next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); 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{}; Loading @@ -309,7 +312,8 @@ TEST_F(LeExtendedScanningManagerTest, start_scan_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->StartScan(&mock_callbacks_); next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_SET_EXTENDED_SCAN_ENABLE); test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); Loading Loading
system/gd/hci/le_advertising_manager.cc +91 −12 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ struct LeAdvertisingManager::impl { le_advertising_interface_ = hci_layer_->GetLeAdvertisingInterface( common::Bind(&LeAdvertisingManager::impl::handle_event, common::Unretained(this)), module_handler_); num_instances_ = controller_->GetControllerLeNumberOfSupportedAdverisingSets(); enabled_sets_ = std::vector<EnabledSet>(num_instances_); if (controller_->IsSupported(hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS)) { advertising_api_type_ = AdvertisingApiType::LE_5_0; } else if (controller_->IsSupported(hci::OpCode::LE_MULTI_ADVT)) { Loading Loading @@ -112,6 +113,7 @@ struct LeAdvertisingManager::impl { } void remove_advertiser(AdvertiserId id) { stop_advertising(id); std::unique_lock lock(id_mutex_); if (advertising_sets_.count(id) == 0) { return; Loading Loading @@ -173,6 +175,7 @@ struct LeAdvertisingManager::impl { ExtendedAdvertisingConfig new_config; AdvertisingConfig* base_config_ptr = &new_config; *(base_config_ptr) = config; new_config.legacy_pdus = true; create_extended_advertiser(id, new_config, scan_callback, set_terminated_callback, handler); } break; } Loading @@ -186,14 +189,70 @@ struct LeAdvertisingManager::impl { create_advertiser(id, config, scan_callback, set_terminated_callback, handler); return; } LOG_ALWAYS_FATAL("LE_SET_EXTENDED_ADVERTISING_PARAMETERS isn't implemented."); /* le_advertising_interface_->EnqueueCommand(hci::LeSetExtendedAdvertisingParametersBuilder::Create(config.interval_min, config.interval_max, config.event_type, config.address_type, config.peer_address_type, config.peer_address, config.channel_map, config.filter_policy, id, config.tx_power), common::BindOnce(impl::check_status), module_handler_); */ if (config.legacy_pdus) { LegacyAdvertisingProperties legacy_properties = LegacyAdvertisingProperties::ADV_IND; if (config.connectable && config.directed) { if (config.high_duty_directed_connectable) { legacy_properties = LegacyAdvertisingProperties::ADV_DIRECT_IND_HIGH; } else { legacy_properties = LegacyAdvertisingProperties::ADV_DIRECT_IND_LOW; } } if (config.scannable && !config.connectable) { legacy_properties = LegacyAdvertisingProperties::ADV_SCAN_IND; } if (!config.scannable && !config.connectable) { legacy_properties = LegacyAdvertisingProperties::ADV_NONCONN_IND; } le_advertising_interface_->EnqueueCommand( LeSetExtendedAdvertisingLegacyParametersBuilder::Create( id, legacy_properties, config.interval_min, config.interval_max, config.channel_map, config.own_address_type, config.peer_address_type, config.peer_address, config.filter_policy, config.tx_power, (config.use_le_coded_phy ? PrimaryPhyType::LE_CODED : PrimaryPhyType::LE_1M), config.sid, config.enable_scan_request_notifications), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingParametersCompleteView>), module_handler_); } else { uint8_t legacy_properties = (config.connectable ? 0x1 : 0x00) | (config.scannable ? 0x2 : 0x00) | (config.directed ? 0x4 : 0x00) | (config.high_duty_directed_connectable ? 0x8 : 0x00); uint8_t extended_properties = (config.anonymous ? 0x20 : 0x00) | (config.include_tx_power ? 0x40 : 0x00); le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingParametersBuilder::Create( id, legacy_properties, extended_properties, config.interval_min, config.interval_max, config.channel_map, config.own_address_type, config.peer_address_type, config.peer_address, config.filter_policy, config.tx_power, (config.use_le_coded_phy ? PrimaryPhyType::LE_CODED : PrimaryPhyType::LE_1M), config.secondary_max_skip, config.secondary_advertising_phy, config.sid, config.enable_scan_request_notifications), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingParametersCompleteView>), module_handler_); } le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingRandomAddressBuilder::Create(id, config.random_address), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingRandomAddressCompleteView>), module_handler_); if (!config.scan_response.empty()) { le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingScanResponseBuilder::Create(id, config.operation, config.fragment_preference, config.scan_response), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingScanResponseCompleteView>), module_handler_); } le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingDataBuilder::Create(id, config.operation, config.fragment_preference, config.advertisement), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingDataCompleteView>), module_handler_); EnabledSet curr_set; curr_set.advertising_handle_ = id; curr_set.duration_ = 0; // TODO: 0 means until the host disables it curr_set.max_extended_advertising_events_ = 0; // TODO: 0 is no maximum std::vector<EnabledSet> enabled_sets = {curr_set}; enabled_sets_[id] = curr_set; le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::ENABLED, enabled_sets), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingEnableCompleteView>), module_handler_); advertising_sets_[id].scan_callback = scan_callback; advertising_sets_[id].set_terminated_callback = set_terminated_callback; advertising_sets_[id].handler = handler; Loading @@ -204,10 +263,29 @@ struct LeAdvertisingManager::impl { LOG_INFO("Unknown advertising set %u", advertising_set); return; } le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED), common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), module_handler_); switch (advertising_api_type_) { case (AdvertisingApiType::LE_4_0): le_advertising_interface_->EnqueueCommand( hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED), common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), module_handler_); break; case (AdvertisingApiType::ANDROID_HCI): le_advertising_interface_->EnqueueCommand( hci::LeMultiAdvtSetEnableBuilder::Create(Enable::DISABLED, advertising_set), common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_); break; case (AdvertisingApiType::LE_5_0): { EnabledSet curr_set; curr_set.advertising_handle_ = advertising_set; std::vector<EnabledSet> enabled_vector{curr_set}; le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::DISABLED, enabled_vector), common::BindOnce(impl::check_status<LeSetExtendedAdvertisingEnableCompleteView>), module_handler_); } break; } std::unique_lock lock(id_mutex_); enabled_sets_[advertising_set].advertising_handle_ = -1; advertising_sets_.erase(advertising_set); } Loading @@ -223,6 +301,7 @@ struct LeAdvertisingManager::impl { std::mutex id_mutex_; size_t num_instances_; std::vector<hci::EnabledSet> enabled_sets_; AdvertisingApiType advertising_api_type_{0}; Loading Loading @@ -323,7 +402,7 @@ AdvertiserId LeAdvertisingManager::ExtendedCreateAdvertiser( } void LeAdvertisingManager::RemoveAdvertiser(AdvertiserId id) { pimpl_->remove_advertiser(id); GetHandler()->Post(common::BindOnce(&impl::remove_advertiser, common::Unretained(pimpl_.get()), id)); } } // namespace hci Loading
system/gd/hci/le_advertising_manager.h +5 −2 Original line number Diff line number Diff line Loading @@ -50,9 +50,12 @@ class ExtendedAdvertisingConfig : public AdvertisingConfig { bool include_tx_power; bool use_le_coded_phy; // Primary advertisement PHY is LE Coded uint8_t secondary_max_skip; // maximum advertising events to be skipped, 0x0 send AUX_ADV_IND prior ot the next event uint8_t secondary_advertising_phy; // 1 = 1M, 2 = 2M, 3 = coded SecondaryPhyType secondary_advertising_phy; uint8_t sid; bool enable_scan_request_notifications; Enable enable_scan_request_notifications; OwnAddressType own_address_type; Operation operation; FragmentPreference fragment_preference; }; using AdvertiserId = int32_t; Loading
system/gd/hci/le_advertising_manager_test.cc +107 −36 Original line number Diff line number Diff line Loading @@ -83,9 +83,15 @@ class TestHciLayer : public HciLayer { void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override { command_queue_.push_back(std::move(command)); auto packet_view = CommandPacketView::Create(GetPacketView(std::move(command))); ASSERT(packet_view.IsValid()); command_queue_.push_back(packet_view); command_status_callbacks.push_back(std::move(on_status)); if (command_promise_ != nullptr) { if (command_promise_ != nullptr && (command_op_code_ == OpCode::NONE || command_op_code_ == packet_view.GetOpCode())) { if (command_op_code_ == OpCode::LE_MULTI_ADVT && command_sub_ocf_ != SubOcf::SET_ENABLE) { return; } command_promise_->set_value(command_queue_.size()); command_promise_.reset(); } Loading @@ -93,30 +99,43 @@ class TestHciLayer : public HciLayer { void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override { command_queue_.push_back(std::move(command)); auto packet_view = CommandPacketView::Create(GetPacketView(std::move(command))); ASSERT(packet_view.IsValid()); command_queue_.push_back(packet_view); command_complete_callbacks.push_back(std::move(on_complete)); if (command_promise_ != nullptr) { if (command_promise_ != nullptr && (command_op_code_ == OpCode::NONE || command_op_code_ == packet_view.GetOpCode())) { if (command_op_code_ == OpCode::LE_MULTI_ADVT) { auto sub_view = LeMultiAdvtView::Create(LeAdvertisingCommandView::Create(packet_view)); ASSERT(sub_view.IsValid()); if (sub_view.GetSubCmd() != command_sub_ocf_) { return; } } command_promise_->set_value(command_queue_.size()); command_promise_.reset(); } } std::future<size_t> GetCommandFuture() { std::future<size_t> GetCommandFuture(OpCode op_code = OpCode::NONE) { ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time"); command_op_code_ = op_code; command_promise_ = std::make_unique<std::promise<size_t>>(); return command_promise_->get_future(); } std::unique_ptr<CommandPacketBuilder> GetLastCommand() { ASSERT(!command_queue_.empty()); auto last = std::move(command_queue_.front()); command_queue_.pop_front(); return last; std::future<size_t> GetSubCommandFuture(SubOcf sub_ocf) { ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time"); command_op_code_ = OpCode::LE_MULTI_ADVT; command_sub_ocf_ = sub_ocf; command_promise_ = std::make_unique<std::promise<size_t>>(); return command_promise_->get_future(); } ConnectionManagementCommandView GetCommandPacket(OpCode op_code) { auto packet_view = GetPacketView(GetLastCommand()); CommandPacketView command_packet_view = CommandPacketView::Create(packet_view); ASSERT(!command_queue_.empty()); CommandPacketView command_packet_view = CommandPacketView::Create(command_queue_.front()); command_queue_.pop_front(); ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view); ASSERT(command.IsValid()); EXPECT_EQ(command.GetOpCode(), op_code); Loading Loading @@ -178,9 +197,11 @@ class TestHciLayer : public HciLayer { std::list<base::OnceCallback<void(CommandCompleteView)>> command_complete_callbacks; std::list<base::OnceCallback<void(CommandStatusView)>> command_status_callbacks; std::list<std::unique_ptr<CommandPacketBuilder>> command_queue_; std::list<CommandPacketView> command_queue_; mutable std::mutex mutex_; std::unique_ptr<std::promise<size_t>> command_promise_{}; OpCode command_op_code_; SubOcf command_sub_ocf_; }; class LeAdvertisingManagerTest : public ::testing::Test { Loading Loading @@ -287,7 +308,7 @@ TEST_F(LeAdvertisingManagerTest, create_advertiser_test) { advertising_config.advertisement = gap_data; advertising_config.scan_response = gap_data; auto next_command_future = test_hci_layer_->GetCommandFuture(); auto last_command_future = test_hci_layer_->GetCommandFuture(OpCode::LE_SET_ADVERTISING_ENABLE); auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback, client_handler_); ASSERT_NE(LeAdvertisingManager::kInvalidId, id); Loading @@ -295,21 +316,22 @@ TEST_F(LeAdvertisingManagerTest, create_advertiser_test) { OpCode::LE_SET_ADVERTISING_PARAMETERS, OpCode::LE_SET_RANDOM_ADDRESS, OpCode::LE_SET_SCAN_RESPONSE_DATA, OpCode::LE_SET_ADVERTISING_DATA, OpCode::LE_SET_ADVERTISING_ENABLE, }; auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_NE(std::future_status::timeout, result); size_t num_commands = next_command_future.get(); for (size_t i = 0; i < adv_opcodes.size(); i++) { auto packet = test_hci_layer_->GetCommandPacket(adv_opcodes[i]); std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)}; auto result = last_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); for (size_t i = 0; i < adv_opcodes.size(); i++) { auto packet_view = test_hci_layer_->GetCommandPacket(adv_opcodes[i]); CommandPacketView command_packet_view = CommandPacketView::Create(packet_view); ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view); test_hci_layer_->IncomingEvent( CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector))); if (i < adv_opcodes.size() - 1 && --num_commands == 1) { next_command_future = test_hci_layer_->GetCommandFuture(); result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_NE(std::future_status::timeout, result); num_commands = next_command_future.get(); } } // Disable the advertiser last_command_future = test_hci_layer_->GetCommandFuture(OpCode::LE_SET_ADVERTISING_ENABLE); le_advertising_manager_->RemoveAdvertiser(id); result = last_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->IncomingEvent(LeSetAdvertisingEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); } TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) { Loading @@ -327,7 +349,7 @@ TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) { advertising_config.advertisement = gap_data; advertising_config.scan_response = gap_data; auto next_command_future = test_hci_layer_->GetCommandFuture(); auto next_command_future = test_hci_layer_->GetSubCommandFuture(SubOcf::SET_ENABLE); auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback, client_handler_); ASSERT_NE(LeAdvertisingManager::kInvalidId, id); Loading @@ -335,22 +357,71 @@ TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) { SubOcf::SET_PARAM, SubOcf::SET_DATA, SubOcf::SET_SCAN_RESP, SubOcf::SET_RANDOM_ADDR, SubOcf::SET_ENABLE, }; auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_NE(std::future_status::timeout, result); ASSERT_EQ(std::future_status::ready, result); size_t num_commands = next_command_future.get(); for (size_t i = 0; i < sub_ocf.size(); i++) { auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_MULTI_ADVT); std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS), static_cast<uint8_t>(sub_ocf[i])}; test_hci_layer_->IncomingEvent(CommandCompleteBuilder::Create(uint8_t{1}, OpCode::LE_MULTI_ADVT, std::make_unique<RawBuilder>(success_vector))); if (i < sub_ocf.size() - 1 && --num_commands == 1) { next_command_future = test_hci_layer_->GetCommandFuture(); auto sub_packet = LeMultiAdvtView::Create(LeAdvertisingCommandView::Create(packet)); ASSERT(sub_packet.IsValid()); test_hci_layer_->IncomingEvent(LeMultiAdvtCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, sub_ocf[i])); num_commands -= 1; } ASSERT_EQ(0, num_commands); // Disable the advertiser next_command_future = test_hci_layer_->GetSubCommandFuture(SubOcf::SET_ENABLE); le_advertising_manager_->RemoveAdvertiser(id); result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_NE(std::future_status::timeout, result); num_commands = next_command_future.get(); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->IncomingEvent(LeMultiAdvtSetEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); } TEST_F(LeExtendedAdvertisingManagerTest, create_advertiser_test) { ExtendedAdvertisingConfig advertising_config{}; advertising_config.event_type = AdvertisingEventType::ADV_IND; advertising_config.address_type = AddressType::PUBLIC_DEVICE_ADDRESS; std::vector<GapData> 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); advertising_config.advertisement = gap_data; advertising_config.scan_response = gap_data; advertising_config.channel_map = 1; auto last_command_future = test_hci_layer_->GetCommandFuture(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE); auto id = le_advertising_manager_->ExtendedCreateAdvertiser(advertising_config, scan_callback, set_terminated_callback, client_handler_); ASSERT_NE(LeAdvertisingManager::kInvalidId, id); std::vector<OpCode> adv_opcodes = { OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS, OpCode::LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS, OpCode::LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE, OpCode::LE_SET_EXTENDED_ADVERTISING_DATA, OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE, }; auto result = last_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)}; ASSERT_EQ(std::future_status::ready, result); for (size_t i = 0; i < adv_opcodes.size(); i++) { auto packet_view = test_hci_layer_->GetCommandPacket(adv_opcodes[i]); CommandPacketView command_packet_view = CommandPacketView::Create(packet_view); ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view); if (adv_opcodes[i] == OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS) { test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingParametersCompleteBuilder::Create( uint8_t{1}, ErrorCode::SUCCESS, static_cast<uint8_t>(-23))); } else { test_hci_layer_->IncomingEvent( CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector))); } } // Disable the advertiser last_command_future = test_hci_layer_->GetCommandFuture(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE); le_advertising_manager_->RemoveAdvertiser(id); result = last_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); } } // namespace } // namespace hci } // namespace bluetooth
system/gd/hci/le_scanning_manager_test.cc +8 −4 Original line number Diff line number Diff line Loading @@ -191,7 +191,8 @@ class LeScanningManagerTest : public ::testing::Test { fake_registry_.Start<LeScanningManager>(&thread_); le_scanning_manager = static_cast<LeScanningManager*>(fake_registry_.GetModuleUnderTest(&LeScanningManager::Factory)); config_future.wait_for(std::chrono::duration(std::chrono::milliseconds(1000))); auto result = config_future.wait_for(std::chrono::duration(std::chrono::milliseconds(1000))); ASSERT_EQ(std::future_status::ready, result); HandleConfiguration(); } Loading Loading @@ -257,7 +258,8 @@ TEST_F(LeScanningManagerTest, start_scan_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->StartScan(&mock_callbacks_); next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); 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{}; Loading @@ -283,7 +285,8 @@ TEST_F(LeAndroidHciScanningManagerTest, start_scan_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->StartScan(&mock_callbacks_); next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); 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{}; Loading @@ -309,7 +312,8 @@ TEST_F(LeExtendedScanningManagerTest, start_scan_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->StartScan(&mock_callbacks_); next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); ASSERT_EQ(std::future_status::ready, result); auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_SET_EXTENDED_SCAN_ENABLE); test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); Loading