1
0
Fork 0

bt: refresh vendor_libs from aosp main

last commit:
 * b63b23b984 Merge "Add test for attp_build_value_cmd" into main

Signed-off-by: hmz007 <hmz007@gmail.com>
master
hmz007 1 year ago
parent bc6622c358
commit b1e8fbd310

@ -27,15 +27,11 @@ cc_binary {
proprietary: true,
relative_install_path: "hw",
srcs: [
"hci_packetizer.cc",
"h4_protocol.cc",
"bluetooth_hci.cc",
"h4_protocol.cc",
"hci_packetizer.cc",
"service.cc",
],
cflags: [
"-Wall",
"-Werror",
],
header_libs: ["libbluetooth_headers"],
shared_libs: [
"android.hardware.bluetooth@1.0",
@ -61,14 +57,39 @@ cc_library_static {
srcs: [
"async_fd_watcher.cc",
],
shared_libs: [
"liblog",
],
export_include_dirs: [
".",
],
}
cc_test_host {
name: "bluetooth-btlinux-hci-test",
srcs: [
"async_fd_watcher.cc",
"h4_protocol.cc",
"h4_protocol_unittest.cc",
"hci_packetizer.cc",
],
cflags: [
"-DNO_THREAD_PRIORITY",
"-Wall",
"-Werror",
],
shared_libs: [
"libbase",
"libhidlbase",
"liblog",
"libutils",
],
export_include_dirs: [
".",
static_libs: [
"libgmock",
],
}
sanitize: {
address: true,
cfi: true,
},
test_suites: ["general-tests"],
}

@ -29,7 +29,9 @@
#include "unistd.h"
static const int INVALID_FD = -1;
#ifndef NO_THREAD_PRIORITY
static const int BT_RT_PRIORITY = 1;
#endif
namespace android {
namespace hardware {
@ -117,7 +119,7 @@ int AsyncFdWatcher::notifyThread() {
}
void AsyncFdWatcher::ThreadRoutine() {
#ifndef NO_THREAD_PRIORITY
// Make watching thread RT.
struct sched_param rt_params;
rt_params.sched_priority = BT_RT_PRIORITY;
@ -125,6 +127,7 @@ void AsyncFdWatcher::ThreadRoutine() {
ALOGE("%s unable to set SCHED_FIFO for pid %d, tid %d, error %s", __func__,
getpid(), gettid(), strerror(errno));
}
#endif
while (running_) {
fd_set read_fds;

@ -15,18 +15,17 @@
//
#define LOG_TAG "android.hardware.bluetooth@1.1-btlinux"
#include <errno.h>
#include "bluetooth_hci.h"
#include <fcntl.h>
#include <poll.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <utils/Log.h>
#include "bluetooth_hci.h"
#include <cerrno>
#define BTPROTO_HCI 1
@ -301,12 +300,31 @@ Return<void> BluetoothHci::initialize_impl(
}
hci::H4Protocol* h4_hci = new hci::H4Protocol(
hci_fd,
[cb](const hidl_vec<uint8_t>& packet) { cb->hciEventReceived(packet); },
[cb](const hidl_vec<uint8_t>& packet) { cb->aclDataReceived(packet); },
[cb](const hidl_vec<uint8_t>& packet) { cb->scoDataReceived(packet); },
[cb](const hidl_vec<uint8_t>& packet) {
auto status = cb->hciEventReceived(packet);
if (!status.isOk()) {
ALOGE("VendorInterface -> Unable to call hciEventReceived");
}
},
[cb](const hidl_vec<uint8_t>& packet) {
auto status = cb->aclDataReceived(packet);
if (!status.isOk()) {
ALOGE("VendorInterface -> Unable to call hciAclReceived");
}
},
[cb](const hidl_vec<uint8_t>& packet) {
auto status = cb->scoDataReceived(packet);
if (!status.isOk()) {
ALOGE("VendorInterface -> Unable to call hciScoReceived");
}
},
[cb_1_1](const hidl_vec<uint8_t>& packet) {
cb_1_1->isoDataReceived(packet);
});
auto status = cb_1_1->isoDataReceived(packet);
if (!status.isOk()) {
ALOGE("VendorInterface -> Unable to call hciIsoReceived");
}
},
[]() { ALOGE("UART disconnected."); });
fd_watcher_.WatchFdForNonBlockingReads(
hci_fd, [h4_hci](int fd) { h4_hci->OnDataReady(fd); });

@ -28,6 +28,17 @@ namespace hardware {
namespace bluetooth {
namespace hci {
H4Protocol::H4Protocol(int fd, PacketReadCallback event_cb,
PacketReadCallback acl_cb, PacketReadCallback sco_cb,
PacketReadCallback iso_cb,
OnDisconnectCallback disconnect_cb)
: uart_fd_(fd),
event_cb_(std::move(event_cb)),
acl_cb_(std::move(acl_cb)),
sco_cb_(std::move(sco_cb)),
iso_cb_(std::move(iso_cb)),
disconnect_cb_(std::move(disconnect_cb)) {}
size_t H4Protocol::Send(uint8_t type, const uint8_t* data, size_t length) {
/* For HCI communication over USB dongle, multiple write results in
* response timeout as driver expect type + data at once to process
@ -56,51 +67,68 @@ size_t H4Protocol::Send(uint8_t type, const uint8_t* data, size_t length) {
return ret;
}
void H4Protocol::OnPacketReady() {
size_t H4Protocol::on_packet_ready(const hidl_vec<uint8_t>& packet) {
switch (hci_packet_type_) {
case HCI_PACKET_TYPE_EVENT:
event_cb_(hci_packetizer_.GetPacket());
event_cb_(packet);
break;
case HCI_PACKET_TYPE_ACL_DATA:
acl_cb_(hci_packetizer_.GetPacket());
acl_cb_(packet);
break;
case HCI_PACKET_TYPE_SCO_DATA:
sco_cb_(hci_packetizer_.GetPacket());
sco_cb_(packet);
break;
case HCI_PACKET_TYPE_ISO_DATA:
iso_cb_(hci_packetizer_.GetPacket());
iso_cb_(packet);
break;
default: {
bool bad_packet_type = true;
CHECK(!bad_packet_type);
LOG_ALWAYS_FATAL("Unhandled packet of type 0x%x", hci_packet_type_);
}
}
// Get ready for the next type byte.
hci_packet_type_ = HCI_PACKET_TYPE_UNKNOWN;
return packet.size();
}
void H4Protocol::OnDataReady(int fd) {
void H4Protocol::send_data_to_packetizer(uint8_t* buffer, size_t length) {
std::vector<uint8_t> input_buffer{buffer, buffer + length};
size_t buffer_offset = 0;
while (buffer_offset < input_buffer.size()) {
if (hci_packet_type_ == HCI_PACKET_TYPE_UNKNOWN) {
/**
* read full buffer. ACL max length is 2 bytes, and SCO max length is 2
* byte. so taking 64K as buffer length.
* Question : Why to read in single chunk rather than multiple reads,
* which can give parameter length arriving in response ?
* Answer: The multiple reads does not work with BT USB dongle. At least
* with Bluetooth 2.0 supported USB dongle. After first read, either
* firmware/kernel (do not know who is responsible - inputs ??) driver
* discard the whole message and successive read results in forever
* blocking loop. - Is there any other way to make it work with multiple
* reads, do not know yet (it can eliminate need of this function) ?
* Reading in single shot gives expected response.
*/
const size_t max_plen = 64*1024;
hidl_vec<uint8_t> tpkt;
tpkt.resize(max_plen);
size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, tpkt.data(), max_plen));
hci_packet_type_ = static_cast<HciPacketType>(tpkt.data()[0]);
hci_packetizer_.CbHciPacket(tpkt.data()+1, bytes_read-1);
hci_packet_type_ =
static_cast<HciPacketType>(input_buffer.data()[buffer_offset]);
buffer_offset += 1;
} else {
bool packet_ready = hci_packetizer_.OnDataReady(
hci_packet_type_, input_buffer, buffer_offset);
if (packet_ready) {
// Call packet callback and move offset.
buffer_offset += on_packet_ready(hci_packetizer_.GetPacket());
// Get ready for the next type byte.
hci_packet_type_ = HCI_PACKET_TYPE_UNKNOWN;
} else {
// The data was consumed, but there wasn't a packet.
buffer_offset = input_buffer.size();
}
}
}
}
void H4Protocol::OnDataReady(int fd) {
if (disconnected_) {
return;
}
uint8_t buffer[kMaxPacketLength];
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, kMaxPacketLength));
if (bytes_read == 0) {
ALOGI("No bytes read, calling the disconnect callback");
disconnected_ = true;
disconnect_cb_();
return;
}
if (bytes_read < 0) {
ALOGW("error reading from UART (%s)", strerror(errno));
return;
}
send_data_to_packetizer(buffer, bytes_read);
}
} // namespace hci

@ -29,34 +29,43 @@ namespace hci {
using ::android::hardware::hidl_vec;
using PacketReadCallback = std::function<void(const hidl_vec<uint8_t>&)>;
using OnDisconnectCallback = std::function<void()>;
class H4Protocol {
public:
H4Protocol(int fd, PacketReadCallback event_cb, PacketReadCallback acl_cb,
PacketReadCallback sco_cb, PacketReadCallback iso_cb)
: uart_fd_(fd),
event_cb_(event_cb),
acl_cb_(acl_cb),
sco_cb_(sco_cb),
iso_cb_(iso_cb),
hci_packetizer_([this]() { OnPacketReady(); }) {}
PacketReadCallback sco_cb, PacketReadCallback iso_cb,
OnDisconnectCallback disconnect_cb);
size_t Send(uint8_t type, const uint8_t* data, size_t length);
virtual ~H4Protocol() {}
void OnPacketReady();
size_t Send(uint8_t type, const uint8_t* data, size_t length);
void OnDataReady(int fd);
private:
int uart_fd_;
bool disconnected_{false};
size_t on_packet_ready(const hidl_vec<uint8_t>& packet);
void send_data_to_packetizer(uint8_t* buffer, size_t length);
PacketReadCallback event_cb_;
PacketReadCallback acl_cb_;
PacketReadCallback sco_cb_;
PacketReadCallback iso_cb_;
OnDisconnectCallback disconnect_cb_;
HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
HciPacketizer hci_packetizer_;
/**
* Question : Why read in single chunk rather than multiple reads?
* Answer: Using multiple reads does not work with some BT USB dongles.
* Reading in single shot gives expected response.
* ACL max length is 2 bytes, so using 64K as the buffer length.
*/
static constexpr size_t kMaxPacketLength = 64 * 1024;
};
} // namespace hci

@ -0,0 +1,448 @@
/*
* Copyright 2022 The Android Open Source Project
*
* 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
*
* http://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.
*/
#define LOG_TAG "bt_h4_unittest"
#include "h4_protocol.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdint>
#include <cstring>
#include <future>
#include <vector>
#include "async_fd_watcher.h"
#include "log/log.h"
using android::hardware::bluetooth::async::AsyncFdWatcher;
using android::hardware::bluetooth::hci::H4Protocol;
using ::testing::Eq;
static char sample_data1[100] = "A point is that which has no part.";
static char sample_data2[100] = "A line is breadthless length.";
static char sample_data3[100] = "The ends of a line are points.";
static char sample_data4[100] =
"A plane surface is a surface which lies evenly with the straight ...";
static char acl_data[100] =
"A straight line is a line which lies evenly with the points on itself.";
static char sco_data[100] =
"A surface is that which has length and breadth only.";
static char event_data[100] = "The edges of a surface are lines.";
static char iso_data[100] =
"A plane angle is the inclination to one another of two lines in a ...";
// 5 seconds. Just don't hang.
static constexpr size_t kTimeoutMs = 5000;
MATCHER_P3(PacketMatches, header_, header_length, payload,
"Match header_length bytes of header and then the payload") {
size_t payload_length = strlen(payload);
if (header_length + payload_length != arg.size()) {
return false;
}
if (memcmp(header_, arg.data(), header_length) != 0) {
return false;
}
return memcmp(payload, arg.data() + header_length, payload_length) == 0;
};
ACTION_P(Notify, barrier) {
ALOGD("%s", __func__);
barrier->set_value();
}
class H4ProtocolTest : public ::testing::Test {
protected:
void SetUp() override {
ALOGD("%s", __func__);
int sockfd[2];
socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
chip_uart_fd_ = sockfd[1];
stack_uart_fd_ = sockfd[0];
h4_hci_ = std::make_shared<H4Protocol>(
stack_uart_fd_, event_cb_.AsStdFunction(), acl_cb_.AsStdFunction(),
sco_cb_.AsStdFunction(), iso_cb_.AsStdFunction(),
disconnect_cb_.AsStdFunction());
}
void TearDown() override {
close(stack_uart_fd_);
close(chip_uart_fd_);
}
virtual void CallDataReady() { h4_hci_->OnDataReady(stack_uart_fd_); }
void SendAndReadUartOutbound(HciPacketType type, char* data) {
ALOGD("%s sending", __func__);
int data_length = strlen(data);
h4_hci_->Send(type, (uint8_t*)data, data_length);
int uart_length = data_length + 1; // + 1 for data type code
int i;
ALOGD("%s reading", __func__);
for (i = 0; i < uart_length; i++) {
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(chip_uart_fd_, &read_fds);
TEMP_FAILURE_RETRY(
select(chip_uart_fd_ + 1, &read_fds, nullptr, nullptr, nullptr));
char byte;
TEMP_FAILURE_RETRY(read(chip_uart_fd_, &byte, 1));
EXPECT_EQ(i == 0 ? static_cast<uint8_t>(type) : data[i - 1], byte);
}
EXPECT_EQ(i, uart_length);
}
void ExpectInboundAclData(char* payload, std::promise<void>* promise) {
// h4 type[1] + handle[2] + size[2]
header_[0] = static_cast<uint8_t>(HCI_PACKET_TYPE_ACL_DATA);
header_[1] = 19;
header_[2] = 92;
int length = strlen(payload);
header_[3] = length & 0xFF;
header_[4] = (length >> 8) & 0xFF;
ALOGD("(%d bytes) %s", length, payload);
EXPECT_CALL(acl_cb_, Call(PacketMatches(header_ + 1, HCI_ACL_PREAMBLE_SIZE,
payload)))
.WillOnce(Notify(promise));
}
void WaitForTimeout(std::promise<void>* promise) {
auto future = promise->get_future();
auto status = future.wait_for(std::chrono::milliseconds(kTimeoutMs));
EXPECT_EQ(status, std::future_status::ready);
}
void WriteInboundAclData(char* payload) {
// Use the header_ computed in ExpectInboundAclData
TEMP_FAILURE_RETRY(
write(chip_uart_fd_, header_, HCI_ACL_PREAMBLE_SIZE + 1));
TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
}
void ExpectInboundScoData(char* payload, std::promise<void>* promise) {
// h4 type[1] + handle[2] + size[1]
header_[0] = static_cast<uint8_t>(HCI_PACKET_TYPE_SCO_DATA);
header_[1] = 20;
header_[2] = 17;
header_[3] = strlen(payload) & 0xFF;
EXPECT_CALL(sco_cb_, Call(PacketMatches(header_ + 1, HCI_SCO_PREAMBLE_SIZE,
payload)))
.WillOnce(Notify(promise));
}
void WriteInboundScoData(char* payload) {
// Use the header_ computed in ExpectInboundScoData
ALOGD("%s writing", __func__);
TEMP_FAILURE_RETRY(
write(chip_uart_fd_, header_, HCI_SCO_PREAMBLE_SIZE + 1));
TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
}
void ExpectInboundEvent(char* payload, std::promise<void>* promise) {
// h4 type[1] + event_code[1] + size[1]
header_[0] = static_cast<uint8_t>(HCI_PACKET_TYPE_EVENT);
header_[1] = 9;
header_[2] = strlen(payload) & 0xFF;
EXPECT_CALL(event_cb_, Call(PacketMatches(
header_ + 1, HCI_EVENT_PREAMBLE_SIZE, payload)))
.WillOnce(Notify(promise));
}
void WriteInboundEvent(char* payload) {
// Use the header_ computed in ExpectInboundEvent
char preamble[3] = {static_cast<uint8_t>(HCI_PACKET_TYPE_EVENT), 9, 0};
preamble[2] = strlen(payload) & 0xFF;
ALOGD("%s writing", __func__);
TEMP_FAILURE_RETRY(
write(chip_uart_fd_, header_, HCI_EVENT_PREAMBLE_SIZE + 1));
TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
}
void ExpectInboundIsoData(char* payload, std::promise<void>* promise) {
// h4 type[1] + handle[2] + size[1]
header_[0] = static_cast<uint8_t>(HCI_PACKET_TYPE_ISO_DATA);
header_[1] = 19;
header_[2] = 92;
int length = strlen(payload);
header_[3] = length & 0xFF;
header_[4] = (length >> 8) & 0x3F;
EXPECT_CALL(iso_cb_, Call(PacketMatches(header_ + 1, HCI_ISO_PREAMBLE_SIZE,
payload)))
.WillOnce(Notify(promise));
}
void WriteInboundIsoData(char* payload) {
// Use the header_ computed in ExpectInboundIsoData
ALOGD("%s writing", __func__);
TEMP_FAILURE_RETRY(
write(chip_uart_fd_, header_, HCI_ISO_PREAMBLE_SIZE + 1));
TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
}
void WriteAndExpectManyInboundAclDataPackets(char* payload) {
size_t kNumPackets = 20;
// h4 type[1] + handle[2] + size[2]
char preamble[5] = {static_cast<uint8_t>(HCI_PACKET_TYPE_ACL_DATA), 19, 92,
0, 0};
int length = strlen(payload);
preamble[3] = length & 0xFF;
preamble[4] = (length >> 8) & 0xFF;
EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, sizeof(preamble) - 1,
payload)))
.Times(kNumPackets);
for (size_t i = 0; i < kNumPackets; i++) {
TEMP_FAILURE_RETRY(write(chip_uart_fd_, preamble, sizeof(preamble)));
TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
}
CallDataReady();
}
testing::MockFunction<void(const std::vector<uint8_t>&)> cmd_cb_;
testing::MockFunction<void(const std::vector<uint8_t>&)> event_cb_;
testing::MockFunction<void(const std::vector<uint8_t>&)> acl_cb_;
testing::MockFunction<void(const std::vector<uint8_t>&)> sco_cb_;
testing::MockFunction<void(const std::vector<uint8_t>&)> iso_cb_;
testing::MockFunction<void(void)> disconnect_cb_;
std::shared_ptr<H4Protocol> h4_hci_;
int chip_uart_fd_;
int stack_uart_fd_;
char header_[5];
};
// Test sending data sends correct data onto the UART
TEST_F(H4ProtocolTest, TestSends) {
SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1);
SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2);
SendAndReadUartOutbound(HCI_PACKET_TYPE_SCO_DATA, sample_data3);
SendAndReadUartOutbound(HCI_PACKET_TYPE_ISO_DATA, sample_data4);
}
// Ensure we properly parse data coming from the UART
TEST_F(H4ProtocolTest, TestReads) {
std::promise<void> acl_promise;
std::promise<void> sco_promise;
std::promise<void> event_promise;
std::promise<void> iso_promise;
ExpectInboundAclData(acl_data, &acl_promise);
WriteInboundAclData(acl_data);
CallDataReady();
ExpectInboundScoData(sco_data, &sco_promise);
WriteInboundScoData(sco_data);
CallDataReady();
ExpectInboundEvent(event_data, &event_promise);
WriteInboundEvent(event_data);
CallDataReady();
ExpectInboundIsoData(iso_data, &iso_promise);
WriteInboundIsoData(iso_data);
CallDataReady();
WaitForTimeout(&acl_promise);
WaitForTimeout(&sco_promise);
WaitForTimeout(&event_promise);
WaitForTimeout(&iso_promise);
}
TEST_F(H4ProtocolTest, TestMultiplePackets) {
WriteAndExpectManyInboundAclDataPackets(sco_data);
}
TEST_F(H4ProtocolTest, TestDisconnect) {
EXPECT_CALL(disconnect_cb_, Call());
close(chip_uart_fd_);
CallDataReady();
}
TEST_F(H4ProtocolTest, TestPartialWrites) {
size_t payload_len = strlen(acl_data);
const size_t kNumIntervals = payload_len + 1;
// h4 type[1] + handle[2] + size[2]
header_[0] = static_cast<uint8_t>(HCI_PACKET_TYPE_ACL_DATA);
header_[1] = 19;
header_[2] = 92;
header_[3] = payload_len & 0xFF;
header_[4] = (payload_len >> 8) & 0xFF;
EXPECT_CALL(acl_cb_,
Call(PacketMatches(header_ + 1, sizeof(header_) - 1, acl_data)))
.Times(kNumIntervals);
for (size_t interval = 1; interval < kNumIntervals + 1; interval++) {
// Use the header_ data that expect already set up.
if (interval < HCI_ACL_PREAMBLE_SIZE) {
TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, interval));
CallDataReady();
TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_ + interval,
HCI_ACL_PREAMBLE_SIZE + 1 - interval));
CallDataReady();
} else {
TEMP_FAILURE_RETRY(
write(chip_uart_fd_, header_, HCI_ACL_PREAMBLE_SIZE + 1));
CallDataReady();
}
for (size_t bytes = 0; bytes + interval <= payload_len; bytes += interval) {
TEMP_FAILURE_RETRY(write(chip_uart_fd_, acl_data + bytes, interval));
CallDataReady();
}
size_t extra_bytes = payload_len % interval;
if (extra_bytes) {
TEMP_FAILURE_RETRY(write(
chip_uart_fd_, acl_data + payload_len - extra_bytes, extra_bytes));
CallDataReady();
}
}
}
class H4ProtocolAsyncTest : public H4ProtocolTest {
protected:
void SetUp() override {
H4ProtocolTest::SetUp();
fd_watcher_.WatchFdForNonBlockingReads(
stack_uart_fd_, [this](int fd) { h4_hci_->OnDataReady(fd); });
}
void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
void CallDataReady() override {
// The Async test can't call data ready.
FAIL();
}
void SendAndReadUartOutbound(HciPacketType type, char* data) {
ALOGD("%s sending", __func__);
int data_length = strlen(data);
h4_hci_->Send(type, (uint8_t*)data, data_length);
int uart_length = data_length + 1; // + 1 for data type code
int i;
ALOGD("%s reading", __func__);
for (i = 0; i < uart_length; i++) {
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(chip_uart_fd_, &read_fds);
TEMP_FAILURE_RETRY(
select(chip_uart_fd_ + 1, &read_fds, nullptr, nullptr, nullptr));
char byte;
TEMP_FAILURE_RETRY(read(chip_uart_fd_, &byte, 1));
EXPECT_EQ(i == 0 ? static_cast<uint8_t>(type) : data[i - 1], byte);
}
EXPECT_EQ(i, uart_length);
}
void WriteAndExpectInboundAclData(char* payload) {
std::promise<void> promise;
ExpectInboundAclData(payload, &promise);
WriteInboundAclData(payload);
WaitForTimeout(&promise);
}
void WriteAndExpectInboundScoData(char* payload) {
std::promise<void> promise;
ExpectInboundScoData(payload, &promise);
WriteInboundScoData(payload);
WaitForTimeout(&promise);
}
void WriteAndExpectInboundEvent(char* payload) {
std::promise<void> promise;
ExpectInboundEvent(payload, &promise);
WriteInboundEvent(payload);
WaitForTimeout(&promise);
}
void WriteAndExpectInboundIsoData(char* payload) {
std::promise<void> promise;
ExpectInboundIsoData(payload, &promise);
WriteInboundIsoData(payload);
WaitForTimeout(&promise);
}
void WriteAndExpectManyInboundAclDataPackets(char* payload) {
const size_t kNumPackets = 20;
// h4 type[1] + handle[2] + size[2]
char preamble[5] = {static_cast<uint8_t>(HCI_PACKET_TYPE_ACL_DATA), 19, 92,
0, 0};
int length = strlen(payload);
preamble[3] = length & 0xFF;
preamble[4] = (length >> 8) & 0xFF;
EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, sizeof(preamble) - 1,
payload)))
.Times(kNumPackets);
for (size_t i = 0; i < kNumPackets; i++) {
TEMP_FAILURE_RETRY(write(chip_uart_fd_, preamble, sizeof(preamble)));
TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
}
WriteAndExpectInboundEvent(event_data);
}
AsyncFdWatcher fd_watcher_;
};
// Test sending data sends correct data onto the UART
TEST_F(H4ProtocolAsyncTest, TestSends) {
SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1);
SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2);
SendAndReadUartOutbound(HCI_PACKET_TYPE_SCO_DATA, sample_data3);
SendAndReadUartOutbound(HCI_PACKET_TYPE_ISO_DATA, sample_data4);
}
// Ensure we properly parse data coming from the UART
TEST_F(H4ProtocolAsyncTest, TestReads) {
WriteAndExpectInboundAclData(acl_data);
WriteAndExpectInboundScoData(sco_data);
WriteAndExpectInboundEvent(event_data);
WriteAndExpectInboundIsoData(iso_data);
}
TEST_F(H4ProtocolAsyncTest, TestMultiplePackets) {
WriteAndExpectManyInboundAclDataPackets(sco_data);
}
TEST_F(H4ProtocolAsyncTest, TestDisconnect) {
std::promise<void> promise;
EXPECT_CALL(disconnect_cb_, Call()).WillOnce(Notify(&promise));
close(chip_uart_fd_);
WaitForTimeout(&promise);
}

@ -44,6 +44,10 @@ const size_t HCI_LENGTH_OFFSET_SCO = 2;
const size_t HCI_EVENT_PREAMBLE_SIZE = 2;
const size_t HCI_LENGTH_OFFSET_EVT = 1;
// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.5)
const size_t HCI_ISO_PREAMBLE_SIZE = 4;
const size_t HCI_LENGTH_OFFSET_ISO = 2;
const size_t HCI_PREAMBLE_SIZE_MAX = HCI_ACL_PREAMBLE_SIZE;
// Event codes (Volume 2, Part E, 7.7.14)

@ -17,22 +17,27 @@
#include "hci_packetizer.h"
#define LOG_TAG "android.hardware.bluetooth.hci_packetizer"
#include <android-base/logging.h>
#include <utils/Log.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <log/log.h>
namespace {
const size_t preamble_size_for_type[] = {
0, HCI_COMMAND_PREAMBLE_SIZE, HCI_ACL_PREAMBLE_SIZE, HCI_SCO_PREAMBLE_SIZE,
HCI_EVENT_PREAMBLE_SIZE};
const size_t packet_length_offset_for_type[] = {
0, HCI_LENGTH_OFFSET_CMD, HCI_LENGTH_OFFSET_ACL, HCI_LENGTH_OFFSET_SCO,
HCI_LENGTH_OFFSET_EVT};
const size_t header_size_for_type[] = {0,
HCI_COMMAND_PREAMBLE_SIZE,
HCI_ACL_PREAMBLE_SIZE,
HCI_SCO_PREAMBLE_SIZE,
HCI_EVENT_PREAMBLE_SIZE,
HCI_ISO_PREAMBLE_SIZE};
const size_t packet_length_offset_for_type[] = {0,
HCI_LENGTH_OFFSET_CMD,
HCI_LENGTH_OFFSET_ACL,
HCI_LENGTH_OFFSET_SCO,
HCI_LENGTH_OFFSET_EVT,
HCI_LENGTH_OFFSET_ISO};
size_t HciGetPacketLengthForType(HciPacketType type, const uint8_t* preamble) {
size_t HciGetPacketLengthForType(HciPacketType type,
const std::vector<uint8_t>& preamble) {
size_t offset = packet_length_offset_for_type[type];
if (type != HCI_PACKET_TYPE_ACL_DATA) return preamble[offset];
return (((preamble[offset + 1]) << 8) | preamble[offset]);
@ -47,47 +52,64 @@ namespace hci {
const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const { return packet_; }
void HciPacketizer::CbHciPacket(uint8_t *data, size_t len) {
packet_.setToExternal(data, len);
packet_ready_cb_();
}
size_t HciPacketizer::fill_header(HciPacketType packet_type,
const std::vector<uint8_t>& buffer,
size_t offset) {
size_t header_size = header_size_for_type[static_cast<size_t>(packet_type)];
if (bytes_remaining_ == 0) {
bytes_remaining_ = header_size;
packet_buffer_.clear();
}
// Add as much of the header as is available to the packet.
size_t bytes_to_copy = std::min(bytes_remaining_, buffer.size() - offset);
packet_buffer_.insert(packet_buffer_.end(), buffer.begin() + offset,
buffer.begin() + offset + bytes_to_copy);
bytes_remaining_ -= bytes_to_copy;
void HciPacketizer::OnDataReady(int fd, HciPacketType packet_type) {
switch (state_) {
case HCI_PREAMBLE: {
size_t bytes_read = TEMP_FAILURE_RETRY(
read(fd, preamble_ + bytes_read_,
preamble_size_for_type[packet_type] - bytes_read_));
CHECK(bytes_read > 0);
bytes_read_ += bytes_read;
if (bytes_read_ == preamble_size_for_type[packet_type]) {
size_t packet_length =
HciGetPacketLengthForType(packet_type, preamble_);
packet_.resize(preamble_size_for_type[packet_type] + packet_length);
memcpy(packet_.data(), preamble_, preamble_size_for_type[packet_type]);
bytes_remaining_ = packet_length;
state_ = HCI_PAYLOAD;
bytes_read_ = 0;
}
break;
// If the header is complete, find the payload size and transition.
if (bytes_remaining_ == 0) {
bytes_remaining_ = HciGetPacketLengthForType(packet_type, packet_buffer_);
// If there are no bytes remaining, this is a completed packet.
if (bytes_remaining_ > 0) {
state_ = HCI_PAYLOAD;
}
}
return bytes_to_copy;
}
void HciPacketizer::fill_payload(const std::vector<uint8_t>& buffer,
size_t offset) {
// Add as much of the payload as is available to the end of the packet.
size_t bytes_to_copy = std::min(bytes_remaining_, buffer.size() - offset);
packet_buffer_.insert(packet_buffer_.end(), buffer.begin() + offset,
buffer.begin() + offset + bytes_to_copy);
bytes_remaining_ -= bytes_to_copy;
case HCI_PAYLOAD: {
size_t bytes_read = TEMP_FAILURE_RETRY(read(
fd,
packet_.data() + preamble_size_for_type[packet_type] + bytes_read_,
bytes_remaining_));
CHECK(bytes_read > 0);
bytes_remaining_ -= bytes_read;
bytes_read_ += bytes_read;
if (bytes_remaining_ == 0) {
packet_ready_cb_();
state_ = HCI_PREAMBLE;
bytes_read_ = 0;
}
break;
// If there are no bytes remaining, this is a completed packet.
if (bytes_remaining_ == 0) {
state_ = HCI_HEADER;
}
}
bool HciPacketizer::OnDataReady(HciPacketType packet_type,
const std::vector<uint8_t>& buffer,
size_t offset) {
// Start with the header.
size_t header_bytes = 0;
if (state_ == HCI_HEADER) {
header_bytes = fill_header(packet_type, buffer, offset);
}
// If there are bytes left in this packet, fill the payload.
if (state_ == HCI_PAYLOAD && bytes_remaining_ > 0) {
if (offset + header_bytes < buffer.size()) {
fill_payload(buffer, offset + header_bytes);
}
}
// If there are no bytes remaining, this is a completed packet.
if (bytes_remaining_ == 0) {
packet_.setToExternal(packet_buffer_.data(), packet_buffer_.size());
}
return bytes_remaining_ == 0;
}
} // namespace hci

@ -16,10 +16,11 @@
#pragma once
#include <functional>
#include <hidl/HidlSupport.h>
#include <functional>
#include <vector>
#include "hci_internals.h"
namespace android {
@ -32,20 +33,20 @@ using HciPacketReadyCallback = std::function<void(void)>;
class HciPacketizer {
public:
HciPacketizer(HciPacketReadyCallback packet_cb)
: packet_ready_cb_(packet_cb){};
void OnDataReady(int fd, HciPacketType packet_type);
void CbHciPacket(uint8_t* data, size_t length);
HciPacketizer() = default;
bool OnDataReady(HciPacketType packet_type, const std::vector<uint8_t>& data,
size_t offset);
const hidl_vec<uint8_t>& GetPacket() const;
protected:
enum State { HCI_PREAMBLE, HCI_PAYLOAD };
State state_{HCI_PREAMBLE};
uint8_t preamble_[HCI_PREAMBLE_SIZE_MAX];
private:
size_t fill_header(HciPacketType packet_type,
const std::vector<uint8_t>& data, size_t offset);
void fill_payload(const std::vector<uint8_t>& data, size_t offset);
enum State { HCI_HEADER, HCI_PAYLOAD };
State state_{HCI_HEADER};
hidl_vec<uint8_t> packet_;
std::vector<uint8_t> packet_buffer_;
size_t bytes_remaining_{0};
size_t bytes_read_{0};
HciPacketReadyCallback packet_ready_cb_;
};
} // namespace hci

Loading…
Cancel
Save