Enforce out-of-band mode for InjectEndpoint and relax discovery checks for Bluetooth callbacks.

PiperOrigin-RevId: 798228332
This commit is contained in:
Guogang Li
2025-08-22 08:58:41 -07:00
committed by Copybara-Service
parent 9c7c7a9f6f
commit 9d06831a9c
7 changed files with 260 additions and 12 deletions
+2
View File
@@ -310,6 +310,7 @@ cc_test(
"//internal/interop:authentication_transport_interface",
"//internal/interop:device",
"//internal/platform:base",
"//internal/platform:mac_address",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
@@ -550,6 +551,7 @@ cc_test(
],
deps = [
":internal",
":types",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:mac_address",
@@ -15,10 +15,16 @@
#include "connections/implementation/injected_bluetooth_device_store.h"
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include "absl/status/statusor.h"
#include "connections/implementation/bluetooth_device_name.h"
#include "connections/implementation/pcp.h"
#include "connections/implementation/webrtc_state.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/mac_address.h"
@@ -65,8 +71,8 @@ BluetoothDevice InjectedBluetoothDeviceStore::CreateInjectedBluetoothDevice(
MacAddress remote_mac_address;
if (!MacAddress::FromUint64(bluetooth_mac_address_bytes_uint64.value(),
remote_mac_address)
|| !remote_mac_address.IsSet()) {
remote_mac_address) ||
!remote_mac_address.IsSet()) {
return BluetoothDevice(/*device=*/nullptr);
}
@@ -93,5 +99,15 @@ BluetoothDevice InjectedBluetoothDeviceStore::CreateInjectedBluetoothDevice(
return device_to_return;
}
bool InjectedBluetoothDeviceStore::IsInjectedDevice(
const std::string& mac_address) {
for (const auto& device : devices_) {
if (device->GetMacAddress() == mac_address) {
return true;
}
}
return false;
}
} // namespace connections
} // namespace nearby
@@ -16,11 +16,13 @@
#define CORE_INTERNAL_INJECTED_BLUETOOTH_DEVICE_STORE_H_
#include <memory>
#include <string>
#include <vector>
#include "connections/implementation/pcp.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/bluetooth_classic.h"
namespace nearby {
namespace connections {
@@ -53,6 +55,10 @@ class InjectedBluetoothDeviceStore {
const std::string& endpoint_id, const ByteArray& endpoint_info,
const ByteArray& service_id_hash, Pcp pcp);
// Returns true if the provided MAC address(format as "A0:12:34:56:78:90") is
// associated with an injected BluetoothDevice.
bool IsInjectedDevice(const std::string& mac_address);
private:
// Devices created by this class. BluetoothDevice objects returned by
// CreateInjectedBluetoothDevice() store pointers to underlying
@@ -15,12 +15,14 @@
#include "connections/implementation/injected_bluetooth_device_store.h"
#include <array>
#include <string>
#include "gtest/gtest.h"
#include "connections/implementation/bluetooth_device_name.h"
#include "connections/implementation/pcp.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/bluetooth_utils.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/bluetooth_adapter.h"
namespace nearby {
namespace connections {
@@ -49,6 +51,7 @@ TEST_F(InjectedBluetoothDeviceStoreTest, Success) {
remote_bluetooth_mac_address, kTestEndpointId, endpoint_info,
service_id_hash, Pcp::kP2pPointToPoint);
EXPECT_TRUE(device.IsValid());
EXPECT_TRUE(store_.IsInjectedDevice(device.GetMacAddress()));
EXPECT_EQ(BluetoothUtils::ToString(remote_bluetooth_mac_address),
device.GetMacAddress());
@@ -71,6 +74,8 @@ TEST_F(InjectedBluetoothDeviceStoreTest, Fail_InvalidBluetoothMac) {
remote_bluetooth_mac_address, kTestEndpointId, endpoint_info,
service_id_hash, Pcp::kP2pPointToPoint);
EXPECT_FALSE(device.IsValid());
EXPECT_FALSE(
store_.IsInjectedDevice(remote_bluetooth_mac_address.string_data()));
}
TEST_F(InjectedBluetoothDeviceStoreTest, Fail_InvalidEndpointId) {
@@ -435,7 +435,8 @@ void P2pClusterPcpHandler::BluetoothDeviceDiscoveredHandler(
}
// Make sure we are still discovering before proceeding.
if (!bluetooth_medium_.IsDiscovering(service_id)) {
if (!bluetooth_medium_.IsDiscovering(service_id) &&
!client->GetDiscoveryOptions().is_out_of_band_connection) {
LOG(WARNING) << "Skipping discovered Bluetooth device due to "
"no longer discovering.";
return;
@@ -483,7 +484,8 @@ void P2pClusterPcpHandler::BluetoothNameChangedHandler(
return;
}
if (!bluetooth_medium_.IsDiscovering(service_id)) {
if (!bluetooth_medium_.IsDiscovering(service_id) &&
!client->GetDiscoveryOptions().is_out_of_band_connection) {
LOG(WARNING) << "Ignoring name changed Bluetooth device due to no "
"longer discovering.";
return;
@@ -563,7 +565,8 @@ void P2pClusterPcpHandler::BluetoothDeviceLostHandler(
"p2p-bt-device-lost", [this, client, service_id,
device_name_string]() RUN_ON_PCP_HANDLER_THREAD() {
// Make sure we are still discovering before proceeding.
if (!bluetooth_medium_.IsDiscovering(service_id)) {
if (!bluetooth_medium_.IsDiscovering(service_id) &&
!client->GetDiscoveryOptions().is_out_of_band_connection) {
LOG(WARNING) << "Ignoring lost Bluetooth device due to no "
"longer discovering.";
return;
@@ -1442,6 +1445,13 @@ Status P2pClusterPcpHandler::InjectEndpointImpl(
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,
@@ -3123,8 +3133,7 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartAwdlAdvertising(
<< ", endpoint_info="
<< absl::BytesToHexString(local_endpoint_info.data()) << "}.";
awdl_medium_.StopAcceptingConnections(service_id);
return {
Error(OperationResultCode::NEARBY_AWDL_ADVERTISE_TO_BYTES_FAILURE)};
return {Error(OperationResultCode::NEARBY_AWDL_ADVERTISE_TO_BYTES_FAILURE)};
}
LOG(INFO) << "In StartAwdlAdvertising("
<< absl::BytesToHexString(local_endpoint_info.data())
@@ -35,6 +35,7 @@
#include "connections/implementation/mediums/mediums.h"
#include "connections/listeners.h"
#include "connections/medium_selector.h"
#include "connections/out_of_band_connection_metadata.h"
#include "connections/status.h"
#include "connections/strategy.h"
#include "connections/v3/connection_listening_options.h"
@@ -42,6 +43,7 @@
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/logging.h"
#include "internal/platform/mac_address.h"
#include "internal/platform/medium_environment.h"
namespace nearby {
@@ -143,6 +145,16 @@ class P2pClusterPcpHandlerTest : public testing::Test {
};
}
// Returns a 6 bytes mac address from a given address.
// address: it is in format of "01:02:03:04:05:06".
ByteArray GetSixBytesMacAddress(std::string address) {
MacAddress mac_address;
MacAddress::FromString(address, mac_address);
uint8_t bytes[6];
mac_address.ToBytes(bytes);
return ByteArray(reinterpret_cast<char*>(bytes), 6);
}
ClientProxy client_a_;
ClientProxy client_b_;
ClientProxy client_c_;
@@ -1341,6 +1353,192 @@ TEST_P(P2pClusterPcpHandlerTestWithParam, CanUpdateAwdlAdvertisingOptions) {
env_.Stop();
}
TEST_F(P2pClusterPcpHandlerTest, FailedToInjectEndpointWithoutDiscovery) {
env_.Start();
std::string endpoint_name{"endpoint_name"};
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);
OutOfBandConnectionMetadata metadata = {
.medium = location::nearby::proto::connections::Medium::BLUETOOTH,
.endpoint_id = "ABCD",
.endpoint_info = ByteArray("endpoint_info"),
.remote_bluetooth_mac_address = ByteArray("\x01\x02\x03\x04\x05\x06"),
};
handler_a.InjectEndpoint(&client_a_, service_id_, metadata);
env_.Sync();
EXPECT_FALSE(ibds_a.IsInjectedDevice("01:02:03:04:05:06"));
env_.Stop();
}
TEST_F(P2pClusterPcpHandlerTest, CanInjectEndpoint) {
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{
.bluetooth = true,
}},
/* auto_upgrade_bandwidth= */ false,
/* enforce_topology_constraints= */ false,
/* is_out_of_band_connection= */ true,
};
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::BLUETOOTH,
.endpoint_id = endpoint_id,
.endpoint_info = endpoint_info,
.remote_bluetooth_mac_address = GetSixBytesMacAddress(
mediums_a.GetBluetoothRadio().GetBluetoothAdapter().GetMacAddress()),
};
handler_a.InjectEndpoint(&client_a_, service_id_, metadata);
EXPECT_TRUE(found_latch.Await(absl::Milliseconds(1000)).result());
EXPECT_EQ(found_endpoint_id, endpoint_id);
EXPECT_TRUE(ibds_a.IsInjectedDevice(
mediums_a.GetBluetoothRadio().GetBluetoothAdapter().GetMacAddress()));
handler_a.StopDiscovery(&client_a_);
env_.Stop();
}
TEST_F(P2pClusterPcpHandlerTest, CanConnectToInjectedEndpoint) {
env_.Start();
// Setup handler_a (advertiser)
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);
mediums_a.GetBluetoothRadio().GetBluetoothAdapter().SetName("Device A");
// Setup handler_b (discoverer)
Mediums mediums_b;
EndpointChannelManager ecm_b;
EndpointManager em_b(&ecm_b);
BwuManager bwu_b(mediums_b, em_b, ecm_b, {}, {});
InjectedBluetoothDeviceStore ibds_b;
P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b, ibds_b);
mediums_b.GetBluetoothRadio().GetBluetoothAdapter().SetName("Device B");
CountDownLatch found_latch(1);
CountDownLatch connect_latch(2);
std::string discovered_endpoint_id;
ByteArray discovered_endpoint_info;
// 1. Advertiser starts advertising
std::string endpoint_info_name = "Advertiser Info";
EXPECT_EQ(handler_a.StartAdvertising(
&client_a_, service_id_, GetBluetoothOnlyAdvertisingOptions(),
{
.endpoint_info = ByteArray{endpoint_info_name},
.listener =
{
.initiated_cb =
[&](const std::string& endpoint_id,
const ConnectionResponseInfo& info) {
connect_latch.CountDown();
},
},
}),
Status{Status::kSuccess});
// 2. Discoverer starts out-of-band discovery
DiscoveryOptions discovery_options{
{Strategy::kP2pCluster,
BooleanMediumSelector{
.bluetooth = true,
}},
/* auto_upgrade_bandwidth= */ false,
/* enforce_topology_constraints= */ false,
/* is_out_of_band_connection= */ true,
};
EXPECT_EQ(handler_b.StartDiscovery(
&client_b_, service_id_, discovery_options,
{
.endpoint_found_cb =
[&](const std::string& endpoint_id,
const ByteArray& endpoint_info,
const std::string& service_id) {
discovered_endpoint_id = endpoint_id;
discovered_endpoint_info = endpoint_info;
found_latch.CountDown();
},
}),
Status{Status::kSuccess});
// 3. Inject the endpoint into the discoverer
OutOfBandConnectionMetadata metadata = {
.medium = location::nearby::proto::connections::Medium::BLUETOOTH,
.endpoint_id = client_a_.GetLocalEndpointId(),
.endpoint_info = ByteArray{endpoint_info_name},
.remote_bluetooth_mac_address = GetSixBytesMacAddress(
mediums_a.GetBluetoothRadio().GetBluetoothAdapter().GetMacAddress()),
};
handler_b.InjectEndpoint(&client_b_, service_id_, metadata);
EXPECT_TRUE(found_latch.Await(absl::Milliseconds(1000)).result());
EXPECT_EQ(discovered_endpoint_id, client_a_.GetLocalEndpointId());
// 4. Discoverer requests connection to the injected endpoint
client_b_.AddCancellationFlag(discovered_endpoint_id);
handler_b.RequestConnection(
&client_b_, discovered_endpoint_id,
{.endpoint_info = discovered_endpoint_info,
.listener =
{
.initiated_cb =
[&](const std::string& endpoint_id,
const ConnectionResponseInfo& info) {
connect_latch.CountDown();
},
}},
{});
EXPECT_TRUE(connect_latch.Await(absl::Milliseconds(2000)).result());
handler_a.StopAdvertising(&client_a_);
handler_b.StopDiscovery(&client_b_);
env_.Stop();
}
INSTANTIATE_TEST_SUITE_P(
ParametrisedPcpHandlerTest, P2pClusterPcpHandlerTestWithParam,
::testing::Combine(/*mediums=*/::testing::ValuesIn(kTestCases),
@@ -31,6 +31,7 @@
#include "internal/platform/implementation/g3/bluetooth_adapter.h"
#include "internal/platform/logging.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/types.h"
namespace nearby {
namespace g3 {
@@ -173,10 +174,21 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
LOG(INFO) << "G3 ConnectToService [self]: medium=" << this
<< ", adapter=" << &GetAdapter()
<< ", device=" << &GetAdapter().GetDevice();
// First, find an instance of remote medium, that exposed this device.
auto& adapter = static_cast<BluetoothDevice&>(remote_device).GetAdapter();
// Find the device in the MediumEnvironment, so that injected devices are
// supported in tests.
api::BluetoothDevice* device =
MediumEnvironment::Instance().FindBluetoothDevice(
remote_device.GetMacAddress());
if (device == nullptr) {
LOG(ERROR) << "G3 ConnectToService [peer]: device=" << &remote_device
<< " not found";
return {};
}
auto& adapter = down_cast<BluetoothDevice*>(device)->GetAdapter();
auto* medium =
static_cast<BluetoothClassicMedium*>(adapter.GetBluetoothClassicMedium());
down_cast<BluetoothClassicMedium*>(adapter.GetBluetoothClassicMedium());
if (!medium) return {}; // Adapter is not bound to medium. Bail out.