diff --git a/connections/implementation/mediums/BUILD b/connections/implementation/mediums/BUILD index 554b8288..15490a29 100644 --- a/connections/implementation/mediums/BUILD +++ b/connections/implementation/mediums/BUILD @@ -97,6 +97,7 @@ cc_library( "//connections/implementation/proto:offline_wire_formats_cc_proto", "//internal/platform:base", "//internal/platform:types", + "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/strings", ], diff --git a/connections/implementation/mediums/ble_v2/BUILD b/connections/implementation/mediums/ble_v2/BUILD index dd542fd6..02dafdfd 100644 --- a/connections/implementation/mediums/ble_v2/BUILD +++ b/connections/implementation/mediums/ble_v2/BUILD @@ -49,6 +49,7 @@ cc_library( "//internal/platform:types", "//internal/platform:util", "//internal/platform:uuid", + "//internal/platform/implementation:comm", "//proto/mediums:ble_frames_cc_proto", "@aappleby_smhasher//:libmurmur3", "@com_google_absl//absl/base:core_headers", diff --git a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc index 949855ed..b5b5f566 100644 --- a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc +++ b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc @@ -21,6 +21,7 @@ #include #include +#include "absl/status/statusor.h" #include "absl/strings/escaping.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/mediums/ble_v2/advertisement_read_result.h" @@ -29,13 +30,17 @@ #include "connections/implementation/mediums/ble_v2/ble_utils.h" #include "connections/implementation/mediums/ble_v2/bloom_filter.h" #include "connections/implementation/mediums/ble_v2/discovered_peripheral_callback.h" +#include "connections/implementation/mediums/ble_v2/instant_on_lost_advertisement.h" #include "internal/flags/nearby_flags.h" #include "internal/platform/ble_v2.h" #include "internal/platform/byte_array.h" +#include "internal/platform/implementation/ble_v2.h" #include "internal/platform/logging.h" #include "internal/platform/multi_thread_executor.h" #include "internal/platform/mutex_lock.h" +using ::nearby::api::ble_v2::BleAdvertisementData; + namespace nearby { namespace connections { namespace mediums { @@ -98,8 +103,7 @@ void DiscoveredPeripheralTracker::StopTracking(const std::string& service_id) { } void DiscoveredPeripheralTracker::ProcessFoundBleAdvertisement( - BleV2Peripheral peripheral, - ::nearby::api::ble_v2::BleAdvertisementData advertisement_data, + BleV2Peripheral peripheral, BleAdvertisementData advertisement_data, AdvertisementFetcher advertisement_fetcher) { MutexLock lock(&mutex_); @@ -116,6 +120,10 @@ void DiscoveredPeripheralTracker::ProcessFoundBleAdvertisement( return; } + if (HandleOnLostAdvertisementLocked(peripheral, advertisement_data)) { + return; + } + if (IsSkippableGattAdvertisement(advertisement_data)) { NEARBY_LOGS(INFO) << "Ignore GATT advertisement and wait for extended advertisement."; @@ -127,6 +135,49 @@ void DiscoveredPeripheralTracker::ProcessFoundBleAdvertisement( std::move(advertisement_fetcher)); } +bool DiscoveredPeripheralTracker::HandleOnLostAdvertisementLocked( + BleV2Peripheral peripheral, + const BleAdvertisementData& advertisement_data) { + auto service_data = + advertisement_data.service_data.find(bleutils::kCopresenceServiceUuid); + if (service_data == advertisement_data.service_data.end()) { + return false; + } + absl::StatusOr on_lost_advertisement = + InstantOnLostAdvertisement::CreateFromBytes( + service_data->second.AsStringView()); + if (!on_lost_advertisement.ok()) { + return false; + } + NEARBY_LOGS(INFO) << __func__ << ": Found OnLost advertisement for hash:" + << absl::BytesToHexString(on_lost_advertisement->GetHash()); + for (const auto& it : gatt_advertisement_infos_) { + if (it.second.advertisement_header.GetAdvertisementHash().string_data() == + on_lost_advertisement->GetHash()) { + auto discovery_cb_it = service_id_infos_.find(it.second.service_id); + if (discovery_cb_it == service_id_infos_.end()) { + NEARBY_LOGS(INFO) + << __func__ + << ": Discarding OnLost advertisement for untracked service_id"; + return false; + } + auto advertisements = + gatt_advertisements_[it.second.advertisement_header]; + for (const auto& advertisement : advertisements) { + if (advertisement.IsValid()) { + discovery_cb_it->second.discovered_peripheral_callback + .peripheral_lost_cb(peripheral, it.second.service_id, + advertisement.GetData(), false); + NEARBY_LOGS(INFO) << __func__ << ": OnLost triggered for service_id " + << it.second.service_id; + return true; + } + } + } + } + return false; +} + void DiscoveredPeripheralTracker::ProcessLostGattAdvertisements() { MutexLock lock(&mutex_); diff --git a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h index 7e463ed5..2f588f14 100644 --- a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h +++ b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h @@ -29,6 +29,7 @@ #include "connections/implementation/mediums/ble_v2/ble_advertisement_header.h" #include "connections/implementation/mediums/ble_v2/discovered_peripheral_callback.h" #include "connections/implementation/mediums/lost_entity_tracker.h" +#include "internal/platform/ble_v2.h" #include "internal/platform/byte_array.h" #include "internal/platform/multi_thread_executor.h" #include "internal/platform/mutex.h" @@ -244,6 +245,15 @@ class DiscoveredPeripheralTracker { const BleAdvertisementHeader& advertisement_header) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + // Processes on lost advertisements. Returns true when the advertisement: + // 1. Is an Instant On Lost BLE advertisement. + // 2. Matches a peripheral's advertisement hash that has previously been + // discovered. + bool HandleOnLostAdvertisementLocked( + BleV2Peripheral peripheral, + const ::nearby::api::ble_v2::BleAdvertisementData& advertisement_data) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + Mutex mutex_; bool is_extended_advertisement_available_; diff --git a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker_test.cc b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker_test.cc index 45993a01..f7ef765c 100644 --- a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker_test.cc +++ b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker_test.cc @@ -17,10 +17,13 @@ #include #include +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "connections/implementation/mediums/ble_v2/advertisement_read_result.h" #include "connections/implementation/mediums/ble_v2/ble_utils.h" #include "connections/implementation/mediums/ble_v2/bloom_filter.h" +#include "connections/implementation/mediums/ble_v2/instant_on_lost_advertisement.h" #include "internal/platform/ble_v2.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/medium_environment.h" @@ -956,6 +959,70 @@ TEST_F(DiscoveredPeripheralTrackerTest, EXPECT_FALSE(lost_latch.Await(kWaitDuration).result()); } +TEST_F(DiscoveredPeripheralTrackerTest, LostPeripheralForInstantOnLost) { + std::vector service_ids = {std::string(kServiceIdA)}; + ByteArray advertisement_hash = GenerateRandomAdvertisementHash(); + ByteArray advertisement_header_bytes = + CreateBleAdvertisementHeader(advertisement_hash, service_ids); + ByteArray advertisement_bytes = CreateBleAdvertisement( + std::string(kServiceIdA), ByteArray(std::string(kData)), + ByteArray(std::string(kDeviceToken))); + CountDownLatch found_latch(1); + CountDownLatch lost_latch(1); + CountDownLatch fetch_latch(1); + + discovered_peripheral_tracker_.StartTracking( + std::string(kServiceIdA), + { + .peripheral_discovered_cb = + [&found_latch](BleV2Peripheral peripheral, + const std::string& service_id, + const ByteArray& advertisement_bytes, + bool fast_advertisement) { + EXPECT_EQ(advertisement_bytes, ByteArray(std::string(kData))); + EXPECT_FALSE(fast_advertisement); + found_latch.CountDown(); + }, + .peripheral_lost_cb = + [&lost_latch]( + BleV2Peripheral peripheral, const std::string& service_id, + const ByteArray& advertisement_bytes, + bool fast_advertisement) { lost_latch.CountDown(); }, + }, + {}); + + api::ble_v2::BleAdvertisementData advertisement_data; + if (!advertisement_header_bytes.Empty()) { + advertisement_data.service_data.insert( + {bleutils::kCopresenceServiceUuid, advertisement_header_bytes}); + } + + FindAdvertisement(advertisement_data, {advertisement_bytes}, fetch_latch); + + // We should receive a client callback of a peripheral discovery. + fetch_latch.Await(kWaitDuration); + ASSERT_TRUE(found_latch.Await(kWaitDuration).result()); + EXPECT_EQ(GetFetchAdvertisementCallbackCount(), 1); + + auto advertisement = InstantOnLostAdvertisement::CreateFromHash( + advertisement_hash.AsStringView()); + ASSERT_OK(advertisement); + api::ble_v2::BleAdvertisementData loss_advertisement_data; + loss_advertisement_data.service_data.insert( + {bleutils::kCopresenceServiceUuid, ByteArray(advertisement->ToBytes())}); + + FindAdvertisement(loss_advertisement_data, + {ByteArray(advertisement->ToBytes())}, fetch_latch); + + // Then, go through a cycle of onLost. Since we triggered a forced loss via + // the instant on los advertisement, the lost call should trigger the onLost + // client callback. + discovered_peripheral_tracker_.ProcessLostGattAdvertisements(); + + // We should receive a client callback of a lost peripheral + EXPECT_TRUE(lost_latch.Await(kWaitDuration).result()); +} + } // namespace } // namespace mediums