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.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/log.h"
38 #include "os/thread.h"
39
40 using namespace bluetooth;
41 using namespace std::chrono_literals;
42
43 template <typename T>
CreateCommandView(std::shared_ptr<std::vector<uint8_t>> bytes)44 T CreateCommandView(std::shared_ptr<std::vector<uint8_t>> bytes) {
45 return T::Create(hci::CommandView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
46 }
47
48 template <typename T>
CreateAclCommandView(std::shared_ptr<std::vector<uint8_t>> bytes)49 T CreateAclCommandView(std::shared_ptr<std::vector<uint8_t>> bytes) {
50 return T::Create(CreateCommandView<hci::AclCommandView>(bytes));
51 }
52
53 constexpr uint16_t kConnectionHandle = 123;
54 constexpr size_t kQueueSize = 10;
55
56 constexpr uint16_t kIntervalMin = 0x20;
57 constexpr uint16_t kIntervalMax = 0x40;
58 constexpr uint16_t kLatency = 0x60;
59 constexpr uint16_t kTimeout = 0x80;
60 constexpr uint16_t kContinuationNumber = 0x32;
61
62 namespace bluetooth::hci::acl_manager {
63
64 namespace {
65
66 class TestLeConnectionManagementCallbacks : public hci::acl_manager::LeConnectionManagementCallbacks {
OnConnectionUpdate(hci::ErrorCode,uint16_t,uint16_t,uint16_t)67 void OnConnectionUpdate(
68 hci::ErrorCode /* hci_status */,
69 uint16_t /* connection_interval */,
70 uint16_t /* connection_latency */,
71 uint16_t /* supervision_timeout */) override {}
OnDataLengthChange(uint16_t,uint16_t,uint16_t,uint16_t)72 virtual void OnDataLengthChange(
73 uint16_t /* tx_octets */,
74 uint16_t /* tx_time */,
75 uint16_t /* rx_octets */,
76 uint16_t /* rx_time */) override {}
OnDisconnection(hci::ErrorCode)77 virtual void OnDisconnection(hci::ErrorCode /* reason */) override {}
OnReadRemoteVersionInformationComplete(hci::ErrorCode,uint8_t,uint16_t,uint16_t)78 virtual void OnReadRemoteVersionInformationComplete(
79 hci::ErrorCode /* hci_status */,
80 uint8_t /* lmp_version */,
81 uint16_t /* manufacturer_name */,
82 uint16_t /* sub_version */) override {}
OnLeReadRemoteFeaturesComplete(hci::ErrorCode,uint64_t)83 virtual void OnLeReadRemoteFeaturesComplete(
84 hci::ErrorCode /* hci_status */, uint64_t /* features */) override {}
OnPhyUpdate(hci::ErrorCode,uint8_t,uint8_t)85 virtual void OnPhyUpdate(
86 hci::ErrorCode /* hci_status */, uint8_t /* tx_phy */, uint8_t /* rx_phy */) override {}
87 MOCK_METHOD(
88 void,
89 OnLeSubrateChange,
90 (hci::ErrorCode hci_status,
91 uint16_t subrate_factor,
92 uint16_t peripheral_latency,
93 uint16_t continuation_number,
94 uint16_t supervision_timeout),
95 (override));
96
97 // give access to private method for test:
98 friend class LeAclConnectionTest;
99 FRIEND_TEST(LeAclConnectionTest, LeSubrateRequest_success);
100 FRIEND_TEST(LeAclConnectionTest, LeSubrateRequest_error);
101 };
102
103 class TestLeAclConnectionInterface : public hci::LeAclConnectionInterface {
104 private:
EnqueueCommand(std::unique_ptr<hci::AclCommandBuilder> command,common::ContextualOnceCallback<void (hci::CommandStatusView)> on_status)105 void EnqueueCommand(
106 std::unique_ptr<hci::AclCommandBuilder> command,
107 common::ContextualOnceCallback<void(hci::CommandStatusView)> on_status) override {
108 const std::lock_guard<std::mutex> lock(command_queue_mutex_);
109 command_queue_.push(std::move(command));
110 command_status_callbacks.push_back(std::move(on_status));
111 if (command_promise_ != nullptr) {
112 std::promise<void>* prom = command_promise_.release();
113 prom->set_value();
114 delete prom;
115 }
116 }
117
EnqueueCommand(std::unique_ptr<hci::AclCommandBuilder> command,common::ContextualOnceCallback<void (hci::CommandCompleteView)> on_complete)118 void EnqueueCommand(
119 std::unique_ptr<hci::AclCommandBuilder> command,
120 common::ContextualOnceCallback<void(hci::CommandCompleteView)> on_complete) override {
121 const std::lock_guard<std::mutex> lock(command_queue_mutex_);
122 command_queue_.push(std::move(command));
123 command_complete_callbacks.push_back(std::move(on_complete));
124 if (command_promise_ != nullptr) {
125 std::promise<void>* prom = command_promise_.release();
126 prom->set_value();
127 delete prom;
128 }
129 }
130
131 public:
132 virtual ~TestLeAclConnectionInterface() = default;
133
DequeueCommand()134 std::unique_ptr<hci::CommandBuilder> DequeueCommand() {
135 const std::lock_guard<std::mutex> lock(command_queue_mutex_);
136 auto packet = std::move(command_queue_.front());
137 command_queue_.pop();
138 return std::move(packet);
139 }
140
DequeueCommandBytes()141 std::shared_ptr<std::vector<uint8_t>> DequeueCommandBytes() {
142 auto command = DequeueCommand();
143 auto bytes = std::make_shared<std::vector<uint8_t>>();
144 packet::BitInserter bi(*bytes);
145 command->Serialize(bi);
146 return bytes;
147 }
148
DequeueStatusCallback()149 common::ContextualOnceCallback<void(hci::CommandStatusView)> DequeueStatusCallback() {
150 auto on_status = std::move(command_status_callbacks.front());
151 command_status_callbacks.pop_front();
152 return std::move(on_status);
153 }
154
IsPacketQueueEmpty() const155 bool IsPacketQueueEmpty() const {
156 const std::lock_guard<std::mutex> lock(command_queue_mutex_);
157 return command_queue_.empty();
158 }
159
NumberOfQueuedCommands() const160 size_t NumberOfQueuedCommands() const {
161 const std::lock_guard<std::mutex> lock(command_queue_mutex_);
162 return command_queue_.size();
163 }
164
165 private:
166 std::list<common::ContextualOnceCallback<void(hci::CommandCompleteView)>> command_complete_callbacks;
167 std::list<common::ContextualOnceCallback<void(hci::CommandStatusView)>> command_status_callbacks;
168 std::queue<std::unique_ptr<hci::CommandBuilder>> command_queue_;
169 mutable std::mutex command_queue_mutex_;
170 std::unique_ptr<std::promise<void>> command_promise_;
171 std::unique_ptr<std::future<void>> command_future_;
172 };
173
174 class LeAclConnectionTest : public ::testing::Test {
175 protected:
SetUp()176 void SetUp() override {
177 thread_ = new os::Thread("thread", os::Thread::Priority::NORMAL);
178 handler_ = new os::Handler(thread_);
179 queue_ = std::make_shared<LeAclConnection::Queue>(kQueueSize);
180 sync_handler();
181 connection_ = new LeAclConnection(
182 queue_,
183 &le_acl_connection_interface_,
184 kConnectionHandle,
185 DataAsCentral{address_1},
186 address_2);
187 connection_->RegisterCallbacks(&callbacks_, handler_);
188 }
189
TearDown()190 void TearDown() override {
191 handler_->Clear();
192 delete connection_;
193 delete handler_;
194 delete thread_;
195 }
196
sync_handler()197 void sync_handler() {
198 log::assert_that(thread_ != nullptr, "assert failed: thread_ != nullptr");
199 log::assert_that(
200 thread_->GetReactor()->WaitForIdle(2s),
201 "assert failed: thread_->GetReactor()->WaitForIdle(2s)");
202 }
203
204 AddressWithType address_1 =
205 AddressWithType(Address{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}, AddressType::RANDOM_DEVICE_ADDRESS);
206 AddressWithType address_2 =
207 AddressWithType(Address{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}, AddressType::PUBLIC_DEVICE_ADDRESS);
208 os::Handler* handler_{nullptr};
209 os::Thread* thread_{nullptr};
210 std::shared_ptr<LeAclConnection::Queue> queue_;
211
212 TestLeAclConnectionInterface le_acl_connection_interface_;
213 TestLeConnectionManagementCallbacks callbacks_;
214 LeAclConnection* connection_;
215 };
216
TEST_F(LeAclConnectionTest,simple)217 TEST_F(LeAclConnectionTest, simple) {
218 // empty
219 }
220
TEST_F(LeAclConnectionTest,LeSubrateRequest_success)221 TEST_F(LeAclConnectionTest, LeSubrateRequest_success) {
222 connection_->LeSubrateRequest(kIntervalMin, kIntervalMax, kLatency, kContinuationNumber, kTimeout);
223
224 auto command = CreateAclCommandView<LeSubrateRequestView>(le_acl_connection_interface_.DequeueCommandBytes());
225 ASSERT_TRUE(command.IsValid());
226 ASSERT_EQ(kIntervalMin, command.GetSubrateMin());
227 ASSERT_EQ(kIntervalMax, command.GetSubrateMax());
228 ASSERT_EQ(kLatency, command.GetMaxLatency());
229 ASSERT_EQ(kContinuationNumber, command.GetContinuationNumber());
230 ASSERT_EQ(kTimeout, command.GetSupervisionTimeout());
231
232 EXPECT_CALL(callbacks_, OnLeSubrateChange).Times(0);
233
234 auto status_builder = LeSubrateRequestStatusBuilder::Create(ErrorCode::SUCCESS, 0x01);
235 hci::EventView event = hci::EventView::Create(GetPacketView(std::move(status_builder)));
236 hci::CommandStatusView command_status = hci::CommandStatusView::Create(event);
237 auto on_status = le_acl_connection_interface_.DequeueStatusCallback();
238 on_status(command_status);
239 sync_handler();
240 }
241
TEST_F(LeAclConnectionTest,LeSubrateRequest_error)242 TEST_F(LeAclConnectionTest, LeSubrateRequest_error) {
243 EXPECT_CALL(callbacks_, OnLeSubrateChange(ErrorCode::UNKNOWN_HCI_COMMAND, 0, 0, 0, 0));
244
245 connection_->LeSubrateRequest(kIntervalMin, kIntervalMax, kLatency, kContinuationNumber, kTimeout);
246
247 auto command = CreateAclCommandView<LeSubrateRequestView>(le_acl_connection_interface_.DequeueCommandBytes());
248 ASSERT_TRUE(command.IsValid());
249 ASSERT_EQ(kIntervalMin, command.GetSubrateMin());
250 ASSERT_EQ(kIntervalMax, command.GetSubrateMax());
251 ASSERT_EQ(kLatency, command.GetMaxLatency());
252 ASSERT_EQ(kContinuationNumber, command.GetContinuationNumber());
253 ASSERT_EQ(kTimeout, command.GetSupervisionTimeout());
254
255 auto status_builder = LeSubrateRequestStatusBuilder::Create(ErrorCode::UNKNOWN_HCI_COMMAND, 0x01);
256 hci::EventView event = hci::EventView::Create(GetPacketView(std::move(status_builder)));
257 hci::CommandStatusView command_status = hci::CommandStatusView::Create(event);
258 auto on_status = le_acl_connection_interface_.DequeueStatusCallback();
259 on_status(std::move(command_status));
260 sync_handler();
261 }
262
263 } // namespace
264 } // namespace bluetooth::hci::acl_manager
265