From 13b4d3150c475ccb6dcd9ae1ad5feab7635d3d08 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Tue, 5 Nov 2019 12:27:29 +0100 Subject: [PATCH] bluetooth: V1.1 Add ISO Test: run rootcanal, verify 1.1 HAL can be used Bug: 144413056 Change-Id: Ic5b33602e1e4ba8e6d16623b9f8c46f674fc476c --- bluetooth/1.0/default/bluetooth_hci.cc | 3 + bluetooth/1.0/default/h4_protocol.cc | 3 + bluetooth/1.0/default/h4_protocol.h | 4 +- bluetooth/1.0/default/hci_internals.h | 3 +- .../1.0/default/test/h4_protocol_unittest.cc | 38 +- bluetooth/1.0/default/vendor_interface.cc | 9 +- bluetooth/1.0/default/vendor_interface.h | 4 +- .../VtsHalBluetoothV1_0TargetTest.cpp | 54 +- bluetooth/1.1/Android.bp | 18 + bluetooth/1.1/IBluetoothHci.hal | 44 + bluetooth/1.1/IBluetoothHciCallbacks.hal | 31 + bluetooth/1.1/default/Android.bp | 42 + bluetooth/1.1/default/OWNERS | 3 + .../android.hardware.bluetooth@1.1-service.rc | 9 + bluetooth/1.1/default/bluetooth_hci.cc | 197 +++++ bluetooth/1.1/default/bluetooth_hci.h | 63 ++ bluetooth/1.1/default/service.cpp | 43 + bluetooth/1.1/vts/OWNERS | 6 + bluetooth/1.1/vts/functional/Android.bp | 27 + .../VtsHalBluetoothV1_1TargetTest.cpp | 760 ++++++++++++++++++ .../compatibility_matrix.current.xml | 2 +- current.txt | 4 +- 22 files changed, 1317 insertions(+), 50 deletions(-) create mode 100644 bluetooth/1.1/Android.bp create mode 100644 bluetooth/1.1/IBluetoothHci.hal create mode 100644 bluetooth/1.1/IBluetoothHciCallbacks.hal create mode 100644 bluetooth/1.1/default/Android.bp create mode 100644 bluetooth/1.1/default/OWNERS create mode 100644 bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc create mode 100644 bluetooth/1.1/default/bluetooth_hci.cc create mode 100644 bluetooth/1.1/default/bluetooth_hci.h create mode 100644 bluetooth/1.1/default/service.cpp create mode 100644 bluetooth/1.1/vts/OWNERS create mode 100644 bluetooth/1.1/vts/functional/Android.bp create mode 100644 bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp diff --git a/bluetooth/1.0/default/bluetooth_hci.cc b/bluetooth/1.0/default/bluetooth_hci.cc index e14e3d7042..a2211f4e83 100644 --- a/bluetooth/1.0/default/bluetooth_hci.cc +++ b/bluetooth/1.0/default/bluetooth_hci.cc @@ -89,6 +89,9 @@ Return BluetoothHci::initialize( if (!hidl_status.isOk()) { ALOGE("VendorInterface -> Unable to call scoDataReceived()"); } + }, + [cb](const hidl_vec&) { + ALOGE("VendorInterface -> No callback for ISO packets in HAL V1_0"); }); if (!rc) { auto hidl_status = cb->initializationComplete(Status::INITIALIZATION_ERROR); diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc index 98e3273f31..8c24f76452 100644 --- a/bluetooth/1.0/default/h4_protocol.cc +++ b/bluetooth/1.0/default/h4_protocol.cc @@ -58,6 +58,9 @@ void H4Protocol::OnPacketReady() { case HCI_PACKET_TYPE_SCO_DATA: sco_cb_(hci_packetizer_.GetPacket()); break; + case HCI_PACKET_TYPE_ISO_DATA: + iso_cb_(hci_packetizer_.GetPacket()); + break; default: LOG_ALWAYS_FATAL("%s: Unimplemented packet type %d", __func__, static_cast(hci_packet_type_)); diff --git a/bluetooth/1.0/default/h4_protocol.h b/bluetooth/1.0/default/h4_protocol.h index 0d0a1caf19..0c82fd6aa5 100644 --- a/bluetooth/1.0/default/h4_protocol.h +++ b/bluetooth/1.0/default/h4_protocol.h @@ -31,11 +31,12 @@ namespace hci { class H4Protocol : public HciProtocol { public: H4Protocol(int fd, PacketReadCallback event_cb, PacketReadCallback acl_cb, - PacketReadCallback sco_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(); }) {} size_t Send(uint8_t type, const uint8_t* data, size_t length); @@ -50,6 +51,7 @@ class H4Protocol : public HciProtocol { PacketReadCallback event_cb_; PacketReadCallback acl_cb_; PacketReadCallback sco_cb_; + PacketReadCallback iso_cb_; HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN}; hci::HciPacketizer hci_packetizer_; diff --git a/bluetooth/1.0/default/hci_internals.h b/bluetooth/1.0/default/hci_internals.h index 1e1f3001c0..24e944fdec 100644 --- a/bluetooth/1.0/default/hci_internals.h +++ b/bluetooth/1.0/default/hci_internals.h @@ -24,7 +24,8 @@ enum HciPacketType { HCI_PACKET_TYPE_COMMAND = 1, HCI_PACKET_TYPE_ACL_DATA = 2, HCI_PACKET_TYPE_SCO_DATA = 3, - HCI_PACKET_TYPE_EVENT = 4 + HCI_PACKET_TYPE_EVENT = 4, + HCI_PACKET_TYPE_ISO_DATA = 5, }; // 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1) diff --git a/bluetooth/1.0/default/test/h4_protocol_unittest.cc b/bluetooth/1.0/default/test/h4_protocol_unittest.cc index ba56c0d6f3..283243dd36 100644 --- a/bluetooth/1.0/default/test/h4_protocol_unittest.cc +++ b/bluetooth/1.0/default/test/h4_protocol_unittest.cc @@ -42,11 +42,15 @@ 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 ..."; MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") { size_t length = strlen(payload) + preamble_length; @@ -75,9 +79,9 @@ class H4ProtocolTest : public ::testing::Test { 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()); + H4Protocol* h4_hci = new H4Protocol( + sockfd[0], event_cb_.AsStdFunction(), acl_cb_.AsStdFunction(), + sco_cb_.AsStdFunction(), iso_cb_.AsStdFunction()); fd_watcher_.WatchFdForNonBlockingReads( sockfd[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); }); protocol_ = h4_hci; @@ -184,9 +188,35 @@ class H4ProtocolTest : public ::testing::Test { } } + void WriteAndExpectInboundIsoData(char* payload) { + // h4 type[1] + handle[2] + size[1] + char preamble[4] = {HCI_PACKET_TYPE_ISO_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(iso_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 lock(mutex); + done.wait_until(lock, timeout_time); + } + } + testing::MockFunction&)> event_cb_; testing::MockFunction&)> acl_cb_; testing::MockFunction&)> sco_cb_; + testing::MockFunction&)> iso_cb_; async::AsyncFdWatcher fd_watcher_; H4Protocol* protocol_; int fake_uart_; @@ -197,6 +227,7 @@ 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 @@ -204,6 +235,7 @@ TEST_F(H4ProtocolTest, TestReads) { WriteAndExpectInboundAclData(acl_data); WriteAndExpectInboundScoData(sco_data); WriteAndExpectInboundEvent(event_data); + WriteAndExpectInboundIsoData(iso_data); } } // namespace implementation diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc index d56e344e74..d809313db6 100644 --- a/bluetooth/1.0/default/vendor_interface.cc +++ b/bluetooth/1.0/default/vendor_interface.cc @@ -162,14 +162,14 @@ class FirmwareStartupTimer { bool VendorInterface::Initialize( InitializeCompleteCallback initialize_complete_cb, PacketReadCallback event_cb, PacketReadCallback acl_cb, - PacketReadCallback sco_cb) { + PacketReadCallback sco_cb, PacketReadCallback iso_cb) { if (g_vendor_interface) { ALOGE("%s: No previous Shutdown()?", __func__); return false; } g_vendor_interface = new VendorInterface(); return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb, - sco_cb); + sco_cb, iso_cb); } void VendorInterface::Shutdown() { @@ -185,7 +185,8 @@ VendorInterface* VendorInterface::get() { return g_vendor_interface; } bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb, PacketReadCallback event_cb, PacketReadCallback acl_cb, - PacketReadCallback sco_cb) { + PacketReadCallback sco_cb, + PacketReadCallback iso_cb) { initialize_complete_cb_ = initialize_complete_cb; // Initialize vendor interface @@ -248,7 +249,7 @@ bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb, if (fd_count == 1) { hci::H4Protocol* h4_hci = - new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb); + new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb, iso_cb); fd_watcher_.WatchFdForNonBlockingReads( fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); }); hci_ = h4_hci; diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h index 1d69040d90..040f31a221 100644 --- a/bluetooth/1.0/default/vendor_interface.h +++ b/bluetooth/1.0/default/vendor_interface.h @@ -38,7 +38,7 @@ class VendorInterface { public: static bool Initialize(InitializeCompleteCallback initialize_complete_cb, PacketReadCallback event_cb, PacketReadCallback acl_cb, - PacketReadCallback sco_cb); + PacketReadCallback sco_cb, PacketReadCallback iso_cb); static void Shutdown(); static VendorInterface* get(); @@ -51,7 +51,7 @@ class VendorInterface { bool Open(InitializeCompleteCallback initialize_complete_cb, PacketReadCallback event_cb, PacketReadCallback acl_cb, - PacketReadCallback sco_cb); + PacketReadCallback sco_cb, PacketReadCallback iso_cb); void Close(); void OnTimeout(); diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp index beb9a3eaff..ef02eff67c 100644 --- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp +++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp @@ -24,8 +24,9 @@ #include #include -#include -#include +#include +#include +#include #include #include @@ -137,30 +138,12 @@ class ThroughputLogger { std::chrono::steady_clock::time_point start_time_; }; -// Test environment for Bluetooth HIDL HAL. -class BluetoothHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static BluetoothHidlEnvironment* Instance() { - static BluetoothHidlEnvironment* instance = new BluetoothHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { - registerTestService(); - } - - private: - BluetoothHidlEnvironment() {} -}; - // The main test class for Bluetooth HIDL HAL. -class BluetoothHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class BluetoothHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { // currently test passthrough mode only - bluetooth = - ::testing::VtsHalHidlTargetTestBase::getService(); + bluetooth = IBluetoothHci::getService(GetParam()); ASSERT_NE(bluetooth, nullptr); ALOGI("%s: getService() for bluetooth is %s", __func__, bluetooth->isRemote() ? "remote" : "local"); @@ -617,10 +600,10 @@ void BluetoothHidlTest::enterLoopbackMode(std::vector& sco_handles, } // Empty test: Initialize()/Close() are called in SetUp()/TearDown(). -TEST_F(BluetoothHidlTest, InitializeAndClose) {} +TEST_P(BluetoothHidlTest, InitializeAndClose) {} // Send an HCI Reset with sendHciCommand and wait for a command complete event. -TEST_F(BluetoothHidlTest, HciReset) { +TEST_P(BluetoothHidlTest, HciReset) { hidl_vec cmd = COMMAND_HCI_RESET; bluetooth->sendHciCommand(cmd); @@ -628,7 +611,7 @@ TEST_F(BluetoothHidlTest, HciReset) { } // Read and check the HCI version of the controller. -TEST_F(BluetoothHidlTest, HciVersionTest) { +TEST_P(BluetoothHidlTest, HciVersionTest) { hidl_vec cmd = COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION; bluetooth->sendHciCommand(cmd); @@ -649,7 +632,7 @@ TEST_F(BluetoothHidlTest, HciVersionTest) { } // Send an unknown HCI command and wait for the error message. -TEST_F(BluetoothHidlTest, HciUnknownCommand) { +TEST_P(BluetoothHidlTest, HciUnknownCommand) { hidl_vec cmd = COMMAND_HCI_SHOULD_BE_UNKNOWN; bluetooth->sendHciCommand(cmd); @@ -676,14 +659,14 @@ TEST_F(BluetoothHidlTest, HciUnknownCommand) { } // Enter loopback mode, but don't send any packets. -TEST_F(BluetoothHidlTest, WriteLoopbackMode) { +TEST_P(BluetoothHidlTest, WriteLoopbackMode) { std::vector sco_connection_handles; std::vector acl_connection_handles; enterLoopbackMode(sco_connection_handles, acl_connection_handles); } // Enter loopback mode and send single packets. -TEST_F(BluetoothHidlTest, LoopbackModeSinglePackets) { +TEST_P(BluetoothHidlTest, LoopbackModeSinglePackets) { setBufferSizes(); std::vector sco_connection_handles; @@ -720,7 +703,7 @@ TEST_F(BluetoothHidlTest, LoopbackModeSinglePackets) { } // Enter loopback mode and send packets for bandwidth measurements. -TEST_F(BluetoothHidlTest, LoopbackModeBandwidth) { +TEST_P(BluetoothHidlTest, LoopbackModeBandwidth) { setBufferSizes(); std::vector sco_connection_handles; @@ -758,11 +741,8 @@ TEST_F(BluetoothHidlTest, LoopbackModeBandwidth) { } } -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(BluetoothHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - BluetoothHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; -} +INSTANTIATE_TEST_SUITE_P( + PerInstance, BluetoothHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IBluetoothHci::descriptor)), + android::hardware::PrintInstanceNameToString); diff --git a/bluetooth/1.1/Android.bp b/bluetooth/1.1/Android.bp new file mode 100644 index 0000000000..4204aed7dc --- /dev/null +++ b/bluetooth/1.1/Android.bp @@ -0,0 +1,18 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.bluetooth@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IBluetoothHci.hal", + "IBluetoothHciCallbacks.hal", + ], + interfaces: [ + "android.hardware.bluetooth@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/bluetooth/1.1/IBluetoothHci.hal b/bluetooth/1.1/IBluetoothHci.hal new file mode 100644 index 0000000000..0f69c6eadd --- /dev/null +++ b/bluetooth/1.1/IBluetoothHci.hal @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 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. + */ + +package android.hardware.bluetooth@1.1; + +import @1.0::HciPacket; +import @1.0::IBluetoothHci; +import IBluetoothHciCallbacks; + +/** + * The Host Controller Interface (HCI) is the layer defined by the Bluetooth + * specification between the software that runs on the host and the Bluetooth + * controller chip. This boundary is the natural choice for a Hardware + * Abstraction Layer (HAL). Dealing only in HCI packets and events simplifies + * the stack and abstracts away power management, initialization, and other + * implementation-specific details related to the hardware. + */ +interface IBluetoothHci extends @1.0::IBluetoothHci { + /** + * Same as @1.0, but uses 1.1 Callbacks version + */ + initialize_1_1(@1.1::IBluetoothHciCallbacks callback); + + /** + * Send an ISO data packet (as specified in the Bluetooth Specification + * V6.0) to the Bluetooth controller. + * Packets must be processed in order. + * @param data HCI data packet to be sent + */ + sendIsoData(HciPacket data); +}; diff --git a/bluetooth/1.1/IBluetoothHciCallbacks.hal b/bluetooth/1.1/IBluetoothHciCallbacks.hal new file mode 100644 index 0000000000..62cbe4515a --- /dev/null +++ b/bluetooth/1.1/IBluetoothHciCallbacks.hal @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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. + */ + +package android.hardware.bluetooth@1.1; + +import @1.0::HciPacket; +import @1.0::IBluetoothHciCallbacks; + +/** + * The interface from the Bluetooth Controller to the stack. + */ +interface IBluetoothHciCallbacks extends @1.0::IBluetoothHciCallbacks { + /** + * Send a ISO data packet form the controller to the host. + * @param data the ISO HCI packet to be passed to the host stack + */ + isoDataReceived(HciPacket data); +}; diff --git a/bluetooth/1.1/default/Android.bp b/bluetooth/1.1/default/Android.bp new file mode 100644 index 0000000000..4f7fecbeb6 --- /dev/null +++ b/bluetooth/1.1/default/Android.bp @@ -0,0 +1,42 @@ +// +// Copyright (C) 2019 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. + +cc_binary { + name: "android.hardware.bluetooth@1.1-service", + defaults: ["hidl_defaults"], + relative_install_path: "hw", + vendor: true, + init_rc: ["android.hardware.bluetooth@1.1-service.rc"], + srcs: [ + "service.cpp", + "bluetooth_hci.cc", + ], + + shared_libs: [ + "liblog", + "libcutils", + "libdl", + "libbase", + "libutils", + "libhardware", + "libhidlbase", + "android.hardware.bluetooth@1.0-impl", + "android.hardware.bluetooth@1.1", + ], + + static_libs: [ + "android.hardware.bluetooth-hci", + ], +} diff --git a/bluetooth/1.1/default/OWNERS b/bluetooth/1.1/default/OWNERS new file mode 100644 index 0000000000..0c01df6df0 --- /dev/null +++ b/bluetooth/1.1/default/OWNERS @@ -0,0 +1,3 @@ +zachoverflow@google.com +mylesgw@google.com +jpawlowski@google.com diff --git a/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc b/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc new file mode 100644 index 0000000000..49f0be3c10 --- /dev/null +++ b/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc @@ -0,0 +1,9 @@ +service vendor.bluetooth-1-1 /vendor/bin/hw/android.hardware.bluetooth@1.1-service + interface android.hardware.bluetooth@1.1::IBluetoothHci default + interface android.hardware.bluetooth@1.0::IBluetoothHci default + class hal + capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE + user bluetooth + group bluetooth + writepid /dev/stune/foreground/tasks + diff --git a/bluetooth/1.1/default/bluetooth_hci.cc b/bluetooth/1.1/default/bluetooth_hci.cc new file mode 100644 index 0000000000..7ccce801c7 --- /dev/null +++ b/bluetooth/1.1/default/bluetooth_hci.cc @@ -0,0 +1,197 @@ +/* + * Copyright 2016 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 "android.hardware.bluetooth@1.1-impl" +#include "bluetooth_hci.h" + +#include + +#include "vendor_interface.h" + +using android::hardware::bluetooth::V1_0::implementation::VendorInterface; + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_1 { +namespace implementation { + +static const uint8_t HCI_DATA_TYPE_COMMAND = 1; +static const uint8_t HCI_DATA_TYPE_ACL = 2; +static const uint8_t HCI_DATA_TYPE_SCO = 3; +static const uint8_t HCI_DATA_TYPE_ISO = 5; + +class BluetoothDeathRecipient : public hidl_death_recipient { + public: + BluetoothDeathRecipient(const sp hci) : mHci(hci) {} + + virtual void serviceDied( + uint64_t /*cookie*/, + const wp<::android::hidl::base::V1_0::IBase>& /*who*/) { + ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died"); + has_died_ = true; + mHci->close(); + } + sp mHci; + bool getHasDied() const { return has_died_; } + void setHasDied(bool has_died) { has_died_ = has_died; } + + private: + bool has_died_; +}; + +BluetoothHci::BluetoothHci() + : death_recipient_(new BluetoothDeathRecipient(this)) {} + +Return BluetoothHci::initialize_1_1( + const ::android::sp& cb) { + ALOGI("BluetoothHci::initialize_1_1()"); + if (cb == nullptr) { + ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)"); + return Void(); + } + + death_recipient_->setHasDied(false); + cb->linkToDeath(death_recipient_, 0); + + bool rc = VendorInterface::Initialize( + [cb](bool status) { + auto hidl_status = cb->initializationComplete( + status ? V1_0::Status::SUCCESS + : V1_0::Status::INITIALIZATION_ERROR); + if (!hidl_status.isOk()) { + ALOGE("VendorInterface -> Unable to call initializationComplete()"); + } + }, + [cb](const hidl_vec& packet) { + auto hidl_status = cb->hciEventReceived(packet); + if (!hidl_status.isOk()) { + ALOGE("VendorInterface -> Unable to call hciEventReceived()"); + } + }, + [cb](const hidl_vec& packet) { + auto hidl_status = cb->aclDataReceived(packet); + if (!hidl_status.isOk()) { + ALOGE("VendorInterface -> Unable to call aclDataReceived()"); + } + }, + [cb](const hidl_vec& packet) { + auto hidl_status = cb->scoDataReceived(packet); + if (!hidl_status.isOk()) { + ALOGE("VendorInterface -> Unable to call scoDataReceived()"); + } + }, + [cb](const hidl_vec& packet) { + auto hidl_status = cb->isoDataReceived(packet); + if (!hidl_status.isOk()) { + ALOGE("VendorInterface -> Unable to call isoDataReceived()"); + } + }); + if (!rc) { + auto hidl_status = + cb->initializationComplete(V1_0::Status::INITIALIZATION_ERROR); + if (!hidl_status.isOk()) { + ALOGE("VendorInterface -> Unable to call initializationComplete(ERR)"); + } + } + + unlink_cb_ = [cb](sp& death_recipient) { + if (death_recipient->getHasDied()) + ALOGI("Skipping unlink call, service died."); + else + cb->unlinkToDeath(death_recipient); + }; + + return Void(); +} + +class OldCbWrapper : public V1_1::IBluetoothHciCallbacks { + public: + const ::android::sp old_cb_; + OldCbWrapper(const ::android::sp& old_cb) + : old_cb_(old_cb) {} + + virtual ~OldCbWrapper() = default; + + Return initializationComplete(V1_0::Status status) override { + return old_cb_->initializationComplete(status); + }; + + Return hciEventReceived( + const ::android::hardware::hidl_vec& event) override { + return old_cb_->hciEventReceived(event); + }; + + Return aclDataReceived( + const ::android::hardware::hidl_vec& data) override { + return old_cb_->aclDataReceived(data); + }; + + Return scoDataReceived( + const ::android::hardware::hidl_vec& data) override { + return old_cb_->scoDataReceived(data); + }; + + Return isoDataReceived( + const ::android::hardware::hidl_vec&) override { + ALOGE("Please use HAL V1_1 for ISO."); + return Void(); + }; +}; + +Return BluetoothHci::initialize( + const ::android::sp& cb) { + ALOGE("Using initialize from HAL V1_0 instead of initialize_1_1."); + return initialize_1_1(new OldCbWrapper(cb)); +} + +Return BluetoothHci::close() { + ALOGI("BluetoothHci::close()"); + unlink_cb_(death_recipient_); + VendorInterface::Shutdown(); + return Void(); +} + +Return BluetoothHci::sendHciCommand(const hidl_vec& command) { + sendDataToController(HCI_DATA_TYPE_COMMAND, command); + return Void(); +} + +Return BluetoothHci::sendAclData(const hidl_vec& data) { + sendDataToController(HCI_DATA_TYPE_ACL, data); + return Void(); +} + +Return BluetoothHci::sendScoData(const hidl_vec& data) { + sendDataToController(HCI_DATA_TYPE_SCO, data); + return Void(); +} + +Return BluetoothHci::sendIsoData(const hidl_vec& data) { + sendDataToController(HCI_DATA_TYPE_ISO, data); + return Void(); +} + +void BluetoothHci::sendDataToController(const uint8_t type, + const hidl_vec& data) { + VendorInterface::get()->Send(type, data.data(), data.size()); +} + +} // namespace implementation +} // namespace V1_1 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/1.1/default/bluetooth_hci.h b/bluetooth/1.1/default/bluetooth_hci.h new file mode 100644 index 0000000000..5f59cb0404 --- /dev/null +++ b/bluetooth/1.1/default/bluetooth_hci.h @@ -0,0 +1,63 @@ +/* + * Copyright 2019 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. + */ + +#ifndef HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_ +#define HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_ + +#include +#include + +#include + +#include + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; + +class BluetoothDeathRecipient; + +class BluetoothHci : public V1_1::IBluetoothHci { + public: + BluetoothHci(); + Return initialize( + const ::android::sp& cb) override; + Return initialize_1_1( + const ::android::sp& cb) override; + Return sendHciCommand(const hidl_vec& packet) override; + Return sendAclData(const hidl_vec& data) override; + Return sendScoData(const hidl_vec& data) override; + Return sendIsoData(const hidl_vec& data) override; + Return close() override; + + private: + void sendDataToController(const uint8_t type, const hidl_vec& data); + ::android::sp death_recipient_; + std::function&)> unlink_cb_; +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace bluetooth +} // namespace hardware +} // namespace android + +#endif // HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_ diff --git a/bluetooth/1.1/default/service.cpp b/bluetooth/1.1/default/service.cpp new file mode 100644 index 0000000000..affa855634 --- /dev/null +++ b/bluetooth/1.1/default/service.cpp @@ -0,0 +1,43 @@ +// +// Copyright 2019 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 "android.hardware.bluetooth@1.1-service" + +#include +#include + +#include "bluetooth_hci.h" + +// Generated HIDL files +using android::hardware::bluetooth::V1_1::IBluetoothHci; +using android::hardware::bluetooth::V1_1::implementation::BluetoothHci; + +using android::sp; +using android::status_t; + +int main() { + ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/); + + sp bluetoothHci = new BluetoothHci(); + const status_t status = bluetoothHci->registerAsService(); + if (status != ::android::OK) { + ALOGE("Cannot register Bluetooth HAL service"); + return 1; // or handle error + } + + ::android::hardware::joinRpcThreadpool(); + return 1; // joinRpcThreadpool should never return +} diff --git a/bluetooth/1.1/vts/OWNERS b/bluetooth/1.1/vts/OWNERS new file mode 100644 index 0000000000..ff6fd932b4 --- /dev/null +++ b/bluetooth/1.1/vts/OWNERS @@ -0,0 +1,6 @@ +zachoverflow@google.com +siyuanh@google.com +mylesgw@google.com +jpawlowski@google.com +hsz@google.com + diff --git a/bluetooth/1.1/vts/functional/Android.bp b/bluetooth/1.1/vts/functional/Android.bp new file mode 100644 index 0000000000..8d6d7490e3 --- /dev/null +++ b/bluetooth/1.1/vts/functional/Android.bp @@ -0,0 +1,27 @@ +// +// Copyright (C) 2019 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. +// + +cc_test { + name: "VtsHalBluetoothV1_1TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalBluetoothV1_1TargetTest.cpp"], + static_libs: [ + "android.hardware.bluetooth@1.1", + "android.hardware.bluetooth@1.0", + "libbluetooth-types", + ], + test_suites: ["general-tests", "vts-core"], +} diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp new file mode 100644 index 0000000000..659b2c89d6 --- /dev/null +++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp @@ -0,0 +1,760 @@ +/* + * Copyright (C) 2019 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 "bluetooth_hidl_hal_test" +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +using ::android::sp; +using ::android::hardware::hidl_death_recipient; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::bluetooth::V1_0::Status; +using ::android::hardware::bluetooth::V1_1::IBluetoothHci; +using ::android::hardware::bluetooth::V1_1::IBluetoothHciCallbacks; + +#define HCI_MINIMUM_HCI_VERSION 5 // Bluetooth Core Specification 3.0 + HS +#define HCI_MINIMUM_LMP_VERSION 5 // Bluetooth Core Specification 3.0 + HS +#define NUM_HCI_COMMANDS_BANDWIDTH 1000 +#define NUM_SCO_PACKETS_BANDWIDTH 1000 +#define NUM_ACL_PACKETS_BANDWIDTH 1000 +#define WAIT_FOR_INIT_TIMEOUT std::chrono::milliseconds(2000) +#define WAIT_FOR_HCI_EVENT_TIMEOUT std::chrono::milliseconds(2000) +#define WAIT_FOR_SCO_DATA_TIMEOUT std::chrono::milliseconds(1000) +#define WAIT_FOR_ACL_DATA_TIMEOUT std::chrono::milliseconds(1000) +#define INTERFACE_CLOSE_DELAY_MS std::chrono::milliseconds(200) + +#define COMMAND_HCI_SHOULD_BE_UNKNOWN \ + { 0xff, 0x3B, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 } +#define COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION \ + { 0x01, 0x10, 0x00 } +#define COMMAND_HCI_READ_BUFFER_SIZE \ + { 0x05, 0x10, 0x00 } +#define COMMAND_HCI_WRITE_LOOPBACK_MODE_LOCAL \ + { 0x02, 0x18, 0x01, 0x01 } +#define COMMAND_HCI_RESET \ + { 0x03, 0x0c, 0x00 } +#define COMMAND_HCI_WRITE_LOCAL_NAME \ + { 0x13, 0x0c, 0xf8 } +#define HCI_STATUS_SUCCESS 0x00 +#define HCI_STATUS_UNKNOWN_HCI_COMMAND 0x01 + +#define EVENT_CONNECTION_COMPLETE 0x03 +#define EVENT_COMMAND_COMPLETE 0x0e +#define EVENT_COMMAND_STATUS 0x0f +#define EVENT_NUMBER_OF_COMPLETED_PACKETS 0x13 +#define EVENT_LOOPBACK_COMMAND 0x19 + +#define EVENT_CODE_BYTE 0 +#define EVENT_LENGTH_BYTE 1 +#define EVENT_FIRST_PAYLOAD_BYTE 2 +#define EVENT_COMMAND_STATUS_STATUS_BYTE 2 +#define EVENT_COMMAND_STATUS_ALLOWED_PACKETS_BYTE 3 +#define EVENT_COMMAND_STATUS_OPCODE_LSBYTE 4 // Bytes 4 and 5 +#define EVENT_COMMAND_COMPLETE_ALLOWED_PACKETS_BYTE 2 +#define EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE 3 // Bytes 3 and 4 +#define EVENT_COMMAND_COMPLETE_STATUS_BYTE 5 +#define EVENT_COMMAND_COMPLETE_FIRST_PARAM_BYTE 6 +#define EVENT_LOCAL_HCI_VERSION_BYTE EVENT_COMMAND_COMPLETE_FIRST_PARAM_BYTE +#define EVENT_LOCAL_LMP_VERSION_BYTE EVENT_LOCAL_HCI_VERSION_BYTE + 3 + +#define EVENT_CONNECTION_COMPLETE_PARAM_LENGTH 11 +#define EVENT_CONNECTION_COMPLETE_TYPE 11 +#define EVENT_CONNECTION_COMPLETE_TYPE_SCO 0 +#define EVENT_CONNECTION_COMPLETE_TYPE_ACL 1 +#define EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE 3 +#define EVENT_COMMAND_STATUS_LENGTH 4 + +#define EVENT_NUMBER_OF_COMPLETED_PACKETS_NUM_HANDLES 2 + +#define ACL_BROADCAST_FLAG_OFFSET 6 +#define ACL_BROADCAST_FLAG_POINT_TO_POINT 0x0 +#define ACL_BROADCAST_POINT_TO_POINT \ + (ACL_BROADCAST_FLAG_POINT_TO_POINT << ACL_BROADCAST_FLAG_OFFSET) + +#define ACL_PACKET_BOUNDARY_FLAG_OFFSET 4 +#define ACL_PACKET_BOUNDARY_FLAG_FIRST_AUTO_FLUSHABLE 0x2 +#define ACL_PACKET_BOUNDARY_FIRST_AUTO_FLUSHABLE \ + (ACL_PACKET_BOUNDARY_FLAG_FIRST_AUTO_FLUSHABLE \ + << ACL_PACKET_BOUNDARY_FLAG_OFFSET) + +// To be removed in VTS release builds +#define ACL_HANDLE_QCA_DEBUG_MESSAGE 0xedc + +constexpr char kCallbackNameAclEventReceived[] = "aclDataReceived"; +constexpr char kCallbackNameHciEventReceived[] = "hciEventReceived"; +constexpr char kCallbackNameInitializationComplete[] = "initializationComplete"; +constexpr char kCallbackNameScoEventReceived[] = "scoDataReceived"; +constexpr char kCallbackNameIsoEventReceived[] = "isoDataReceived"; + +class ThroughputLogger { + public: + ThroughputLogger(std::string task) + : task_(task), start_time_(std::chrono::steady_clock::now()) {} + + ~ThroughputLogger() { + if (total_bytes_ == 0) return; + std::chrono::duration duration = + std::chrono::steady_clock::now() - start_time_; + double s = duration.count(); + if (s == 0) return; + double rate_kb = (static_cast(total_bytes_) / s) / 1024; + ALOGD("%s %.1f KB/s (%zu bytes in %.3fs)", task_.c_str(), rate_kb, + total_bytes_, s); + } + + void setTotalBytes(size_t total_bytes) { total_bytes_ = total_bytes; } + + private: + size_t total_bytes_; + std::string task_; + std::chrono::steady_clock::time_point start_time_; +}; + +// The main test class for Bluetooth HIDL HAL. +class BluetoothHidlTest : public ::testing::TestWithParam { + public: + virtual void SetUp() override { + // currently test passthrough mode only + bluetooth = IBluetoothHci::getService(GetParam()); + ASSERT_NE(bluetooth, nullptr); + ALOGI("%s: getService() for bluetooth is %s", __func__, + bluetooth->isRemote() ? "remote" : "local"); + + bluetooth_hci_death_recipient = new BluetoothHciDeathRecipient(); + ASSERT_NE(bluetooth_hci_death_recipient, nullptr); + ASSERT_TRUE( + bluetooth->linkToDeath(bluetooth_hci_death_recipient, 0).isOk()); + + bluetooth_cb = new BluetoothHciCallbacks(*this); + ASSERT_NE(bluetooth_cb, nullptr); + + max_acl_data_packet_length = 0; + max_sco_data_packet_length = 0; + max_acl_data_packets = 0; + max_sco_data_packets = 0; + + initialized = false; + event_cb_count = 0; + acl_cb_count = 0; + sco_cb_count = 0; + + ASSERT_FALSE(initialized); + // Should not be checked in production code + ASSERT_TRUE(bluetooth->initialize(bluetooth_cb).isOk()); + + bluetooth_cb->SetWaitTimeout(kCallbackNameInitializationComplete, + WAIT_FOR_INIT_TIMEOUT); + bluetooth_cb->SetWaitTimeout(kCallbackNameHciEventReceived, + WAIT_FOR_HCI_EVENT_TIMEOUT); + bluetooth_cb->SetWaitTimeout(kCallbackNameAclEventReceived, + WAIT_FOR_ACL_DATA_TIMEOUT); + bluetooth_cb->SetWaitTimeout(kCallbackNameScoEventReceived, + WAIT_FOR_SCO_DATA_TIMEOUT); + + EXPECT_TRUE( + bluetooth_cb->WaitForCallback(kCallbackNameInitializationComplete) + .no_timeout); + + ASSERT_TRUE(initialized); + } + + virtual void TearDown() override { + ALOGI("TearDown"); + // Should not be checked in production code + ASSERT_TRUE(bluetooth->close().isOk()); + std::this_thread::sleep_for(INTERFACE_CLOSE_DELAY_MS); + handle_no_ops(); + EXPECT_EQ(static_cast(0), event_queue.size()); + EXPECT_EQ(static_cast(0), sco_queue.size()); + EXPECT_EQ(static_cast(0), acl_queue.size()); + EXPECT_EQ(static_cast(0), iso_queue.size()); + } + + void setBufferSizes(); + + // Functions called from within tests in loopback mode + void sendAndCheckHCI(int num_packets); + void sendAndCheckSCO(int num_packets, size_t size, uint16_t handle); + void sendAndCheckACL(int num_packets, size_t size, uint16_t handle); + + // Helper functions to try to get a handle on verbosity + void enterLoopbackMode(std::vector* sco_handles, + std::vector* acl_handles); + void handle_no_ops(); + void wait_for_event(bool timeout_is_error); + void wait_for_command_complete_event(hidl_vec cmd); + int wait_for_completed_packets_event(uint16_t handle); + + class BluetoothHciDeathRecipient : public hidl_death_recipient { + public: + void serviceDied( + uint64_t /*cookie*/, + const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) + override { + FAIL(); + } + }; + + // A simple test implementation of BluetoothHciCallbacks. + class BluetoothHciCallbacks + : public ::testing::VtsHalHidlTargetCallbackBase, + public IBluetoothHciCallbacks { + BluetoothHidlTest& parent_; + + public: + BluetoothHciCallbacks(BluetoothHidlTest& parent) : parent_(parent){}; + + virtual ~BluetoothHciCallbacks() = default; + + Return initializationComplete(Status status) override { + parent_.initialized = (status == Status::SUCCESS); + NotifyFromCallback(kCallbackNameInitializationComplete); + ALOGV("%s (status = %d)", __func__, static_cast(status)); + return Void(); + }; + + Return hciEventReceived( + const ::android::hardware::hidl_vec& event) override { + parent_.event_cb_count++; + parent_.event_queue.push(event); + NotifyFromCallback(kCallbackNameHciEventReceived); + ALOGV("Event received (length = %d)", static_cast(event.size())); + return Void(); + }; + + Return aclDataReceived( + const ::android::hardware::hidl_vec& data) override { + parent_.acl_cb_count++; + parent_.acl_queue.push(data); + NotifyFromCallback(kCallbackNameAclEventReceived); + return Void(); + }; + + Return scoDataReceived( + const ::android::hardware::hidl_vec& data) override { + parent_.sco_cb_count++; + parent_.sco_queue.push(data); + NotifyFromCallback(kCallbackNameScoEventReceived); + return Void(); + }; + + Return isoDataReceived( + const ::android::hardware::hidl_vec& data) override { + parent_.iso_cb_count++; + parent_.iso_queue.push(data); + NotifyFromCallback(kCallbackNameIsoEventReceived); + return Void(); + }; + }; + + sp bluetooth; + sp bluetooth_cb; + sp bluetooth_hci_death_recipient; + std::queue> event_queue; + std::queue> acl_queue; + std::queue> sco_queue; + std::queue> iso_queue; + + bool initialized; + + int event_cb_count; + int sco_cb_count; + int acl_cb_count; + int iso_cb_count; + + int max_acl_data_packet_length; + int max_sco_data_packet_length; + int max_acl_data_packets; + int max_sco_data_packets; +}; + +// Discard NO-OPs from the event queue. +void BluetoothHidlTest::handle_no_ops() { + while (event_queue.size() > 0) { + hidl_vec event = event_queue.front(); + EXPECT_GE(event.size(), + static_cast(EVENT_COMMAND_COMPLETE_STATUS_BYTE)); + bool event_is_no_op = + (event[EVENT_CODE_BYTE] == EVENT_COMMAND_COMPLETE) && + (event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE] == 0x00) && + (event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1] == 0x00); + event_is_no_op |= (event[EVENT_CODE_BYTE] == EVENT_COMMAND_STATUS) && + (event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE] == 0x00) && + (event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1] == 0x00); + if (event_is_no_op) { + event_queue.pop(); + } else { + break; + } + } + // To be removed in VTS release builds + while (acl_queue.size() > 0) { + hidl_vec acl_packet = acl_queue.front(); + uint16_t connection_handle = acl_packet[1] & 0xF; + connection_handle <<= 8; + connection_handle |= acl_packet[0]; + bool packet_is_no_op = connection_handle == ACL_HANDLE_QCA_DEBUG_MESSAGE; + if (packet_is_no_op) { + acl_queue.pop(); + } else { + break; + } + } +} + +// Receive an event, discarding NO-OPs. +void BluetoothHidlTest::wait_for_event(bool timeout_is_error = true) { + hidl_vec event; + do { + bool no_timeout = + bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived).no_timeout; + EXPECT_TRUE(no_timeout || !timeout_is_error); + if (no_timeout && timeout_is_error) { + EXPECT_LT(static_cast(0), event_queue.size()); + } + if (event_queue.size() == 0) { + // WaitForCallback timed out. + return; + } + handle_no_ops(); + } while (event_queue.size() == 0); +} + +// Wait until a COMMAND_COMPLETE is received. +void BluetoothHidlTest::wait_for_command_complete_event(hidl_vec cmd) { + wait_for_event(); + hidl_vec event = event_queue.front(); + event_queue.pop(); + + EXPECT_GT(event.size(), + static_cast(EVENT_COMMAND_COMPLETE_STATUS_BYTE)); + EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]); + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]); + EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]); +} + +// Send the command to read the controller's buffer sizes. +void BluetoothHidlTest::setBufferSizes() { + hidl_vec cmd = COMMAND_HCI_READ_BUFFER_SIZE; + bluetooth->sendHciCommand(cmd); + + wait_for_event(); + if (event_queue.size() == 0) return; + + hidl_vec event = event_queue.front(); + event_queue.pop(); + + EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]); + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]); + EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]); + + max_acl_data_packet_length = + event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 1] + + (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 2] << 8); + max_sco_data_packet_length = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 3]; + max_acl_data_packets = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 4] + + (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 5] << 8); + max_sco_data_packets = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 6] + + (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 7] << 8); + + ALOGD("%s: ACL max %d num %d SCO max %d num %d", __func__, + static_cast(max_acl_data_packet_length), + static_cast(max_acl_data_packets), + static_cast(max_sco_data_packet_length), + static_cast(max_sco_data_packets)); +} + +// Send an HCI command (in Loopback mode) and check the response. +void BluetoothHidlTest::sendAndCheckHCI(int num_packets) { + ThroughputLogger logger = {__func__}; + int command_size = 0; + for (int n = 0; n < num_packets; n++) { + // Send an HCI packet + std::vector write_name = COMMAND_HCI_WRITE_LOCAL_NAME; + // With a name + char new_name[] = "John Jacob Jingleheimer Schmidt ___________________0"; + size_t new_name_length = strlen(new_name); + for (size_t i = 0; i < new_name_length; i++) + write_name.push_back(static_cast(new_name[i])); + // And the packet number + size_t i = new_name_length - 1; + for (int digits = n; digits > 0; digits = digits / 10, i--) + write_name[i] = static_cast('0' + digits % 10); + // And padding + for (size_t i = 0; i < 248 - new_name_length; i++) + write_name.push_back(static_cast(0)); + + hidl_vec cmd = write_name; + bluetooth->sendHciCommand(cmd); + + // Check the loopback of the HCI packet + wait_for_event(); + if (event_queue.size() == 0) return; + + hidl_vec event = event_queue.front(); + event_queue.pop(); + size_t compare_length = + (cmd.size() > static_cast(0xff) ? static_cast(0xff) + : cmd.size()); + EXPECT_GT(event.size(), compare_length + EVENT_FIRST_PAYLOAD_BYTE - 1); + + EXPECT_EQ(EVENT_LOOPBACK_COMMAND, event[EVENT_CODE_BYTE]); + EXPECT_EQ(compare_length, event[EVENT_LENGTH_BYTE]); + + // Don't compare past the end of the event. + if (compare_length + EVENT_FIRST_PAYLOAD_BYTE > event.size()) { + compare_length = event.size() - EVENT_FIRST_PAYLOAD_BYTE; + ALOGE("Only comparing %d bytes", static_cast(compare_length)); + } + + if (n == num_packets - 1) { + command_size = cmd.size(); + } + + for (size_t i = 0; i < compare_length; i++) + EXPECT_EQ(cmd[i], event[EVENT_FIRST_PAYLOAD_BYTE + i]); + } + logger.setTotalBytes(command_size * num_packets * 2); +} + +// Send a SCO data packet (in Loopback mode) and check the response. +void BluetoothHidlTest::sendAndCheckSCO(int num_packets, size_t size, + uint16_t handle) { + ThroughputLogger logger = {__func__}; + for (int n = 0; n < num_packets; n++) { + // Send a SCO packet + hidl_vec sco_packet; + std::vector sco_vector; + sco_vector.push_back(static_cast(handle & 0xff)); + sco_vector.push_back(static_cast((handle & 0x0f00) >> 8)); + sco_vector.push_back(static_cast(size & 0xff)); + sco_vector.push_back(static_cast((size & 0xff00) >> 8)); + for (size_t i = 0; i < size; i++) { + sco_vector.push_back(static_cast(i + n)); + } + sco_packet = sco_vector; + bluetooth->sendScoData(sco_vector); + + // Check the loopback of the SCO packet + EXPECT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameScoEventReceived) + .no_timeout); + hidl_vec sco_loopback = sco_queue.front(); + sco_queue.pop(); + + EXPECT_EQ(sco_packet.size(), sco_loopback.size()); + size_t successful_bytes = 0; + + for (size_t i = 0; i < sco_packet.size(); i++) { + if (sco_packet[i] == sco_loopback[i]) { + successful_bytes = i; + } else { + ALOGE("Miscompare at %d (expected %x, got %x)", static_cast(i), + sco_packet[i], sco_loopback[i]); + ALOGE("At %d (expected %x, got %x)", static_cast(i + 1), + sco_packet[i + 1], sco_loopback[i + 1]); + break; + } + } + EXPECT_EQ(sco_packet.size(), successful_bytes + 1); + } + logger.setTotalBytes(num_packets * size * 2); +} + +// Send an ACL data packet (in Loopback mode) and check the response. +void BluetoothHidlTest::sendAndCheckACL(int num_packets, size_t size, + uint16_t handle) { + ThroughputLogger logger = {__func__}; + for (int n = 0; n < num_packets; n++) { + // Send an ACL packet + hidl_vec acl_packet; + std::vector acl_vector; + acl_vector.push_back(static_cast(handle & 0xff)); + acl_vector.push_back(static_cast((handle & 0x0f00) >> 8) | + ACL_BROADCAST_POINT_TO_POINT | + ACL_PACKET_BOUNDARY_FIRST_AUTO_FLUSHABLE); + acl_vector.push_back(static_cast(size & 0xff)); + acl_vector.push_back(static_cast((size & 0xff00) >> 8)); + for (size_t i = 0; i < size; i++) { + acl_vector.push_back(static_cast(i + n)); + } + acl_packet = acl_vector; + bluetooth->sendAclData(acl_vector); + + // Check the loopback of the ACL packet + EXPECT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameAclEventReceived) + .no_timeout); + hidl_vec acl_loopback = acl_queue.front(); + acl_queue.pop(); + + EXPECT_EQ(acl_packet.size(), acl_loopback.size()); + size_t successful_bytes = 0; + + for (size_t i = 0; i < acl_packet.size(); i++) { + if (acl_packet[i] == acl_loopback[i]) { + successful_bytes = i; + } else { + ALOGE("Miscompare at %d (expected %x, got %x)", static_cast(i), + acl_packet[i], acl_loopback[i]); + ALOGE("At %d (expected %x, got %x)", static_cast(i + 1), + acl_packet[i + 1], acl_loopback[i + 1]); + break; + } + } + EXPECT_EQ(acl_packet.size(), successful_bytes + 1); + } + logger.setTotalBytes(num_packets * size * 2); +} + +// Return the number of completed packets reported by the controller. +int BluetoothHidlTest::wait_for_completed_packets_event(uint16_t handle) { + int packets_processed = 0; + wait_for_event(false); + if (event_queue.size() == 0) { + ALOGW("%s: WaitForCallback timed out.", __func__); + return packets_processed; + } + while (event_queue.size() > 0) { + hidl_vec event = event_queue.front(); + event_queue.pop(); + + EXPECT_EQ(EVENT_NUMBER_OF_COMPLETED_PACKETS, event[EVENT_CODE_BYTE]); + EXPECT_EQ(1, event[EVENT_NUMBER_OF_COMPLETED_PACKETS_NUM_HANDLES]); + + uint16_t event_handle = event[3] + (event[4] << 8); + EXPECT_EQ(handle, event_handle); + + packets_processed += event[5] + (event[6] << 8); + } + return packets_processed; +} + +// Send local loopback command and initialize SCO and ACL handles. +void BluetoothHidlTest::enterLoopbackMode(std::vector* sco_handles, + std::vector* acl_handles) { + hidl_vec cmd = COMMAND_HCI_WRITE_LOOPBACK_MODE_LOCAL; + bluetooth->sendHciCommand(cmd); + + // Receive connection complete events with data channels + int connection_event_count = 0; + bool command_complete_received = false; + while (true) { + wait_for_event(false); + if (event_queue.size() == 0) { + // Fail if there was no event received or no connections completed. + EXPECT_TRUE(command_complete_received); + EXPECT_LT(0, connection_event_count); + return; + } + hidl_vec event = event_queue.front(); + event_queue.pop(); + EXPECT_GT(event.size(), + static_cast(EVENT_COMMAND_COMPLETE_STATUS_BYTE)); + if (event[EVENT_CODE_BYTE] == EVENT_CONNECTION_COMPLETE) { + EXPECT_GT(event.size(), + static_cast(EVENT_CONNECTION_COMPLETE_TYPE)); + EXPECT_EQ(event[EVENT_LENGTH_BYTE], + EVENT_CONNECTION_COMPLETE_PARAM_LENGTH); + uint8_t connection_type = event[EVENT_CONNECTION_COMPLETE_TYPE]; + + EXPECT_TRUE(connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO || + connection_type == EVENT_CONNECTION_COMPLETE_TYPE_ACL); + + // Save handles + uint16_t handle = event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE] | + event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE + 1] << 8; + if (connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO) + sco_handles->push_back(handle); + else + acl_handles->push_back(handle); + + ALOGD("Connect complete type = %d handle = %d", + event[EVENT_CONNECTION_COMPLETE_TYPE], handle); + connection_event_count++; + } else { + EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]); + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]); + EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]); + command_complete_received = true; + } + } +} + +// Empty test: Initialize()/Close() are called in SetUp()/TearDown(). +TEST_P(BluetoothHidlTest, InitializeAndClose) {} + +// Send an HCI Reset with sendHciCommand and wait for a command complete event. +TEST_P(BluetoothHidlTest, HciReset) { + hidl_vec cmd = COMMAND_HCI_RESET; + bluetooth->sendHciCommand(cmd); + + wait_for_command_complete_event(cmd); +} + +// Read and check the HCI version of the controller. +TEST_P(BluetoothHidlTest, HciVersionTest) { + hidl_vec cmd = COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION; + bluetooth->sendHciCommand(cmd); + + wait_for_event(); + if (event_queue.size() == 0) return; + + hidl_vec event = event_queue.front(); + event_queue.pop(); + EXPECT_GT(event.size(), static_cast(EVENT_LOCAL_LMP_VERSION_BYTE)); + + EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]); + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]); + EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]); + + EXPECT_LE(HCI_MINIMUM_HCI_VERSION, event[EVENT_LOCAL_HCI_VERSION_BYTE]); + EXPECT_LE(HCI_MINIMUM_LMP_VERSION, event[EVENT_LOCAL_LMP_VERSION_BYTE]); +} + +// Send an unknown HCI command and wait for the error message. +TEST_P(BluetoothHidlTest, HciUnknownCommand) { + hidl_vec cmd = COMMAND_HCI_SHOULD_BE_UNKNOWN; + bluetooth->sendHciCommand(cmd); + + wait_for_event(); + if (event_queue.size() == 0) return; + + hidl_vec event = event_queue.front(); + event_queue.pop(); + + EXPECT_GT(event.size(), + static_cast(EVENT_COMMAND_COMPLETE_STATUS_BYTE)); + if (event[EVENT_CODE_BYTE] == EVENT_COMMAND_COMPLETE) { + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]); + EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND, + event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]); + } else { + EXPECT_EQ(EVENT_COMMAND_STATUS, event[EVENT_CODE_BYTE]); + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1]); + EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND, + event[EVENT_COMMAND_STATUS_STATUS_BYTE]); + } +} + +// Enter loopback mode, but don't send any packets. +TEST_P(BluetoothHidlTest, WriteLoopbackMode) { + std::vector sco_connection_handles; + std::vector acl_connection_handles; + enterLoopbackMode(&sco_connection_handles, &acl_connection_handles); +} + +// Enter loopback mode and send single packets. +TEST_P(BluetoothHidlTest, LoopbackModeSinglePackets) { + setBufferSizes(); + + std::vector sco_connection_handles; + std::vector acl_connection_handles; + enterLoopbackMode(&sco_connection_handles, &acl_connection_handles); + + sendAndCheckHCI(1); + + // This should work, but breaks on some current platforms. Figure out how to + // grandfather older devices but test new ones. + if (0 && sco_connection_handles.size() > 0) { + EXPECT_LT(0, max_sco_data_packet_length); + sendAndCheckSCO(1, max_sco_data_packet_length, sco_connection_handles[0]); + int sco_packets_sent = 1; + int completed_packets = + wait_for_completed_packets_event(sco_connection_handles[0]); + if (sco_packets_sent != completed_packets) { + ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__, + sco_packets_sent, completed_packets); + } + } + + if (acl_connection_handles.size() > 0) { + EXPECT_LT(0, max_acl_data_packet_length); + sendAndCheckACL(1, max_acl_data_packet_length, acl_connection_handles[0]); + int acl_packets_sent = 1; + int completed_packets = + wait_for_completed_packets_event(acl_connection_handles[0]); + if (acl_packets_sent != completed_packets) { + ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__, + acl_packets_sent, completed_packets); + } + } +} + +// Enter loopback mode and send packets for bandwidth measurements. +TEST_P(BluetoothHidlTest, LoopbackModeBandwidth) { + setBufferSizes(); + + std::vector sco_connection_handles; + std::vector acl_connection_handles; + enterLoopbackMode(&sco_connection_handles, &acl_connection_handles); + + sendAndCheckHCI(NUM_HCI_COMMANDS_BANDWIDTH); + + // This should work, but breaks on some current platforms. Figure out how to + // grandfather older devices but test new ones. + if (0 && sco_connection_handles.size() > 0) { + EXPECT_LT(0, max_sco_data_packet_length); + sendAndCheckSCO(NUM_SCO_PACKETS_BANDWIDTH, max_sco_data_packet_length, + sco_connection_handles[0]); + int sco_packets_sent = NUM_SCO_PACKETS_BANDWIDTH; + int completed_packets = + wait_for_completed_packets_event(sco_connection_handles[0]); + if (sco_packets_sent != completed_packets) { + ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__, + sco_packets_sent, completed_packets); + } + } + + if (acl_connection_handles.size() > 0) { + EXPECT_LT(0, max_acl_data_packet_length); + sendAndCheckACL(NUM_ACL_PACKETS_BANDWIDTH, max_acl_data_packet_length, + acl_connection_handles[0]); + int acl_packets_sent = NUM_ACL_PACKETS_BANDWIDTH; + int completed_packets = + wait_for_completed_packets_event(acl_connection_handles[0]); + if (acl_packets_sent != completed_packets) { + ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__, + acl_packets_sent, completed_packets); + } + } +} + +INSTANTIATE_TEST_SUITE_P( + PerInstance, BluetoothHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IBluetoothHci::descriptor)), + android::hardware::PrintInstanceNameToString); diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index aeb11c4354..a500ca0bdf 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -75,7 +75,7 @@ android.hardware.bluetooth - 1.0 + 1.0-1 IBluetoothHci default diff --git a/current.txt b/current.txt index 98cb7922af..b811a92c3e 100644 --- a/current.txt +++ b/current.txt @@ -584,6 +584,8 @@ a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardwar fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface # HALs released in Android R +79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc android.hardware.bluetooth@1.1::IBluetoothHci +40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth @@ -596,4 +598,4 @@ b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardwar 274fb1254a6d1a97824ec5c880eeefc0e410dc6d3a2a4c34052201169d2b7de0 android.hardware.radio@1.5::types c8e81d912827a5d49b2ddcdc4eb4556c5d231a899a1dca879309e04210daa4a0 android.hardware.radio@1.5::IRadio a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication -260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse +260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse \ No newline at end of file