From 54f38cbf24a75506abc8be5f95e752c97c648586 Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Mon, 24 Nov 2025 18:17:56 -0800 Subject: [PATCH] Support BLE injection. PiperOrigin-RevId: 836431600 --- .../implementation/p2p_cluster_pcp_handler.cc | 122 ++++++++++++++---- .../implementation/p2p_cluster_pcp_handler.h | 9 ++ .../p2p_cluster_pcp_handler_test.cc | 61 +++++++++ 3 files changed, 165 insertions(+), 27 deletions(-) diff --git a/connections/implementation/p2p_cluster_pcp_handler.cc b/connections/implementation/p2p_cluster_pcp_handler.cc index 554c1d97..7a9c1252 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.cc +++ b/connections/implementation/p2p_cluster_pcp_handler.cc @@ -1199,34 +1199,16 @@ Status P2pClusterPcpHandler::StopDiscoveryImpl(ClientProxy* client) { Status P2pClusterPcpHandler::InjectEndpointImpl( ClientProxy* client, const std::string& service_id, const OutOfBandConnectionMetadata& metadata) { - LOG(INFO) << "InjectEndpoint."; - // Bluetooth is the only supported out-of-band connection medium. - if (metadata.medium != BLUETOOTH) { - LOG(WARNING) << "InjectEndpointImpl: Only Bluetooth is supported."; - return {Status::kError}; + switch (metadata.medium) { + case BLUETOOTH: + return InjectBluetoothEndpoint(client, service_id, metadata); + case BLE: + return InjectBleEndpoint(client, service_id, metadata); + default: + LOG(WARNING) << "InjectEndpointImpl: medium " + << Medium_Name(metadata.medium) << " is not supported."; + return {Status::kError}; } - - // Make sure discovery is in out-of-band mode from the API definition in - // core.h. - if (!client->GetDiscoveryOptions().is_out_of_band_connection) { - LOG(WARNING) << "InjectEndpointImpl: Discovery is not in out-of-band mode."; - return {Status::kError}; - } - - BluetoothDevice remote_bluetooth_device = - injected_bluetooth_device_store_.CreateInjectedBluetoothDevice( - metadata.remote_bluetooth_mac_address, metadata.endpoint_id, - metadata.endpoint_info, - GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength), - GetPcp()); - - if (!remote_bluetooth_device.IsValid()) { - LOG(WARNING) << "InjectEndpointImpl: Invalid parameters."; - return {Status::kError}; - } - - BluetoothDeviceDiscoveredHandler(client, service_id, remote_bluetooth_device); - return {Status::kSuccess}; } BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::ConnectImpl( @@ -2878,5 +2860,91 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WifiLanConnectImpl( }; } +Status P2pClusterPcpHandler::InjectBluetoothEndpoint( + ClientProxy* client, const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) { + LOG(INFO) << "Inject Bluetooth endpoint for service_id=" << service_id; + // Make sure the medium is Bluetooth. + if (metadata.medium != BLUETOOTH) { + LOG(WARNING) << "InjectBluetoothEndpoint: Only Bluetooth is supported."; + return {Status::kError}; + } + + // Make sure discovery is in out-of-band mode from the API definition in + // core.h. + if (!client->GetDiscoveryOptions().is_out_of_band_connection) { + LOG(WARNING) + << "InjectBluetoothEndpoint: Discovery is not in out-of-band mode."; + return {Status::kError}; + } + + BluetoothDevice remote_bluetooth_device = + injected_bluetooth_device_store_.CreateInjectedBluetoothDevice( + metadata.remote_bluetooth_mac_address, metadata.endpoint_id, + metadata.endpoint_info, + GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength), + GetPcp()); + + if (!remote_bluetooth_device.IsValid()) { + LOG(WARNING) << "InjectBluetoothEndpoint: Invalid parameters."; + return {Status::kError}; + } + + BluetoothDeviceDiscoveredHandler(client, service_id, remote_bluetooth_device); + return {Status::kSuccess}; +} + +Status P2pClusterPcpHandler::InjectBleEndpoint( + ClientProxy* client, const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) { + LOG(INFO) << "Inject BLE endpoint for service_id=" << service_id; + + if (!NearbyFlags::GetInstance().GetBoolFlag( + config_package_nearby::nearby_connections_feature:: + kEnableBleMediumInjection)) { + LOG(ERROR) << "InjectBleEndpoint: BLE injection is disabled."; + return {Status::kError}; + } + + if (metadata.medium != Medium::BLE) { + LOG(WARNING) << "InjectBleEndpoint: Only BLE is supported."; + return {Status::kError}; + } + + if (metadata.ble_peripheral_native_id.empty()) { + LOG(WARNING) << "InjectBleEndpoint: Invalid parameters."; + return {Status::kError}; + } + + if (!client->IsDiscovering()) { + LOG(WARNING) + << "InjectBleEndpoint: Only allow injection when discovery is running."; + return {Status::kError}; + } + + std::optional ble_peripheral = + ble_medium_.RetrieveBlePeripheralFromNativeId( + metadata.ble_peripheral_native_id); + if (!ble_peripheral.has_value()) { + LOG(WARNING) << "InjectBleEndpoint: Invalid peripheral native id."; + return {Status::kError}; + } + + ble_peripheral->SetPsm(metadata.psm); + + RunOnPcpHandlerThread( + "p2p-bt-device-discovered", + [this, client, service_id, metadata, ble_peripheral = *ble_peripheral]() + RUN_ON_PCP_HANDLER_THREAD() { + OnEndpointFound(client, + std::make_shared(BleEndpoint{ + {metadata.endpoint_id, metadata.endpoint_info, + service_id, BLE, WebRtcState::kUndefined}, + ble_peripheral})); + }); + + return {Status::kSuccess}; +} + } // namespace connections } // namespace nearby diff --git a/connections/implementation/p2p_cluster_pcp_handler.h b/connections/implementation/p2p_cluster_pcp_handler.h index c49072ea..a3ac0891 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.h +++ b/connections/implementation/p2p_cluster_pcp_handler.h @@ -42,12 +42,14 @@ #include "connections/implementation/mediums/wifi_direct.h" #include "connections/implementation/mediums/wifi_hotspot.h" #include "connections/implementation/mediums/wifi_lan.h" +#include "connections/implementation/webrtc_state.h" #include "connections/medium_selector.h" #include "connections/out_of_band_connection_metadata.h" #include "connections/power_level.h" #include "connections/status.h" #include "connections/v3/connection_listening_options.h" #include "internal/interop/device.h" +#include "internal/platform/awdl.h" #include "internal/platform/ble.h" #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/bluetooth_classic.h" @@ -306,6 +308,13 @@ class P2pClusterPcpHandler : public BasePcpHandler { BasePcpHandler::ConnectImplResult WifiLanConnectImpl( ClientProxy* client, WifiLanEndpoint* endpoint); + // Endpoints injection. + Status InjectBluetoothEndpoint(ClientProxy* client, + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata); + Status InjectBleEndpoint(ClientProxy* client, const std::string& service_id, + const OutOfBandConnectionMetadata& metadata); + Awdl& awdl_medium_; BluetoothRadio& bluetooth_radio_; BluetoothClassic& bluetooth_medium_; diff --git a/connections/implementation/p2p_cluster_pcp_handler_test.cc b/connections/implementation/p2p_cluster_pcp_handler_test.cc index b7f2576a..32118b94 100644 --- a/connections/implementation/p2p_cluster_pcp_handler_test.cc +++ b/connections/implementation/p2p_cluster_pcp_handler_test.cc @@ -1611,6 +1611,67 @@ TEST_F(P2pClusterPcpHandlerTest, CanConnectToInjectedEndpoint) { env_.Stop(); } +TEST_F(P2pClusterPcpHandlerTest, CanInjectBleEndpoint) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature:: + kEnableBleMediumInjection, + true); + env_.Start(); + Mediums mediums_a; + EndpointChannelManager ecm_a; + EndpointManager em_a(&ecm_a); + BwuManager bwu_a(mediums_a, em_a, ecm_a, {}, {}); + InjectedBluetoothDeviceStore ibds_a; + P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a, ibds_a); + + DiscoveryOptions discovery_options{ + {Strategy::kP2pCluster, + BooleanMediumSelector{ + .ble = true, + }}, + /* auto_upgrade_bandwidth= */ false, + /* enforce_topology_constraints= */ false, + /* is_out_of_band_connection= */ false, + }; + + CountDownLatch found_latch(1); + std::string found_endpoint_id; + + EXPECT_EQ( + handler_a.StartDiscovery(&client_a_, service_id_, discovery_options, + { + .endpoint_found_cb = + [&](const std::string& endpoint_id, + const ByteArray& endpoint_info, + const std::string& service_id) { + found_endpoint_id = endpoint_id; + found_latch.CountDown(); + }, + }), + Status{Status::kSuccess}); + + std::string endpoint_id = "ABCD"; + std::string endpoint_info_name = "endpoint_info"; + ByteArray endpoint_info(endpoint_info_name); + + OutOfBandConnectionMetadata metadata = { + .medium = location::nearby::proto::connections::Medium::BLE, + .endpoint_id = endpoint_id, + .ble_peripheral_native_id = mediums_a.GetBluetoothRadio() + .GetBluetoothAdapter() + .GetAddress() + .ToString(), + .psm = 1234, + }; + + handler_a.InjectEndpoint(&client_a_, service_id_, metadata); + + EXPECT_TRUE(found_latch.Await(absl::Milliseconds(1000)).result()); + EXPECT_EQ(found_endpoint_id, endpoint_id); + handler_a.StopDiscovery(&client_a_); + env_.Stop(); +} + class P2pLostHandlerTestWithParam : public testing::TestWithParam { protected: void SetUp() override {