diff --git a/connections/implementation/BUILD b/connections/implementation/BUILD index ee3eb054..412f3c1c 100644 --- a/connections/implementation/BUILD +++ b/connections/implementation/BUILD @@ -119,6 +119,8 @@ cc_library( "//connections/implementation/flags:connections_flags", "//connections/implementation/mediums", "//connections/implementation/mediums:utils", + "//connections/implementation/mediums/advertisements:dct_advertisement", + "//connections/implementation/mediums/advertisements:util", "//connections/implementation/proto:offline_wire_formats_cc_proto", "//connections/v3:v3_types", "//internal/analytics:event_logger", @@ -146,6 +148,7 @@ cc_library( "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/functional:bind_front", "@com_google_absl//absl/log:check", + "@com_google_absl//absl/random", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", diff --git a/connections/implementation/base_pcp_handler.cc b/connections/implementation/base_pcp_handler.cc index efa1168f..5b8ea72b 100644 --- a/connections/implementation/base_pcp_handler.cc +++ b/connections/implementation/base_pcp_handler.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ #include "connections/implementation/endpoint_channel_manager.h" #include "connections/implementation/endpoint_manager.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "connections/implementation/mediums/advertisements/advertisement_util.h" #include "connections/implementation/mediums/mediums.h" #include "connections/implementation/mediums/utils.h" #include "connections/implementation/mediums/webrtc_peer_id.h" @@ -249,6 +251,18 @@ Status BasePcpHandler::StartAdvertising( } } + if (client->IsDctEnabled()) { + // Update the device name. + std::optional device_name = + nearby::connections::advertisements::ReadDeviceName( + info.endpoint_info); + if (device_name.has_value()) { + client->UpdateDctDeviceName(device_name.value()); + } else { + LOG(ERROR) << "DCT only supports everyone mode for now."; + } + } + auto result = StartAdvertisingImpl( client, service_id, client->GetLocalEndpointId(), info.endpoint_info, compatible_advertising_options); diff --git a/connections/implementation/client_proxy.cc b/connections/implementation/client_proxy.cc index dfe04af8..c0b731a2 100644 --- a/connections/implementation/client_proxy.cc +++ b/connections/implementation/client_proxy.cc @@ -28,9 +28,9 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/functional/any_invocable.h" +#include "absl/random/random.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" @@ -39,6 +39,7 @@ #include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/analytics/discovery_metadata_params.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "connections/implementation/mediums/advertisements/dct_advertisement.h" #include "connections/listeners.h" #include "connections/medium_selector.h" #include "connections/payload.h" @@ -107,6 +108,9 @@ ClientProxy::ClientProxy(::nearby::analytics::EventLogger* event_logger) NEARBY_LOGS(INFO) << "[safe-to-disconnect]: Local enabled: " << supports_safe_to_disconnect_ << "; Version: " << local_safe_to_disconnect_version_; + // Generate a 7 bits dedup value. + absl::BitGen bitgen; + dct_dedup_ = absl::Uniform(bitgen, 0, 1 << 7); } ClientProxy::~ClientProxy() { Reset(); } @@ -115,24 +119,29 @@ std::int64_t ClientProxy::GetClientId() const { return client_id_; } std::string ClientProxy::GetLocalEndpointId() { MutexLock lock(&mutex_); - if (!local_endpoint_id_.empty()) { - NEARBY_LOGS(INFO) << __func__ - << ": Reusing cached endpoint id: " << local_endpoint_id_; + if (IsDctEnabled() && GetEndpointIdForDct().has_value()) { + NEARBY_LOGS(INFO) << "DCT is using genereted endpoint id."; + return GetEndpointIdForDct().value(); + } else { + if (!local_endpoint_id_.empty()) { + NEARBY_LOGS(INFO) << __func__ << ": 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: " + << local_endpoint_id_; + } else { + local_endpoint_id_ = + external_device_provider_->GetLocalDevice()->GetEndpointId(); + NEARBY_LOGS(INFO) + << __func__ + << ": From external device provider, populating 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: " - << local_endpoint_id_; - } else { - local_endpoint_id_ = - external_device_provider_->GetLocalDevice()->GetEndpointId(); - NEARBY_LOGS(INFO) - << __func__ - << ": From external device provider, populating endpoint id: " - << local_endpoint_id_; - } - return local_endpoint_id_; } const NearbyDevice* ClientProxy::GetLocalDevice() { @@ -1301,6 +1310,48 @@ void ClientProxy::SetWebRtcNonCellular(bool webrtc_non_cellular) { webrtc_non_cellular_ = webrtc_non_cellular; } +bool ClientProxy::IsDctEnabled() const { + if (api::ImplementationPlatform::GetCurrentOS() != api::OSName::kApple) { + return false; + } + +#if defined(NC_IOS_SDK) + return true; +#else + return false; +#endif +} + +uint8_t ClientProxy::GetDctDedup() const { return dct_dedup_; } + +void ClientProxy::UpdateDctDeviceName(absl::string_view device_name) { + if (!dct_device_name_.empty() && dct_device_name_ != device_name) { + // Need to update dedup value if device name is changed. + absl::BitGen bitgen; + dct_dedup_ = absl::Uniform(bitgen, 0, 1 << 7); + } + + dct_device_name_ = device_name; + + // The DCT endpoint ID should be derived from device name and dedup value. + std::optional dct_endpoint_id = + advertisements::ble::DctAdvertisement::GenerateEndpointId( + dct_dedup_, dct_device_name_); + if (dct_endpoint_id.has_value()) { + dct_endpoint_id_ = *dct_endpoint_id; + } else { + dct_endpoint_id_.clear(); + } +} + +std::optional ClientProxy::GetEndpointIdForDct() const { + if (dct_endpoint_id_.empty()) { + return std::nullopt; + } + + return dct_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 545a4b4e..bbf202a1 100644 --- a/connections/implementation/client_proxy.h +++ b/connections/implementation/client_proxy.h @@ -339,6 +339,17 @@ class ClientProxy final { // Sets the WebRTC non cellular network status. void SetWebRtcNonCellular(bool webrtc_non_cellular); + // Returns true if DCT advertising/scanning is enabled. + bool IsDctEnabled() const; + + // Gets the DCT dedup value. This is used to dedup the same device name when + // scanning for multiple devices. + // It is 7 bits derived from the local endpoint ID. + uint8_t GetDctDedup() const; + + // Updates the DCT device name before advertising. + void UpdateDctDeviceName(absl::string_view device_name); + /** Bitmask for bt multiplex connection support. */ // Note. Deprecates the first and second bit of BT_MULTIPLEX_ENABLED and // WIFI_LAN_MULTIPLEX_ENABLED and shift them to the third and the forth bit. @@ -436,6 +447,15 @@ class ClientProxy final { std::string ToString(PayloadProgressInfo::Status status) const; + std::optional GetEndpointIdForDct() const; + + // The device name used for DCT advertising. + std::string dct_device_name_; + // The dedup value used for DCT advertising. + uint8_t dct_dedup_ = 0; + // The endpoint ID used for DCT advertising. + std::string dct_endpoint_id_; + mutable RecursiveMutex mutex_; std::int64_t client_id_; std::string local_endpoint_id_; diff --git a/connections/implementation/mediums/advertisements/BUILD b/connections/implementation/mediums/advertisements/BUILD index 09928b43..6e4713cd 100644 --- a/connections/implementation/mediums/advertisements/BUILD +++ b/connections/implementation/mediums/advertisements/BUILD @@ -22,7 +22,6 @@ cc_library( name = "common", srcs = ["data_element.cc"], hdrs = ["data_element.h"], - compatible_with = ["//buildenv/target:non_prod"], deps = [ "//internal/platform:base", "//internal/platform:logging", @@ -35,7 +34,6 @@ cc_library( name = "dct_advertisement", srcs = ["dct_advertisement.cc"], hdrs = ["dct_advertisement.h"], - compatible_with = ["//buildenv/target:non_prod"], deps = [ ":common", "//internal/crypto_cros", @@ -51,7 +49,6 @@ cc_library( name = "util", srcs = ["advertisement_util.cc"], hdrs = ["advertisement_util.h"], - compatible_with = ["//buildenv/target:non_prod"], deps = [ ":dct_advertisement", "//internal/platform:base", diff --git a/connections/implementation/mediums/ble_v2.cc b/connections/implementation/mediums/ble_v2.cc index 7ca9d2da..2d3d2080 100644 --- a/connections/implementation/mediums/ble_v2.cc +++ b/connections/implementation/mediums/ble_v2.cc @@ -149,6 +149,27 @@ ErrorOr BleV2::StartAdvertising(const std::string& service_id, return {Error(OperationResultCode::MEDIUM_UNAVAILABLE_BLE_NOT_AVAILABLE)}; } + if (advertising_type == AdvertisingType::kDct) { + advertising_infos_.insert( + {service_id, AdvertisingInfo{.dct_advertisement = advertisement_bytes, + .power_level = power_level, + .advertising_type = advertising_type}}); + + if (!StartDctAdvertisingLocked(service_id, power_level, + advertisement_bytes)) { + LOG(ERROR) << "Failed to start BLE DCT advertising for service_id=" + << service_id; + advertising_infos_.erase(service_id); + return {Error( + OperationResultCode::CONNECTIVITY_BLE_START_ADVERTISING_FAILURE)}; + } + + LOG(INFO) << "Successfully started BLE DCT advertising for service_id=" + << service_id << " with advetsiement data " + << absl::BytesToHexString(advertisement_bytes.AsStringView()); + return {true}; + } + // Wrap the connections advertisement to the medium advertisement. ByteArray service_id_hash = mediums::bleutils::GenerateHash( service_id, mediums::BleAdvertisement::kServiceIdHashLength); @@ -171,11 +192,9 @@ ErrorOr BleV2::StartAdvertising(const std::string& service_id, } advertising_infos_.insert( - {service_id, - AdvertisingInfo{.medium_advertisement = medium_advertisement, - .power_level = power_level, - .is_fast_advertisement = - advertising_type == AdvertisingType::kFast}}); + {service_id, AdvertisingInfo{.medium_advertisement = medium_advertisement, + .power_level = power_level, + .advertising_type = advertising_type}}); // TODO(hais): need to update here after cros support RAII StartAdvertising. // After all platforms support RAII StartAdvertising, then we can stop @@ -908,7 +927,7 @@ bool BleV2::StartAdvertisingLocked(const std::string& service_id) { } const AdvertisingInfo& info = it->second; - if (info.is_fast_advertisement) { + if (info.advertising_type == AdvertisingType::kFast) { return StartFastAdvertisingLocked(service_id, info.power_level, info.medium_advertisement); } else { @@ -1078,6 +1097,20 @@ bool BleV2::StartGattAdvertisingLocked( return true; } +bool BleV2::StartDctAdvertisingLocked(const std::string& service_id, + PowerLevel power_level, + const ByteArray& dct_advertisement) { + BleAdvertisementData advertising_data; + advertising_data.is_extended_advertisement = false; + advertising_data.service_data.insert( + {mediums::bleutils::kDctServiceUuid, dct_advertisement}); + + return medium_.StartAdvertising( + advertising_data, + {.tx_power_level = PowerLevelToTxPowerLevel(power_level), + .is_connectable = false}); +} + bool BleV2::StartAsyncScanningLocked(absl::string_view service_id, PowerLevel power_level) { CHECK(FeatureFlags::GetInstance().GetFlags().enable_ble_v2_async_scanning); diff --git a/connections/implementation/mediums/ble_v2.h b/connections/implementation/mediums/ble_v2.h index 6c6d0a3a..1b57c1ce 100644 --- a/connections/implementation/mediums/ble_v2.h +++ b/connections/implementation/mediums/ble_v2.h @@ -166,8 +166,9 @@ class BleV2 final { private: struct AdvertisingInfo { mediums::BleAdvertisement medium_advertisement; + ByteArray dct_advertisement; PowerLevel power_level; - bool is_fast_advertisement; + AdvertisingType advertising_type; }; // Same as IsAvailable(), but must be called with `mutex_` held. @@ -230,6 +231,10 @@ class BleV2 final { const ByteArray& medium_advertisement_bytes, bool extended_advertisement_advertised) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + bool StartDctAdvertisingLocked(const std::string& service_id, + PowerLevel power_level, + const ByteArray& dct_advertisement) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); // Called by StartScanning when using the async methods. bool StartAsyncScanningLocked(absl::string_view service_id, PowerLevel power_level) diff --git a/connections/implementation/p2p_cluster_pcp_handler.cc b/connections/implementation/p2p_cluster_pcp_handler.cc index b66b6806..3d5b5d63 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.cc +++ b/connections/implementation/p2p_cluster_pcp_handler.cc @@ -16,7 +16,9 @@ #include #include +#include #include +#include #include #include #include @@ -39,6 +41,8 @@ #include "connections/implementation/endpoint_manager.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/injected_bluetooth_device_store.h" +#include "connections/implementation/mediums/advertisements/advertisement_util.h" +#include "connections/implementation/mediums/advertisements/dct_advertisement.h" #include "connections/implementation/mediums/ble_v2.h" #include "connections/implementation/mediums/bluetooth_classic.h" #include "connections/implementation/mediums/mediums.h" @@ -2538,7 +2542,24 @@ ErrorOr P2pClusterPcpHandler::StartBleV2Advertising( local_endpoint_info, bluetooth_mac_address, /*uwb_address=*/ByteArray{}, web_rtc_state)); } - if (advertisement_bytes.Empty()) { + + ByteArray dct_advertisement_bytes; + if (client->IsDctEnabled()) { + // Try to read device name from local_endpoint_info. + std::optional device_name = + advertisements::ReadDeviceName(local_endpoint_info); + // TODO(b/399740422): Get the real PSM from the L2CAP medium. + uint16_t psm = 0x11; + if (device_name.has_value()) { + std::optional dct_advertisement = + advertisements::ble::DctAdvertisement::Create( + service_id, *device_name, psm, client->GetDctDedup()); + if (dct_advertisement.has_value()) { + dct_advertisement_bytes = ByteArray(dct_advertisement->ToData()); + } + } + } + if (advertisement_bytes.Empty() && dct_advertisement_bytes.Empty()) { LOG(WARNING) << "In StartBleV2Advertising(" << absl::BytesToHexString(local_endpoint_info.data()) << "), client=" << client->GetClientId() @@ -2552,12 +2573,19 @@ ErrorOr P2pClusterPcpHandler::StartBleV2Advertising( << "), client=" << client->GetClientId() << " generated BleAdvertisement with service_id=" << service_id; - ErrorOr ble_v2_result = ble_v2_medium_.StartAdvertising( - service_id, power_level, - advertising_options.fast_advertisement_service_uuid.empty() - ? BleV2::AdvertisingType::kRegular - : BleV2::AdvertisingType::kFast, - advertisement_bytes); + ErrorOr ble_v2_result = false; + if (dct_advertisement_bytes.Empty()) { + ble_v2_result = ble_v2_medium_.StartAdvertising( + service_id, power_level, + advertising_options.fast_advertisement_service_uuid.empty() + ? BleV2::AdvertisingType::kRegular + : BleV2::AdvertisingType::kFast, + advertisement_bytes); + } else { + ble_v2_result = ble_v2_medium_.StartAdvertising( + service_id, power_level, BleV2::AdvertisingType::kDct, + dct_advertisement_bytes); + } if (ble_v2_result.has_error()) { LOG(WARNING) << "In StartBleV2Advertising(" << absl::BytesToHexString(local_endpoint_info.data())