Loading system/gd/hci/le_scanning_manager.cc +20 −7 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <memory> #include <unordered_map> #include "android_bluetooth_flags.h" #include "hci/acl_manager.h" #include "hci/controller.h" #include "hci/event_checkers.h" Loading Loading @@ -373,8 +374,15 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { extended_event_type = transform_to_extended_event_type({.legacy = true}); break; case AdvertisingEventType::SCAN_RESPONSE: if (IS_FLAG_ENABLED(fix_nonconnectable_scannable_advertisement)) { // We don't know if the initial advertising report was connectable or not. // LeScanningReassembler fixes the connectable field. extended_event_type = transform_to_extended_event_type( {.scannable = true, .scan_response = true, .legacy = true}); } else { extended_event_type = transform_to_extended_event_type( {.connectable = true, .scannable = true, .scan_response = true, .legacy = true}); } break; default: LOG_WARN("Unsupported event type:%d", (uint16_t)report.event_type_); Loading Loading @@ -450,10 +458,11 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { scanning_reassembler_.SetIgnoreScanResponses( filter_policy_ == LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY); auto complete_advertising_data = scanning_reassembler_.ProcessAdvertisingReport( std::optional<LeScanningReassembler::CompleteAdvertisingData> processed_report = scanning_reassembler_.ProcessAdvertisingReport( event_type, address_type, address, advertising_sid, advertising_data); if (complete_advertising_data.has_value()) { if (processed_report.has_value()) { switch (address_type) { case (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS: case (uint8_t)AddressType::PUBLIC_IDENTITY_ADDRESS: Loading @@ -465,8 +474,12 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { break; } const uint16_t result_event_type = IS_FLAG_ENABLED(fix_nonconnectable_scannable_advertisement) ? processed_report->extended_event_type : event_type; scanning_callbacks_->OnScanResult( event_type, result_event_type, address_type, address, primary_phy, Loading @@ -475,7 +488,7 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { tx_power, get_rssi_after_calibration(rssi), periodic_advertising_interval, complete_advertising_data.value()); std::move(processed_report->data)); } } Loading system/gd/hci/le_scanning_manager_test.cc +69 −3 Original line number Diff line number Diff line Loading @@ -29,12 +29,13 @@ #include <queue> #include <vector> #include "hci/hci_layer_fake.h" #include "android_bluetooth_flags.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/hci_layer_fake.h" #include "hci/uuid.h" #include "os/thread.h" #include "packet/raw_builder.h" Loading @@ -51,6 +52,13 @@ using packet::RawBuilder; namespace { // Event type fields. // TODO(b/315496838): Use a common enum for event type bits. static constexpr uint16_t kConnectable = 0x1; static constexpr uint16_t kScannable = 0x2; static constexpr uint16_t kScanResponse = 0x8; static constexpr uint16_t kLegacy = 0x10; hci::AdvertisingPacketContentFilterCommand make_filter(const hci::ApcfFilterType& filter_type) { hci::AdvertisingPacketContentFilterCommand filter{}; filter.filter_type = filter_type; Loading Loading @@ -362,9 +370,11 @@ TEST_F(LeScanningManagerTest, start_scan_test) { // Enable scan le_scanning_manager->Scan(true); ASSERT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); test_hci_layer_->IncomingEvent( LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); ASSERT_EQ(OpCode::LE_SET_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); test_hci_layer_->IncomingEvent( LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); LeAdvertisingResponse report = make_advertising_report(); EXPECT_CALL(mock_callbacks_, OnScanResult); Loading @@ -372,6 +382,62 @@ TEST_F(LeScanningManagerTest, start_scan_test) { test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); } TEST_F(LeScanningManagerTest, legacy_adv_scan_ind_report_with_scan_response) { start_le_scanning_manager(); le_scanning_manager->Scan(true); ASSERT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); test_hci_layer_->IncomingEvent( LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); ASSERT_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(); // Scannable & not connectable! report.event_type_ = AdvertisingEventType::ADV_SCAN_IND; test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); LeAdvertisingResponse scan_response = make_advertising_report(); scan_response.event_type_ = AdvertisingEventType::SCAN_RESPONSE; // The 'connectable' bit should NOT be set. uint16_t extended_event_type = kLegacy | kScannable | kScanResponse; if (!IS_FLAG_ENABLED(fix_nonconnectable_scannable_advertisement)) { extended_event_type |= kConnectable; } EXPECT_CALL(mock_callbacks_, OnScanResult(extended_event_type, _, _, _, _, _, _, _, _, _)); test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({scan_response})); } TEST_F(LeScanningManagerTest, legacy_adv_ind_report_with_scan_response) { start_le_scanning_manager(); le_scanning_manager->Scan(true); ASSERT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); test_hci_layer_->IncomingEvent( LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); ASSERT_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(); // Scannable & connectable! report.event_type_ = AdvertisingEventType::ADV_IND; test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); LeAdvertisingResponse scan_response = make_advertising_report(); scan_response.event_type_ = AdvertisingEventType::SCAN_RESPONSE; uint16_t extended_event_type = kLegacy | kScannable | kConnectable | kScanResponse; EXPECT_CALL(mock_callbacks_, OnScanResult(extended_event_type, _, _, _, _, _, _, _, _, _)); test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({scan_response})); } TEST_F(LeScanningManagerTest, is_ad_type_filter_supported_false_test) { start_le_scanning_manager(); ASSERT_TRUE(fake_registry_.IsStarted(&HciLayer::Factory)); Loading system/gd/hci/le_scanning_reassembler.cc +19 −6 Original line number Diff line number Diff line Loading @@ -32,7 +32,8 @@ namespace bluetooth::hci { std::optional<std::vector<uint8_t>> LeScanningReassembler::ProcessAdvertisingReport( std::optional<LeScanningReassembler::CompleteAdvertisingData> LeScanningReassembler::ProcessAdvertisingReport( uint16_t event_type, uint8_t address_type, Address address, Loading Loading @@ -67,7 +68,7 @@ std::optional<std::vector<uint8_t>> LeScanningReassembler::ProcessAdvertisingRep // Concatenate the data with existing fragments. std::list<AdvertisingFragment>::iterator advertising_fragment = AppendFragment(key, advertising_data); AppendFragment(key, event_type, advertising_data); // Trim the advertising data when the complete payload is received. if (data_status != DataStatus::CONTINUING) { Loading @@ -89,9 +90,11 @@ std::optional<std::vector<uint8_t>> LeScanningReassembler::ProcessAdvertisingRep // Otherwise the full advertising report has been reassembled, // removed the cache entry and return the complete advertising data. std::vector<uint8_t> complete_advertising_data = std::move(advertising_fragment->data); CompleteAdvertisingData result{ .extended_event_type = advertising_fragment->extended_event_type, .data = std::move(advertising_fragment->data)}; cache_.erase(advertising_fragment); return complete_advertising_data; return result; } /// Trim the advertising data by removing empty or overflowing Loading Loading @@ -140,9 +143,19 @@ bool LeScanningReassembler::AdvertisingKey::operator==(const AdvertisingKey& oth /// If the advertiser is unknown a new entry is added, optionally by /// dropping the oldest advertiser. std::list<LeScanningReassembler::AdvertisingFragment>::iterator LeScanningReassembler::AppendFragment(const AdvertisingKey& key, const std::vector<uint8_t>& data) { LeScanningReassembler::AppendFragment( const AdvertisingKey& key, uint16_t extended_event_type, const std::vector<uint8_t>& data) { auto it = FindFragment(key); if (it != cache_.end()) { // Legacy scan responses don't contain a 'connectable' bit, so this adds the // 'connectable' bit from the initial report. if ((extended_event_type & (1 << kLegacyBit)) && (extended_event_type & (1 << kScanResponseBit))) { it->extended_event_type = extended_event_type | (it->extended_event_type & (1 << kConnectableBit)); } else { it->extended_event_type = extended_event_type; } it->data.insert(it->data.end(), data.cbegin(), data.cend()); return it; } Loading @@ -151,7 +164,7 @@ LeScanningReassembler::AppendFragment(const AdvertisingKey& key, const std::vect cache_.pop_back(); } cache_.emplace_front(key, data); cache_.emplace_front(key, extended_event_type, data); return cache_.begin(); } Loading system/gd/hci/le_scanning_reassembler.h +18 −5 Original line number Diff line number Diff line Loading @@ -29,14 +29,21 @@ namespace bluetooth::hci { /// The LE Scanning reassembler is responsible for defragmenting /// LE advertising reports that are too large to fit inside an HCI event /// and were fragmented by the compiler. /// and were fragmented by the controller. /// The reassembler also joins scan response data with the /// matching advertising data. class LeScanningReassembler { public: struct CompleteAdvertisingData { uint16_t extended_event_type; std::vector<uint8_t> data; }; LeScanningReassembler(){}; LeScanningReassembler(const LeScanningReassembler&) = delete; LeScanningReassembler& operator=(const LeScanningReassembler&) = delete; /// Process an incoming advertsing report, extracted from any of the Loading @@ -44,7 +51,7 @@ class LeScanningReassembler { /// events. /// Returns the completed advertising data if the event was complete, or the /// completion of a fragmented advertising event. std::optional<std::vector<uint8_t>> ProcessAdvertisingReport( std::optional<CompleteAdvertisingData> ProcessAdvertisingReport( uint16_t event_type, uint8_t address_type, Address address, Loading @@ -62,6 +69,7 @@ class LeScanningReassembler { bool ignore_scan_responses_{false}; /// Constants for parsing event_type. static constexpr uint8_t kConnectableBit = 0; static constexpr uint8_t kScannableBit = 1; static constexpr uint8_t kDirectedBit = 2; static constexpr uint8_t kScanResponseBit = 3; Loading Loading @@ -89,10 +97,12 @@ class LeScanningReassembler { /// Packs incomplete advertising data. struct AdvertisingFragment { AdvertisingKey key; uint16_t extended_event_type; std::vector<uint8_t> data; AdvertisingFragment(const AdvertisingKey& key, const std::vector<uint8_t>& data) : key(key), data(data.begin(), data.end()) {} AdvertisingFragment( const AdvertisingKey& key, uint16_t extended_event_type, const std::vector<uint8_t>& data) : key(key), extended_event_type(extended_event_type), data(data.begin(), data.end()) {} }; /// Advertising cache for de-fragmenting extended advertising reports, Loading @@ -105,9 +115,12 @@ class LeScanningReassembler { /// Advertising cache management methods. std::list<AdvertisingFragment>::iterator AppendFragment( const AdvertisingKey& key, const std::vector<uint8_t>& data); const AdvertisingKey& key, uint16_t extended_event_type, const std::vector<uint8_t>& data); void RemoveFragment(const AdvertisingKey& key); bool ContainsFragment(const AdvertisingKey& key); std::list<AdvertisingFragment>::iterator FindFragment(const AdvertisingKey& key); /// Trim the advertising data by removing empty or overflowing Loading system/gd/hci/le_scanning_reassembler_test.cc +138 −79 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ using namespace std::chrono_literals; namespace bluetooth::hci { // Event type fields. static constexpr uint16_t kConnectable = 0x1; static constexpr uint16_t kScannable = 0x2; static constexpr uint16_t kScanResponse = 0x8; static constexpr uint16_t kLegacy = 0x10; Loading Loading @@ -66,16 +67,19 @@ TEST_F(LeScanningReassemblerTest, trim_advertising_data) { TEST_F(LeScanningReassemblerTest, non_scannable_legacy_advertising) { // Test non scannable legacy advertising. ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kLegacy | kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x1, 0x2}), {0x1, 0x2}) .value() .data, std::vector<uint8_t>({0x1, 0x2})); } TEST_F(LeScanningReassemblerTest, scannable_legacy_advertising) { TEST_F(LeScanningReassemblerTest, scannable_non_connectable_legacy_advertising) { // Test scannable legacy advertising with well formed advertising and // scan response payload. ASSERT_FALSE(reassembler_ Loading @@ -87,14 +91,15 @@ TEST_F(LeScanningReassemblerTest, scannable_legacy_advertising) { {0x1, 0x2}) .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( auto processed_report = reassembler_.ProcessAdvertisingReport( kLegacy | kScannable | kScanResponse | kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x3, 0x4, 0x5, 0x6}), std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); {0x3, 0x4, 0x5, 0x6}); ASSERT_TRUE(processed_report.has_value()); ASSERT_EQ(processed_report.value().extended_event_type, kLegacy | kScannable | kScanResponse); ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); // Test scannable legacy advertising with padding after the // advertising and scan response data. Loading @@ -108,15 +113,41 @@ TEST_F(LeScanningReassemblerTest, scannable_legacy_advertising) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kLegacy | kScannable | kScanResponse | kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x3, 0x4, 0x5, 0x6, 0x0, 0x0}), {0x3, 0x4, 0x5, 0x6, 0x0, 0x0}) .value() .data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); } TEST_F(LeScanningReassemblerTest, scannable_connectable_legacy_advertising) { ASSERT_FALSE(reassembler_ .ProcessAdvertisingReport( kLegacy | kScannable | kConnectable, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x1, 0x2}) .has_value()); auto processed_report = reassembler_.ProcessAdvertisingReport( kLegacy | kScannable | kScanResponse, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x3, 0x4, 0x5, 0x6}); ASSERT_TRUE(processed_report.has_value()); ASSERT_EQ( processed_report.value().extended_event_type, kLegacy | kScannable | kScanResponse | kConnectable); ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); } TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) { // Test fragmented non scannable extended advertising. // The split may occur in the middle of a GAP entry. Loading @@ -129,14 +160,15 @@ TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) { {0x1, 0x2, 0x3}) .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( auto processed_report = reassembler_.ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x4, 0x5, 0x6}), std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); {0x4, 0x5, 0x6}); ASSERT_TRUE(processed_report.has_value()); ASSERT_EQ(processed_report.value().extended_event_type, kComplete); ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); // Test fragmented and truncated non scannable extended advertising. // The split may occur in the middle of a GAP entry. Loading @@ -150,12 +182,15 @@ TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kTruncated, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x4, 0x5, 0x6, 0x7}), {0x4, 0x5, 0x6, 0x7}) .value() .data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); // Test fragmented and truncated anonymous, non scannable Loading @@ -170,12 +205,15 @@ TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kTruncated, (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED, Address::kEmpty, kSidNotPresent, {0x4, 0x5, 0x6, 0x7}), {0x4, 0x5, 0x6, 0x7}) .value() .data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); } Loading Loading @@ -211,12 +249,15 @@ TEST_F(LeScanningReassemblerTest, scannable_extended_advertising) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kTruncated, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0xb, 0xc, 0xd, 0xe, 0x0}), {0xb, 0xc, 0xd, 0xe, 0x0}) .value() .data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe})); } Loading @@ -232,23 +273,29 @@ TEST_F(LeScanningReassemblerTest, ignore_scan_responses) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x1, 0x2}), {0x1, 0x2}) .value() .data, std::vector<uint8_t>({0x1, 0x2})); // The option ignore_scan_responses forces scan responses to be dropped. reassembler_.SetIgnoreScanResponses(true); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kScannable | kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x1, 0x2}), {0x1, 0x2}) .value() .data, std::vector<uint8_t>({0x1, 0x2})); } Loading Loading @@ -292,35 +339,47 @@ TEST_F(LeScanningReassemblerTest, interleaved_advertising) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x0}), {0x0}) .value() .data, std::vector<uint8_t>({0x2, 0x0, 0x0})); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x1}), {0x1}) .value() .data, std::vector<uint8_t>({0x2, 0x1, 0x1})); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, 0x1, {0x2}), reassembler_ .ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, 0x1, {0x2}) .value() .data, std::vector<uint8_t>({0x2, 0x2, 0x2})); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kComplete, (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED, Address::kEmpty, 0x1, {0x3}), {0x3}) .value() .data, std::vector<uint8_t>({0x2, 0x3, 0x3})); } Loading Loading
system/gd/hci/le_scanning_manager.cc +20 −7 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <memory> #include <unordered_map> #include "android_bluetooth_flags.h" #include "hci/acl_manager.h" #include "hci/controller.h" #include "hci/event_checkers.h" Loading Loading @@ -373,8 +374,15 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { extended_event_type = transform_to_extended_event_type({.legacy = true}); break; case AdvertisingEventType::SCAN_RESPONSE: if (IS_FLAG_ENABLED(fix_nonconnectable_scannable_advertisement)) { // We don't know if the initial advertising report was connectable or not. // LeScanningReassembler fixes the connectable field. extended_event_type = transform_to_extended_event_type( {.scannable = true, .scan_response = true, .legacy = true}); } else { extended_event_type = transform_to_extended_event_type( {.connectable = true, .scannable = true, .scan_response = true, .legacy = true}); } break; default: LOG_WARN("Unsupported event type:%d", (uint16_t)report.event_type_); Loading Loading @@ -450,10 +458,11 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { scanning_reassembler_.SetIgnoreScanResponses( filter_policy_ == LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY); auto complete_advertising_data = scanning_reassembler_.ProcessAdvertisingReport( std::optional<LeScanningReassembler::CompleteAdvertisingData> processed_report = scanning_reassembler_.ProcessAdvertisingReport( event_type, address_type, address, advertising_sid, advertising_data); if (complete_advertising_data.has_value()) { if (processed_report.has_value()) { switch (address_type) { case (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS: case (uint8_t)AddressType::PUBLIC_IDENTITY_ADDRESS: Loading @@ -465,8 +474,12 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { break; } const uint16_t result_event_type = IS_FLAG_ENABLED(fix_nonconnectable_scannable_advertisement) ? processed_report->extended_event_type : event_type; scanning_callbacks_->OnScanResult( event_type, result_event_type, address_type, address, primary_phy, Loading @@ -475,7 +488,7 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { tx_power, get_rssi_after_calibration(rssi), periodic_advertising_interval, complete_advertising_data.value()); std::move(processed_report->data)); } } Loading
system/gd/hci/le_scanning_manager_test.cc +69 −3 Original line number Diff line number Diff line Loading @@ -29,12 +29,13 @@ #include <queue> #include <vector> #include "hci/hci_layer_fake.h" #include "android_bluetooth_flags.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/hci_layer_fake.h" #include "hci/uuid.h" #include "os/thread.h" #include "packet/raw_builder.h" Loading @@ -51,6 +52,13 @@ using packet::RawBuilder; namespace { // Event type fields. // TODO(b/315496838): Use a common enum for event type bits. static constexpr uint16_t kConnectable = 0x1; static constexpr uint16_t kScannable = 0x2; static constexpr uint16_t kScanResponse = 0x8; static constexpr uint16_t kLegacy = 0x10; hci::AdvertisingPacketContentFilterCommand make_filter(const hci::ApcfFilterType& filter_type) { hci::AdvertisingPacketContentFilterCommand filter{}; filter.filter_type = filter_type; Loading Loading @@ -362,9 +370,11 @@ TEST_F(LeScanningManagerTest, start_scan_test) { // Enable scan le_scanning_manager->Scan(true); ASSERT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); test_hci_layer_->IncomingEvent( LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); ASSERT_EQ(OpCode::LE_SET_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); test_hci_layer_->IncomingEvent( LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); LeAdvertisingResponse report = make_advertising_report(); EXPECT_CALL(mock_callbacks_, OnScanResult); Loading @@ -372,6 +382,62 @@ TEST_F(LeScanningManagerTest, start_scan_test) { test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); } TEST_F(LeScanningManagerTest, legacy_adv_scan_ind_report_with_scan_response) { start_le_scanning_manager(); le_scanning_manager->Scan(true); ASSERT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); test_hci_layer_->IncomingEvent( LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); ASSERT_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(); // Scannable & not connectable! report.event_type_ = AdvertisingEventType::ADV_SCAN_IND; test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); LeAdvertisingResponse scan_response = make_advertising_report(); scan_response.event_type_ = AdvertisingEventType::SCAN_RESPONSE; // The 'connectable' bit should NOT be set. uint16_t extended_event_type = kLegacy | kScannable | kScanResponse; if (!IS_FLAG_ENABLED(fix_nonconnectable_scannable_advertisement)) { extended_event_type |= kConnectable; } EXPECT_CALL(mock_callbacks_, OnScanResult(extended_event_type, _, _, _, _, _, _, _, _, _)); test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({scan_response})); } TEST_F(LeScanningManagerTest, legacy_adv_ind_report_with_scan_response) { start_le_scanning_manager(); le_scanning_manager->Scan(true); ASSERT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); test_hci_layer_->IncomingEvent( LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); ASSERT_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(); // Scannable & connectable! report.event_type_ = AdvertisingEventType::ADV_IND; test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); LeAdvertisingResponse scan_response = make_advertising_report(); scan_response.event_type_ = AdvertisingEventType::SCAN_RESPONSE; uint16_t extended_event_type = kLegacy | kScannable | kConnectable | kScanResponse; EXPECT_CALL(mock_callbacks_, OnScanResult(extended_event_type, _, _, _, _, _, _, _, _, _)); test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({scan_response})); } TEST_F(LeScanningManagerTest, is_ad_type_filter_supported_false_test) { start_le_scanning_manager(); ASSERT_TRUE(fake_registry_.IsStarted(&HciLayer::Factory)); Loading
system/gd/hci/le_scanning_reassembler.cc +19 −6 Original line number Diff line number Diff line Loading @@ -32,7 +32,8 @@ namespace bluetooth::hci { std::optional<std::vector<uint8_t>> LeScanningReassembler::ProcessAdvertisingReport( std::optional<LeScanningReassembler::CompleteAdvertisingData> LeScanningReassembler::ProcessAdvertisingReport( uint16_t event_type, uint8_t address_type, Address address, Loading Loading @@ -67,7 +68,7 @@ std::optional<std::vector<uint8_t>> LeScanningReassembler::ProcessAdvertisingRep // Concatenate the data with existing fragments. std::list<AdvertisingFragment>::iterator advertising_fragment = AppendFragment(key, advertising_data); AppendFragment(key, event_type, advertising_data); // Trim the advertising data when the complete payload is received. if (data_status != DataStatus::CONTINUING) { Loading @@ -89,9 +90,11 @@ std::optional<std::vector<uint8_t>> LeScanningReassembler::ProcessAdvertisingRep // Otherwise the full advertising report has been reassembled, // removed the cache entry and return the complete advertising data. std::vector<uint8_t> complete_advertising_data = std::move(advertising_fragment->data); CompleteAdvertisingData result{ .extended_event_type = advertising_fragment->extended_event_type, .data = std::move(advertising_fragment->data)}; cache_.erase(advertising_fragment); return complete_advertising_data; return result; } /// Trim the advertising data by removing empty or overflowing Loading Loading @@ -140,9 +143,19 @@ bool LeScanningReassembler::AdvertisingKey::operator==(const AdvertisingKey& oth /// If the advertiser is unknown a new entry is added, optionally by /// dropping the oldest advertiser. std::list<LeScanningReassembler::AdvertisingFragment>::iterator LeScanningReassembler::AppendFragment(const AdvertisingKey& key, const std::vector<uint8_t>& data) { LeScanningReassembler::AppendFragment( const AdvertisingKey& key, uint16_t extended_event_type, const std::vector<uint8_t>& data) { auto it = FindFragment(key); if (it != cache_.end()) { // Legacy scan responses don't contain a 'connectable' bit, so this adds the // 'connectable' bit from the initial report. if ((extended_event_type & (1 << kLegacyBit)) && (extended_event_type & (1 << kScanResponseBit))) { it->extended_event_type = extended_event_type | (it->extended_event_type & (1 << kConnectableBit)); } else { it->extended_event_type = extended_event_type; } it->data.insert(it->data.end(), data.cbegin(), data.cend()); return it; } Loading @@ -151,7 +164,7 @@ LeScanningReassembler::AppendFragment(const AdvertisingKey& key, const std::vect cache_.pop_back(); } cache_.emplace_front(key, data); cache_.emplace_front(key, extended_event_type, data); return cache_.begin(); } Loading
system/gd/hci/le_scanning_reassembler.h +18 −5 Original line number Diff line number Diff line Loading @@ -29,14 +29,21 @@ namespace bluetooth::hci { /// The LE Scanning reassembler is responsible for defragmenting /// LE advertising reports that are too large to fit inside an HCI event /// and were fragmented by the compiler. /// and were fragmented by the controller. /// The reassembler also joins scan response data with the /// matching advertising data. class LeScanningReassembler { public: struct CompleteAdvertisingData { uint16_t extended_event_type; std::vector<uint8_t> data; }; LeScanningReassembler(){}; LeScanningReassembler(const LeScanningReassembler&) = delete; LeScanningReassembler& operator=(const LeScanningReassembler&) = delete; /// Process an incoming advertsing report, extracted from any of the Loading @@ -44,7 +51,7 @@ class LeScanningReassembler { /// events. /// Returns the completed advertising data if the event was complete, or the /// completion of a fragmented advertising event. std::optional<std::vector<uint8_t>> ProcessAdvertisingReport( std::optional<CompleteAdvertisingData> ProcessAdvertisingReport( uint16_t event_type, uint8_t address_type, Address address, Loading @@ -62,6 +69,7 @@ class LeScanningReassembler { bool ignore_scan_responses_{false}; /// Constants for parsing event_type. static constexpr uint8_t kConnectableBit = 0; static constexpr uint8_t kScannableBit = 1; static constexpr uint8_t kDirectedBit = 2; static constexpr uint8_t kScanResponseBit = 3; Loading Loading @@ -89,10 +97,12 @@ class LeScanningReassembler { /// Packs incomplete advertising data. struct AdvertisingFragment { AdvertisingKey key; uint16_t extended_event_type; std::vector<uint8_t> data; AdvertisingFragment(const AdvertisingKey& key, const std::vector<uint8_t>& data) : key(key), data(data.begin(), data.end()) {} AdvertisingFragment( const AdvertisingKey& key, uint16_t extended_event_type, const std::vector<uint8_t>& data) : key(key), extended_event_type(extended_event_type), data(data.begin(), data.end()) {} }; /// Advertising cache for de-fragmenting extended advertising reports, Loading @@ -105,9 +115,12 @@ class LeScanningReassembler { /// Advertising cache management methods. std::list<AdvertisingFragment>::iterator AppendFragment( const AdvertisingKey& key, const std::vector<uint8_t>& data); const AdvertisingKey& key, uint16_t extended_event_type, const std::vector<uint8_t>& data); void RemoveFragment(const AdvertisingKey& key); bool ContainsFragment(const AdvertisingKey& key); std::list<AdvertisingFragment>::iterator FindFragment(const AdvertisingKey& key); /// Trim the advertising data by removing empty or overflowing Loading
system/gd/hci/le_scanning_reassembler_test.cc +138 −79 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ using namespace std::chrono_literals; namespace bluetooth::hci { // Event type fields. static constexpr uint16_t kConnectable = 0x1; static constexpr uint16_t kScannable = 0x2; static constexpr uint16_t kScanResponse = 0x8; static constexpr uint16_t kLegacy = 0x10; Loading Loading @@ -66,16 +67,19 @@ TEST_F(LeScanningReassemblerTest, trim_advertising_data) { TEST_F(LeScanningReassemblerTest, non_scannable_legacy_advertising) { // Test non scannable legacy advertising. ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kLegacy | kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x1, 0x2}), {0x1, 0x2}) .value() .data, std::vector<uint8_t>({0x1, 0x2})); } TEST_F(LeScanningReassemblerTest, scannable_legacy_advertising) { TEST_F(LeScanningReassemblerTest, scannable_non_connectable_legacy_advertising) { // Test scannable legacy advertising with well formed advertising and // scan response payload. ASSERT_FALSE(reassembler_ Loading @@ -87,14 +91,15 @@ TEST_F(LeScanningReassemblerTest, scannable_legacy_advertising) { {0x1, 0x2}) .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( auto processed_report = reassembler_.ProcessAdvertisingReport( kLegacy | kScannable | kScanResponse | kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x3, 0x4, 0x5, 0x6}), std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); {0x3, 0x4, 0x5, 0x6}); ASSERT_TRUE(processed_report.has_value()); ASSERT_EQ(processed_report.value().extended_event_type, kLegacy | kScannable | kScanResponse); ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); // Test scannable legacy advertising with padding after the // advertising and scan response data. Loading @@ -108,15 +113,41 @@ TEST_F(LeScanningReassemblerTest, scannable_legacy_advertising) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kLegacy | kScannable | kScanResponse | kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x3, 0x4, 0x5, 0x6, 0x0, 0x0}), {0x3, 0x4, 0x5, 0x6, 0x0, 0x0}) .value() .data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); } TEST_F(LeScanningReassemblerTest, scannable_connectable_legacy_advertising) { ASSERT_FALSE(reassembler_ .ProcessAdvertisingReport( kLegacy | kScannable | kConnectable, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x1, 0x2}) .has_value()); auto processed_report = reassembler_.ProcessAdvertisingReport( kLegacy | kScannable | kScanResponse, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x3, 0x4, 0x5, 0x6}); ASSERT_TRUE(processed_report.has_value()); ASSERT_EQ( processed_report.value().extended_event_type, kLegacy | kScannable | kScanResponse | kConnectable); ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); } TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) { // Test fragmented non scannable extended advertising. // The split may occur in the middle of a GAP entry. Loading @@ -129,14 +160,15 @@ TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) { {0x1, 0x2, 0x3}) .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( auto processed_report = reassembler_.ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x4, 0x5, 0x6}), std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); {0x4, 0x5, 0x6}); ASSERT_TRUE(processed_report.has_value()); ASSERT_EQ(processed_report.value().extended_event_type, kComplete); ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); // Test fragmented and truncated non scannable extended advertising. // The split may occur in the middle of a GAP entry. Loading @@ -150,12 +182,15 @@ TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kTruncated, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x4, 0x5, 0x6, 0x7}), {0x4, 0x5, 0x6, 0x7}) .value() .data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); // Test fragmented and truncated anonymous, non scannable Loading @@ -170,12 +205,15 @@ TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kTruncated, (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED, Address::kEmpty, kSidNotPresent, {0x4, 0x5, 0x6, 0x7}), {0x4, 0x5, 0x6, 0x7}) .value() .data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6})); } Loading Loading @@ -211,12 +249,15 @@ TEST_F(LeScanningReassemblerTest, scannable_extended_advertising) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kTruncated, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0xb, 0xc, 0xd, 0xe, 0x0}), {0xb, 0xc, 0xd, 0xe, 0x0}) .value() .data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe})); } Loading @@ -232,23 +273,29 @@ TEST_F(LeScanningReassemblerTest, ignore_scan_responses) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x1, 0x2}), {0x1, 0x2}) .value() .data, std::vector<uint8_t>({0x1, 0x2})); // The option ignore_scan_responses forces scan responses to be dropped. reassembler_.SetIgnoreScanResponses(true); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kScannable | kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x1, 0x2}), {0x1, 0x2}) .value() .data, std::vector<uint8_t>({0x1, 0x2})); } Loading Loading @@ -292,35 +339,47 @@ TEST_F(LeScanningReassemblerTest, interleaved_advertising) { .has_value()); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x0}), {0x0}) .value() .data, std::vector<uint8_t>({0x2, 0x0, 0x0})); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS, kTestAddress, kSidNotPresent, {0x1}), {0x1}) .value() .data, std::vector<uint8_t>({0x2, 0x1, 0x1})); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, 0x1, {0x2}), reassembler_ .ProcessAdvertisingReport( kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, 0x1, {0x2}) .value() .data, std::vector<uint8_t>({0x2, 0x2, 0x2})); ASSERT_EQ( reassembler_.ProcessAdvertisingReport( reassembler_ .ProcessAdvertisingReport( kComplete, (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED, Address::kEmpty, 0x1, {0x3}), {0x3}) .value() .data, std::vector<uint8_t>({0x2, 0x3, 0x3})); } Loading