mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-15 07:06:11 -04:00
Interface definition for Ble L2CAP Medium in Nearby Connections layer
PiperOrigin-RevId: 741054574
This commit is contained in:
committed by
Copybara-Service
parent
df2ddd0f20
commit
04b2f9cfc6
@@ -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 =
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user