/* * Copyright (C) 2023 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // TODO: Remove custom logging defines from PDL packets. #undef LOG_INFO #undef LOG_DEBUG #undef LOG_TAG #define LOG_TAG "VtsHalBluetooth" #include "hci/hci_packets.h" #include "packet/raw_builder.h" using aidl::android::hardware::bluetooth::IBluetoothHci; using aidl::android::hardware::bluetooth::IBluetoothHciCallbacks; using aidl::android::hardware::bluetooth::Status; using ndk::ScopedAStatus; using ndk::SpAIBinder; using ::bluetooth::hci::CommandBuilder; using ::bluetooth::hci::CommandCompleteView; using ::bluetooth::hci::CommandView; using ::bluetooth::hci::ErrorCode; using ::bluetooth::hci::EventView; using ::bluetooth::hci::LeReadLocalSupportedFeaturesBuilder; using ::bluetooth::hci::LeReadLocalSupportedFeaturesCompleteView; using ::bluetooth::hci::LeReadNumberOfSupportedAdvertisingSetsBuilder; using ::bluetooth::hci::LeReadNumberOfSupportedAdvertisingSetsCompleteView; using ::bluetooth::hci::LeReadResolvingListSizeBuilder; using ::bluetooth::hci::LeReadResolvingListSizeCompleteView; using ::bluetooth::hci::LLFeaturesBits; using ::bluetooth::hci::OpCode; using ::bluetooth::hci::OpCodeText; using ::bluetooth::hci::PacketView; using ::bluetooth::hci::ReadLocalVersionInformationBuilder; using ::bluetooth::hci::ReadLocalVersionInformationCompleteView; static constexpr uint8_t kMinLeAdvSetForBt5 = 16; static constexpr uint8_t kMinLeAdvSetForBt5FoTv = 10; static constexpr uint8_t kMinLeResolvingListForBt5 = 8; static constexpr size_t kNumHciCommandsBandwidth = 100; static constexpr size_t kNumScoPacketsBandwidth = 100; static constexpr size_t kNumAclPacketsBandwidth = 100; static constexpr std::chrono::milliseconds kWaitForInitTimeout(2000); static constexpr std::chrono::milliseconds kWaitForHciEventTimeout(2000); static constexpr std::chrono::milliseconds kWaitForScoDataTimeout(1000); static constexpr std::chrono::milliseconds kWaitForAclDataTimeout(1000); static constexpr std::chrono::milliseconds kInterfaceCloseDelayMs(200); // To discard Qualcomm ACL debugging static constexpr uint16_t kAclHandleQcaDebugMessage = 0xedc; static int get_vsr_api_level() { int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1); if (vendor_api_level != -1) { return vendor_api_level; } // Android S and older devices do not define ro.vendor.api_level vendor_api_level = ::android::base::GetIntProperty("ro.board.api_level", -1); if (vendor_api_level == -1) { vendor_api_level = ::android::base::GetIntProperty("ro.board.first_api_level", -1); } int product_api_level = ::android::base::GetIntProperty("ro.product.first_api_level", -1); if (product_api_level == -1) { product_api_level = ::android::base::GetIntProperty("ro.build.version.sdk", -1); EXPECT_NE(product_api_level, -1) << "Could not find ro.build.version.sdk"; } // VSR API level is the minimum of vendor_api_level and product_api_level. if (vendor_api_level == -1 || vendor_api_level > product_api_level) { return product_api_level; } return vendor_api_level; } static bool isTv() { return testing::deviceSupportsFeature("android.software.leanback") || testing::deviceSupportsFeature("android.hardware.type.television"); } class ThroughputLogger { public: explicit ThroughputLogger(std::string task) : total_bytes_(0), task_(std::move(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 HAL. class BluetoothAidlTest : public ::testing::TestWithParam { public: void SetUp() override { // currently test passthrough mode only hci = IBluetoothHci::fromBinder( SpAIBinder(AServiceManager_waitForService(GetParam().c_str()))); ASSERT_NE(hci, nullptr); ALOGI("%s: getService() for bluetooth hci is %s", __func__, hci->isRemote() ? "remote" : "local"); // Lambda function auto on_binder_death = [](void* /*cookie*/) { FAIL(); }; bluetooth_hci_death_recipient = AIBinder_DeathRecipient_new(on_binder_death); ASSERT_NE(bluetooth_hci_death_recipient, nullptr); ASSERT_EQ(STATUS_OK, AIBinder_linkToDeath(hci->asBinder().get(), bluetooth_hci_death_recipient, nullptr)); hci_cb = ndk::SharedRefBase::make(*this); ASSERT_NE(hci_cb, nullptr); max_acl_data_packet_length = 0; max_sco_data_packet_length = 0; max_acl_data_packets = 0; max_sco_data_packets = 0; event_cb_count = 0; acl_cb_count = 0; sco_cb_count = 0; ASSERT_TRUE(hci->initialize(hci_cb).isOk()); auto future = initialized_promise.get_future(); auto timeout_status = future.wait_for(kWaitForInitTimeout); ASSERT_EQ(timeout_status, std::future_status::ready); ASSERT_TRUE(future.get()); } void TearDown() override { ALOGI("TearDown"); // Should not be checked in production code ASSERT_TRUE(hci->close().isOk()); std::this_thread::sleep_for(kInterfaceCloseDelayMs); handle_no_ops(); discard_qca_debugging(); 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(); void setSynchronousFlowControlEnable(); // 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(); void handle_no_ops(); void discard_qca_debugging(); void wait_for_event(bool timeout_is_error); void wait_for_command_complete_event(OpCode opCode, std::vector& complete_event); // Wait until a command complete is received. // Command complete will be consumed after this method void wait_and_validate_command_complete_event(OpCode opCode); int wait_for_completed_packets_event(uint16_t handle); void send_and_wait_for_cmd_complete(std::unique_ptr cmd, std::vector& cmd_complete); // A simple test implementation of BluetoothHciCallbacks. class BluetoothHciCallbacks : public aidl::android::hardware::bluetooth::BnBluetoothHciCallbacks { BluetoothAidlTest& parent_; public: explicit BluetoothHciCallbacks(BluetoothAidlTest& parent) : parent_(parent){}; ~BluetoothHciCallbacks() override = default; ndk::ScopedAStatus initializationComplete(Status status) override { parent_.initialized_promise.set_value(status == Status::SUCCESS); ALOGV("%s (status = %d)", __func__, static_cast(status)); return ScopedAStatus::ok(); }; ndk::ScopedAStatus hciEventReceived( const std::vector& event) override { parent_.event_cb_count++; parent_.event_queue.push(event); ALOGI("Event received (length = %d)", static_cast(event.size())); return ScopedAStatus::ok(); }; ndk::ScopedAStatus aclDataReceived( const std::vector& data) override { parent_.acl_cb_count++; parent_.acl_queue.push(data); return ScopedAStatus::ok(); }; ndk::ScopedAStatus scoDataReceived( const std::vector& data) override { parent_.sco_cb_count++; parent_.sco_queue.push(data); return ScopedAStatus::ok(); }; ndk::ScopedAStatus isoDataReceived( const std::vector& data) override { parent_.iso_cb_count++; parent_.iso_queue.push(data); return ScopedAStatus::ok(); }; }; template class WaitQueue { public: WaitQueue() = default; ; virtual ~WaitQueue() = default; bool empty() const { std::lock_guard lock(m_); return q_.empty(); }; size_t size() const { std::lock_guard lock(m_); return q_.size(); }; void push(const T& v) { std::lock_guard lock(m_); q_.push(v); ready_.notify_one(); }; bool pop(T& v) { std::lock_guard lock(m_); if (q_.empty()) { return false; } v = std::move(q_.front()); q_.pop(); return true; }; void pop() { std::lock_guard lock(m_); if (q_.empty()) { return; } q_.pop(); }; bool front(T& v) { std::lock_guard lock(m_); if (q_.empty()) { return false; } v = q_.front(); return true; }; void wait() { std::unique_lock lock(m_); while (q_.empty()) { ready_.wait(lock); } }; bool waitWithTimeout(std::chrono::milliseconds timeout) { std::unique_lock lock(m_); while (q_.empty()) { if (ready_.wait_for(lock, timeout) == std::cv_status::timeout) { return false; } } return true; }; bool tryPopWithTimeout(T& v, std::chrono::milliseconds timeout) { std::unique_lock lock(m_); while (q_.empty()) { if (ready_.wait_for(lock, timeout) == std::cv_status::timeout) { return false; } } v = std::move(q_.front()); q_.pop(); return true; }; private: mutable std::mutex m_; std::queue q_; std::condition_variable_any ready_; }; std::shared_ptr hci; std::shared_ptr hci_cb; AIBinder_DeathRecipient* bluetooth_hci_death_recipient{}; WaitQueue> event_queue; WaitQueue> acl_queue; WaitQueue> sco_queue; WaitQueue> iso_queue; std::promise initialized_promise; 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{}; std::vector sco_connection_handles; std::vector acl_connection_handles; }; // Discard NO-OPs from the event queue. void BluetoothAidlTest::handle_no_ops() { while (!event_queue.empty()) { std::vector event; event_queue.front(event); auto complete_view = ::bluetooth::hci::CommandCompleteView::Create( ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView( std::make_shared>(event)))); auto status_view = ::bluetooth::hci::CommandCompleteView::Create( ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView( std::make_shared>(event)))); bool is_complete_no_op = complete_view.IsValid() && complete_view.GetCommandOpCode() == ::bluetooth::hci::OpCode::NONE; bool is_status_no_op = status_view.IsValid() && status_view.GetCommandOpCode() == ::bluetooth::hci::OpCode::NONE; if (is_complete_no_op || is_status_no_op) { event_queue.pop(); } else { break; } } } // Discard Qualcomm ACL debugging void BluetoothAidlTest::discard_qca_debugging() { while (!acl_queue.empty()) { std::vector acl_packet; acl_queue.front(acl_packet); auto acl_view = ::bluetooth::hci::AclView::Create(::bluetooth::hci::PacketView( std::make_shared>(acl_packet))); EXPECT_TRUE(acl_view.IsValid()); if (acl_view.GetHandle() == kAclHandleQcaDebugMessage) { acl_queue.pop(); } else { break; } } } // Receive an event, discarding NO-OPs. void BluetoothAidlTest::wait_for_event(bool timeout_is_error = true) { // Wait until we get something that's not a no-op. while (true) { bool event_ready = event_queue.waitWithTimeout(kWaitForHciEventTimeout); ASSERT_TRUE(event_ready || !timeout_is_error); if (event_queue.empty()) { // waitWithTimeout timed out return; } handle_no_ops(); if (!event_queue.empty()) { // There's an event in the queue that's not a no-op. return; } } } void BluetoothAidlTest::wait_for_command_complete_event( OpCode opCode, std::vector& complete_event) { ASSERT_NO_FATAL_FAILURE(wait_for_event()); ASSERT_FALSE(event_queue.empty()); ASSERT_TRUE(event_queue.pop(complete_event)); auto complete_view = ::bluetooth::hci::CommandCompleteView::Create( ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView( std::make_shared>(complete_event)))); ASSERT_TRUE(complete_view.IsValid()); ASSERT_EQ(complete_view.GetCommandOpCode(), opCode); ASSERT_EQ(complete_view.GetPayload()[0], static_cast(::bluetooth::hci::ErrorCode::SUCCESS)); } void BluetoothAidlTest::wait_and_validate_command_complete_event( ::bluetooth::hci::OpCode opCode) { std::vector complete_event; ASSERT_NO_FATAL_FAILURE( wait_for_command_complete_event(opCode, complete_event)); } // Send the command to read the controller's buffer sizes. void BluetoothAidlTest::setBufferSizes() { std::vector cmd; ::bluetooth::packet::BitInserter bi{cmd}; ::bluetooth::hci::ReadBufferSizeBuilder::Create()->Serialize(bi); hci->sendHciCommand(cmd); ASSERT_NO_FATAL_FAILURE(wait_for_event()); std::vector event; ASSERT_TRUE(event_queue.pop(event)); auto complete_view = ::bluetooth::hci::ReadBufferSizeCompleteView::Create( ::bluetooth::hci::CommandCompleteView::Create( ::bluetooth::hci::EventView::Create( ::bluetooth::hci::PacketView( std::make_shared>(event))))); ASSERT_TRUE(complete_view.IsValid()); ASSERT_EQ(complete_view.GetStatus(), ::bluetooth::hci::ErrorCode::SUCCESS); max_acl_data_packet_length = complete_view.GetAclDataPacketLength(); max_sco_data_packet_length = complete_view.GetSynchronousDataPacketLength(); max_acl_data_packets = complete_view.GetTotalNumAclDataPackets(); max_sco_data_packets = complete_view.GetTotalNumSynchronousDataPackets(); 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)); } // Enable flow control packets for SCO void BluetoothAidlTest::setSynchronousFlowControlEnable() { std::vector cmd; ::bluetooth::packet::BitInserter bi{cmd}; ::bluetooth::hci::WriteSynchronousFlowControlEnableBuilder::Create( ::bluetooth::hci::Enable::ENABLED) ->Serialize(bi); hci->sendHciCommand(cmd); wait_and_validate_command_complete_event( ::bluetooth::hci::OpCode::WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE); } // Send an HCI command (in Loopback mode) and check the response. void BluetoothAidlTest::sendAndCheckHci(int num_packets) { ThroughputLogger logger{__func__}; size_t command_size = 0; char new_name[] = "John Jacob Jingleheimer Schmidt ___________________"; size_t new_name_length = strlen(new_name); for (int n = 0; n < num_packets; n++) { // The name to set is new_name std::array name_array{}; for (size_t i = 0; i < new_name_length; i++) { name_array[i] = new_name[i]; } // And the packet number char number[11] = "0000000000"; snprintf(number, sizeof(number), "%010d", static_cast(n)); for (size_t i = new_name_length; i < new_name_length + sizeof(number) - 1; i++) { name_array[new_name_length + i] = number[i]; } std::vector write_name; ::bluetooth::packet::BitInserter bi{write_name}; ::bluetooth::hci::WriteLocalNameBuilder::Create(name_array)->Serialize(bi); hci->sendHciCommand(write_name); // Check the loopback of the HCI packet ASSERT_NO_FATAL_FAILURE(wait_for_event()); std::vector event; ASSERT_TRUE(event_queue.pop(event)); auto event_view = ::bluetooth::hci::LoopbackCommandView::Create( ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView( std::make_shared>(event)))); ASSERT_TRUE(event_view.IsValid()); std::vector looped_back_command{event_view.GetPayload().begin(), event_view.GetPayload().end()}; ASSERT_EQ(looped_back_command, write_name); if (n == num_packets - 1) { command_size = write_name.size(); } } logger.setTotalBytes(command_size * num_packets * 2); } // Send a SCO data packet (in Loopback mode) and check the response. void BluetoothAidlTest::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 std::vector sco_packet; std::vector payload; for (size_t i = 0; i < size; i++) { payload.push_back(static_cast(i + n)); } ::bluetooth::packet::BitInserter bi{sco_packet}; ::bluetooth::hci::ScoBuilder::Create( handle, ::bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED, payload) ->Serialize(bi); hci->sendScoData(sco_packet); // Check the loopback of the SCO packet std::vector sco_loopback; ASSERT_TRUE( sco_queue.tryPopWithTimeout(sco_loopback, kWaitForScoDataTimeout)); ASSERT_EQ(sco_packet, sco_loopback); } logger.setTotalBytes(num_packets * size * 2); } // Send an ACL data packet (in Loopback mode) and check the response. void BluetoothAidlTest::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 with counting data auto payload = std::make_unique<::bluetooth::packet::RawBuilder>(); for (size_t i = 0; i < size; i++) { payload->AddOctets1(static_cast(i + n)); } std::vector acl_packet; ::bluetooth::packet::BitInserter bi{acl_packet}; ::bluetooth::hci::AclBuilder::Create( handle, ::bluetooth::hci::PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, ::bluetooth::hci::BroadcastFlag::POINT_TO_POINT, std::move(payload)) ->Serialize(bi); hci->sendAclData(acl_packet); std::vector acl_loopback; // Check the loopback of the ACL packet ASSERT_TRUE( acl_queue.tryPopWithTimeout(acl_loopback, kWaitForAclDataTimeout)); ASSERT_EQ(acl_packet, acl_loopback); } logger.setTotalBytes(num_packets * size * 2); } // Return the number of completed packets reported by the controller. int BluetoothAidlTest::wait_for_completed_packets_event(uint16_t handle) { int packets_processed = 0; while (true) { // There should be at least one event. wait_for_event(packets_processed == 0); if (event_queue.empty()) { if (packets_processed == 0) { ALOGW("%s: waitForBluetoothCallback timed out.", __func__); } return packets_processed; } std::vector event; EXPECT_TRUE(event_queue.pop(event)); auto event_view = ::bluetooth::hci::NumberOfCompletedPacketsView::Create( ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView( std::make_shared>(event)))); if (!event_view.IsValid()) { ADD_FAILURE(); return packets_processed; } auto completed_packets = event_view.GetCompletedPackets(); for (const auto& entry : completed_packets) { EXPECT_EQ(handle, entry.connection_handle_); packets_processed += entry.host_num_of_completed_packets_; } } return packets_processed; } // Send local loopback command and initialize SCO and ACL handles. void BluetoothAidlTest::enterLoopbackMode() { std::vector cmd; ::bluetooth::packet::BitInserter bi{cmd}; ::bluetooth::hci::WriteLoopbackModeBuilder::Create( bluetooth::hci::LoopbackMode::ENABLE_LOCAL) ->Serialize(bi); hci->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.empty()) { // Fail if there was no event received or no connections completed. ASSERT_TRUE(command_complete_received); ASSERT_LT(0, connection_event_count); return; } std::vector event; ASSERT_TRUE(event_queue.pop(event)); auto event_view = ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView( std::make_shared>(event))); ASSERT_TRUE(event_view.IsValid()); if (event_view.GetEventCode() == ::bluetooth::hci::EventCode::CONNECTION_COMPLETE) { auto complete_view = ::bluetooth::hci::ConnectionCompleteView::Create(event_view); ASSERT_TRUE(complete_view.IsValid()); switch (complete_view.GetLinkType()) { case ::bluetooth::hci::LinkType::ACL: acl_connection_handles.push_back(complete_view.GetConnectionHandle()); break; case ::bluetooth::hci::LinkType::SCO: sco_connection_handles.push_back(complete_view.GetConnectionHandle()); break; default: ASSERT_EQ(complete_view.GetLinkType(), ::bluetooth::hci::LinkType::ACL); } connection_event_count++; } else { auto command_complete_view = ::bluetooth::hci::WriteLoopbackModeCompleteView::Create( ::bluetooth::hci::CommandCompleteView::Create(event_view)); ASSERT_TRUE(command_complete_view.IsValid()); ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, command_complete_view.GetStatus()); command_complete_received = true; } } } void BluetoothAidlTest::send_and_wait_for_cmd_complete( std::unique_ptr cmd, std::vector& cmd_complete) { std::vector cmd_bytes = cmd->SerializeToBytes(); hci->sendHciCommand(cmd_bytes); auto view = CommandView::Create( PacketView(std::make_shared>(cmd_bytes))); ASSERT_TRUE(view.IsValid()); ALOGI("Waiting for %s[0x%x]", OpCodeText(view.GetOpCode()).c_str(), static_cast(view.GetOpCode())); ASSERT_NO_FATAL_FAILURE( wait_for_command_complete_event(view.GetOpCode(), cmd_complete)); } // Empty test: Initialize()/Close() are called in SetUp()/TearDown(). TEST_P(BluetoothAidlTest, InitializeAndClose) {} // Send an HCI Reset with sendHciCommand and wait for a command complete event. TEST_P(BluetoothAidlTest, HciReset) { std::vector reset; ::bluetooth::packet::BitInserter bi{reset}; ::bluetooth::hci::ResetBuilder::Create()->Serialize(bi); hci->sendHciCommand(reset); wait_and_validate_command_complete_event(::bluetooth::hci::OpCode::RESET); } // Read and check the HCI version of the controller. TEST_P(BluetoothAidlTest, HciVersionTest) { std::vector cmd; ::bluetooth::packet::BitInserter bi{cmd}; ::bluetooth::hci::ReadLocalVersionInformationBuilder::Create()->Serialize(bi); hci->sendHciCommand(cmd); ASSERT_NO_FATAL_FAILURE(wait_for_event()); std::vector event; ASSERT_TRUE(event_queue.pop(event)); auto complete_view = ::bluetooth::hci::ReadLocalVersionInformationCompleteView::Create( ::bluetooth::hci::CommandCompleteView::Create( ::bluetooth::hci::EventView::Create( ::bluetooth::hci::PacketView( std::make_shared>(event))))); ASSERT_TRUE(complete_view.IsValid()); ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, complete_view.GetStatus()); auto version = complete_view.GetLocalVersionInformation(); ASSERT_LE(::bluetooth::hci::HciVersion::V_3_0, version.hci_version_); ASSERT_LE(::bluetooth::hci::LmpVersion::V_3_0, version.lmp_version_); } // Send an unknown HCI command and wait for the error message. TEST_P(BluetoothAidlTest, HciUnknownCommand) { std::vector cmd; ::bluetooth::packet::BitInserter bi{cmd}; ::bluetooth::hci::CommandBuilder::Create( static_cast<::bluetooth::hci::OpCode>(0x3cff), std::make_unique<::bluetooth::packet::RawBuilder>()) ->Serialize(bi); hci->sendHciCommand(cmd); ASSERT_NO_FATAL_FAILURE(wait_for_event()); std::vector event; ASSERT_TRUE(event_queue.pop(event)); auto event_view = ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView( std::make_shared>(event))); ASSERT_TRUE(event_view.IsValid()); switch (event_view.GetEventCode()) { case ::bluetooth::hci::EventCode::COMMAND_COMPLETE: { auto command_complete = ::bluetooth::hci::CommandCompleteView::Create(event_view); ASSERT_TRUE(command_complete.IsValid()); ASSERT_EQ(command_complete.GetPayload()[0], static_cast( ::bluetooth::hci::ErrorCode::UNKNOWN_HCI_COMMAND)); } break; case ::bluetooth::hci::EventCode::COMMAND_STATUS: { auto command_status = ::bluetooth::hci::CommandStatusView::Create(event_view); ASSERT_TRUE(command_status.IsValid()); ASSERT_EQ(command_status.GetStatus(), ::bluetooth::hci::ErrorCode::UNKNOWN_HCI_COMMAND); } break; default: ADD_FAILURE(); } } // Enter loopback mode, but don't send any packets. TEST_P(BluetoothAidlTest, WriteLoopbackMode) { enterLoopbackMode(); } // Enter loopback mode and send a single command. TEST_P(BluetoothAidlTest, LoopbackModeSingleCommand) { setBufferSizes(); enterLoopbackMode(); sendAndCheckHci(1); } // Enter loopback mode and send a single SCO packet. TEST_P(BluetoothAidlTest, LoopbackModeSingleSco) { setBufferSizes(); setSynchronousFlowControlEnable(); enterLoopbackMode(); if (!sco_connection_handles.empty()) { ASSERT_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); } } } // Enter loopback mode and send a single ACL packet. TEST_P(BluetoothAidlTest, LoopbackModeSingleAcl) { setBufferSizes(); enterLoopbackMode(); if (!acl_connection_handles.empty()) { ASSERT_LT(0, max_acl_data_packet_length); sendAndCheckAcl(1, max_acl_data_packet_length - 1, 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); } } ASSERT_GE(acl_cb_count, 1); } // Enter loopback mode and send command packets for bandwidth measurements. TEST_P(BluetoothAidlTest, LoopbackModeCommandBandwidth) { setBufferSizes(); enterLoopbackMode(); sendAndCheckHci(kNumHciCommandsBandwidth); } // Enter loopback mode and send SCO packets for bandwidth measurements. TEST_P(BluetoothAidlTest, LoopbackModeScoBandwidth) { setBufferSizes(); setSynchronousFlowControlEnable(); enterLoopbackMode(); if (!sco_connection_handles.empty()) { ASSERT_LT(0, max_sco_data_packet_length); sendAndCheckSco(kNumScoPacketsBandwidth, max_sco_data_packet_length, sco_connection_handles[0]); int sco_packets_sent = kNumScoPacketsBandwidth; 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); } } } // Enter loopback mode and send packets for ACL bandwidth measurements. TEST_P(BluetoothAidlTest, LoopbackModeAclBandwidth) { setBufferSizes(); enterLoopbackMode(); if (!acl_connection_handles.empty()) { ASSERT_LT(0, max_acl_data_packet_length); sendAndCheckAcl(kNumAclPacketsBandwidth, max_acl_data_packet_length - 1, acl_connection_handles[0]); int acl_packets_sent = kNumAclPacketsBandwidth; 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); } } } // Set all bits in the event mask TEST_P(BluetoothAidlTest, SetEventMask) { std::vector cmd; ::bluetooth::packet::BitInserter bi{cmd}; uint64_t full_mask = UINT64_MAX; ::bluetooth::hci::SetEventMaskBuilder::Create(full_mask)->Serialize(bi); hci->sendHciCommand(cmd); wait_and_validate_command_complete_event( ::bluetooth::hci::OpCode::SET_EVENT_MASK); } // Set all bits in the LE event mask TEST_P(BluetoothAidlTest, SetLeEventMask) { std::vector cmd; ::bluetooth::packet::BitInserter bi{cmd}; uint64_t full_mask = UINT64_MAX; ::bluetooth::hci::LeSetEventMaskBuilder::Create(full_mask)->Serialize(bi); hci->sendHciCommand(cmd); wait_and_validate_command_complete_event( ::bluetooth::hci::OpCode::LE_SET_EVENT_MASK); } // Call initialize twice, second one should fail. TEST_P(BluetoothAidlTest, CallInitializeTwice) { class SecondCb : public aidl::android::hardware::bluetooth::BnBluetoothHciCallbacks { public: ndk::ScopedAStatus initializationComplete(Status status) override { EXPECT_EQ(status, Status::ALREADY_INITIALIZED); init_promise.set_value(); return ScopedAStatus::ok(); }; ndk::ScopedAStatus hciEventReceived( const std::vector& /*event*/) override { ADD_FAILURE(); return ScopedAStatus::ok(); }; ndk::ScopedAStatus aclDataReceived( const std::vector& /*data*/) override { ADD_FAILURE(); return ScopedAStatus::ok(); }; ndk::ScopedAStatus scoDataReceived( const std::vector& /*data*/) override { ADD_FAILURE(); return ScopedAStatus::ok(); }; ndk::ScopedAStatus isoDataReceived( const std::vector& /*data*/) override { ADD_FAILURE(); return ScopedAStatus::ok(); }; std::promise init_promise; }; std::shared_ptr second_cb = ndk::SharedRefBase::make(); ASSERT_NE(second_cb, nullptr); auto future = second_cb->init_promise.get_future(); ASSERT_TRUE(hci->initialize(second_cb).isOk()); auto status = future.wait_for(std::chrono::seconds(1)); ASSERT_EQ(status, std::future_status::ready); } TEST_P(BluetoothAidlTest, Vsr_Bluetooth5Requirements) { std::vector version_event; send_and_wait_for_cmd_complete(ReadLocalVersionInformationBuilder::Create(), version_event); auto version_view = ReadLocalVersionInformationCompleteView::Create( CommandCompleteView::Create(EventView::Create(PacketView( std::make_shared>(version_event))))); ASSERT_TRUE(version_view.IsValid()); ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, version_view.GetStatus()); auto version = version_view.GetLocalVersionInformation(); if (version.hci_version_ < ::bluetooth::hci::HciVersion::V_5_0) { // This test does not apply to controllers below 5.0 return; }; // When HCI version is 5.0, LMP version must also be at least 5.0 ASSERT_GE(static_cast(version.lmp_version_), static_cast(version.hci_version_)); std::vector le_features_event; send_and_wait_for_cmd_complete(LeReadLocalSupportedFeaturesBuilder::Create(), le_features_event); auto le_features_view = LeReadLocalSupportedFeaturesCompleteView::Create( CommandCompleteView::Create(EventView::Create(PacketView( std::make_shared>(le_features_event))))); ASSERT_TRUE(le_features_view.IsValid()); ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, le_features_view.GetStatus()); auto le_features = le_features_view.GetLeFeatures(); ASSERT_TRUE(le_features & static_cast(LLFeaturesBits::LL_PRIVACY)); ASSERT_TRUE(le_features & static_cast(LLFeaturesBits::LE_2M_PHY)); ASSERT_TRUE(le_features & static_cast(LLFeaturesBits::LE_CODED_PHY)); ASSERT_TRUE(le_features & static_cast(LLFeaturesBits::LE_EXTENDED_ADVERTISING)); std::vector num_adv_set_event; send_and_wait_for_cmd_complete( LeReadNumberOfSupportedAdvertisingSetsBuilder::Create(), num_adv_set_event); auto num_adv_set_view = LeReadNumberOfSupportedAdvertisingSetsCompleteView::Create( CommandCompleteView::Create(EventView::Create(PacketView( std::make_shared>(num_adv_set_event))))); ASSERT_TRUE(num_adv_set_view.IsValid()); ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, num_adv_set_view.GetStatus()); auto num_adv_set = num_adv_set_view.GetNumberSupportedAdvertisingSets(); if (isTv() && get_vsr_api_level() == __ANDROID_API_U__) { ASSERT_GE(num_adv_set, kMinLeAdvSetForBt5FoTv); } else { ASSERT_GE(num_adv_set, kMinLeAdvSetForBt5); } std::vector num_resolving_list_event; send_and_wait_for_cmd_complete(LeReadResolvingListSizeBuilder::Create(), num_resolving_list_event); auto num_resolving_list_view = LeReadResolvingListSizeCompleteView::Create( CommandCompleteView::Create(EventView::Create(PacketView( std::make_shared>(num_resolving_list_event))))); ASSERT_TRUE(num_resolving_list_view.IsValid()); ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, num_resolving_list_view.GetStatus()); auto num_resolving_list = num_resolving_list_view.GetResolvingListSize(); ASSERT_GE(num_resolving_list, kMinLeResolvingListForBt5); } GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothAidlTest); INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAidlTest, testing::ValuesIn(android::getAidlHalInstanceNames( IBluetoothHci::descriptor)), android::PrintInstanceNameToString); int main(int argc, char** argv) { ABinderProcess_startThreadPool(); ::testing::InitGoogleTest(&argc, argv); int status = RUN_ALL_TESTS(); ALOGI("Test result = %d", status); return status; }