Merge "Initial Target-side VTS tests for Short Message Service(SMS) Radio Hal Apis"
diff --git a/bluetooth/1.0/default/Android.bp b/bluetooth/1.0/default/Android.bp
index fb20195..e04c2f4 100644
--- a/bluetooth/1.0/default/Android.bp
+++ b/bluetooth/1.0/default/Android.bp
@@ -56,6 +56,9 @@
name: "android.hardware.bluetooth-hci",
srcs: [
"hci_packetizer.cc",
+ "hci_protocol.cc",
+ "h4_protocol.cc",
+ "mct_protocol.cc",
],
export_include_dirs: ["."],
shared_libs: [
@@ -71,16 +74,21 @@
name: "bluetooth-vendor-interface-unit-tests",
srcs: [
"test/async_fd_watcher_unittest.cc",
+ "test/h4_protocol_unittest.cc",
+ "test/mct_protocol_unittest.cc",
],
local_include_dirs: [
"test",
],
shared_libs: [
"libbase",
+ "libhidlbase",
"liblog",
],
static_libs: [
"android.hardware.bluetooth-async",
+ "android.hardware.bluetooth-hci",
+ "libgmock",
],
}
diff --git a/bluetooth/1.0/default/bluetooth_hci.cc b/bluetooth/1.0/default/bluetooth_hci.cc
index 1d6e600..5a282bf 100644
--- a/bluetooth/1.0/default/bluetooth_hci.cc
+++ b/bluetooth/1.0/default/bluetooth_hci.cc
@@ -44,21 +44,14 @@
event_cb_->initializationComplete(
status ? Status::SUCCESS : Status::INITIALIZATION_ERROR);
},
- [this](HciPacketType type, const hidl_vec<uint8_t>& packet) {
- switch (type) {
- case HCI_PACKET_TYPE_EVENT:
- event_cb_->hciEventReceived(packet);
- break;
- case HCI_PACKET_TYPE_ACL_DATA:
- event_cb_->aclDataReceived(packet);
- break;
- case HCI_PACKET_TYPE_SCO_DATA:
- event_cb_->scoDataReceived(packet);
- break;
- default:
- ALOGE("%s Unexpected event type %d", __func__, type);
- break;
- }
+ [this](const hidl_vec<uint8_t>& packet) {
+ event_cb_->hciEventReceived(packet);
+ },
+ [this](const hidl_vec<uint8_t>& packet) {
+ event_cb_->aclDataReceived(packet);
+ },
+ [this](const hidl_vec<uint8_t>& packet) {
+ event_cb_->scoDataReceived(packet);
});
if (!rc) event_cb_->initializationComplete(Status::INITIALIZATION_ERROR);
return Void();
diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc
new file mode 100644
index 0000000..8f24b5e
--- /dev/null
+++ b/bluetooth/1.0/default/h4_protocol.cc
@@ -0,0 +1,71 @@
+//
+// Copyright 2017 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.
+//
+
+#include "h4_protocol.h"
+
+#define LOG_TAG "android.hardware.bluetooth-hci-h4"
+#include <android-base/logging.h>
+#include <assert.h>
+#include <fcntl.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+size_t H4Protocol::Send(uint8_t type, const uint8_t* data, size_t length) {
+ int rv = WriteSafely(uart_fd_, &type, sizeof(type));
+ if (rv == sizeof(type)) {
+ rv = WriteSafely(uart_fd_, data, length);
+ }
+ return rv;
+}
+
+void H4Protocol::OnPacketReady() {
+ switch (hci_packet_type_) {
+ case HCI_PACKET_TYPE_EVENT:
+ event_cb_(hci_packetizer_.GetPacket());
+ break;
+ case HCI_PACKET_TYPE_ACL_DATA:
+ acl_cb_(hci_packetizer_.GetPacket());
+ break;
+ case HCI_PACKET_TYPE_SCO_DATA:
+ sco_cb_(hci_packetizer_.GetPacket());
+ break;
+ default: {
+ bool bad_packet_type = true;
+ CHECK(!bad_packet_type);
+ }
+ }
+ // Get ready for the next type byte.
+ hci_packet_type_ = HCI_PACKET_TYPE_UNKNOWN;
+}
+
+void H4Protocol::OnDataReady(int fd) {
+ if (hci_packet_type_ == HCI_PACKET_TYPE_UNKNOWN) {
+ uint8_t buffer[1] = {0};
+ size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
+ CHECK(bytes_read == 1);
+ hci_packet_type_ = static_cast<HciPacketType>(buffer[0]);
+ } else {
+ hci_packetizer_.OnDataReady(fd, hci_packet_type_);
+ }
+}
+
+} // namespace hci
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/h4_protocol.h b/bluetooth/1.0/default/h4_protocol.h
new file mode 100644
index 0000000..0d0a1ca
--- /dev/null
+++ b/bluetooth/1.0/default/h4_protocol.h
@@ -0,0 +1,61 @@
+//
+// Copyright 2017 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.
+//
+
+#pragma once
+
+#include <hidl/HidlSupport.h>
+
+#include "async_fd_watcher.h"
+#include "bt_vendor_lib.h"
+#include "hci_internals.h"
+#include "hci_protocol.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+class H4Protocol : public HciProtocol {
+ public:
+ H4Protocol(int fd, PacketReadCallback event_cb, PacketReadCallback acl_cb,
+ PacketReadCallback sco_cb)
+ : uart_fd_(fd),
+ event_cb_(event_cb),
+ acl_cb_(acl_cb),
+ sco_cb_(sco_cb),
+ hci_packetizer_([this]() { OnPacketReady(); }) {}
+
+ size_t Send(uint8_t type, const uint8_t* data, size_t length);
+
+ void OnPacketReady();
+
+ void OnDataReady(int fd);
+
+ private:
+ int uart_fd_;
+
+ PacketReadCallback event_cb_;
+ PacketReadCallback acl_cb_;
+ PacketReadCallback sco_cb_;
+
+ HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
+ hci::HciPacketizer hci_packetizer_;
+};
+
+} // namespace hci
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/hci_packetizer.cc b/bluetooth/1.0/default/hci_packetizer.cc
index 1a50196..9549858 100644
--- a/bluetooth/1.0/default/hci_packetizer.cc
+++ b/bluetooth/1.0/default/hci_packetizer.cc
@@ -18,7 +18,6 @@
#define LOG_TAG "android.hardware.bluetooth.hci_packetizer"
#include <android-base/logging.h>
-#include <cutils/properties.h>
#include <utils/Log.h>
#include <dlfcn.h>
@@ -46,63 +45,40 @@
namespace bluetooth {
namespace hci {
-HciPacketType HciPacketizer::GetPacketType() const {
- return hci_packet_type_;
-}
+const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const { return packet_; }
-const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const {
- return hci_packet_;
-}
-
-void HciPacketizer::OnDataReady(int fd) {
- switch (hci_parser_state_) {
- case HCI_IDLE: {
- uint8_t buffer[1] = {0};
- size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
- CHECK(bytes_read == 1);
- hci_packet_type_ = static_cast<HciPacketType>(buffer[0]);
- CHECK(hci_packet_type_ >= HCI_PACKET_TYPE_ACL_DATA &&
- hci_packet_type_ <= HCI_PACKET_TYPE_EVENT)
- << "buffer[0] = " << static_cast<unsigned int>(buffer[0]);
- hci_parser_state_ = HCI_TYPE_READY;
- hci_packet_bytes_remaining_ = preamble_size_for_type[hci_packet_type_];
- hci_packet_bytes_read_ = 0;
- break;
- }
-
- case HCI_TYPE_READY: {
+void HciPacketizer::OnDataReady(int fd, HciPacketType packet_type) {
+ switch (state_) {
+ case HCI_PREAMBLE: {
size_t bytes_read = TEMP_FAILURE_RETRY(
- read(fd, hci_packet_preamble_ + hci_packet_bytes_read_,
- hci_packet_bytes_remaining_));
+ read(fd, preamble_ + bytes_read_,
+ preamble_size_for_type[packet_type] - bytes_read_));
CHECK(bytes_read > 0);
- hci_packet_bytes_remaining_ -= bytes_read;
- hci_packet_bytes_read_ += bytes_read;
- if (hci_packet_bytes_remaining_ == 0) {
+ bytes_read_ += bytes_read;
+ if (bytes_read_ == preamble_size_for_type[packet_type]) {
size_t packet_length =
- HciGetPacketLengthForType(hci_packet_type_, hci_packet_preamble_);
- hci_packet_.resize(preamble_size_for_type[hci_packet_type_] +
- packet_length);
- memcpy(hci_packet_.data(), hci_packet_preamble_,
- preamble_size_for_type[hci_packet_type_]);
- hci_packet_bytes_remaining_ = packet_length;
- hci_parser_state_ = HCI_PAYLOAD;
- hci_packet_bytes_read_ = 0;
+ 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;
}
case HCI_PAYLOAD: {
- size_t bytes_read = TEMP_FAILURE_RETRY(
- read(fd,
- hci_packet_.data() + preamble_size_for_type[hci_packet_type_] +
- hci_packet_bytes_read_,
- hci_packet_bytes_remaining_));
+ 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);
- hci_packet_bytes_remaining_ -= bytes_read;
- hci_packet_bytes_read_ += bytes_read;
- if (hci_packet_bytes_remaining_ == 0) {
- hci_packet_ready_cb_();
- hci_parser_state_ = HCI_IDLE;
+ bytes_remaining_ -= bytes_read;
+ bytes_read_ += bytes_read;
+ if (bytes_remaining_ == 0) {
+ packet_ready_cb_();
+ state_ = HCI_PREAMBLE;
+ bytes_read_ = 0;
}
break;
}
diff --git a/bluetooth/1.0/default/hci_packetizer.h b/bluetooth/1.0/default/hci_packetizer.h
index e9c01dc..90579bd 100644
--- a/bluetooth/1.0/default/hci_packetizer.h
+++ b/bluetooth/1.0/default/hci_packetizer.h
@@ -32,20 +32,19 @@
class HciPacketizer {
public:
- HciPacketizer(HciPacketReadyCallback packet_cb) : hci_packet_ready_cb_(packet_cb) {};
- void OnDataReady(int fd);
+ HciPacketizer(HciPacketReadyCallback packet_cb)
+ : packet_ready_cb_(packet_cb){};
+ void OnDataReady(int fd, HciPacketType packet_type);
const hidl_vec<uint8_t>& GetPacket() const;
- HciPacketType GetPacketType() const;
protected:
- enum HciParserState { HCI_IDLE, HCI_TYPE_READY, HCI_PAYLOAD };
- HciParserState hci_parser_state_{HCI_IDLE};
- HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
- uint8_t hci_packet_preamble_[HCI_PREAMBLE_SIZE_MAX];
- hidl_vec<uint8_t> hci_packet_;
- size_t hci_packet_bytes_remaining_;
- size_t hci_packet_bytes_read_;
- HciPacketReadyCallback hci_packet_ready_cb_;
+ enum State { HCI_PREAMBLE, HCI_PAYLOAD };
+ State state_{HCI_PREAMBLE};
+ uint8_t preamble_[HCI_PREAMBLE_SIZE_MAX];
+ hidl_vec<uint8_t> packet_;
+ size_t bytes_remaining_{0};
+ size_t bytes_read_{0};
+ HciPacketReadyCallback packet_ready_cb_;
};
} // namespace hci
diff --git a/bluetooth/1.0/default/hci_protocol.cc b/bluetooth/1.0/default/hci_protocol.cc
new file mode 100644
index 0000000..cd709b4
--- /dev/null
+++ b/bluetooth/1.0/default/hci_protocol.cc
@@ -0,0 +1,74 @@
+//
+// Copyright 2017 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.
+//
+
+#include "hci_protocol.h"
+
+#define LOG_TAG "android.hardware.bluetooth-hci-hci_protocol"
+#include <android-base/logging.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <utils/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};
+
+size_t HciGetPacketLengthForType(HciPacketType type, const 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]);
+}
+
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+size_t HciProtocol::WriteSafely(int fd, const uint8_t* data, size_t length) {
+ size_t transmitted_length = 0;
+ while (length > 0) {
+ ssize_t ret =
+ TEMP_FAILURE_RETRY(write(fd, data + transmitted_length, length));
+
+ if (ret == -1) {
+ if (errno == EAGAIN) continue;
+ ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+ break;
+
+ } else if (ret == 0) {
+ // Nothing written :(
+ ALOGE("%s zero bytes written - something went wrong...", __func__);
+ break;
+ }
+
+ transmitted_length += ret;
+ length -= ret;
+ }
+
+ return transmitted_length;
+}
+
+} // namespace hci
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/hci_protocol.h b/bluetooth/1.0/default/hci_protocol.h
new file mode 100644
index 0000000..6821107
--- /dev/null
+++ b/bluetooth/1.0/default/hci_protocol.h
@@ -0,0 +1,49 @@
+//
+// Copyright 2017 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.
+//
+
+#pragma once
+
+#include <hidl/HidlSupport.h>
+
+#include "bt_vendor_lib.h"
+#include "hci_internals.h"
+#include "hci_packetizer.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+using ::android::hardware::hidl_vec;
+using PacketReadCallback = std::function<void(const hidl_vec<uint8_t>&)>;
+
+// Implementation of HCI protocol bits common to different transports
+class HciProtocol {
+ public:
+ HciProtocol() = default;
+ virtual ~HciProtocol(){};
+
+ // Protocol-specific implementation of sending packets.
+ virtual size_t Send(uint8_t type, const uint8_t* data, size_t length) = 0;
+
+ protected:
+ static size_t WriteSafely(int fd, const uint8_t* data, size_t length);
+};
+
+} // namespace hci
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/mct_protocol.cc b/bluetooth/1.0/default/mct_protocol.cc
new file mode 100644
index 0000000..813cebd
--- /dev/null
+++ b/bluetooth/1.0/default/mct_protocol.cc
@@ -0,0 +1,71 @@
+//
+// Copyright 2017 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.
+//
+
+#include "mct_protocol.h"
+
+#include <assert.h>
+
+#define LOG_TAG "android.hardware.bluetooth-hci-mct"
+#include <android-base/logging.h>
+#include <utils/Log.h>
+
+#include <fcntl.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+MctProtocol::MctProtocol(int* fds, PacketReadCallback event_cb,
+ PacketReadCallback acl_cb)
+ : event_cb_(event_cb),
+ acl_cb_(acl_cb),
+ event_packetizer_([this]() { OnEventPacketReady(); }),
+ acl_packetizer_([this]() { OnAclDataPacketReady(); }) {
+ for (int i = 0; i < CH_MAX; i++) {
+ uart_fds_[i] = fds[i];
+ }
+}
+
+size_t MctProtocol::Send(uint8_t type, const uint8_t* data, size_t length) {
+ if (type == HCI_PACKET_TYPE_COMMAND)
+ return WriteSafely(uart_fds_[CH_CMD], data, length);
+ if (type == HCI_PACKET_TYPE_ACL_DATA)
+ return WriteSafely(uart_fds_[CH_ACL_OUT], data, length);
+ CHECK(type == HCI_PACKET_TYPE_COMMAND || type == HCI_PACKET_TYPE_ACL_DATA);
+ return 0;
+}
+
+void MctProtocol::OnEventPacketReady() {
+ event_cb_(event_packetizer_.GetPacket());
+}
+
+void MctProtocol::OnAclDataPacketReady() {
+ acl_cb_(acl_packetizer_.GetPacket());
+}
+
+void MctProtocol::OnEventDataReady(int fd) {
+ event_packetizer_.OnDataReady(fd, HCI_PACKET_TYPE_EVENT);
+}
+
+void MctProtocol::OnAclDataReady(int fd) {
+ acl_packetizer_.OnDataReady(fd, HCI_PACKET_TYPE_ACL_DATA);
+}
+
+} // namespace hci
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/mct_protocol.h b/bluetooth/1.0/default/mct_protocol.h
new file mode 100644
index 0000000..6991746
--- /dev/null
+++ b/bluetooth/1.0/default/mct_protocol.h
@@ -0,0 +1,56 @@
+//
+// Copyright 2017 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.
+//
+
+#pragma once
+
+#include <hidl/HidlSupport.h>
+
+#include "async_fd_watcher.h"
+#include "bt_vendor_lib.h"
+#include "hci_internals.h"
+#include "hci_protocol.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+class MctProtocol : public HciProtocol {
+ public:
+ MctProtocol(int* fds, PacketReadCallback event_cb, PacketReadCallback acl_cb);
+
+ size_t Send(uint8_t type, const uint8_t* data, size_t length);
+
+ void OnEventPacketReady();
+ void OnAclDataPacketReady();
+
+ void OnEventDataReady(int fd);
+ void OnAclDataReady(int fd);
+
+ private:
+ int uart_fds_[CH_MAX];
+
+ PacketReadCallback event_cb_;
+ PacketReadCallback acl_cb_;
+
+ hci::HciPacketizer event_packetizer_;
+ hci::HciPacketizer acl_packetizer_;
+};
+
+} // namespace hci
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/test/h4_protocol_unittest.cc b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
new file mode 100644
index 0000000..d53aaa9
--- /dev/null
+++ b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
@@ -0,0 +1,213 @@
+//
+// Copyright 2017 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 <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <mutex>
+#include <vector>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+using ::testing::Eq;
+using hci::H4Protocol;
+
+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 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.";
+
+MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") {
+ size_t length = strlen(payload) + preamble_length;
+ if (length != arg.size()) {
+ return false;
+ }
+
+ if (memcmp(preamble, arg.data(), preamble_length) != 0) {
+ return false;
+ }
+
+ return memcmp(payload, arg.data() + preamble_length,
+ length - preamble_length) == 0;
+};
+
+ACTION_P2(Notify, mutex, condition) {
+ ALOGD("%s", __func__);
+ std::unique_lock<std::mutex> lock(*mutex);
+ condition->notify_one();
+}
+
+class H4ProtocolTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ ALOGD("%s", __func__);
+
+ int sockfd[2];
+ socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
+ H4Protocol* h4_hci =
+ new H4Protocol(sockfd[0], event_cb_.AsStdFunction(),
+ acl_cb_.AsStdFunction(), sco_cb_.AsStdFunction());
+ fd_watcher_.WatchFdForNonBlockingReads(
+ sockfd[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
+ protocol_ = h4_hci;
+
+ fake_uart_ = sockfd[1];
+ }
+
+ void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
+
+ void SendAndReadUartOutbound(uint8_t type, char* data) {
+ ALOGD("%s sending", __func__);
+ int data_length = strlen(data);
+ protocol_->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(fake_uart_, &read_fds);
+ TEMP_FAILURE_RETRY(select(fake_uart_ + 1, &read_fds, NULL, NULL, NULL));
+
+ char byte;
+ TEMP_FAILURE_RETRY(read(fake_uart_, &byte, 1));
+
+ EXPECT_EQ(i == 0 ? type : data[i - 1], byte);
+ }
+
+ EXPECT_EQ(i, uart_length);
+ }
+
+ void WriteAndExpectInboundAclData(char* payload) {
+ // h4 type[1] + handle[2] + size[2]
+ char preamble[5] = {HCI_PACKET_TYPE_ACL_DATA, 19, 92, 0, 0};
+ int length = strlen(payload);
+ preamble[3] = length & 0xFF;
+ preamble[4] = (length >> 8) & 0xFF;
+
+ ALOGD("%s writing", __func__);
+ TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
+ TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
+
+ ALOGD("%s waiting", __func__);
+ std::mutex mutex;
+ std::condition_variable done;
+ EXPECT_CALL(acl_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
+ payload)))
+ .WillOnce(Notify(&mutex, &done));
+
+ // Fail if it takes longer than 100 ms.
+ auto timeout_time =
+ std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ done.wait_until(lock, timeout_time);
+ }
+ }
+
+ void WriteAndExpectInboundScoData(char* payload) {
+ // h4 type[1] + handle[2] + size[1]
+ char preamble[4] = {HCI_PACKET_TYPE_SCO_DATA, 20, 17, 0};
+ preamble[3] = strlen(payload) & 0xFF;
+
+ ALOGD("%s writing", __func__);
+ TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
+ TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
+
+ ALOGD("%s waiting", __func__);
+ std::mutex mutex;
+ std::condition_variable done;
+ EXPECT_CALL(sco_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
+ payload)))
+ .WillOnce(Notify(&mutex, &done));
+
+ // Fail if it takes longer than 100 ms.
+ auto timeout_time =
+ std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ done.wait_until(lock, timeout_time);
+ }
+ }
+
+ void WriteAndExpectInboundEvent(char* payload) {
+ // h4 type[1] + event_code[1] + size[1]
+ char preamble[3] = {HCI_PACKET_TYPE_EVENT, 9, 0};
+ preamble[2] = strlen(payload) & 0xFF;
+ ALOGD("%s writing", __func__);
+ TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
+ TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
+
+ ALOGD("%s waiting", __func__);
+ std::mutex mutex;
+ std::condition_variable done;
+ EXPECT_CALL(event_cb_, Call(HidlVecMatches(preamble + 1,
+ sizeof(preamble) - 1, payload)))
+ .WillOnce(Notify(&mutex, &done));
+
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ done.wait(lock);
+ }
+ }
+
+ testing::MockFunction<void(const hidl_vec<uint8_t>&)> event_cb_;
+ testing::MockFunction<void(const hidl_vec<uint8_t>&)> acl_cb_;
+ testing::MockFunction<void(const hidl_vec<uint8_t>&)> sco_cb_;
+ async::AsyncFdWatcher fd_watcher_;
+ H4Protocol* protocol_;
+ int fake_uart_;
+};
+
+// 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);
+}
+
+// Ensure we properly parse data coming from the UART
+TEST_F(H4ProtocolTest, TestReads) {
+ WriteAndExpectInboundAclData(acl_data);
+ WriteAndExpectInboundScoData(sco_data);
+ WriteAndExpectInboundEvent(event_data);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/test/mct_protocol_unittest.cc b/bluetooth/1.0/default/test/mct_protocol_unittest.cc
new file mode 100644
index 0000000..5751a5e
--- /dev/null
+++ b/bluetooth/1.0/default/test/mct_protocol_unittest.cc
@@ -0,0 +1,200 @@
+//
+// Copyright 2017 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 "mct_protocol.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <mutex>
+#include <vector>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+using ::testing::Eq;
+using hci::MctProtocol;
+
+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 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.";
+
+MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") {
+ size_t length = strlen(payload) + preamble_length;
+ if (length != arg.size()) {
+ return false;
+ }
+
+ if (memcmp(preamble, arg.data(), preamble_length) != 0) {
+ return false;
+ }
+
+ return memcmp(payload, arg.data() + preamble_length,
+ length - preamble_length) == 0;
+};
+
+ACTION_P2(Notify, mutex, condition) {
+ ALOGD("%s", __func__);
+ std::unique_lock<std::mutex> lock(*mutex);
+ condition->notify_one();
+}
+
+class MctProtocolTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ ALOGD("%s", __func__);
+
+ int mct_fds[CH_MAX];
+ MakeFakeUartFd(CH_CMD, mct_fds, fake_uart_);
+ MakeFakeUartFd(CH_EVT, mct_fds, fake_uart_);
+ MakeFakeUartFd(CH_ACL_IN, mct_fds, fake_uart_);
+ MakeFakeUartFd(CH_ACL_OUT, mct_fds, fake_uart_);
+
+ MctProtocol* mct_hci = new MctProtocol(mct_fds, event_cb_.AsStdFunction(),
+ acl_cb_.AsStdFunction());
+ fd_watcher_.WatchFdForNonBlockingReads(
+ mct_fds[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
+ fd_watcher_.WatchFdForNonBlockingReads(
+ mct_fds[CH_ACL_IN], [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+ protocol_ = mct_hci;
+ }
+
+ void MakeFakeUartFd(int index, int* host_side, int* controller_side) {
+ int sockfd[2];
+ socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
+ host_side[index] = sockfd[0];
+ controller_side[index] = sockfd[1];
+ }
+
+ void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
+
+ void SendAndReadUartOutbound(uint8_t type, char* data, int outbound_fd) {
+ ALOGD("%s sending", __func__);
+ int data_length = strlen(data);
+ protocol_->Send(type, (uint8_t*)data, data_length);
+
+ ALOGD("%s reading", __func__);
+ int i;
+ for (i = 0; i < data_length; i++) {
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ FD_SET(outbound_fd, &read_fds);
+ TEMP_FAILURE_RETRY(select(outbound_fd + 1, &read_fds, NULL, NULL, NULL));
+
+ char byte;
+ TEMP_FAILURE_RETRY(read(outbound_fd, &byte, 1));
+
+ EXPECT_EQ(data[i], byte);
+ }
+
+ EXPECT_EQ(i, data_length);
+ }
+
+ void WriteAndExpectInboundAclData(char* payload) {
+ // handle[2] + size[2]
+ char preamble[4] = {19, 92, 0, 0};
+ int length = strlen(payload);
+ preamble[2] = length & 0xFF;
+ preamble[3] = (length >> 8) & 0xFF;
+
+ ALOGD("%s writing", __func__);
+ TEMP_FAILURE_RETRY(
+ write(fake_uart_[CH_ACL_IN], preamble, sizeof(preamble)));
+ TEMP_FAILURE_RETRY(write(fake_uart_[CH_ACL_IN], payload, strlen(payload)));
+
+ ALOGD("%s waiting", __func__);
+ std::mutex mutex;
+ std::condition_variable done;
+ EXPECT_CALL(acl_cb_,
+ Call(HidlVecMatches(preamble, sizeof(preamble), payload)))
+ .WillOnce(Notify(&mutex, &done));
+
+ // Fail if it takes longer than 100 ms.
+ auto timeout_time =
+ std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ done.wait_until(lock, timeout_time);
+ }
+ }
+
+ void WriteAndExpectInboundEvent(char* payload) {
+ // event_code[1] + size[1]
+ char preamble[2] = {9, 0};
+ preamble[1] = strlen(payload) & 0xFF;
+
+ ALOGD("%s writing", __func__);
+ TEMP_FAILURE_RETRY(write(fake_uart_[CH_EVT], preamble, sizeof(preamble)));
+ TEMP_FAILURE_RETRY(write(fake_uart_[CH_EVT], payload, strlen(payload)));
+
+ ALOGD("%s waiting", __func__);
+ std::mutex mutex;
+ std::condition_variable done;
+ EXPECT_CALL(event_cb_,
+ Call(HidlVecMatches(preamble, sizeof(preamble), payload)))
+ .WillOnce(Notify(&mutex, &done));
+
+ // Fail if it takes longer than 100 ms.
+ auto timeout_time =
+ std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ done.wait_until(lock, timeout_time);
+ }
+ }
+
+ testing::MockFunction<void(const hidl_vec<uint8_t>&)> event_cb_;
+ testing::MockFunction<void(const hidl_vec<uint8_t>&)> acl_cb_;
+ async::AsyncFdWatcher fd_watcher_;
+ MctProtocol* protocol_;
+ int fake_uart_[CH_MAX];
+};
+
+// Test sending data sends correct data onto the UART
+TEST_F(MctProtocolTest, TestSends) {
+ SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1,
+ fake_uart_[CH_CMD]);
+ SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2,
+ fake_uart_[CH_ACL_OUT]);
+}
+
+// Ensure we properly parse data coming from the UART
+TEST_F(MctProtocolTest, TestReads) {
+ WriteAndExpectInboundAclData(acl_data);
+ WriteAndExpectInboundEvent(event_data);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index 2c55d1c..6d3b56f 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -27,6 +27,8 @@
#include <fcntl.h>
#include "bluetooth_address.h"
+#include "h4_protocol.h"
+#include "mct_protocol.h"
static const char* VENDOR_LIBRARY_NAME = "libbt-vendor.so";
static const char* VENDOR_LIBRARY_SYMBOL_NAME =
@@ -64,30 +66,6 @@
return packet;
}
-size_t write_safely(int fd, const uint8_t* data, size_t length) {
- size_t transmitted_length = 0;
- while (length > 0) {
- ssize_t ret =
- TEMP_FAILURE_RETRY(write(fd, data + transmitted_length, length));
-
- if (ret == -1) {
- if (errno == EAGAIN) continue;
- ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
- break;
-
- } else if (ret == 0) {
- // Nothing written :(
- ALOGE("%s zero bytes written - something went wrong...", __func__);
- break;
- }
-
- transmitted_length += ret;
- length -= ret;
- }
-
- return transmitted_length;
-}
-
bool internal_command_event_match(const hidl_vec<uint8_t>& packet) {
uint8_t event_code = packet[0];
if (event_code != HCI_COMMAND_COMPLETE_EVENT) {
@@ -185,10 +163,12 @@
bool VendorInterface::Initialize(
InitializeCompleteCallback initialize_complete_cb,
- PacketReadCallback packet_read_cb) {
+ PacketReadCallback event_cb, PacketReadCallback acl_cb,
+ PacketReadCallback sco_cb) {
assert(!g_vendor_interface);
g_vendor_interface = new VendorInterface();
- return g_vendor_interface->Open(initialize_complete_cb, packet_read_cb);
+ return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb,
+ sco_cb);
}
void VendorInterface::Shutdown() {
@@ -201,9 +181,10 @@
VendorInterface* VendorInterface::get() { return g_vendor_interface; }
bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
- PacketReadCallback packet_read_cb) {
+ PacketReadCallback event_cb,
+ PacketReadCallback acl_cb,
+ PacketReadCallback sco_cb) {
initialize_complete_cb_ = initialize_complete_cb;
- packet_read_cb_ = packet_read_cb;
// Initialize vendor interface
@@ -241,28 +222,41 @@
power_state = BT_VND_PWR_ON;
lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
- // Get the UART socket
+ // Get the UART socket(s)
int fd_list[CH_MAX] = {0};
int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);
- if (fd_count != 1) {
- ALOGE("%s fd count %d != 1; we can't handle this currently...", __func__,
- fd_count);
- return false;
+ for (int i = 0; i < fd_count; i++) {
+ if (fd_list[i] == INVALID_FD) {
+ ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]);
+ return false;
+ }
}
- uart_fd_ = fd_list[0];
- if (uart_fd_ == INVALID_FD) {
- ALOGE("%s unable to determine UART fd", __func__);
- return false;
+ event_cb_ = event_cb;
+ PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) {
+ HandleIncomingEvent(event);
+ };
+
+ if (fd_count == 1) {
+ hci::H4Protocol* h4_hci =
+ new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb);
+ fd_watcher_.WatchFdForNonBlockingReads(
+ fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
+ hci_ = h4_hci;
+ } else {
+ hci::MctProtocol* mct_hci =
+ new hci::MctProtocol(fd_list, intercept_events, acl_cb);
+ fd_watcher_.WatchFdForNonBlockingReads(
+ fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
+ if (fd_count >= CH_ACL_IN)
+ fd_watcher_.WatchFdForNonBlockingReads(
+ fd_list[CH_ACL_IN],
+ [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+ hci_ = mct_hci;
}
- ALOGI("%s UART fd: %d", __func__, uart_fd_);
-
- fd_watcher_.WatchFdForNonBlockingReads(uart_fd_,
- [this](int fd) { hci_packetizer_.OnDataReady(fd); });
-
// Initially, the power management is off.
lpm_wake_deasserted = true;
@@ -276,12 +270,16 @@
void VendorInterface::Close() {
fd_watcher_.StopWatchingFileDescriptors();
+ if (hci_ != nullptr) {
+ delete hci_;
+ hci_ = nullptr;
+ }
+
if (lib_interface_ != nullptr) {
bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE;
lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr);
- uart_fd_ = INVALID_FD;
int power_state = BT_VND_PWR_OFF;
lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
}
@@ -298,8 +296,6 @@
}
size_t VendorInterface::Send(uint8_t type, const uint8_t* data, size_t length) {
- if (uart_fd_ == INVALID_FD) return 0;
-
recent_activity_flag = true;
if (lpm_wake_deasserted == true) {
@@ -313,11 +309,7 @@
ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
}
- int rv = write_safely(uart_fd_, &type, sizeof(type));
- if (rv == sizeof(type))
- rv = write_safely(uart_fd_, data, length);
-
- return rv;
+ return hci_->Send(type, data, length);
}
void VendorInterface::OnFirmwareConfigured(uint8_t result) {
@@ -357,26 +349,18 @@
recent_activity_flag = false;
}
-void VendorInterface::OnPacketReady() {
- VendorInterface::get()->HandleIncomingPacket();
-}
+void VendorInterface::HandleIncomingEvent(const hidl_vec<uint8_t>& hci_packet) {
+ if (internal_command.cb != nullptr &&
+ internal_command_event_match(hci_packet)) {
+ HC_BT_HDR* bt_hdr = WrapPacketAndCopy(HCI_PACKET_TYPE_EVENT, hci_packet);
-void VendorInterface::HandleIncomingPacket() {
- HciPacketType hci_packet_type = hci_packetizer_.GetPacketType();
- hidl_vec<uint8_t> hci_packet = hci_packetizer_.GetPacket();
- if (internal_command.cb != nullptr &&
- hci_packet_type == HCI_PACKET_TYPE_EVENT &&
- internal_command_event_match(hci_packet)) {
- HC_BT_HDR* bt_hdr =
- WrapPacketAndCopy(HCI_PACKET_TYPE_EVENT, hci_packet);
-
- // The callbacks can send new commands, so don't zero after calling.
- tINT_CMD_CBACK saved_cb = internal_command.cb;
- internal_command.cb = nullptr;
- saved_cb(bt_hdr);
- } else {
- packet_read_cb_(hci_packet_type, hci_packet);
- }
+ // The callbacks can send new commands, so don't zero after calling.
+ tINT_CMD_CBACK saved_cb = internal_command.cb;
+ internal_command.cb = nullptr;
+ saved_cb(bt_hdr);
+ } else {
+ event_cb_(hci_packet);
+ }
}
} // namespace implementation
diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h
index 8115640..a401ee6 100644
--- a/bluetooth/1.0/default/vendor_interface.h
+++ b/bluetooth/1.0/default/vendor_interface.h
@@ -20,7 +20,7 @@
#include "async_fd_watcher.h"
#include "bt_vendor_lib.h"
-#include "hci_packetizer.h"
+#include "hci_protocol.h"
namespace android {
namespace hardware {
@@ -30,15 +30,15 @@
using ::android::hardware::hidl_vec;
using InitializeCompleteCallback = std::function<void(bool success)>;
-using PacketReadCallback =
- std::function<void(HciPacketType, const hidl_vec<uint8_t> &)>;
+using PacketReadCallback = std::function<void(const hidl_vec<uint8_t>&)>;
class FirmwareStartupTimer;
class VendorInterface {
public:
static bool Initialize(InitializeCompleteCallback initialize_complete_cb,
- PacketReadCallback packet_read_cb);
+ PacketReadCallback event_cb, PacketReadCallback acl_cb,
+ PacketReadCallback sco_cb);
static void Shutdown();
static VendorInterface *get();
@@ -46,27 +46,25 @@
void OnFirmwareConfigured(uint8_t result);
- static void OnPacketReady();
-
private:
virtual ~VendorInterface() = default;
bool Open(InitializeCompleteCallback initialize_complete_cb,
- PacketReadCallback packet_read_cb);
+ PacketReadCallback event_cb, PacketReadCallback acl_cb,
+ PacketReadCallback sco_cb);
void Close();
void OnTimeout();
- void HandleIncomingPacket();
+ void HandleIncomingEvent(const hidl_vec<uint8_t>& hci_packet);
void *lib_handle_;
bt_vendor_interface_t *lib_interface_;
async::AsyncFdWatcher fd_watcher_;
- int uart_fd_;
- PacketReadCallback packet_read_cb_;
InitializeCompleteCallback initialize_complete_cb_;
+ hci::HciProtocol* hci_;
- hci::HciPacketizer hci_packetizer_ {VendorInterface::OnPacketReady};
+ PacketReadCallback event_cb_;
FirmwareStartupTimer *firmware_startup_timer_;
};
diff --git a/tests/Android.bp b/tests/Android.bp
index 41043d9..9bb4bf5 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -15,6 +15,7 @@
"memory/1.0",
"memory/1.0/default",
"msgq/1.0",
+ "msgq/1.0/default",
"pointer/1.0",
"pointer/1.0/default",
"pointer/1.0/default/lib",
diff --git a/tests/msgq/1.0/default/Android.bp b/tests/msgq/1.0/default/Android.bp
new file mode 100644
index 0000000..b53fcd3
--- /dev/null
+++ b/tests/msgq/1.0/default/Android.bp
@@ -0,0 +1,19 @@
+cc_library_shared {
+ name: "android.hardware.tests.msgq@1.0-impl",
+ relative_install_path: "hw",
+ proprietary: true,
+ srcs: [
+ "TestMsgQ.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libfmq",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "android.hardware.tests.msgq@1.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/tests/msgq/1.0/default/TestMsgQ.cpp b/tests/msgq/1.0/default/TestMsgQ.cpp
new file mode 100644
index 0000000..7cc4f5b
--- /dev/null
+++ b/tests/msgq/1.0/default/TestMsgQ.cpp
@@ -0,0 +1,135 @@
+#include "TestMsgQ.h"
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace msgq {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::tests::msgq::V1_0::ITestMsgQ follow.
+Return<void> TestMsgQ::configureFmqSyncReadWrite(configureFmqSyncReadWrite_cb _hidl_cb) {
+ static constexpr size_t kNumElementsInQueue = 1024;
+ mFmqSynchronized.reset(new (std::nothrow) MessageQueueSync(
+ kNumElementsInQueue, true /* configureEventFlagWord */));
+ if ((mFmqSynchronized == nullptr) || (mFmqSynchronized->isValid() == false)) {
+ _hidl_cb(false /* ret */, MessageQueueSync::Descriptor());
+ } else {
+ /*
+ * Initialize the EventFlag word with bit FMQ_NOT_FULL.
+ */
+ auto evFlagWordPtr = mFmqSynchronized->getEventFlagWord();
+ if (evFlagWordPtr != nullptr) {
+ std::atomic_init(evFlagWordPtr,
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL));
+ }
+ _hidl_cb(true /* ret */, *mFmqSynchronized->getDesc());
+ }
+ return Void();
+}
+
+Return<void> TestMsgQ::getFmqUnsyncWrite(bool configureFmq, getFmqUnsyncWrite_cb _hidl_cb) {
+ if (configureFmq) {
+ static constexpr size_t kNumElementsInQueue = 1024;
+ mFmqUnsynchronized.reset(new (std::nothrow) MessageQueueUnsync(kNumElementsInQueue));
+ }
+ if ((mFmqUnsynchronized == nullptr) ||
+ (mFmqUnsynchronized->isValid() == false)) {
+ _hidl_cb(false /* ret */, MessageQueueUnsync::Descriptor());
+ } else {
+ _hidl_cb(true /* ret */, *mFmqUnsynchronized->getDesc());
+ }
+ return Void();
+}
+
+Return<bool> TestMsgQ::requestWriteFmqSync(int32_t count) {
+ std::vector<uint16_t> data(count);
+ for (int i = 0; i < count; i++) {
+ data[i] = i;
+ }
+ bool result = mFmqSynchronized->write(&data[0], count);
+ return result;
+}
+
+Return<bool> TestMsgQ::requestReadFmqSync(int32_t count) {
+ std::vector<uint16_t> data(count);
+ bool result = mFmqSynchronized->read(&data[0], count)
+ && verifyData(&data[0], count);
+ return result;
+}
+
+Return<bool> TestMsgQ::requestWriteFmqUnsync(int32_t count) {
+ std::vector<uint16_t> data(count);
+ for (int i = 0; i < count; i++) {
+ data[i] = i;
+ }
+ bool result = mFmqUnsynchronized->write(&data[0], count);
+ return result;
+}
+
+Return<bool> TestMsgQ::requestReadFmqUnsync(int32_t count) {
+ std::vector<uint16_t> data(count);
+ bool result =
+ mFmqUnsynchronized->read(&data[0], count) && verifyData(&data[0], count);
+ return result;
+}
+
+Return<void> TestMsgQ::requestBlockingRead(int32_t count) {
+ std::vector<uint16_t> data(count);
+ bool result = mFmqSynchronized->readBlocking(
+ &data[0],
+ count,
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+ 5000000000 /* timeOutNanos */);
+
+ if (result == false) {
+ ALOGE("Blocking read fails");
+ }
+ return Void();
+}
+
+Return<void> TestMsgQ::requestBlockingReadDefaultEventFlagBits(int32_t count) {
+ std::vector<uint16_t> data(count);
+ bool result = mFmqSynchronized->readBlocking(
+ &data[0],
+ count);
+
+ if (result == false) {
+ ALOGE("Blocking read fails");
+ }
+
+ return Void();
+}
+
+Return<void> TestMsgQ::requestBlockingReadRepeat(int32_t count, int32_t numIter) {
+ std::vector<uint16_t> data(count);
+ for (int i = 0; i < numIter; i++) {
+ bool result = mFmqSynchronized->readBlocking(
+ &data[0],
+ count,
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+ 5000000000 /* timeOutNanos */);
+
+ if (result == false) {
+ ALOGE("Blocking read fails");
+ break;
+ }
+ }
+ return Void();
+}
+
+
+// Methods from ::android::hidl::base::V1_0::IBase follow.
+
+ITestMsgQ* HIDL_FETCH_ITestMsgQ(const char* /* name */) {
+ return new TestMsgQ();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace msgq
+} // namespace tests
+} // namespace hardware
+} // namespace android
diff --git a/tests/msgq/1.0/default/TestMsgQ.h b/tests/msgq/1.0/default/TestMsgQ.h
new file mode 100644
index 0000000..760d931
--- /dev/null
+++ b/tests/msgq/1.0/default/TestMsgQ.h
@@ -0,0 +1,77 @@
+#ifndef ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
+#define ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
+
+#include <android/hardware/tests/msgq/1.0/ITestMsgQ.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <fmq/MessageQueue.h>
+#include <fmq/EventFlag.h>
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace msgq {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tests::msgq::V1_0::ITestMsgQ;
+using ::android::hidl::base::V1_0::DebugInfo;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::kUnsynchronizedWrite;
+using android::hardware::MQDescriptorSync;
+using android::hardware::MQDescriptorUnsync;
+
+using android::hardware::MessageQueue;
+
+struct TestMsgQ : public ITestMsgQ {
+ typedef MessageQueue<uint16_t, kSynchronizedReadWrite> MessageQueueSync;
+ typedef MessageQueue<uint16_t, kUnsynchronizedWrite> MessageQueueUnsync;
+
+ TestMsgQ() : mFmqSynchronized(nullptr), mFmqUnsynchronized(nullptr) {}
+
+ // Methods from ::android::hardware::tests::msgq::V1_0::ITestMsgQ follow.
+ Return<void> configureFmqSyncReadWrite(configureFmqSyncReadWrite_cb _hidl_cb) override;
+ Return<void> getFmqUnsyncWrite(bool configureFmq, getFmqUnsyncWrite_cb _hidl_cb) override;
+ Return<bool> requestWriteFmqSync(int32_t count) override;
+ Return<bool> requestReadFmqSync(int32_t count) override;
+ Return<bool> requestWriteFmqUnsync(int32_t count) override;
+ Return<bool> requestReadFmqUnsync(int32_t count) override;
+ Return<void> requestBlockingRead(int32_t count) override;
+ Return<void> requestBlockingReadDefaultEventFlagBits(int32_t count) override;
+ Return<void> requestBlockingReadRepeat(int32_t count, int32_t numIter) override;
+
+ // Methods from ::android::hidl::base::V1_0::IBase follow.
+private:
+ std::unique_ptr<MessageQueueSync> mFmqSynchronized;
+ std::unique_ptr<MessageQueueUnsync> mFmqUnsynchronized;
+
+ /*
+ * Utility function to verify data read from the fast message queue.
+ */
+ bool verifyData(uint16_t* data, int count) {
+ for (int i = 0; i < count; i++) {
+ if (data[i] != i) return false;
+ }
+ return true;
+ }
+};
+
+extern "C" ITestMsgQ* HIDL_FETCH_ITestMsgQ(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace msgq
+} // namespace tests
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
diff --git a/wifi/1.0/default/hidl_struct_util.cpp b/wifi/1.0/default/hidl_struct_util.cpp
index 485ae7e..5917efc 100644
--- a/wifi/1.0/default/hidl_struct_util.cpp
+++ b/wifi/1.0/default/hidl_struct_util.cpp
@@ -354,7 +354,10 @@
hidl_scan_params.buckets[bucket_idx];
legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
legacy_scan_params->buckets[bucket_idx];
- legacy_bucket_spec.bucket = bucket_idx;
+ if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
+ return false;
+ }
+ legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
legacy_bucket_spec.band =
convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
diff --git a/wifi/1.0/default/wifi.cpp b/wifi/1.0/default/wifi.cpp
index 3d482b4..b48844e 100644
--- a/wifi/1.0/default/wifi.cpp
+++ b/wifi/1.0/default/wifi.cpp
@@ -115,6 +115,7 @@
}
}
}
+ LOG(INFO) << "Wifi HAL started";
return wifi_status;
}
@@ -139,6 +140,13 @@
}
}
}
+ // Clear the chip object and its child objects since the HAL is now
+ // stopped.
+ if (chip_.get()) {
+ chip_->invalidate();
+ chip_.clear();
+ }
+ LOG(INFO) << "Wifi HAL stopped";
return wifi_status;
}
@@ -172,13 +180,7 @@
WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController() {
run_state_ = RunState::STOPPING;
- const auto on_complete_callback_ = [&]() {
- if (chip_.get()) {
- chip_->invalidate();
- }
- chip_.clear();
- run_state_ = RunState::STOPPED;
- };
+ const auto on_complete_callback_ = [&]() { run_state_ = RunState::STOPPED; };
legacy_hal::wifi_error legacy_status =
legacy_hal_->stop(on_complete_callback_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
diff --git a/wifi/1.0/types.hal b/wifi/1.0/types.hal
index 83e6660..d90d5be 100644
--- a/wifi/1.0/types.hal
+++ b/wifi/1.0/types.hal
@@ -320,6 +320,11 @@
*/
struct StaBackgroundScanBucketParameters {
/**
+ * Bucket index. This index is used to report results in
+ * |StaScanData.bucketsScanned|.
+ */
+ uint32_t bucketIdx;
+ /**
* Bands to scan or |BAND_UNSPECIFIED| if frequencies list must be used
* instead.
*/
diff --git a/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal
index dd1d1c4..2223022 100644
--- a/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal
+++ b/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal
@@ -278,8 +278,10 @@
* reject.
* @param statusCode 802.11 code to indicate the reject reason.
* Refer to section 8.4.1.9 of IEEE 802.11 spec.
+ * @param timedOut Whether failure is due to timeout rather
+ * than explicit rejection response from the AP.
*/
- oneway onAssociationRejected(Bssid bssid, uint32_t statusCode);
+ oneway onAssociationRejected(Bssid bssid, uint32_t statusCode, bool timedOut);
/**
* Used to indicate the timeout of authentication to an AP.
diff --git a/wifi/supplicant/1.0/ISupplicantStaNetwork.hal b/wifi/supplicant/1.0/ISupplicantStaNetwork.hal
index 37e8d3f..7d5159a 100644
--- a/wifi/supplicant/1.0/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.0/ISupplicantStaNetwork.hal
@@ -277,6 +277,20 @@
setPskPassphrase(string psk) generates (SupplicantStatus status);
/**
+ * Set raw psk for WPA_PSK network.
+ *
+ * @param psk value to set as specified in IEEE 802.11i-2004 standard.
+ * This is the calculated using 'wpa_passphrase <ssid> [passphrase]'
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setPsk(uint8_t[32] psk) generates (SupplicantStatus status);
+
+ /**
* Set WEP key for WEP network.
*
* @param keyIdx Index of wep key to set.
@@ -662,6 +676,8 @@
/**
* Get passphrase for WPA_PSK network.
+ * Must return a failure if network has no passphrase set (use |getPsk| if
+ * network was configured with raw psk instead).
*
* @return status Status of the operation.
* Possible status codes:
@@ -672,6 +688,19 @@
getPskPassphrase() generates (SupplicantStatus status, string psk);
/**
+ * Get raw psk for WPA_PSK network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ * @param psk value set.
+ */
+ getPsk() generates (SupplicantStatus status, uint8_t[32] psk);
+
+ /**
* Get WEP key for WEP network.
*
* @param keyIdx Index of wep key to be fetched.