1 /*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "hci/acl_manager/le_acl_connection.h"
18
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21
22 #include <chrono>
23 #include <cstdint>
24 #include <future>
25 #include <list>
26 #include <memory>
27 #include <mutex>
28 #include <queue>
29 #include <vector>
30
31 #include "hci/acl_manager/le_connection_management_callbacks_mock.h"
32 #include "hci/address_with_type.h"
33 #include "hci/hci_layer_fake.h"
34 #include "hci/hci_packets.h"
35 #include "hci/le_acl_connection_interface.h"
36 #include "os/handler.h"
37 #include "os/thread.h"
38
39 using namespace bluetooth;
40 using namespace std::chrono_literals;
41
42 template <typename T>
CreateCommandView(std::shared_ptr<std::vector<uint8_t>> bytes)43 T CreateCommandView(std::shared_ptr<std::vector<uint8_t>> bytes) {
44 return T::Create(hci::CommandView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
45 }
46
47 template <typename T>
CreateAclCommandView(std::shared_ptr<std::vector<uint8_t>> bytes)48 T CreateAclCommandView(std::shared_ptr<std::vector<uint8_t>> bytes) {
49 return T::Create(CreateCommandView<hci::AclCommandView>(bytes));
50 }
51
52 constexpr uint16_t kConnectionHandle = 123;
53 constexpr size_t kQueueSize = 10;
54
55 constexpr uint16_t kIntervalMin = 0x20;
56 constexpr uint16_t kIntervalMax = 0x40;
57 constexpr uint16_t kLatency = 0x60;
58 constexpr uint16_t kTimeout = 0x80;
59 constexpr uint16_t kContinuationNumber = 0x32;
60
61 namespace bluetooth::hci::acl_manager {
62
63 namespace {
64 class TestLeAclConnectionInterface : public hci::LeAclConnectionInterface {
65 private:
EnqueueCommand(std::unique_ptr<hci::AclCommandBuilder> command,common::ContextualOnceCallback<void (hci::CommandStatusView)> on_status)66 void EnqueueCommand(
67 std::unique_ptr<hci::AclCommandBuilder> command,
68 common::ContextualOnceCallback<void(hci::CommandStatusView)> on_status) override {
69 const std::lock_guard<std::mutex> lock(command_queue_mutex_);
70 command_queue_.push(std::move(command));
71 command_status_callbacks.push_back(std::move(on_status));
72 if (command_promise_ != nullptr) {
73 std::promise<void>* prom = command_promise_.release();
74 prom->set_value();
75 delete prom;
76 }
77 }
78
EnqueueCommand(std::unique_ptr<hci::AclCommandBuilder> command,common::ContextualOnceCallback<void (hci::CommandCompleteView)> on_complete)79 void EnqueueCommand(
80 std::unique_ptr<hci::AclCommandBuilder> command,
81 common::ContextualOnceCallback<void(hci::CommandCompleteView)> on_complete) override {
82 const std::lock_guard<std::mutex> lock(command_queue_mutex_);
83 command_queue_.push(std::move(command));
84 command_complete_callbacks.push_back(std::move(on_complete));
85 if (command_promise_ != nullptr) {
86 std::promise<void>* prom = command_promise_.release();
87 prom->set_value();
88 delete prom;
89 }
90 }
91
EnqueueCommand(std::unique_ptr<hci::AclCommandBuilder>,common::ContextualOnceCallback<void (hci::CommandStatusOrCompleteView)>)92 void EnqueueCommand(
93 std::unique_ptr<hci::AclCommandBuilder> /* command */,
94 common::ContextualOnceCallback<
95 void(hci::CommandStatusOrCompleteView)> /* on_status_or_complete */) override {
96 FAIL();
97 }
98
99 public:
100 virtual ~TestLeAclConnectionInterface() = default;
101
DequeueCommand()102 std::unique_ptr<hci::CommandBuilder> DequeueCommand() {
103 const std::lock_guard<std::mutex> lock(command_queue_mutex_);
104 auto packet = std::move(command_queue_.front());
105 command_queue_.pop();
106 return packet;
107 }
108
DequeueCommandBytes()109 std::shared_ptr<std::vector<uint8_t>> DequeueCommandBytes() {
110 auto command = DequeueCommand();
111 auto bytes = std::make_shared<std::vector<uint8_t>>();
112 packet::BitInserter bi(*bytes);
113 command->Serialize(bi);
114 return bytes;
115 }
116
DequeueStatusCallback()117 common::ContextualOnceCallback<void(hci::CommandStatusView)> DequeueStatusCallback() {
118 auto on_status = std::move(command_status_callbacks.front());
119 command_status_callbacks.pop_front();
120 return on_status;
121 }
122
IsPacketQueueEmpty() const123 bool IsPacketQueueEmpty() const {
124 const std::lock_guard<std::mutex> lock(command_queue_mutex_);
125 return command_queue_.empty();
126 }
127
NumberOfQueuedCommands() const128 size_t NumberOfQueuedCommands() const {
129 const std::lock_guard<std::mutex> lock(command_queue_mutex_);
130 return command_queue_.size();
131 }
132
133 private:
134 std::list<common::ContextualOnceCallback<void(hci::CommandCompleteView)>>
135 command_complete_callbacks;
136 std::list<common::ContextualOnceCallback<void(hci::CommandStatusView)>> command_status_callbacks;
137 std::queue<std::unique_ptr<hci::CommandBuilder>> command_queue_;
138 mutable std::mutex command_queue_mutex_;
139 std::unique_ptr<std::promise<void>> command_promise_;
140 std::unique_ptr<std::future<void>> command_future_;
141 };
142
143 class LeAclConnectionTest : public ::testing::Test {
144 protected:
SetUp()145 void SetUp() override {
146 thread_ = new os::Thread("thread", os::Thread::Priority::NORMAL);
147 handler_ = new os::Handler(thread_);
148 queue_ = std::make_shared<LeAclConnection::Queue>(kQueueSize);
149 sync_handler();
150 connection_ = new LeAclConnection(queue_, &le_acl_connection_interface_, kConnectionHandle,
151 DataAsCentral{address_1}, address_2);
152 connection_->RegisterCallbacks(&callbacks_, handler_);
153 }
154
TearDown()155 void TearDown() override {
156 handler_->Clear();
157 delete connection_;
158 delete handler_;
159 delete thread_;
160 }
161
sync_handler()162 void sync_handler() {
163 log::assert_that(thread_ != nullptr, "assert failed: thread_ != nullptr");
164 log::assert_that(thread_->GetReactor()->WaitForIdle(2s),
165 "assert failed: thread_->GetReactor()->WaitForIdle(2s)");
166 }
167
168 AddressWithType address_1 = AddressWithType(Address{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}},
169 AddressType::RANDOM_DEVICE_ADDRESS);
170 AddressWithType address_2 = AddressWithType(Address{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}},
171 AddressType::PUBLIC_DEVICE_ADDRESS);
172 os::Handler* handler_{nullptr};
173 os::Thread* thread_{nullptr};
174 std::shared_ptr<LeAclConnection::Queue> queue_;
175
176 TestLeAclConnectionInterface le_acl_connection_interface_;
177 MockLeConnectionManagementCallbacks callbacks_;
178 LeAclConnection* connection_;
179 };
180
TEST_F(LeAclConnectionTest,simple)181 TEST_F(LeAclConnectionTest, simple) {
182 // empty
183 }
184
TEST_F(LeAclConnectionTest,LeSubrateRequest_success)185 TEST_F(LeAclConnectionTest, LeSubrateRequest_success) {
186 connection_->LeSubrateRequest(kIntervalMin, kIntervalMax, kLatency, kContinuationNumber,
187 kTimeout);
188
189 auto command = CreateAclCommandView<LeSubrateRequestView>(
190 le_acl_connection_interface_.DequeueCommandBytes());
191 ASSERT_TRUE(command.IsValid());
192 ASSERT_EQ(kIntervalMin, command.GetSubrateMin());
193 ASSERT_EQ(kIntervalMax, command.GetSubrateMax());
194 ASSERT_EQ(kLatency, command.GetMaxLatency());
195 ASSERT_EQ(kContinuationNumber, command.GetContinuationNumber());
196 ASSERT_EQ(kTimeout, command.GetSupervisionTimeout());
197
198 EXPECT_CALL(callbacks_, OnLeSubrateChange).Times(0);
199
200 auto status_builder = LeSubrateRequestStatusBuilder::Create(ErrorCode::SUCCESS, 0x01);
201 hci::EventView event = hci::EventView::Create(GetPacketView(std::move(status_builder)));
202 hci::CommandStatusView command_status = hci::CommandStatusView::Create(event);
203 auto on_status = le_acl_connection_interface_.DequeueStatusCallback();
204 on_status(command_status);
205 sync_handler();
206 }
207
TEST_F(LeAclConnectionTest,LeSubrateRequest_error)208 TEST_F(LeAclConnectionTest, LeSubrateRequest_error) {
209 EXPECT_CALL(callbacks_, OnLeSubrateChange(ErrorCode::UNKNOWN_HCI_COMMAND, 0, 0, 0, 0));
210
211 connection_->LeSubrateRequest(kIntervalMin, kIntervalMax, kLatency, kContinuationNumber,
212 kTimeout);
213
214 auto command = CreateAclCommandView<LeSubrateRequestView>(
215 le_acl_connection_interface_.DequeueCommandBytes());
216 ASSERT_TRUE(command.IsValid());
217 ASSERT_EQ(kIntervalMin, command.GetSubrateMin());
218 ASSERT_EQ(kIntervalMax, command.GetSubrateMax());
219 ASSERT_EQ(kLatency, command.GetMaxLatency());
220 ASSERT_EQ(kContinuationNumber, command.GetContinuationNumber());
221 ASSERT_EQ(kTimeout, command.GetSupervisionTimeout());
222
223 auto status_builder = LeSubrateRequestStatusBuilder::Create(ErrorCode::UNKNOWN_HCI_COMMAND, 0x01);
224 hci::EventView event = hci::EventView::Create(GetPacketView(std::move(status_builder)));
225 hci::CommandStatusView command_status = hci::CommandStatusView::Create(event);
226 auto on_status = le_acl_connection_interface_.DequeueStatusCallback();
227 on_status(std::move(command_status));
228 sync_handler();
229 }
230
231 } // namespace
232 } // namespace bluetooth::hci::acl_manager
233