From a3049fe43687008847a5e63b4dd57268a3c2c60b Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Thu, 20 Mar 2025 12:22:19 -0700 Subject: [PATCH] Internal bug fix PiperOrigin-RevId: 738897253 --- .../mediums/ble_v2/instant_on_lost_manager.cc | 286 +++++++++++------- .../mediums/ble_v2/instant_on_lost_manager.h | 54 ++-- .../ble_v2/instant_on_lost_manager_test.cc | 36 +-- 3 files changed, 217 insertions(+), 159 deletions(-) diff --git a/connections/implementation/mediums/ble_v2/instant_on_lost_manager.cc b/connections/implementation/mediums/ble_v2/instant_on_lost_manager.cc index a6f389ed..44672eeb 100644 --- a/connections/implementation/mediums/ble_v2/instant_on_lost_manager.cc +++ b/connections/implementation/mediums/ble_v2/instant_on_lost_manager.cc @@ -17,8 +17,11 @@ #include #include #include +#include +#include "absl/functional/any_invocable.h" #include "absl/strings/escaping.h" +#include "absl/strings/string_view.h" #include "absl/time/clock.h" #include "absl/time/time.h" #include "connections/implementation/mediums/ble_v2/ble_utils.h" @@ -26,9 +29,11 @@ #include "internal/platform/ble_v2.h" #include "internal/platform/byte_array.h" #include "internal/platform/cancelable_alarm.h" +#include "internal/platform/count_down_latch.h" +#include "internal/platform/exception.h" #include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/system_clock.h" #include "internal/platform/logging.h" -#include "internal/platform/mutex_lock.h" namespace nearby { namespace connections { @@ -38,123 +43,144 @@ namespace { constexpr int kMaxAdvertisingOnLostHashCount = InstantOnLostAdvertisement::kMaxHashCount; constexpr absl::Duration kInstantOnLostAdvertiseDuration = absl::Seconds(2); +constexpr absl::Duration kShutdownWaitDuration = absl::Seconds(1); +constexpr absl::Duration kTestWaitDuration = absl::Seconds(3); } // namespace void InstantOnLostManager::OnAdvertisingStarted( const std::string& service_id, const ByteArray& advertisement_data) { - MutexLock lock(&mutex_); - if (is_shutdown_) { - NEARBY_LOGS(WARNING) << __func__ << ": InstantOnLostManager is shutdown."; - return; - } - - if (service_id.empty()) { - NEARBY_LOGS(WARNING) << __func__ << ": Invalid service ID."; - return; - } - - if (advertisement_data.Empty()) { - NEARBY_LOGS(WARNING) << __func__ << ": Invalid advertisement data."; - return; - } - - ByteArray advertisement_hash = - bleutils::GenerateAdvertisementHash(advertisement_data); - - // Check whether the hash is in on lost list. - for (auto& it : active_on_lost_advertising_list_) { - if (it.hash == std::string(advertisement_hash)) { - StopOnLostAdvertising(); - if (stop_advertising_alarm_ != nullptr) { - stop_advertising_alarm_->Cancel(); - } - - active_on_lost_advertising_list_.remove(it); - if (!active_on_lost_advertising_list_.empty()) { - StartInstantOnLostAdvertisement(); - } - NEARBY_LOGS(INFO) << __func__ << ": Remove the lost hash " - << absl::BytesToHexString( - advertisement_hash.AsStringView()) - << " from the list."; - break; + RunOnInstantOnLostThread("OnAdvertisingStarted", [this, service_id, + advertisement_data]() { + if (service_id.empty()) { + LOG(WARNING) << __func__ << ": Invalid service ID."; + return; } - } - active_advertising_map_[service_id] = advertisement_hash; - NEARBY_LOGS(INFO) << __func__ - << ": OnAdvertisingStarted from service ID: " << service_id - << " with hash: " - << absl::BytesToHexString( - advertisement_hash.AsStringView()); + if (advertisement_data.Empty()) { + LOG(WARNING) << __func__ << ": Invalid advertisement data."; + return; + } + + ByteArray advertisement_hash = + bleutils::GenerateAdvertisementHash(advertisement_data); + + // Check whether the hash is in on lost list. + for (auto& it : active_on_lost_advertising_list_) { + if (it.hash == std::string(advertisement_hash)) { + StopOnLostAdvertising(); + if (stop_advertising_alarm_ != nullptr) { + stop_advertising_alarm_->Cancel(); + } + + active_on_lost_advertising_list_.remove(it); + if (!active_on_lost_advertising_list_.empty()) { + StartInstantOnLostAdvertisement(); + } + LOG(INFO) << __func__ << ": Remove the lost hash " + << absl::BytesToHexString(advertisement_hash.AsStringView()) + << " from the list."; + break; + } + } + + active_advertising_map_[service_id] = advertisement_hash; + LOG(INFO) << __func__ + << ": OnAdvertisingStarted from service ID: " << service_id + << " with hash: " + << absl::BytesToHexString(advertisement_hash.AsStringView()); + }); } void InstantOnLostManager::OnAdvertisingStopped(const std::string& service_id) { - MutexLock lock(&mutex_); + RunOnInstantOnLostThread("OnAdvertisingStopped", [this, service_id]() { + auto active_advertising = active_advertising_map_.extract(service_id); - if (is_shutdown_) { - NEARBY_LOGS(WARNING) << __func__ << ": InstantOnLostManager is shutdown."; - return; - } + if (active_advertising.empty()) { + LOG(WARNING) << __func__ + << ": Stopped advertising for service ID: " << service_id + << " but it is not found in the active advertising map."; + return; + } - auto active_advertising = active_advertising_map_.extract(service_id); + const ByteArray& advertisement_hash = active_advertising.mapped(); - if (active_advertising.empty()) { - NEARBY_LOGS(WARNING) - << __func__ << ": Stopped advertising for service ID: " << service_id - << " but it is not found in the active advertising map."; - return; - } + if (active_on_lost_advertising_list_.size() >= + kMaxAdvertisingOnLostHashCount) { + active_on_lost_advertising_list_.pop_front(); + } - const ByteArray& advertisement_hash = active_advertising.mapped(); + active_on_lost_advertising_list_.push_back( + {absl::Now(), std::string(advertisement_hash)}); - if (active_on_lost_advertising_list_.size() >= - kMaxAdvertisingOnLostHashCount) { - active_on_lost_advertising_list_.pop_front(); - } + if (!StartInstantOnLostAdvertisement()) { + LOG(ERROR) << __func__ << ": Failed to advertise instant onLost BLE."; + } - active_on_lost_advertising_list_.push_back( - {absl::Now(), std::string(advertisement_hash)}); - - if (!StartInstantOnLostAdvertisement()) { - NEARBY_LOGS(ERROR) << __func__ - << ": Failed to advertise instant onLost BLE."; - } - - NEARBY_LOGS(INFO) << __func__ - << ": OnAdvertisingStopped from service ID: " << service_id; + LOG(INFO) << __func__ + << ": OnAdvertisingStopped from service ID: " << service_id; + }); } bool InstantOnLostManager::Shutdown() { - MutexLock lock(&mutex_); - if (is_shutdown_) { - NEARBY_LOGS(WARNING) << __func__ - << ": InstantOnLostManager is already shutdown."; - return false; + CountDownLatch latch(1); + RunOnInstantOnLostThread("Shutdown", [this, &latch]() { + if (is_shutdown_) { + LOG(WARNING) << __func__ << ": InstantOnLostManager is already shutdown."; + latch.CountDown(); + return; + } + + is_shutdown_ = true; + + if (stop_advertising_alarm_ != nullptr) { + stop_advertising_alarm_->Cancel(); + } + + StopOnLostAdvertising(); + + active_on_lost_advertising_list_.clear(); + active_advertising_map_.clear(); + + LOG(INFO) << __func__ << ": InstantOnLostManager is shutdown."; + latch.CountDown(); + }); + + ExceptionOr result = latch.Await(kShutdownWaitDuration); + if (result.ok()) { + return result.result(); } - - if (stop_advertising_alarm_ != nullptr) { - stop_advertising_alarm_->Cancel(); - } - - StopOnLostAdvertising(); - - active_on_lost_advertising_list_.clear(); - active_advertising_map_.clear(); - is_shutdown_ = true; - - NEARBY_LOGS(INFO) << __func__ << ": InstantOnLostManager is shutdown."; - return true; + return false; } -std::list InstantOnLostManager::GetOnLostHashes() { - MutexLock lock(&mutex_); - return GetOnLostHashesInternal(); +std::list InstantOnLostManager::GetOnLostHashesForTesting() { + CountDownLatch latch(1); + std::list result; + RunOnInstantOnLostThread("GetOnLostHashes", [&latch, &result, this]() { + result = GetOnLostHashesInternal(); + latch.CountDown(); + }); + + ExceptionOr latch_result = latch.Await(kTestWaitDuration); + if (latch_result.ok() && latch_result.result()) { + return result; + } + return {}; } -bool InstantOnLostManager::IsOnLostAdvertising() { - MutexLock lock(&mutex_); - return is_on_lost_advertising_; +bool InstantOnLostManager::IsOnLostAdvertisingForTesting() { + CountDownLatch latch(1); + bool is_on_lost_advertising = false; + RunOnInstantOnLostThread("IsOnLostAdvertising", + [&latch, &is_on_lost_advertising, this]() { + is_on_lost_advertising = is_on_lost_advertising_; + latch.CountDown(); + }); + ExceptionOr result = latch.Await(kTestWaitDuration); + if (result.ok() && result.result()) { + return is_on_lost_advertising; + } + + return false; } bool InstantOnLostManager::StartInstantOnLostAdvertisement() { @@ -167,8 +193,8 @@ bool InstantOnLostManager::StartInstantOnLostAdvertisement() { absl::StatusOr on_lost_advertisement = InstantOnLostAdvertisement::CreateFromHashes(GetOnLostHashesInternal()); if (!on_lost_advertisement.ok()) { - NEARBY_LOGS(ERROR) << __func__ - << ": Failed to create instant on lost advertisement."; + LOG(ERROR) << __func__ + << ": Failed to create instant on lost advertisement."; return false; } @@ -180,11 +206,12 @@ bool InstantOnLostManager::StartInstantOnLostAdvertisement() { StopOnLostAdvertising(); if (!ble_medium_.StartAdvertising(advertisement_data, advertise_parameters)) { - NEARBY_LOGS(ERROR) << __func__ - << ": Failed to start advertising for instant on lost."; + LOG(ERROR) << __func__ + << ": Failed to start advertising for instant on lost."; return false; } + last_advertising_start_time_ = SystemClock::ElapsedRealtime(); if (stop_advertising_alarm_ != nullptr) { stop_advertising_alarm_->Cancel(); } @@ -192,20 +219,33 @@ bool InstantOnLostManager::StartInstantOnLostAdvertisement() { // Schedule to stop the advertising. stop_advertising_alarm_ = std::make_unique( "stop_instant_on_lost_advertising", - [this]() { - MutexLock lock(&mutex_); - StopOnLostAdvertising(); - // All hashes already advertised for enough time, we should clear the - // list. - active_on_lost_advertising_list_.clear(); - is_on_lost_advertising_ = false; + [this, start_time = last_advertising_start_time_]() { + // It is running on timer thread, so we need to run it on instant on + // lost thread. + RunOnInstantOnLostThread( + "stop_instant_on_lost_advertising", [this, start_time]() { + if (start_time != last_advertising_start_time_) { + LOG(WARNING) + << "Skip to stop instant on lost advertising due to " + "the start time is changed."; + return; + } + + LOG(INFO) << "Stop instant on lost advertising after duration."; + + StopOnLostAdvertising(); + // All hashes already advertised for enough time, we should clear + // the list. + active_on_lost_advertising_list_.clear(); + is_on_lost_advertising_ = false; + }); }, - kInstantOnLostAdvertiseDuration, &executor_); + kInstantOnLostAdvertiseDuration, &service_thread_); is_on_lost_advertising_ = true; - NEARBY_LOGS(INFO) - << __func__ << ": Started instant on lost advertising with hashes count: " - << active_on_lost_advertising_list_.size(); + LOG(INFO) << __func__ + << ": Started instant on lost advertising with hashes count: " + << active_on_lost_advertising_list_.size(); return true; } @@ -215,12 +255,12 @@ bool InstantOnLostManager::StopOnLostAdvertising() { } if (!ble_medium_.StopAdvertising()) { - NEARBY_LOGS(ERROR) << __func__ << ": Failed to stop on lost advertising."; + LOG(ERROR) << __func__ << ": Failed to stop on lost advertising."; return false; } is_on_lost_advertising_ = false; - NEARBY_LOGS(INFO) << __func__ << ": Stopped instant on lost advertising"; + LOG(INFO) << __func__ << ": Stopped instant on lost advertising"; return true; } @@ -244,6 +284,28 @@ std::list InstantOnLostManager::GetOnLostHashesInternal() { return result; } +void InstantOnLostManager::RunOnInstantOnLostThread( + absl::string_view task_name, absl::AnyInvocable task) { + service_thread_.Execute( + [this, name = std::string(task_name), task = std::move(task)]() mutable { + if (is_shutdown_) { + LOG(WARNING) << "Skip to run InstantOnLost task " << name + << " due to InstantOnLost is closed"; + return; + } + + LOG(INFO) << __func__ << ": Scheduled to run task " << name + << " on InstantOnLost thread."; + + VLOG(1) << __func__ << ": Started to run task " << name + << " on InstantOnLost thread. "; + task(); + + VLOG(1) << __func__ << ": Completed to run task " << name + << " on InstantOnLost thread."; + }); +} + } // namespace mediums } // namespace connections } // namespace nearby diff --git a/connections/implementation/mediums/ble_v2/instant_on_lost_manager.h b/connections/implementation/mediums/ble_v2/instant_on_lost_manager.h index 77bcc424..ea335d98 100644 --- a/connections/implementation/mediums/ble_v2/instant_on_lost_manager.h +++ b/connections/implementation/mediums/ble_v2/instant_on_lost_manager.h @@ -19,35 +19,36 @@ #include #include -#include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" +#include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" #include "absl/time/time.h" #include "internal/platform/ble_v2.h" #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/byte_array.h" #include "internal/platform/cancelable_alarm.h" -#include "internal/platform/mutex.h" #include "internal/platform/scheduled_executor.h" namespace nearby { namespace connections { namespace mediums { +// This InstantOnLostManager class is thread-compatible, and all methods are +// executed on a single thread. class InstantOnLostManager { public: InstantOnLostManager() = default; ~InstantOnLostManager() = default; void OnAdvertisingStarted(const std::string& service_id, - const ByteArray& advertisement_data) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnAdvertisingStopped(const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); + const ByteArray& advertisement_data); + void OnAdvertisingStopped(const std::string& service_id); - bool Shutdown() ABSL_LOCKS_EXCLUDED(mutex_); + bool Shutdown(); - std::list GetOnLostHashes() ABSL_LOCKS_EXCLUDED(mutex_); - bool IsOnLostAdvertising() ABSL_LOCKS_EXCLUDED(mutex_); + // For testing only. + std::list GetOnLostHashesForTesting(); + bool IsOnLostAdvertisingForTesting(); private: struct OnLostAdvertisementHashInfo { @@ -59,34 +60,29 @@ class InstantOnLostManager { } }; - bool StartInstantOnLostAdvertisement() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - bool StopOnLostAdvertising() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - void RemoveExpiredOnLostAdvertisements() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - std::list GetOnLostHashesInternal() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + bool StartInstantOnLostAdvertisement(); + bool StopOnLostAdvertising(); + void RemoveExpiredOnLostAdvertisements(); + std::list GetOnLostHashesInternal(); - Mutex mutex_; + void RunOnInstantOnLostThread(absl::string_view task_name, + absl::AnyInvocable task); - std::unique_ptr stop_advertising_alarm_ - ABSL_GUARDED_BY(mutex_); + bool is_shutdown_ = false; + ScheduledExecutor service_thread_; + std::unique_ptr stop_advertising_alarm_; // BLE medium used for lost packet advertising. - BluetoothAdapter adapter_ ABSL_GUARDED_BY(mutex_); - BleV2Medium ble_medium_ ABSL_GUARDED_BY(mutex_) = BleV2Medium{adapter_}; - bool is_on_lost_advertising_ ABSL_GUARDED_BY(mutex_) = false; - - bool is_shutdown_ ABSL_GUARDED_BY(mutex_) = false; - - ScheduledExecutor executor_ ABSL_GUARDED_BY(mutex_); + BluetoothAdapter adapter_; + BleV2Medium ble_medium_ = BleV2Medium{adapter_}; + bool is_on_lost_advertising_ = false; + absl::Time last_advertising_start_time_ = absl::InfinitePast(); // Active on lost advertising, the maximum size is 5. - std::list active_on_lost_advertising_list_ - ABSL_GUARDED_BY(mutex_); + std::list active_on_lost_advertising_list_; // Map of service ID to advertisement data hash. - absl::flat_hash_map active_advertising_map_ - ABSL_GUARDED_BY(mutex_); + absl::flat_hash_map active_advertising_map_; }; } // namespace mediums diff --git a/connections/implementation/mediums/ble_v2/instant_on_lost_manager_test.cc b/connections/implementation/mediums/ble_v2/instant_on_lost_manager_test.cc index 38e8f37a..cc8c4a29 100644 --- a/connections/implementation/mediums/ble_v2/instant_on_lost_manager_test.cc +++ b/connections/implementation/mediums/ble_v2/instant_on_lost_manager_test.cc @@ -44,9 +44,9 @@ TEST(InstantOnLostManager, StartOnLostAdvertisingAfterStopAdvertising) { instant_on_lost_manager.OnAdvertisingStarted( std::string(kServiceIdA), ByteArray(kData1.data(), kData1.size())); instant_on_lost_manager.OnAdvertisingStopped(std::string(kServiceIdA)); - EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertising()); + EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertisingForTesting()); absl::SleepFor(kOnLostAdvertisingDuration); - EXPECT_FALSE(instant_on_lost_manager.IsOnLostAdvertising()); + EXPECT_FALSE(instant_on_lost_manager.IsOnLostAdvertisingForTesting()); } TEST(InstantOnLostManager, NoOnLostAdvertisingWhenAdvertiseAgain) { @@ -56,7 +56,7 @@ TEST(InstantOnLostManager, NoOnLostAdvertisingWhenAdvertiseAgain) { instant_on_lost_manager.OnAdvertisingStopped(std::string(kServiceIdA)); instant_on_lost_manager.OnAdvertisingStarted( std::string(kServiceIdA), ByteArray(kData1.data(), kData1.size())); - EXPECT_FALSE(instant_on_lost_manager.IsOnLostAdvertising()); + EXPECT_FALSE(instant_on_lost_manager.IsOnLostAdvertisingForTesting()); instant_on_lost_manager.Shutdown(); } @@ -65,18 +65,18 @@ TEST(InstantOnLostManager, MultipleAdvertisingOnSameServiceId) { instant_on_lost_manager.OnAdvertisingStarted( std::string(kServiceIdA), ByteArray(kData1.data(), kData1.size())); instant_on_lost_manager.OnAdvertisingStopped(std::string(kServiceIdA)); - EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertising()); - EXPECT_EQ(instant_on_lost_manager.GetOnLostHashes().size(), 1); + EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertisingForTesting()); + EXPECT_EQ(instant_on_lost_manager.GetOnLostHashesForTesting().size(), 1); instant_on_lost_manager.OnAdvertisingStarted( std::string(kServiceIdA), ByteArray(kData2.data(), kData2.size())); instant_on_lost_manager.OnAdvertisingStopped(std::string(kServiceIdA)); - EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertising()); - EXPECT_EQ(instant_on_lost_manager.GetOnLostHashes().size(), 2); + EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertisingForTesting()); + EXPECT_EQ(instant_on_lost_manager.GetOnLostHashesForTesting().size(), 2); instant_on_lost_manager.OnAdvertisingStarted( std::string(kServiceIdA), ByteArray(kData3.data(), kData3.size())); instant_on_lost_manager.OnAdvertisingStopped(std::string(kServiceIdA)); - EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertising()); - EXPECT_EQ(instant_on_lost_manager.GetOnLostHashes().size(), 3); + EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertisingForTesting()); + EXPECT_EQ(instant_on_lost_manager.GetOnLostHashesForTesting().size(), 3); instant_on_lost_manager.Shutdown(); } @@ -100,8 +100,8 @@ TEST(InstantOnLostManager, MaximumOnLostHashesInOnLostAdvertising) { instant_on_lost_manager.OnAdvertisingStarted( std::string(kServiceIdC), ByteArray(kData6.data(), kData6.size())); instant_on_lost_manager.OnAdvertisingStopped(std::string(kServiceIdC)); - EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertising()); - EXPECT_EQ(instant_on_lost_manager.GetOnLostHashes().size(), 5); + EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertisingForTesting()); + EXPECT_EQ(instant_on_lost_manager.GetOnLostHashesForTesting().size(), 5); instant_on_lost_manager.Shutdown(); } @@ -119,7 +119,7 @@ TEST(InstantOnLostManager, AdvertisingOnShutdownManager) { instant_on_lost_manager.OnAdvertisingStarted( std::string(kServiceIdA), ByteArray(kData1.data(), kData1.size())); instant_on_lost_manager.OnAdvertisingStopped(std::string(kServiceIdA)); - EXPECT_FALSE(instant_on_lost_manager.IsOnLostAdvertising()); + EXPECT_FALSE(instant_on_lost_manager.IsOnLostAdvertisingForTesting()); } TEST(InstantOnLostManager, RemoveExpiredOnLostAdvertisement) { @@ -127,20 +127,20 @@ TEST(InstantOnLostManager, RemoveExpiredOnLostAdvertisement) { instant_on_lost_manager.OnAdvertisingStarted( std::string(kServiceIdA), ByteArray(kData1.data(), kData1.size())); instant_on_lost_manager.OnAdvertisingStopped(std::string(kServiceIdA)); - EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertising()); - EXPECT_EQ(instant_on_lost_manager.GetOnLostHashes().size(), 1); + EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertisingForTesting()); + EXPECT_EQ(instant_on_lost_manager.GetOnLostHashesForTesting().size(), 1); absl::SleepFor(absl::Milliseconds(1050)); instant_on_lost_manager.OnAdvertisingStarted( std::string(kServiceIdA), ByteArray(kData2.data(), kData2.size())); instant_on_lost_manager.OnAdvertisingStopped(std::string(kServiceIdA)); - EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertising()); - EXPECT_EQ(instant_on_lost_manager.GetOnLostHashes().size(), 2); + EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertisingForTesting()); + EXPECT_EQ(instant_on_lost_manager.GetOnLostHashesForTesting().size(), 2); absl::SleepFor(absl::Milliseconds(1050)); instant_on_lost_manager.OnAdvertisingStarted( std::string(kServiceIdA), ByteArray(kData3.data(), kData3.size())); instant_on_lost_manager.OnAdvertisingStopped(std::string(kServiceIdA)); - EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertising()); - EXPECT_EQ(instant_on_lost_manager.GetOnLostHashes().size(), 2); + EXPECT_TRUE(instant_on_lost_manager.IsOnLostAdvertisingForTesting()); + EXPECT_EQ(instant_on_lost_manager.GetOnLostHashesForTesting().size(), 2); instant_on_lost_manager.Shutdown(); }