From 4f386b95dbd12dcaabd2e467358dff3dc73ec442 Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Tue, 18 Jun 2024 09:09:24 -0700 Subject: [PATCH] Added logic to stabilize endpoint IDs PiperOrigin-RevId: 644407047 --- connections/implementation/BUILD | 3 + .../implementation/base_pcp_handler.cc | 41 ++- connections/implementation/base_pcp_handler.h | 27 +- connections/implementation/client_proxy.cc | 171 ++++++--- connections/implementation/client_proxy.h | 42 ++- .../implementation/client_proxy_test.cc | 346 +++++++++++++++++- 6 files changed, 559 insertions(+), 71 deletions(-) diff --git a/connections/implementation/BUILD b/connections/implementation/BUILD index 512790f0..5adc6b9c 100644 --- a/connections/implementation/BUILD +++ b/connections/implementation/BUILD @@ -237,6 +237,7 @@ cc_test( deps = [ ":internal", ":internal_test", + "//base:casts", "//connections:core_types", "//connections/implementation/analytics", "//connections/implementation/flags:connections_flags", @@ -249,6 +250,7 @@ cc_test( "//internal/interop:authentication_transport_interface", "//internal/interop:device", "//internal/platform:base", + "//internal/platform:cancellation_flag", "//internal/platform:comm", "//internal/platform:test_util", "//internal/platform:types", @@ -260,6 +262,7 @@ cc_test( "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/status", "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", "@com_google_absl//absl/types:span", diff --git a/connections/implementation/base_pcp_handler.cc b/connections/implementation/base_pcp_handler.cc index bcfb02f8..14bdbe4d 100644 --- a/connections/implementation/base_pcp_handler.cc +++ b/connections/implementation/base_pcp_handler.cc @@ -227,20 +227,34 @@ Status BasePcpHandler::StartAdvertising( "start-advertising", [this, client, &service_id, &info, &compatible_advertising_options, &response]() RUN_ON_PCP_HANDLER_THREAD() { - // The endpoint id inside of the advertisement is different to high - // visibility and low visibility mode. In order to decide if client - // should grab the high visibility or low visibility id, it needs to - // tell client which one right now, before - // client#StartedAdvertising. - if (ShouldEnterHighVisibilityMode(compatible_advertising_options)) { - client->EnterHighVisibilityMode(); + if (NearbyFlags::GetInstance().GetBoolFlag( + connections::config_package_nearby::nearby_connections_feature:: + kUseStableEndpointId)) { + if (ShouldEnterStableEndpointIdMode(compatible_advertising_options)) { + client->EnterStableEndpointIdMode(); + } + } else { + // The endpoint id inside of the advertisement is different to high + // visibility and low visibility mode. In order to decide if client + // should grab the high visibility or low visibility id, it needs to + // tell client which one right now, before + // client#StartedAdvertising. + if (ShouldEnterHighVisibilityMode(compatible_advertising_options)) { + client->EnterHighVisibilityMode(); + } } auto result = StartAdvertisingImpl( client, service_id, client->GetLocalEndpointId(), info.endpoint_info, compatible_advertising_options); if (!result.status.Ok()) { - client->ExitHighVisibilityMode(); + if (NearbyFlags::GetInstance().GetBoolFlag( + connections::config_package_nearby:: + nearby_connections_feature::kUseStableEndpointId)) { + client->ExitStableEndpointIdMode(); + } else { + client->ExitHighVisibilityMode(); + } response.Set(result.status); return; } @@ -333,6 +347,17 @@ bool BasePcpHandler::ShouldEnterHighVisibilityMode( advertising_options.allowed.bluetooth; } +bool BasePcpHandler::ShouldEnterStableEndpointIdMode( + const AdvertisingOptions& advertising_options) { + if (advertising_options.use_stable_endpoint_id) { + return true; + } else if (advertising_options.low_power) { + return false; + } else { + return true; + } +} + BooleanMediumSelector BasePcpHandler::ComputeIntersectionOfSupportedMediums( const PendingConnectionInfo& connection_info) { absl::flat_hash_set intersection; diff --git a/connections/implementation/base_pcp_handler.h b/connections/implementation/base_pcp_handler.h index 31ecc08a..c2e58001 100644 --- a/connections/implementation/base_pcp_handler.h +++ b/connections/implementation/base_pcp_handler.h @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -25,28 +26,45 @@ #include "absl/base/thread_annotations.h" #include "absl/container/btree_map.h" #include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" #include "absl/time/time.h" +#include "connections/advertising_options.h" +#include "connections/connection_options.h" +#include "connections/discovery_options.h" +#include "connections/implementation/analytics/packet_meta_data.h" #include "connections/implementation/bwu_manager.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/encryption_runner.h" +#include "connections/implementation/endpoint_channel.h" #include "connections/implementation/endpoint_channel_manager.h" #include "connections/implementation/endpoint_manager.h" #include "connections/implementation/mediums/mediums.h" +#include "connections/implementation/mediums/webrtc_peer_id.h" #include "connections/implementation/pcp.h" #include "connections/implementation/pcp_handler.h" #include "connections/listeners.h" #include "connections/medium_selector.h" +#include "connections/out_of_band_connection_metadata.h" +#include "connections/params.h" #include "connections/status.h" +#include "connections/strategy.h" #include "connections/v3/connection_listening_options.h" #include "connections/v3/listeners.h" #include "internal/interop/authentication_status.h" +#include "internal/interop/device.h" +#include "internal/interop/device_provider.h" #include "internal/platform/atomic_boolean.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/connection_info.h" #include "internal/platform/count_down_latch.h" +#include "internal/platform/exception.h" #include "internal/platform/future.h" -#include "internal/platform/prng.h" +#include "internal/platform/mutex.h" +#include "internal/platform/nsd_service_info.h" +#include "internal/platform/runnable.h" #include "internal/platform/scheduled_executor.h" #include "internal/platform/single_thread_executor.h" @@ -608,6 +626,13 @@ class BasePcpHandler : public PcpHandler, bool ShouldEnterHighVisibilityMode( const AdvertisingOptions& advertising_options); + // Below cases should enter stable endpoint id mode: + // 1. When use stable endpoint id returns true. + // 2. When low power returns false. + // 3. Other cases return true. + bool ShouldEnterStableEndpointIdMode( + const AdvertisingOptions& advertising_options); + // Returns the intersection of supported mediums based on the mediums reported // by the remote client and the local client's advertising options. BooleanMediumSelector ComputeIntersectionOfSupportedMediums( diff --git a/connections/implementation/client_proxy.cc b/connections/implementation/client_proxy.cc index 75a93f5d..e60810db 100644 --- a/connections/implementation/client_proxy.cc +++ b/connections/implementation/client_proxy.cc @@ -15,32 +15,46 @@ #include "connections/implementation/client_proxy.h" #include -#include #include #include -#include #include #include +#include #include #include #include +#include #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/functional/any_invocable.h" #include "absl/strings/escaping.h" #include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "absl/types/span.h" #include "connections/advertising_options.h" +#include "connections/connection_options.h" #include "connections/discovery_options.h" +#include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/listeners.h" #include "connections/medium_selector.h" +#include "connections/payload.h" +#include "connections/status.h" +#include "connections/strategy.h" #include "connections/v3/bandwidth_info.h" #include "connections/v3/connection_listening_options.h" +#include "connections/v3/connection_result.h" +#include "connections/v3/connections_device.h" #include "connections/v3/connections_device_provider.h" +#include "connections/v3/listeners.h" #include "internal/analytics/event_logger.h" #include "internal/flags/nearby_flags.h" +#include "internal/interop/device.h" +#include "internal/platform/byte_array.h" #include "internal/platform/cancelable_alarm.h" +#include "internal/platform/cancellation_flag.h" +#include "internal/platform/error_code_params.h" #include "internal/platform/error_code_recorder.h" #include "internal/platform/feature_flags.h" #include "internal/platform/implementation/platform.h" @@ -52,18 +66,26 @@ namespace nearby { namespace connections { - +namespace { using ::location::nearby::connections::OsInfo; -// The definition is necessary before C++17. -constexpr absl::Duration - ClientProxy::kHighPowerAdvertisementEndpointIdCacheTimeout; - constexpr char kEndpointIdChars[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}; +bool IsFeatureUseStableEndpointIdEnabled() { + return NearbyFlags::GetInstance().GetBoolFlag( + connections::config_package_nearby::nearby_connections_feature:: + kUseStableEndpointId); +} + +} // namespace + +// The definition is necessary before C++17. +constexpr absl::Duration + ClientProxy::kHighPowerAdvertisementEndpointIdCacheTimeout; + ClientProxy::ClientProxy(::nearby::analytics::EventLogger* event_logger) : client_id_(Prng().NextInt64()) { NEARBY_LOGS(INFO) << "ClientProxy ctor event_logger=" << event_logger; @@ -96,18 +118,19 @@ std::string ClientProxy::GetLocalEndpointId() { MutexLock lock(&mutex_); if (!local_endpoint_id_.empty()) { NEARBY_LOGS(INFO) << __func__ - << "Reusing cached endpoint id: " << local_endpoint_id_; + << ": Reusing cached endpoint id: " << local_endpoint_id_; return local_endpoint_id_; } if (external_device_provider_ == nullptr) { local_endpoint_id_ = GenerateLocalEndpointId(); - NEARBY_LOGS(INFO) << __func__ << "Locally generating endpoint id: " + NEARBY_LOGS(INFO) << __func__ << ": Locally generating endpoint id: " << local_endpoint_id_; } else { local_endpoint_id_ = external_device_provider_->GetLocalDevice()->GetEndpointId(); NEARBY_LOGS(INFO) - << __func__ << "From external device provider, populating endpoint id: " + << __func__ + << ": From external device provider, populating endpoint id: " << local_endpoint_id_; } return local_endpoint_id_; @@ -146,13 +169,26 @@ void ClientProxy::SetBluetoothMacAddress( } std::string ClientProxy::GenerateLocalEndpointId() { - if (high_vis_mode_) { - if (!local_high_vis_mode_cache_endpoint_id_.empty()) { - NEARBY_LOGS(INFO) - << "ClientProxy [Local Endpoint Re-using cached endpoint id]: client=" - << GetClientId() << "; local_high_vis_mode_cache_endpoint_id_=" - << local_high_vis_mode_cache_endpoint_id_; - return local_high_vis_mode_cache_endpoint_id_; + if (IsFeatureUseStableEndpointIdEnabled()) { + if (!cached_endpoint_id_.empty()) { + if (stable_endpoint_id_mode_) { + NEARBY_LOGS(INFO) << "ClientProxy [Local Endpoint Re-using cached " + "endpoint id due to in stable endpoint id mode]: " + "client=" + << GetClientId() + << "; cached_endpoint_id_=" << cached_endpoint_id_; + return cached_endpoint_id_; + } + } + } else { + if (high_vis_mode_) { + if (!cached_endpoint_id_.empty()) { + NEARBY_LOGS(INFO) << "ClientProxy [Local Endpoint Re-using cached " + "endpoint id]: client=" + << GetClientId() + << "; cached_endpoint_id_=" << cached_endpoint_id_; + return cached_endpoint_id_; + } } } std::string id; @@ -169,7 +205,11 @@ void ClientProxy::Reset() { StoppedAdvertising(); StoppedDiscovery(); RemoveAllEndpoints(); - ExitHighVisibilityMode(); + if (IsFeatureUseStableEndpointIdEnabled()) { + ExitStableEndpointIdMode(); + } else { + ExitHighVisibilityMode(); + } } void ClientProxy::StartedAdvertising( @@ -181,13 +221,22 @@ void ClientProxy::StartedAdvertising( NEARBY_LOGS(INFO) << "ClientProxy [StartedAdvertising]: client=" << GetClientId(); - if (high_vis_mode_) { - local_high_vis_mode_cache_endpoint_id_ = local_endpoint_id_; - NEARBY_LOGS(INFO) - << "ClientProxy [High Visibility Mode Adv, Cache EndpointId]: client=" - << GetClientId() << "; local_high_vis_mode_cache_endpoint_id_=" - << local_high_vis_mode_cache_endpoint_id_; - CancelClearLocalHighVisModeCacheEndpointIdAlarm(); + if (IsFeatureUseStableEndpointIdEnabled()) { + if (stable_endpoint_id_mode_) { + cached_endpoint_id_ = local_endpoint_id_; + } else { + cached_endpoint_id_.clear(); + } + + CancelClearCachedEndpointIdAlarm(); + } else { + if (high_vis_mode_) { + cached_endpoint_id_ = local_endpoint_id_; + NEARBY_LOGS(INFO) + << "ClientProxy [High Visibility Mode Adv, Cache EndpointId]: client=" + << GetClientId() << "; cached_endpoint_id_=" << cached_endpoint_id_; + CancelClearCachedEndpointIdAlarm(); + } } advertising_info_ = {service_id, listener}; @@ -211,7 +260,11 @@ void ClientProxy::StoppedAdvertising() { // advertising_options_ is purposefully not cleared here. OnSessionComplete(); - ExitHighVisibilityMode(); + if (IsFeatureUseStableEndpointIdEnabled()) { + ExitStableEndpointIdMode(); + } else { + ExitHighVisibilityMode(); + } } bool ClientProxy::IsAdvertising() const { @@ -529,6 +582,12 @@ void ClientProxy::OnDisconnected(const std::string& endpoint_id, bool notify) { } CancelEndpoint(endpoint_id); + + if (IsFeatureUseStableEndpointIdEnabled()) { + if (!stable_endpoint_id_mode_ && !HasOngoingConnection()) { + ScheduleClearCachedEndpointIdAlarm(); + } + } } bool ClientProxy::ConnectionStatusMatches(const std::string& endpoint_id, @@ -625,6 +684,11 @@ std::vector ClientProxy::GetConnectedEndpoints() const { }); } +bool ClientProxy::HasOngoingConnection() const { + return !GetPendingConnectedEndpoints().empty() || + !GetConnectedEndpoints().empty(); +} + std::int32_t ClientProxy::GetNumOutgoingConnections() const { return GetMatchingEndpoints([](const Connection& connection) { return connection.status == Connection::kConnected && @@ -1047,27 +1111,50 @@ void ClientProxy::ExitHighVisibilityMode() { << GetClientId(); high_vis_mode_ = false; - ScheduleClearLocalHighVisModeCacheEndpointIdAlarm(); + ScheduleClearCachedEndpointIdAlarm(); } -void ClientProxy::ScheduleClearLocalHighVisModeCacheEndpointIdAlarm() { - CancelClearLocalHighVisModeCacheEndpointIdAlarm(); +void ClientProxy::EnterStableEndpointIdMode() { + MutexLock lock(&mutex_); + NEARBY_LOGS(INFO) << "ClientProxy [EnterStableEndpointIdMode]: client=" + << GetClientId(); - if (local_high_vis_mode_cache_endpoint_id_.empty()) { + stable_endpoint_id_mode_ = true; +} + +void ClientProxy::ExitStableEndpointIdMode() { + MutexLock lock(&mutex_); + NEARBY_LOGS(INFO) << "ClientProxy [ExitStableEndpointIdMode]: client=" + << GetClientId(); + + stable_endpoint_id_mode_ = false; + ScheduleClearCachedEndpointIdAlarm(); +} + +void ClientProxy::ScheduleClearCachedEndpointIdAlarm() { + CancelClearCachedEndpointIdAlarm(); + + if (cached_endpoint_id_.empty()) { NEARBY_LOGS(VERBOSE) << "ClientProxy [There is no cached local high power " "advertising endpoint Id]: client=" << GetClientId(); return; } + if (IsFeatureUseStableEndpointIdEnabled() && HasOngoingConnection()) { + NEARBY_LOGS(VERBOSE) << "ClientProxy [Handle clearing cached endpoint ID " + "during disconnection]: client=" + << GetClientId(); + return; + } + // Schedule to clear cache high visibility mode advertisement endpoint id in // 30s. NEARBY_LOGS(INFO) << "ClientProxy [High Visibility Mode Adv, Schedule to " "Clear Cache EndpointId]: client=" << GetClientId() - << "; local_high_vis_mode_cache_endpoint_id_=" - << local_high_vis_mode_cache_endpoint_id_; - clear_local_high_vis_mode_cache_endpoint_id_alarm_ = + << "; cached_endpoint_id_=" << cached_endpoint_id_; + cached_endpoint_id_alarm_ = std::make_unique( "clear_high_power_endpoint_id_cache", [this]() { @@ -1075,19 +1162,18 @@ void ClientProxy::ScheduleClearLocalHighVisModeCacheEndpointIdAlarm() { NEARBY_LOGS(INFO) << "ClientProxy [Cleared cached local high power advertising " "endpoint Id.]: client=" - << GetClientId() << "; local_high_vis_mode_cache_endpoint_id_=" - << local_high_vis_mode_cache_endpoint_id_; - local_high_vis_mode_cache_endpoint_id_.clear(); + << GetClientId() + << "; cached_endpoint_id_=" << cached_endpoint_id_; + cached_endpoint_id_.clear(); }, kHighPowerAdvertisementEndpointIdCacheTimeout, &single_thread_executor_); } -void ClientProxy::CancelClearLocalHighVisModeCacheEndpointIdAlarm() { - if (clear_local_high_vis_mode_cache_endpoint_id_alarm_ && - clear_local_high_vis_mode_cache_endpoint_id_alarm_->IsValid()) { - clear_local_high_vis_mode_cache_endpoint_id_alarm_->Cancel(); - clear_local_high_vis_mode_cache_endpoint_id_alarm_.reset(); +void ClientProxy::CancelClearCachedEndpointIdAlarm() { + if (cached_endpoint_id_alarm_ && cached_endpoint_id_alarm_->IsValid()) { + cached_endpoint_id_alarm_->Cancel(); + cached_endpoint_id_alarm_.reset(); } } @@ -1143,7 +1229,7 @@ bool ClientProxy::IsMultiplexSocketSupported(absl::string_view endpoint_id, } int combined_result = GetLocalMultiplexSocketBitmask() & - item->first.remote_multiplex_socket_bitmask; + item->first.remote_multiplex_socket_bitmask; switch (medium) { case Medium::BLUETOOTH: return (combined_result & kBtMultiplexEnabled) != 0; @@ -1154,7 +1240,6 @@ bool ClientProxy::IsMultiplexSocketSupported(absl::string_view endpoint_id, } } - std::string ClientProxy::ToString(PayloadProgressInfo::Status status) const { switch (status) { case PayloadProgressInfo::Status::kSuccess: diff --git a/connections/implementation/client_proxy.h b/connections/implementation/client_proxy.h index 4d8e409b..1d34c91c 100644 --- a/connections/implementation/client_proxy.h +++ b/connections/implementation/client_proxy.h @@ -24,6 +24,7 @@ #include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" +#include "absl/time/time.h" #include "connections/advertising_options.h" #include "connections/connection_options.h" #include "connections/discovery_options.h" @@ -31,6 +32,7 @@ #include "connections/implementation/proto/offline_wire_formats.pb.h" #include "connections/listeners.h" #include "connections/medium_selector.h" +#include "connections/payload.h" #include "connections/status.h" #include "connections/strategy.h" #include "connections/v3/connection_listening_options.h" @@ -49,6 +51,8 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/types/span.h" +#include "internal/platform/os_name.h" +#include "internal/platform/scheduled_executor.h" namespace nearby { namespace connections { @@ -191,6 +195,9 @@ class ClientProxy final { std::vector GetConnectedEndpoints() const; // Returns all endpoints that are still awaiting acceptance. std::vector GetPendingConnectedEndpoints() const; + // Returns true if there is at least one connected connection or one pending + // connection. + bool HasOngoingConnection() const; // Returns the number of endpoints that are connected and outgoing. std::int32_t GetNumOutgoingConnections() const; // Returns the number of endpoints that are connected and incoming. @@ -260,6 +267,12 @@ class ClientProxy final { // rotates. void ExitHighVisibilityMode(); + // Enters stable endpoint ID mode. + void EnterStableEndpointIdMode(); + // Cleans up any modifications in stable endpoint ID mode. The endpoint id + // always rotates. + void ExitStableEndpointIdMode(); + std::string Dump(); const location::nearby::connections::OsInfo& GetLocalOsInfo() const; @@ -282,9 +295,7 @@ class ClientProxy final { return supports_safe_to_disconnect_; } - bool IsSupportAutoReconnect() const { - return support_auto_reconnect_; - } + bool IsSupportAutoReconnect() const { return support_auto_reconnect_; } const std::int32_t& GetLocalSafeToDisconnectVersion() const { return local_safe_to_disconnect_version_; @@ -385,8 +396,8 @@ class ClientProxy final { absl::AnyInvocable pred) const; std::string GenerateLocalEndpointId(); - void ScheduleClearLocalHighVisModeCacheEndpointIdAlarm(); - void CancelClearLocalHighVisModeCacheEndpointIdAlarm(); + void ScheduleClearCachedEndpointIdAlarm(); + void CancelClearCachedEndpointIdAlarm(); location::nearby::connections::OsInfo::OsType OSNameToOsInfoType( api::OSName osName); @@ -402,18 +413,17 @@ class ClientProxy final { // id is stable for 30s. When high_visibility_mode_ is false, the endpoint id // always rotates. bool high_vis_mode_ = false; - // Caches the endpoint id when it is in high visibility mode advertisement for - // 30s. Currently, Nearby Connections keeps rotating endpoint id. The client - // (Nearby Share) treats different endpoints as different receivers, duplicate - // share targets for same devices occur on share sheet in this case. - // Therefore, we remember the high visibility mode advertisement endpoint id - // here. empty if 1) There is no high power advertisement before 2) The - // endpoint id cached here in previous high visibility mode advertisement - // expires. - std::string local_high_vis_mode_cache_endpoint_id_; + + // If advertising is in stable endpoint ID mode, the endpoint ID is stable + // for 30s after advertising or disconnection. When stable_endpoint_id_mode_ + // is false, the endpoint id always rotates. + bool stable_endpoint_id_mode_ = false; + + // Caches the endpoint id for stable endpoint ID mode. + std::string cached_endpoint_id_; + ScheduledExecutor single_thread_executor_; - std::unique_ptr - clear_local_high_vis_mode_cache_endpoint_id_alarm_; + std::unique_ptr cached_endpoint_id_alarm_; // If not empty, we are currently advertising and accepting connection // requests for the given service_id. diff --git a/connections/implementation/client_proxy_test.cc b/connections/implementation/client_proxy_test.cc index c4382557..91f170fc 100644 --- a/connections/implementation/client_proxy_test.cc +++ b/connections/implementation/client_proxy_test.cc @@ -15,28 +15,45 @@ #include "connections/implementation/client_proxy.h" #include -#include #include #include #include #include #include +#include "base/casts.h" #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" #include "absl/time/clock.h" #include "absl/time/time.h" #include "absl/types/span.h" +#include "connections/advertising_options.h" +#include "connections/connection_options.h" +#include "connections/discovery_options.h" +#include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/listeners.h" +#include "connections/medium_selector.h" +#include "connections/payload.h" +#include "connections/status.h" #include "connections/strategy.h" #include "connections/v3/connection_listening_options.h" +#include "connections/v3/connection_result.h" +#include "connections/v3/connections_device_provider.h" +#include "connections/v3/listeners.h" #include "internal/analytics/mock_event_logger.h" +#include "internal/flags/nearby_flags.h" +#include "internal/interop/device.h" #include "internal/interop/device_provider.h" #include "internal/platform/byte_array.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/feature_flags.h" #include "internal/platform/medium_environment.h" +#include "internal/platform/mutex.h" +#include "internal/platform/mutex_lock.h" #include "proto/connections_enums.pb.h" namespace nearby { @@ -149,11 +166,30 @@ class ClientProxyTest : public ::testing::TestWithParam { advertising_options.allowed.bluetooth; } + bool ShouldEnterStableEndpointIdMode( + const AdvertisingOptions& advertising_options) { + if (advertising_options.use_stable_endpoint_id) { + return true; + } else if (advertising_options.low_power) { + return false; + } else { + return true; + } + } + Endpoint StartAdvertising( ClientProxy* client, ConnectionListener listener, AdvertisingOptions advertising_options = AdvertisingOptions{}) { - if (ShouldEnterHighVisibilityMode(advertising_options)) { - client->EnterHighVisibilityMode(); + if (NearbyFlags::GetInstance().GetBoolFlag( + connections::config_package_nearby::nearby_connections_feature:: + kUseStableEndpointId)) { + if (ShouldEnterStableEndpointIdMode(advertising_options)) { + client->EnterStableEndpointIdMode(); + } + } else { + if (ShouldEnterHighVisibilityMode(advertising_options)) { + client->EnterHighVisibilityMode(); + } } Endpoint endpoint{ .info = ByteArray{"advertising endpoint name"}, @@ -315,6 +351,13 @@ class ClientProxyTest : public ::testing::TestWithParam { client->OnPayloadProgress(endpoint.id, {}); } + void EnableUseStableEndpointIdFeature() { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + connections::config_package_nearby::nearby_connections_feature:: + kUseStableEndpointId, + true); + } + MockConnectionListener mock_advertising_connection_; MockDiscoveryListener mock_discovery_; @@ -747,6 +790,270 @@ TEST_F(ClientProxyTest, EXPECT_NE(advertising_endpoint_1.id, advertising_endpoint_2.id); } +TEST_F(ClientProxyTest, + RotateWhenLowVizAdvertisementAfterHighVizAndStableAdvertisement) { + EnableUseStableEndpointIdFeature(); + BooleanMediumSelector booleanMediumSelector; + booleanMediumSelector.bluetooth = true; + + AdvertisingOptions high_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + false, // low_power + true, // enable_bluetooth_listening + false, // enable_webrtc_listening + true, // use_stable_endpoint_id + }; + Endpoint advertising_endpoint_1 = + StartAdvertising(&client1_, advertising_connection_listener_, + high_viz_advertising_options); + + StopAdvertising(&client1_); + + AdvertisingOptions low_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + true, // low_power + }; + + Endpoint advertising_endpoint_2 = StartAdvertising( + &client1_, advertising_connection_listener_, low_viz_advertising_options); + + EXPECT_NE(advertising_endpoint_1.id, advertising_endpoint_2.id); +} + +TEST_F( + ClientProxyTest, + NoRotateWhenLowVizStableAdvertisementAfterHighVizAndStableAdvertisement) { + EnableUseStableEndpointIdFeature(); + BooleanMediumSelector booleanMediumSelector; + booleanMediumSelector.bluetooth = true; + + AdvertisingOptions high_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + false, // low_power + true, // enable_bluetooth_listening + false, // enable_webrtc_listening + true, // use_stable_endpoint_id + }; + Endpoint advertising_endpoint_1 = + StartAdvertising(&client1_, advertising_connection_listener_, + high_viz_advertising_options); + + StopAdvertising(&client1_); + + AdvertisingOptions low_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + true, // low_power + true, // enable_bluetooth_listening + false, // enable_webrtc_listening + true, // use_stable_endpoint_id + }; + + Endpoint advertising_endpoint_2 = StartAdvertising( + &client1_, advertising_connection_listener_, low_viz_advertising_options); + + EXPECT_EQ(advertising_endpoint_1.id, advertising_endpoint_2.id); +} + +TEST_F( + ClientProxyTest, + NoRotateWhenAdvertisementHasConnectionAfterStableAdvertisementForAWhile) { + EnableUseStableEndpointIdFeature(); + BooleanMediumSelector booleanMediumSelector; + booleanMediumSelector.bluetooth = true; + + AdvertisingOptions high_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + true, // low_power + true, // enable_bluetooth_listening + false, // enable_webrtc_listening + true, // use_stable_endpoint_id + }; + Endpoint advertising_endpoint_1 = + StartAdvertising(&client1_, advertising_connection_listener_, + high_viz_advertising_options); + + OnAdvertisingConnectionInitiated(&client1_, advertising_endpoint_1); + StopAdvertising(&client1_); + + // Client should use cached endpoint id when having connection. + EXPECT_EQ(client1_.GetLocalEndpointId(), advertising_endpoint_1.id); + + // Wait to expire and then advertise. + absl::SleepFor(ClientProxy::kHighPowerAdvertisementEndpointIdCacheTimeout + + absl::Milliseconds(100)); + AdvertisingOptions low_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + true, // low_power + }; + + Endpoint advertising_endpoint_2 = StartAdvertising( + &client1_, advertising_connection_listener_, low_viz_advertising_options); + + EXPECT_EQ(advertising_endpoint_1.id, advertising_endpoint_2.id); +} + +TEST_F(ClientProxyTest, RotateWhenLowVizAdvertisementAfterDisconnection) { + EnableUseStableEndpointIdFeature(); + BooleanMediumSelector booleanMediumSelector; + booleanMediumSelector.bluetooth = true; + + AdvertisingOptions high_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + false, // low_power + true, // enable_bluetooth_listening + false, // enable_webrtc_listening + true, // use_stable_endpoint_id + }; + Endpoint advertising_endpoint_1 = + StartAdvertising(&client1_, advertising_connection_listener_, + high_viz_advertising_options); + + OnAdvertisingConnectionInitiated(&client1_, advertising_endpoint_1); + StopAdvertising(&client1_); + absl::SleepFor(absl::Seconds(2)); + client1_.OnDisconnected(advertising_endpoint_1.id, true); + + AdvertisingOptions low_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + true, // low_power + }; + + Endpoint advertising_endpoint_2 = StartAdvertising( + &client1_, advertising_connection_listener_, low_viz_advertising_options); + + EXPECT_NE(advertising_endpoint_1.id, advertising_endpoint_2.id); +} + +TEST_F(ClientProxyTest, + NoRotateWhenLowVizAndStableAdvertisementAfterDisconnection) { + EnableUseStableEndpointIdFeature(); + BooleanMediumSelector booleanMediumSelector; + booleanMediumSelector.bluetooth = true; + + AdvertisingOptions high_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + false, // low_power + true, // enable_bluetooth_listening + false, // enable_webrtc_listening + true, // use_stable_endpoint_id + }; + Endpoint advertising_endpoint_1 = + StartAdvertising(&client1_, advertising_connection_listener_, + high_viz_advertising_options); + + OnAdvertisingConnectionInitiated(&client1_, advertising_endpoint_1); + StopAdvertising(&client1_); + absl::SleepFor(absl::Seconds(2)); + client1_.OnDisconnected(advertising_endpoint_1.id, true); + + AdvertisingOptions low_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + true, // low_power + true, // enable_bluetooth_listening + false, // enable_webrtc_listening + true, // use_stable_endpoint_id + }; + + Endpoint advertising_endpoint_2 = StartAdvertising( + &client1_, advertising_connection_listener_, low_viz_advertising_options); + + EXPECT_EQ(advertising_endpoint_1.id, advertising_endpoint_2.id); +} + +TEST_F(ClientProxyTest, RotateWhenAdvertisementAfterDisconnectionForAWhile) { + EnableUseStableEndpointIdFeature(); + BooleanMediumSelector booleanMediumSelector; + booleanMediumSelector.bluetooth = true; + + AdvertisingOptions high_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + false, // low_power + true, // enable_bluetooth_listening + false, // enable_webrtc_listening + true, // use_stable_endpoint_id + }; + Endpoint advertising_endpoint_1 = + StartAdvertising(&client1_, advertising_connection_listener_, + high_viz_advertising_options); + + OnAdvertisingConnectionInitiated(&client1_, advertising_endpoint_1); + StopAdvertising(&client1_); + client1_.OnDisconnected(advertising_endpoint_1.id, true); + + // Wait to expire and then advertise. + absl::SleepFor(ClientProxy::kHighPowerAdvertisementEndpointIdCacheTimeout + + absl::Milliseconds(100)); + AdvertisingOptions low_viz_advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + true, // low_power + }; + + Endpoint advertising_endpoint_2 = StartAdvertising( + &client1_, advertising_connection_listener_, low_viz_advertising_options); + + EXPECT_NE(advertising_endpoint_1.id, advertising_endpoint_2.id); +} + // Tests endpoint_id rotates when discover. TEST_F(ClientProxyTest, EndpointIdRotateWhenStartDiscovery) { BooleanMediumSelector booleanMediumSelector; @@ -774,6 +1081,36 @@ TEST_F(ClientProxyTest, EndpointIdRotateWhenStartDiscovery) { EXPECT_NE(advertising_endpoint_1.id, advertising_endpoint_2.id); } +TEST_F(ClientProxyTest, + EndpointIdRotateWhenStartDiscoveryAfterStableAdvertising) { + BooleanMediumSelector booleanMediumSelector; + booleanMediumSelector.bluetooth = true; + + AdvertisingOptions advertising_options{ + { + strategy_, + booleanMediumSelector, + }, + false, // auto_upgrade_bandwidth + false, // enforce_topology_constraints + false, // low_power + true, // enable_bluetooth_listening + false, // enable_webrtc_listening + true, // use_stable_endpoint_id + }; + + Endpoint advertising_endpoint_1 = StartAdvertising( + &client1_, advertising_connection_listener_, advertising_options); + + StopAdvertising(&client1_); + StartDiscovery(&client1_, GetDiscoveryListener()); + + Endpoint advertising_endpoint_2 = StartAdvertising( + &client1_, advertising_connection_listener_, advertising_options); + + EXPECT_NE(advertising_endpoint_1.id, advertising_endpoint_2.id); +} + // Tests the low visibility mode with bluetooth disabled advertisment. TEST_F(ClientProxyTest, EndpointIdRotateWhenLowVizAdvertisementWithBluetoothDisabled) { @@ -788,6 +1125,9 @@ TEST_F(ClientProxyTest, false, // auto_upgrade_bandwidth false, // enforce_topology_constraints false, // low_power + true, // enable_bluetooth_listening + false, // enable_webrtc_listening + true, // use_stable_endpoint_id }; Endpoint advertising_endpoint_1 = StartAdvertising(