[BLEREFACTOR]: Implement DispatchPacket in BleSocket.

PiperOrigin-RevId: 834079972
This commit is contained in:
Edwin Wu
2025-11-18 20:04:29 -08:00
committed by Copybara-Service
parent 9357295089
commit 9ce1286bfa
4 changed files with 334 additions and 7 deletions
+6 -1
View File
@@ -82,11 +82,16 @@ cc_test(
deps = [
":ble",
":ble_socket",
"//connections/implementation/flags:connections_flags",
"//internal/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:util",
"//internal/platform/implementation:comm",
"//internal/platform/implementation/g3",
"//internal/platform/implementation/g3", # buildcleaner: keep
"//proto:connections_enums_cc_proto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:string_view",
"@com_google_googletest//:gtest_main",
],
@@ -20,6 +20,7 @@
#include <utility>
#include "absl/status/statusor.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "connections/implementation/mediums/ble/ble_packet.h"
@@ -196,8 +197,34 @@ Medium BleSocket::GetMediumLocked() const {
}
ExceptionOr<ByteArray> BleSocket::DispatchPacket() {
// TODO(b/419654808): Implement this method.
return {Exception::kFailed};
MutexLock lock(&mutex_);
if (!ble_input_stream_) {
return Exception::kFailed;
}
ExceptionOr<ByteArray> read_bytes =
ble_input_stream_->Read(BlePacket::kServiceIdHashLength);
while (read_bytes.ok()) {
ByteArray read_bytes_result = read_bytes.result();
if (BlePacket::IsControlPacketBytes(read_bytes_result)) {
ExceptionOr<ByteArray> handle_result = ProcessBleControlPacketLocked();
if (!handle_result.ok()) {
return handle_result;
}
read_bytes = ble_input_stream_->Read(BlePacket::kServiceIdHashLength);
} else {
if (read_bytes_result != service_id_hash_) {
LOG(WARNING)
<< "Received data packet with incorrect service ID hash. Expected: "
<< absl::BytesToHexString(service_id_hash_.string_data())
<< ", Received: "
<< absl::BytesToHexString(read_bytes_result.string_data());
return Exception::kFailed;
}
break;
}
}
return read_bytes;
}
ExceptionOr<std::int32_t> BleSocket::ReadPayloadLength() {
@@ -224,6 +251,55 @@ Exception BleSocket::WritePayloadLength(int payload_length) {
return ble_output_stream_->WritePayloadLength(payload_length);
}
ExceptionOr<ByteArray> BleSocket::ProcessBleControlPacketLocked() {
// Read the first 4 bytes (packet block 1).
ExceptionOr<ByteArray> read_bytes = ble_input_stream_->Read(4);
if (!read_bytes.ok()) {
return read_bytes;
}
if (read_bytes.result().size() != 4) {
return Exception::kFailed;
}
ByteArray packet_block_1 = read_bytes.result();
// Read the length from the 3rd byte of the packet block (0-indexed).
int packet_block_2_size = packet_block_1.data()[3];
// Read the left bytes for the packet block 2).
read_bytes = ble_input_stream_->Read(packet_block_2_size);
if (!read_bytes.ok()) {
return read_bytes;
}
if (read_bytes.result().size() != packet_block_2_size) {
return Exception::kFailed;
}
ByteArray packet_block_2 = read_bytes.result();
// Concatenate the two packet blocks.
std::string str1(packet_block_1);
std::string str2(packet_block_2);
std::string result_str = absl::StrCat(str1, str2);
ByteArray packet_block = ByteArray(result_str);
// Create the BlePacket from the concatenated packet block.
absl::StatusOr<BlePacket> ble_packet_status_or =
BlePacket::CreateControlPacket(packet_block);
if (!ble_packet_status_or.ok()) {
return Exception::kFailed;
}
BlePacket ble_packet = ble_packet_status_or.value();
ble_packet.ParseControlPacketData(packet_block.AsStringView());
if (!ble_packet.IsValid()) {
return Exception::kFailed;
}
if (service_id_hash_ != ble_packet.GetServiceIdHash()) {
return Exception::kFailed;
}
LOG(INFO) << "Received BLE Socket Control frame: "
<< BlePacket::SocketControlFrameTypeToString(
ble_packet.GetControlFrameType());
return Exception::kSuccess;
}
Exception BleSocket::SendIntroduction() {
// TODO(b/419654808): Implement this method.
return {Exception::kFailed};
@@ -341,6 +341,21 @@ class BleSocket final {
std::unique_ptr<BleOutputStream> ble_output_stream,
nearby::BleL2capSocket l2cap_socket);
/**
* Processes a control packet received from the socket.
*
* This function is called when a control packet is received from the socket.
* It is responsible for parsing the packet to identify its type and
* determining the appropriate action.
*
* @return An `ExceptionOr<ByteArray>` containing the payload of the
* received packet on success. For certain control packets that have no
* payload, the `ByteArray` may be empty. Returns an `Exception` if a
* protocol error occurs or the read operation fails.
*/
ExceptionOr<ByteArray> ProcessBleControlPacketLocked()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
::location::nearby::proto::connections::Medium GetMediumLocked() const
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
Exception CloseLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
@@ -14,42 +14,79 @@
#include "connections/implementation/mediums/ble/ble_socket.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include "gtest/gtest.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "connections/implementation/mediums/ble/ble_packet.h"
#include "internal/flags/nearby_flags.h"
#include "internal/platform/ble.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/byte_utils.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
#include "proto/connections_enums.proto.h"
namespace nearby {
namespace connections {
namespace mediums {
namespace {
using ::location::nearby::proto::connections::Medium;
constexpr absl::string_view kServiceIdHash{"\x0a\x0b\x0c"};
class FakeInputStream : public InputStream {
public:
ExceptionOr<ByteArray> Read(std::int64_t size) override {
return ExceptionOr<ByteArray>(Exception::kIo);
if (exception_on_read_) {
return ExceptionOr<ByteArray>(Exception::kIo);
}
if (buffer_.empty()) {
return ExceptionOr<ByteArray>(Exception::kIo);
}
size_t read_size = std::min(static_cast<size_t>(size), buffer_.size());
ByteArray result{buffer_.data(), read_size};
buffer_.erase(0, read_size);
return ExceptionOr<ByteArray>{result};
}
Exception Close() override { return {Exception::kSuccess}; }
void Append(const ByteArray& data) {
absl::StrAppend(&buffer_, std::string(data));
}
void SetExceptionOnRead(bool exception_on_read) {
exception_on_read_ = exception_on_read;
}
private:
std::string buffer_;
bool exception_on_read_ = false;
};
class FakeOutputStream : public OutputStream {
public:
Exception Write(const ByteArray& data) override {
absl::StrAppend(&buffer_, std::string(data));
return {Exception::kSuccess};
}
Exception Flush() override { return {Exception::kSuccess}; }
Exception Close() override { return {Exception::kSuccess}; }
std::string GetPayload() { return buffer_; }
void Clear() { buffer_.clear(); }
private:
std::string buffer_;
};
class FakeBleSocketImpl : public api::ble::BleSocket {
@@ -157,13 +194,109 @@ TEST_F(BleSocketBleMediumTest, GetRemotePeripheralReturnsSameInstance) {
EXPECT_EQ(&peripheral1, &peripheral2);
}
TEST_F(BleSocketBleMediumTest, DispatchPacketWithCorrectServiceIdHash) {
fake_input_stream_.Append(ByteArray(std::string(kServiceIdHash)));
auto result = socket_->DispatchPacket();
EXPECT_TRUE(result.ok());
EXPECT_EQ(result.result(), ByteArray(std::string(kServiceIdHash)));
}
TEST_F(BleSocketBleMediumTest, DispatchPacketWithWrongServiceIdHash) {
fake_input_stream_.Append(ByteArray("\x01\x02\x03"));
auto result = socket_->DispatchPacket();
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.exception(), Exception::kFailed);
}
TEST_F(BleSocketBleMediumTest, DispatchPacketWithControlPacket) {
auto control_packet_status = BlePacket::CreateControlIntroductionPacket(
ByteArray(std::string(kServiceIdHash)));
ASSERT_TRUE(control_packet_status.ok());
BlePacket control_packet = control_packet_status.value();
fake_input_stream_.Append(ByteArray(control_packet));
fake_input_stream_.Append(ByteArray(std::string(kServiceIdHash)));
auto result = socket_->DispatchPacket();
EXPECT_TRUE(result.ok());
EXPECT_EQ(result.result(), ByteArray(std::string(kServiceIdHash)));
}
TEST_F(BleSocketBleMediumTest, DispatchPacketWithReadError) {
fake_input_stream_.SetExceptionOnRead(true);
auto result = socket_->DispatchPacket();
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.exception(), Exception::kIo);
}
TEST_F(BleSocketBleMediumTest, ReadPayloadLengthSuccess) {
constexpr int kPayloadLength = 12345;
fake_input_stream_.Append(ByteArray(byte_utils::IntToBytes(kPayloadLength)));
auto result = socket_->ReadPayloadLength();
EXPECT_TRUE(result.ok());
EXPECT_EQ(result.result(), kPayloadLength);
}
TEST_F(BleSocketBleMediumTest, ReadPayloadLengthReadError) {
fake_input_stream_.SetExceptionOnRead(true);
auto result = socket_->ReadPayloadLength();
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.exception(), Exception::kIo);
}
TEST_F(BleSocketBleMediumTest, ReadPayloadLengthAfterClose) {
socket_->Close();
auto result = socket_->ReadPayloadLength();
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.exception(), Exception::kIo);
}
TEST_F(BleSocketBleMediumTest, WritePayloadLengthSuccess) {
constexpr int kPayloadLength = 12345;
EXPECT_TRUE(socket_->WritePayloadLength(kPayloadLength).Ok());
}
TEST_F(BleSocketBleMediumTest, WritePayloadLengthAfterClose) {
constexpr int kPayloadLength = 12345;
socket_->Close();
EXPECT_FALSE(socket_->WritePayloadLength(kPayloadLength).Ok());
}
TEST_F(BleSocketBleMediumTest, WritePayloadLengthFailsIfCalledTwice) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kRefactorBleL2cap,
true);
constexpr int kPayloadLength = 12345;
EXPECT_TRUE(socket_->WritePayloadLength(kPayloadLength).Ok());
EXPECT_FALSE(socket_->WritePayloadLength(kPayloadLength).Ok());
}
TEST_F(BleSocketBleMediumTest, WritePayloadLengthSucceedsIfCalledAfterWrite) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kRefactorBleL2cap,
true);
constexpr int kPayloadLength = 12345;
ByteArray payload("payload");
EXPECT_TRUE(socket_->WritePayloadLength(kPayloadLength).Ok());
EXPECT_TRUE(socket_->GetOutputStream().Write(payload).Ok());
EXPECT_TRUE(socket_->WritePayloadLength(kPayloadLength).Ok());
}
TEST_F(BleSocketBleMediumTest, IsValid) {
EXPECT_TRUE(socket_->IsValid());
EXPECT_TRUE(socket_->Close().Ok());
EXPECT_TRUE(socket_->IsValid());
}
TEST_F(BleSocketBleMediumTest, GetMedium) {
EXPECT_EQ(socket_->GetMedium(), Medium::BLE);
}
class BleL2capSocketBleMediumTest : public ::testing::Test {
protected:
void SetUp() override {
nearby::BlePeripheral peripheral;
auto fake_l2cap_socket_impl =
std::make_unique<FakeBleL2capSocketImpl>(
fake_input_stream_, fake_output_stream_);
auto fake_l2cap_socket_impl = std::make_unique<FakeBleL2capSocketImpl>(
fake_input_stream_, fake_output_stream_);
fake_l2cap_socket_impl_ = fake_l2cap_socket_impl.get();
@@ -215,6 +348,104 @@ TEST_F(BleL2capSocketBleMediumTest, GetRemotePeripheralReturnsSameInstance) {
EXPECT_EQ(&peripheral1, &peripheral2);
}
TEST_F(BleL2capSocketBleMediumTest, DispatchPacketWithCorrectServiceIdHash) {
fake_input_stream_.Append(ByteArray(std::string(kServiceIdHash)));
auto result = socket_->DispatchPacket();
EXPECT_TRUE(result.ok());
EXPECT_EQ(result.result(), ByteArray(std::string(kServiceIdHash)));
}
TEST_F(BleL2capSocketBleMediumTest, DispatchPacketWithWrongServiceIdHash) {
fake_input_stream_.Append(ByteArray("\x01\x02\x03"));
auto result = socket_->DispatchPacket();
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.exception(), Exception::kFailed);
}
TEST_F(BleL2capSocketBleMediumTest, DispatchPacketWithControlPacket) {
auto control_packet_status = BlePacket::CreateControlIntroductionPacket(
ByteArray(std::string(kServiceIdHash)));
ASSERT_TRUE(control_packet_status.ok());
BlePacket control_packet = control_packet_status.value();
fake_input_stream_.Append(ByteArray(control_packet));
fake_input_stream_.Append(ByteArray(std::string(kServiceIdHash)));
auto result = socket_->DispatchPacket();
EXPECT_TRUE(result.ok());
EXPECT_EQ(result.result(), ByteArray(std::string(kServiceIdHash)));
}
TEST_F(BleL2capSocketBleMediumTest, DispatchPacketWithReadError) {
fake_input_stream_.SetExceptionOnRead(true);
auto result = socket_->DispatchPacket();
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.exception(), Exception::kIo);
}
TEST_F(BleL2capSocketBleMediumTest, ReadPayloadLengthSuccess) {
constexpr int kPayloadLength = 12345;
fake_input_stream_.Append(ByteArray(byte_utils::IntToBytes(kPayloadLength)));
auto result = socket_->ReadPayloadLength();
EXPECT_TRUE(result.ok());
EXPECT_EQ(result.result(), kPayloadLength);
}
TEST_F(BleL2capSocketBleMediumTest, ReadPayloadLengthReadError) {
fake_input_stream_.SetExceptionOnRead(true);
auto result = socket_->ReadPayloadLength();
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.exception(), Exception::kIo);
}
TEST_F(BleL2capSocketBleMediumTest, ReadPayloadLengthAfterClose) {
socket_->Close();
auto result = socket_->ReadPayloadLength();
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.exception(), Exception::kIo);
}
TEST_F(BleL2capSocketBleMediumTest, WritePayloadLengthSuccess) {
constexpr int kPayloadLength = 12345;
EXPECT_TRUE(socket_->WritePayloadLength(kPayloadLength).Ok());
}
TEST_F(BleL2capSocketBleMediumTest, WritePayloadLengthAfterClose) {
constexpr int kPayloadLength = 12345;
socket_->Close();
EXPECT_FALSE(socket_->WritePayloadLength(kPayloadLength).Ok());
}
TEST_F(BleL2capSocketBleMediumTest, WritePayloadLengthFailsIfCalledTwice) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kRefactorBleL2cap,
true);
constexpr int kPayloadLength = 12345;
EXPECT_TRUE(socket_->WritePayloadLength(kPayloadLength).Ok());
EXPECT_FALSE(socket_->WritePayloadLength(kPayloadLength).Ok());
}
TEST_F(BleL2capSocketBleMediumTest,
WritePayloadLengthSucceedsIfCalledAfterWrite) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kRefactorBleL2cap,
true);
constexpr int kPayloadLength = 12345;
ByteArray payload("payload");
EXPECT_TRUE(socket_->WritePayloadLength(kPayloadLength).Ok());
EXPECT_TRUE(socket_->GetOutputStream().Write(payload).Ok());
EXPECT_TRUE(socket_->WritePayloadLength(kPayloadLength).Ok());
}
TEST_F(BleL2capSocketBleMediumTest, IsValid) {
EXPECT_TRUE(socket_->IsValid());
EXPECT_TRUE(socket_->Close().Ok());
EXPECT_TRUE(socket_->IsValid());
}
TEST_F(BleL2capSocketBleMediumTest, GetMedium) {
EXPECT_EQ(socket_->GetMedium(), Medium::BLE_L2CAP);
}
} // namespace
} // namespace mediums
} // namespace connections