Interface definition for Ble L2CAP Medium in Nearby Connections layer

PiperOrigin-RevId: 741054574
This commit is contained in:
Mingshiou Wu
2025-03-27 01:04:16 -07:00
committed by Copybara-Service
parent df2ddd0f20
commit 04b2f9cfc6
13 changed files with 552 additions and 50 deletions
+2
View File
@@ -56,6 +56,7 @@ cc_library(
"base_endpoint_channel.cc",
"base_pcp_handler.cc",
"ble_endpoint_channel.cc",
"ble_l2cap_endpoint_channel.cc",
"ble_v2_endpoint_channel.cc",
"bluetooth_bwu_handler.cc",
"bluetooth_device_name.cc",
@@ -95,6 +96,7 @@ cc_library(
"base_endpoint_channel.h",
"base_pcp_handler.h",
"ble_endpoint_channel.h",
"ble_l2cap_endpoint_channel.h",
"ble_v2_endpoint_channel.h",
"bluetooth_bwu_handler.h",
"bluetooth_device_name.h",
@@ -0,0 +1,78 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/ble_l2cap_endpoint_channel.h"
#include <string>
#include <utility>
#include "connections/implementation/base_endpoint_channel.h"
#include "internal/platform/ble_v2.h"
#include "internal/platform/exception.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/logging.h"
#include "internal/platform/output_stream.h"
namespace nearby {
namespace connections {
namespace {
constexpr int kDefaultBleL2capMaxTransmitPacketSize = 1024; // 1024 bytes
OutputStream* GetOutputStreamOrNull(BleL2capSocket& socket) {
if (socket.GetRemotePeripheral().IsValid()) {
return &socket.GetOutputStream();
}
LOG(WARNING) << "GetOutputStreamOrNull: socket is not valid";
return nullptr;
}
InputStream* GetInputStreamOrNull(BleL2capSocket& socket) {
if (socket.GetRemotePeripheral().IsValid()) {
return &socket.GetInputStream();
}
return nullptr;
}
} // namespace
BleL2capEndpointChannel::BleL2capEndpointChannel(
const std::string& service_id, const std::string& channel_name,
BleL2capSocket socket)
: BaseEndpointChannel(service_id, channel_name,
GetInputStreamOrNull(socket),
GetOutputStreamOrNull(socket)),
ble_l2cap_socket_(std::move(socket)) {}
location::nearby::proto::connections::Medium
BleL2capEndpointChannel::GetMedium() const {
return location::nearby::proto::connections::Medium::BLE_L2CAP;
}
int BleL2capEndpointChannel::GetMaxTransmitPacketSize() const {
return kDefaultBleL2capMaxTransmitPacketSize;
}
void BleL2capEndpointChannel::CloseImpl() {
Exception status = ble_l2cap_socket_.Close();
if (!status.Ok()) {
LOG(WARNING)
<< "Failed to close underlying socket for BleL2capEndpointChannel "
<< GetName() << ": exception=" << status.value;
}
}
} // namespace connections
} // namespace nearby
@@ -0,0 +1,48 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_BLE_L2CAP_ENDPOINT_CHANNEL_H_
#define CORE_INTERNAL_BLE_L2CAP_ENDPOINT_CHANNEL_H_
#include <string>
#include "connections/implementation/base_endpoint_channel.h"
#include "internal/platform/ble_v2.h"
namespace nearby {
namespace connections {
class BleL2capEndpointChannel final : public BaseEndpointChannel {
public:
// Creates both outgoing and incoming Ble channels.
BleL2capEndpointChannel(const std::string& service_id,
const std::string& channel_name,
BleL2capSocket socket);
// Returns the medium of this endpoint channel.
location::nearby::proto::connections::Medium GetMedium() const override;
// Returns the maximum transmit packet size of this endpoint channel.
int GetMaxTransmitPacketSize() const override;
private:
void CloseImpl() override;
BleL2capSocket ble_l2cap_socket_;
};
} // namespace connections
} // namespace nearby
#endif // CORE_INTERNAL_BLE_L2CAP_ENDPOINT_CHANNEL_H_
@@ -40,6 +40,9 @@ constexpr auto kEnableAutoReconnect =
// Disable/Enable BLE v2 in Nearby Connections SDK.
constexpr auto kEnableBleV2 =
flags::Flag<bool>(kConfigPackage, "45401515", false);
// Disable/Enable BLE L2CAP in Nearby Connections SDK.
constexpr auto kEnableBleL2cap =
flags::Flag<bool>(kConfigPackage, "45685706", false);
// Disable/Enable GATT query in thread in BLE V2.
// Manual edit: setting this to false for ChromeOS rollout as well.
constexpr auto kEnableGattQueryInThread =
+164 -41
View File
@@ -175,9 +175,7 @@ ErrorOr<bool> BleV2::StartAdvertising(const std::string& service_id,
// Wrap the connections advertisement to the medium advertisement.
ByteArray service_id_hash = mediums::bleutils::GenerateHash(
service_id, mediums::BleAdvertisement::kServiceIdHashLength);
// Get psm value from L2CAP server if L2CAP is supported. Now just use the
// default value.
int psm = mediums::BleAdvertisementHeader::kDefaultPsmValue;
int psm = medium_.GetPSM();
mediums::BleAdvertisement medium_advertisement = {
mediums::BleAdvertisement::Version::kV2,
mediums::BleAdvertisement::SocketVersion::kV2,
@@ -570,13 +568,13 @@ ErrorOr<bool> BleV2::StartAcceptingConnections(
MutexLock lock(&mutex_);
if (service_id.empty()) {
LOG(INFO)
LOG(WARNING)
<< "Refusing to start accepting BLE connections with empty service id.";
return {Error(OperationResultCode::CLIENT_BLE_DUPLICATE_DISCOVERING)};
}
if (IsAcceptingConnectionsLocked(service_id)) {
LOG(INFO)
LOG(WARNING)
<< "Refusing to start accepting BLE connections for " << service_id
<< " because another BLE peripheral socket is already in-progress.";
return {Error(OperationResultCode::
@@ -596,47 +594,128 @@ ErrorOr<bool> BleV2::StartAcceptingConnections(
}
BleV2ServerSocket server_socket = medium_.OpenServerSocket(service_id);
if (!server_socket.IsValid()) {
LOG(INFO) << "Failed to start accepting Ble connections for service_id="
<< service_id;
return {Error(
OperationResultCode::CONNECTIVITY_BLE_SERVER_SOCKET_CREATION_FAILURE)};
if (server_socket.IsValid()) {
// Mark the fact that there's an in-progress Ble server accepting
// connections.
auto owned_server_socket =
server_sockets_.insert({service_id, std::move(server_socket)})
.first->second;
// Start the accept loop on a dedicated thread - this stays alive and
// listening for new incoming connections until
// StopAcceptingL2capConnections() is invoked.
accept_loops_runner_.Execute(
"ble-accept",
[this, service_id, callback = std::move(callback),
server_socket = std::move(owned_server_socket)]() mutable {
while (true) {
BleV2Socket client_socket = server_socket.Accept();
if (!client_socket.IsValid()) {
LOG(WARNING) << "The client socket to accept is invalid.";
server_socket.Close();
break;
} else {
LOG(INFO) << "The client Ble GATT socket has been accepted.";
}
{
MutexLock lock(&mutex_);
client_socket.SetCloseNotifier([this, service_id]() {
MutexLock lock(&mutex_);
incoming_sockets_.erase(service_id);
});
incoming_sockets_.insert({service_id, client_socket});
}
if (callback) {
callback(std::move(client_socket), service_id);
}
}
});
} else {
LOG(INFO)
<< "Failed to start accepting Ble GATT connections for service_id="
<< service_id;
}
LOG(INFO) << "Start accepting Ble GATT connections for service_id="
<< service_id;
return {true};
}
// TODO(mingshiouwu): Add unit test for ble_l2cap flow
ErrorOr<bool> BleV2::StartAcceptingL2capConnections(
const std::string& service_id, AcceptedL2capConnectionCallback callback) {
MutexLock lock(&mutex_);
if (service_id.empty()) {
LOG(WARNING)
<< "Refusing to start accepting Ble L2CAP connections with empty "
"service id.";
return {Error(OperationResultCode::CLIENT_BLE_DUPLICATE_DISCOVERING)};
}
// Mark the fact that there's an in-progress Ble server accepting
// connections.
auto owned_server_socket =
server_sockets_.insert({service_id, std::move(server_socket)})
.first->second;
if (IsAcceptingL2capConnectionsLocked(service_id)) {
LOG(WARNING)
<< "Refusing to start accepting Ble L2CAP connections for "
<< service_id
<< " because another Ble peripheral socket is already in-progress.";
return {Error(OperationResultCode::
CLIENT_DUPLICATE_ACCEPTING_BLE_CONNECTION_REQUEST)};
}
// Start the accept loop on a dedicated thread - this stays alive and
// listening for new incoming connections until StopAcceptingConnections() is
// invoked.
accept_loops_runner_.Execute(
"ble-accept",
[this, service_id = service_id, callback = std::move(callback),
server_socket = std::move(owned_server_socket)]() mutable {
while (true) {
BleV2Socket client_socket = server_socket.Accept();
if (!client_socket.IsValid()) {
LOG(WARNING) << "The client socket to accept is invalid.";
server_socket.Close();
break;
}
{
MutexLock lock(&mutex_);
client_socket.SetCloseNotifier([this, service_id]() {
if (!radio_.IsEnabled()) {
LOG(INFO) << "Can't start accepting Ble L2CAP connections for "
<< service_id << " because Bluetooth isn't enabled.";
return {Error(OperationResultCode::MISCELLEANEOUS_BT_SYSTEM_SERVICE_NULL)};
}
if (!IsAvailableLocked()) {
LOG(INFO) << "Can't start accepting Ble L2CAP connections for "
<< service_id << " because Ble isn't available.";
return {Error(OperationResultCode::MEDIUM_UNAVAILABLE_BLE_NOT_AVAILABLE)};
}
BleL2capServerSocket server_socket =
medium_.OpenL2capServerSocket(service_id);
if (server_socket.IsValid()) {
// Mark the fact that there's an in-progress Ble server accepting
// connections.
auto owned_server_socket =
l2cap_server_socket_map_.insert({service_id, std::move(server_socket)})
.first->second;
// Start the accept loop on a dedicated thread - this stays alive and
// listening for new incoming connections until StopAcceptingConnections()
// is invoked.
accept_loops_runner_.Execute(
"ble-l2cap-accept",
[this, service_id, callback = std::move(callback),
server_socket = std::move(owned_server_socket)]() mutable {
while (true) {
BleL2capSocket client_socket = server_socket.Accept();
if (!client_socket.IsValid()) {
LOG(WARNING) << "The client L2CAP socket to accept is invalid.";
server_socket.Close();
break;
} else {
LOG(INFO) << "The client L2CAP socket has been accepted.";
}
{
MutexLock lock(&mutex_);
incoming_sockets_.erase(service_id);
});
incoming_sockets_.insert({service_id, client_socket});
client_socket.SetCloseNotifier([this, service_id]() {
MutexLock lock(&mutex_);
incoming_sockets_.erase(service_id);
});
l2cap_incoming_service_id_to_socket_map_.insert(
{service_id, client_socket});
}
if (callback) {
callback(std::move(client_socket), service_id);
}
}
if (callback) {
callback(std::move(client_socket), service_id);
}
}
});
});
} else {
LOG(INFO)
<< "Failed to start accepting Ble L2CAP connections for service_id="
<< service_id;
}
LOG(INFO) << "Start accepting Ble L2CAP connections for service_id="
<< service_id;
return {true};
}
@@ -675,11 +754,51 @@ bool BleV2::StopAcceptingConnections(const std::string& service_id) {
return true;
}
bool BleV2::StopAcceptingL2capConnections(const std::string& service_id) {
MutexLock lock(&mutex_);
const auto it = l2cap_server_socket_map_.find(service_id);
if (it == l2cap_server_socket_map_.end()) {
LOG(INFO) << "Can't stop accepting Ble L2CAP connections because it was "
"never started.";
return false;
}
// Closing the BleL2capServerSocket will kick off the suicide of the thread
// in accept_loops_thread_pool_ that blocks on BleL2capServerSocket.accept().
// That may take some time to complete, but there's no particular reason to
// wait around for it.
auto item = l2cap_server_socket_map_.extract(it);
// Store a handle to the BleL2capServerSocket, so we can use it after
// removing the entry from l2cap_server_socket_map_; making it scoped
// is a bonus that takes care of deallocation before we leave this method.
BleL2capServerSocket& listening_socket = item.mapped();
// Regardless of whether or not we fail to close the existing
// BleL2capServerSocket, remove it from l2cap_server_socket_map_ so that it
// frees up this service for another round.
// Finally, close the BleL2capServerSocket.
if (!listening_socket.Close().Ok()) {
LOG(INFO) << "Failed to close Ble L2CAP server socket for service_id="
<< service_id;
return false;
}
return true;
}
bool BleV2::IsAcceptingConnections(const std::string& service_id) {
MutexLock lock(&mutex_);
return IsAcceptingConnectionsLocked(service_id);
}
bool BleV2::IsAcceptingL2capConnections(const std::string& service_id) {
MutexLock lock(&mutex_);
return IsAcceptingL2capConnectionsLocked(service_id);
}
ErrorOr<BleV2Socket> BleV2::Connect(const std::string& service_id,
const BleV2Peripheral& peripheral,
CancellationFlag* cancellation_flag) {
@@ -741,6 +860,10 @@ bool BleV2::IsAcceptingConnectionsLocked(const std::string& service_id) {
return server_sockets_.contains(service_id);
}
bool BleV2::IsAcceptingL2capConnectionsLocked(const std::string& service_id) {
return l2cap_server_socket_map_.contains(service_id);
}
bool BleV2::IsAdvertisementGattServerRunningLocked() {
return gatt_server_ && gatt_server_->IsValid();
}
+33 -6
View File
@@ -62,6 +62,10 @@ class BleV2 final {
using AcceptedConnectionCallback = absl::AnyInvocable<void(
BleV2Socket socket, const std::string& service_id)>;
// Callback that is invoked when a new l2cap connection is accepted.
using AcceptedL2capConnectionCallback = absl::AnyInvocable<void(
BleL2capSocket socket, const std::string& service_id)>;
// The type of the BLE advertising. In current implementation, we don't
// support multiple advertising types on a Medium instance.
enum class AdvertisingType : int {
@@ -108,7 +112,7 @@ class BleV2 final {
ABSL_LOCKS_EXCLUDED(mutex_);
// (TODO:hais) update this after ble_v2 async api refactor.
// Stop Ble advertising with dummy bytes for legagy device.
// Stop Ble advertising with dummy bytes for legacy device.
bool StopLegacyAdvertising(const std::string& service_id)
ABSL_LOCKS_EXCLUDED(mutex_);
@@ -151,13 +155,26 @@ class BleV2 final {
AcceptedConnectionCallback callback)
ABSL_LOCKS_EXCLUDED(mutex_);
// Starts a worker thread, creates a Ble L2CAP socket, associates it with a
// service id.
ErrorOr<bool> StartAcceptingL2capConnections(
const std::string& service_id,
AcceptedL2capConnectionCallback l2cap_callback)
ABSL_LOCKS_EXCLUDED(mutex_);
// Closes socket corresponding to a service id.
bool StopAcceptingConnections(const std::string& service_id)
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAcceptingL2capConnections(const std::string& service_id)
ABSL_LOCKS_EXCLUDED(mutex_);
bool IsAcceptingConnections(const std::string& service_id)
ABSL_LOCKS_EXCLUDED(mutex_);
bool IsAcceptingL2capConnections(const std::string& service_id)
ABSL_LOCKS_EXCLUDED(mutex_);
// Establishes connection to Ble peripheral.
// Returns socket instance. On success, BleSocket.IsValid() return true.
ErrorOr<BleV2Socket> Connect(const std::string& service_id,
@@ -205,6 +222,10 @@ class BleV2 final {
// `mutex_` held.
bool IsAcceptingConnectionsLocked(const std::string& service_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Same as IsListeningForIncomingConnections(), but must be called with
// `mutex_` held.
bool IsAcceptingL2capConnectionsLocked(const std::string& service_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
bool IsAdvertisementGattServerRunningLocked()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
@@ -222,14 +243,11 @@ class BleV2 final {
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
bool StopAdvertisementGattServerLocked()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
ByteArray CreateAdvertisementHeader(int psm,
bool extended_advertisement_advertised)
ABSL_SHARED_LOCKS_REQUIRED(mutex_);
// For devices that don't have extended nor gatt adverting.
api::ble_v2::BleAdvertisementData CreateAdvertisingDataForLegacyDevice();
bool StartAdvertisingLocked(const std::string& service_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
bool StartFastAdvertisingLocked(
@@ -256,9 +274,7 @@ class BleV2 final {
// Called by StartScanning when using the async methods.
bool StopAsyncScanningLocked(absl::string_view service_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
api::ble_v2::TxPowerLevel PowerLevelToTxPowerLevel(PowerLevel power_level);
void RunOnBleThread(Runnable runnable);
static constexpr int kMaxConcurrentAcceptLoops = 5;
@@ -307,6 +323,17 @@ class BleV2 final {
ABSL_GUARDED_BY(mutex_);
mediums::InstantOnLostManager instant_on_lost_manager_;
// A map of service_id -> L2capServerSocket. If map is non-empty, we
// are currently listening for incoming connections.
absl::flat_hash_map<std::string, BleL2capServerSocket>
l2cap_server_socket_map_ ABSL_GUARDED_BY(mutex_);
// A map of service_id -> BleL2capSocket.
// Tracks currently connected incoming sockets. This lets the device know when
// it's okay to restart L2CAP server related operations.
absl::flat_hash_map<std::string, BleL2capSocket>
l2cap_incoming_service_id_to_socket_map_ ABSL_GUARDED_BY(mutex_);
};
} // namespace connections
@@ -32,6 +32,7 @@
#include "connections/implementation/base_pcp_handler.h"
#include "connections/implementation/ble_advertisement.h"
#include "connections/implementation/ble_endpoint_channel.h"
#include "connections/implementation/ble_l2cap_endpoint_channel.h"
#include "connections/implementation/ble_v2_endpoint_channel.h"
#include "connections/implementation/bluetooth_device_name.h"
#include "connections/implementation/bluetooth_endpoint_channel.h"
@@ -49,6 +50,7 @@
#include "connections/implementation/mediums/utils.h"
#include "connections/implementation/pcp.h"
#include "connections/implementation/pcp_handler.h"
#include "connections/implementation/webrtc_state.h"
#include "connections/implementation/wifi_lan_endpoint_channel.h"
#include "connections/implementation/wifi_lan_service_info.h"
#include "connections/medium_selector.h"
@@ -1386,6 +1388,26 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::kEnableBleV2)) {
// ble_v2
// TODO(mingshiouwu): Add unit test for ble_l2cap flow
bool accepting_ble_connections_success = false;
if (options.enable_ble_listening &&
NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableBleL2cap) &&
!ble_v2_medium_.IsAcceptingL2capConnections(std::string(service_id))) {
if (!ble_v2_medium_.StartAcceptingL2capConnections(
std::string(service_id),
absl::bind_front(
&P2pClusterPcpHandler::BleL2capConnectionAcceptedHandler,
this, client_proxy, local_endpoint_id,
options.listening_endpoint_type))) {
LOG(WARNING) << "Failed to start listening for incoming L2CAP "
"connections on ble_v2";
} else {
accepting_ble_connections_success = true;
}
}
if (options.enable_ble_listening &&
!ble_v2_medium_.IsAcceptingConnections(std::string(service_id))) {
if (!ble_v2_medium_.StartAcceptingConnections(
@@ -1397,9 +1419,12 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
LOG(WARNING)
<< "Failed to start listening for incoming connections on ble_v2";
} else {
started_mediums.push_back(BLE);
accepting_ble_connections_success = true;
}
}
if (accepting_ble_connections_success) {
started_mediums.push_back(BLE);
}
} else {
// ble v1
if (options.enable_ble_listening &&
@@ -2427,6 +2452,29 @@ void P2pClusterPcpHandler::BleV2ConnectionAcceptedHandler(
});
}
void P2pClusterPcpHandler::BleL2capConnectionAcceptedHandler(
ClientProxy* client, absl::string_view local_endpoint_info,
NearbyDevice::Type device_type, BleL2capSocket socket,
const std::string& service_id) {
if (!socket.IsValid()) {
LOG(WARNING) << "Invalid socket in accept L2CAP callback("
<< absl::BytesToHexString(local_endpoint_info)
<< "), client=" << client->GetClientId();
return;
}
RunOnPcpHandlerThread(
"p2p-ble-l2cap-on-incoming-connection",
[this, client, service_id, device_type,
socket = std::move(socket)]() RUN_ON_PCP_HANDLER_THREAD() mutable {
ByteArray remote_peripheral_info = socket.GetRemotePeripheral().GetId();
auto channel = std::make_unique<BleL2capEndpointChannel>(
service_id, std::string(remote_peripheral_info), socket);
OnIncomingConnection(client, remote_peripheral_info, std::move(channel),
BLE, device_type);
});
}
ErrorOr<Medium> P2pClusterPcpHandler::StartBleV2Advertising(
ClientProxy* client, const std::string& service_id,
const std::string& local_endpoint_id, const ByteArray& local_endpoint_info,
@@ -2450,12 +2498,24 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartBleV2Advertising(
<< service_id;
return {Error(OperationResultCode::DEVICE_STATE_RADIO_ENABLING_FAILURE)};
}
ErrorOr<bool> ble_l2cap_result = true;
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableBleL2cap)) {
ble_l2cap_result = ble_v2_medium_.StartAcceptingL2capConnections(
service_id,
absl::bind_front(
&P2pClusterPcpHandler::BleL2capConnectionAcceptedHandler, this,
client, local_endpoint_info.AsStringView(),
NearbyDevice::Type::kConnectionsDevice));
}
ErrorOr<bool> ble_v2_result = ble_v2_medium_.StartAcceptingConnections(
service_id,
absl::bind_front(&P2pClusterPcpHandler::BleV2ConnectionAcceptedHandler,
this, client, local_endpoint_info.AsStringView(),
NearbyDevice::Type::kConnectionsDevice));
if (ble_v2_result.has_error()) {
if (ble_v2_result.has_error() && ble_l2cap_result.has_error()) {
LOG(WARNING)
<< "In StartBleV2Advertising("
<< absl::BytesToHexString(local_endpoint_info.data())
@@ -259,12 +259,16 @@ class P2pClusterPcpHandler : public BasePcpHandler {
const ByteArray& advertisement_bytes,
bool fast_advertisement);
void BleV2LegacyDeviceDiscoveredHandler();
void BleV2ConnectionAcceptedHandler(ClientProxy* client,
absl::string_view local_endpoint_info,
NearbyDevice::Type device_type,
BleV2Socket socket,
const std::string& service_id);
void BleL2capConnectionAcceptedHandler(ClientProxy* client,
absl::string_view local_endpoint_info,
NearbyDevice::Type device_type,
BleL2capSocket socket,
const std::string& service_id);
ErrorOr<location::nearby::proto::connections::Medium> StartBleV2Advertising(
ClientProxy* client, const std::string& service_id,
const std::string& local_endpoint_id,
+9
View File
@@ -19,7 +19,10 @@
#include <utility>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "absl/types/optional.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/logging.h"
#include "internal/platform/mutex_lock.h"
@@ -247,6 +250,12 @@ BleV2ServerSocket BleV2Medium::OpenServerSocket(const std::string& service_id) {
return BleV2ServerSocket(*this, impl_->OpenServerSocket(service_id));
}
BleL2capServerSocket BleV2Medium::OpenL2capServerSocket(
const std::string& service_id) {
// TODO(mingshiouwu): Replace with a real implementation listening flow.
return BleL2capServerSocket(*this, nullptr);
}
BleV2Socket BleV2Medium::Connect(const std::string& service_id,
TxPowerLevel tx_power_level,
const BleV2Peripheral& peripheral,
+82
View File
@@ -335,6 +335,78 @@ class GattClient final {
std::unique_ptr<api::ble_v2::GattClient> impl_;
};
class BleL2capSocket final {
public:
BleL2capSocket(BleV2Peripheral peripheral,
std::unique_ptr<api::ble_v2::BleL2capSocket> socket)
: peripheral_(peripheral) {};
BleL2capSocket(const BleL2capSocket&) = default;
BleL2capSocket& operator=(const BleL2capSocket&) = default;
~BleL2capSocket() = default;
explicit BleL2capSocket(std::unique_ptr<api::ble_v2::BleL2capSocket> socket)
: impl_(std::move(socket)) {}
// Returns InputStream of the BleL2capSocket.
InputStream& GetInputStream() { return impl_->GetInputStream(); }
// Returns OutputStream of the BleL2capSocket.
OutputStream& GetOutputStream() { return impl_->GetOutputStream(); }
// Sets the close notifier by client side.
void SetCloseNotifier(absl::AnyInvocable<void()> notifier) {
impl_->SetCloseNotifier(std::move(notifier));
}
// Closes the BleL2capSocket.
Exception Close() { return impl_->Close(); }
// Returns BlePeripheral object which wraps a valid BlePeripheral pointer.
BleV2Peripheral& GetRemotePeripheral() { return peripheral_; }
// Returns true if a BleL2capSocket is usable. If this method returns false,
// it is not safe to call any other method.
bool IsValid() const { return impl_ != nullptr; }
api::ble_v2::BleL2capSocket& GetImpl() { return *impl_; }
private:
std::shared_ptr<api::ble_v2::BleL2capSocket> impl_;
BleV2Peripheral peripheral_;
};
class BleL2capServerSocket final {
public:
BleL2capServerSocket(
BleV2Medium& medium,
std::unique_ptr<api::ble_v2::BleL2capServerSocket> socket)
: medium_(&medium), impl_(std::move(socket)) {}
BleL2capServerSocket(const BleL2capServerSocket&) = default;
BleL2capServerSocket& operator=(const BleL2capServerSocket&) = default;
~BleL2capServerSocket() = default;
explicit BleL2capServerSocket(
std::unique_ptr<api::ble_v2::BleL2capServerSocket> socket)
: impl_(std::move(socket)) {}
// Accepts an incoming connection.
BleL2capSocket Accept() {
std::unique_ptr<api::ble_v2::BleL2capSocket> socket = impl_->Accept();
if (!socket) {
LOG(INFO) << "BleL2capServerSocket Accept() failed on server socket: "
<< this;
}
return BleL2capSocket(std::move(socket));
}
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception Close() {
LOG(INFO) << "BleL2capServerSocket Closing:: " << this;
return impl_->Close();
}
// Returns true if a BleL2capServerSocket is usable. If this method returns
// false, it is not safe to call any other method.
bool IsValid() const { return impl_ != nullptr; }
api::ble_v2::BleL2capServerSocket& GetImpl() { return *impl_; }
private:
BleV2Medium* medium_ = nullptr;
std::shared_ptr<api::ble_v2::BleL2capServerSocket> impl_;
};
// Container of operations that can be performed over the BLE medium.
class BleV2Medium final {
public:
@@ -440,6 +512,10 @@ class BleV2Medium final {
// On Success, BleServerSocket::IsValid() returns true.
BleV2ServerSocket OpenServerSocket(const std::string& service_id);
// Returns a new BleL2capServerSocket.
// On Success, BleL2capServerSocket::IsValid() returns true.
BleL2capServerSocket OpenL2capServerSocket(const std::string& service_id);
// Returns a new BleLanSocket.
// On Success, BleLanSocket::IsValid() returns true.
BleV2Socket Connect(const std::string& service_id,
@@ -462,6 +538,12 @@ class BleV2Medium final {
impl_->AddAlternateUuidForService(uuid, service_id);
}
// Returns PSM value.
int GetPSM() {
// TODO(mingshiouwu): Replace with real implementation.
return 0;
}
private:
Mutex mutex_;
std::unique_ptr<api::ble_v2::BleMedium> impl_;
+57
View File
@@ -376,6 +376,54 @@ class BleServerSocket {
virtual Exception Close() = 0;
};
// A BLE L2CAP client socket for requesting L2CAP socket.
class BleL2capSocket {
public:
virtual ~BleL2capSocket() = default;
// Returns the InputStream of the BleL2capSocket.
// On error, returned stream will report Exception::kIo on any operation.
//
// The returned object is not owned by the caller, and can be invalidated once
// the BleL2capSocket object is destroyed.
virtual InputStream& GetInputStream() = 0;
// Returns the OutputStream of the BleL2capSocket.
// On error, returned stream will report Exception::kIo on any operation.
//
// The returned object is not owned by the caller, and can be invalidated once
// the BleL2capSocket object is destroyed.
virtual OutputStream& GetOutputStream() = 0;
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
virtual Exception Close() = 0;
// Sets the close notifier by client side.
virtual void SetCloseNotifier(absl::AnyInvocable<void()> notifier) {};
// Returns valid BlePeripheral pointer if there is a connection, and
// nullptr otherwise.
virtual BlePeripheral* GetRemotePeripheral() = 0;
};
// A BLE L2CAP server socket for listening incoming L2CAP socket.
class BleL2capServerSocket {
public:
virtual ~BleL2capServerSocket() = default;
// Blocks until either:
// - at least one incoming connection request is available, or
// - ServerSocket is closed.
// On success, returns connected socket, ready to exchange data.
// Returns nullptr on error.
// Once error is reported, it is permanent, and L2CAP ServerSocket has to be
// closed.
virtual std::unique_ptr<BleL2capSocket> Accept() = 0;
// Closes the L2CAP server socket.
virtual Exception Close() = 0;
};
// The main BLE medium used inside of Nearby. This serves as the entry point
// for all BLE and GATT related operations.
class BleMedium {
@@ -515,6 +563,15 @@ class BleMedium {
virtual std::unique_ptr<BleServerSocket> OpenServerSocket(
const std::string& service_id) = 0;
// Opens a BLE l2cap server socket based on service ID.
//
// On success, returns a new BleL2capServerSocket.
// On error, returns nullptr.
virtual std::unique_ptr<BleL2capServerSocket> OpenL2capServerSocket(
const std::string& service_id) {
return nullptr;
}
// Connects to a BLE peripheral.
//
// On success, returns a new BleSocket.
@@ -779,6 +779,12 @@ std::unique_ptr<api::ble_v2::BleServerSocket> BleV2Medium::OpenServerSocket(
return server_socket;
}
std::unique_ptr<api::ble_v2::BleL2capServerSocket>
BleV2Medium::OpenL2capServerSocket(const std::string& service_id) {
// TODO(mingshiouwu): add more codes for g3 testing.
return nullptr;
}
std::unique_ptr<api::ble_v2::BleSocket> BleV2Medium::Connect(
const std::string& service_id, TxPowerLevel tx_power_level,
api::ble_v2::BlePeripheral& remote_peripheral,
@@ -188,6 +188,9 @@ class BleV2Medium : public api::ble_v2::BleMedium {
std::unique_ptr<api::ble_v2::BleServerSocket> OpenServerSocket(
const std::string& service_id) override ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<api::ble_v2::BleL2capServerSocket> OpenL2capServerSocket(
const std::string& service_id) override ABSL_LOCKS_EXCLUDED(mutex_);
// Connects to existing remote Ble peripheral.
//
// On success, returns a new BleSocket.