blob: d6f74fc4856f836db733609b0c569f06233d00ee [file] [log] [blame]
Myles Watsone4501e52022-09-30 06:20:50 -07001/*
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#define LOG_TAG "bt_h4_unittest"
18
19#include "h4_protocol.h"
20
21#include <gmock/gmock.h>
22#include <gtest/gtest.h>
23#include <log/log.h>
24#include <sys/socket.h>
25#include <sys/types.h>
26#include <unistd.h>
27
28#include <cstdint>
29#include <cstring>
30#include <future>
31#include <vector>
32
33#include "async_fd_watcher.h"
34#include "log/log.h"
35
36using android::hardware::bluetooth::async::AsyncFdWatcher;
37using namespace android::hardware::bluetooth::hci;
38using ::testing::Eq;
39
40static char sample_data1[100] = "A point is that which has no part.";
41static char sample_data2[100] = "A line is breadthless length.";
42static char sample_data3[100] = "The ends of a line are points.";
43static char sample_data4[100] =
44 "A plane surface is a surface which lies evenly with the straight ...";
45static char acl_data[100] =
46 "A straight line is a line which lies evenly with the points on itself.";
47static char sco_data[100] =
48 "A surface is that which has length and breadth only.";
49static char event_data[100] = "The edges of a surface are lines.";
50static char iso_data[100] =
51 "A plane angle is the inclination to one another of two lines in a ...";
52
53MATCHER_P3(PacketMatches, header_, header_length, payload,
54 "Match header_length bytes of header and then the payload") {
55 size_t payload_length = strlen(payload);
56 if (header_length + payload_length != arg.size()) {
57 return false;
58 }
59
60 if (memcmp(header_, arg.data(), header_length) != 0) {
61 return false;
62 }
63
64 return memcmp(payload, arg.data() + header_length, payload_length) == 0;
65};
66
67ACTION_P(Notify, barrier) {
68 ALOGD("%s", __func__);
69 barrier->set_value();
70}
71
72class H4ProtocolTest : public ::testing::Test {
73 protected:
74 void SetUp() override {
75 ALOGD("%s", __func__);
76
77 int sockfd[2];
78 socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
79 chip_uart_fd_ = sockfd[1];
80 stack_uart_fd_ = sockfd[0];
81 h4_hci_ = std::make_shared<H4Protocol>(
82 stack_uart_fd_, cmd_cb_.AsStdFunction(), acl_cb_.AsStdFunction(),
83 sco_cb_.AsStdFunction(), event_cb_.AsStdFunction(),
84 iso_cb_.AsStdFunction(), disconnect_cb_.AsStdFunction());
85 }
86
87 void TearDown() override {
88 close(stack_uart_fd_);
89 close(chip_uart_fd_);
90 }
91
92 virtual void CallDataReady() { h4_hci_->OnDataReady(); }
93
94 void SendAndReadUartOutbound(PacketType type, char* data) {
95 ALOGD("%s sending", __func__);
96 int data_length = strlen(data);
97 h4_hci_->Send(type, (uint8_t*)data, data_length);
98
99 int uart_length = data_length + 1; // + 1 for data type code
100 int i;
101
102 ALOGD("%s reading", __func__);
103 for (i = 0; i < uart_length; i++) {
104 fd_set read_fds;
105 FD_ZERO(&read_fds);
106 FD_SET(chip_uart_fd_, &read_fds);
107 TEMP_FAILURE_RETRY(
108 select(chip_uart_fd_ + 1, &read_fds, nullptr, nullptr, nullptr));
109
110 char byte;
111 TEMP_FAILURE_RETRY(read(chip_uart_fd_, &byte, 1));
112
113 EXPECT_EQ(i == 0 ? static_cast<uint8_t>(type) : data[i - 1], byte);
114 }
115
116 EXPECT_EQ(i, uart_length);
117 }
118
119 void ExpectInboundAclData(char* payload, std::promise<void>* promise) {
120 // h4 type[1] + handle[2] + size[2]
121 header_[0] = static_cast<uint8_t>(PacketType::ACL_DATA);
122 header_[1] = 19;
123 header_[2] = 92;
124 int length = strlen(payload);
125 header_[3] = length & 0xFF;
126 header_[4] = (length >> 8) & 0xFF;
127 ALOGD("(%d bytes) %s", length, payload);
128
129 EXPECT_CALL(acl_cb_,
130 Call(PacketMatches(header_ + 1, kAclHeaderSize, payload)))
131 .WillOnce(Notify(promise));
132 }
133
134 void WaitForTimeout(size_t timeout_ms, std::promise<void>* promise) {
135 auto future = promise->get_future();
136 auto status = future.wait_for(std::chrono::milliseconds(timeout_ms));
137 EXPECT_EQ(status, std::future_status::ready);
138 }
139
140 void WriteInboundAclData(char* payload) {
141 // Use the header_ computed in ExpectInboundAclData
142 TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kAclHeaderSize + 1));
143 TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
144 }
145
146 void ExpectInboundScoData(char* payload, std::promise<void>* promise) {
147 // h4 type[1] + handle[2] + size[1]
148 header_[0] = static_cast<uint8_t>(PacketType::SCO_DATA);
149 header_[1] = 20;
150 header_[2] = 17;
151 header_[3] = strlen(payload) & 0xFF;
152 EXPECT_CALL(sco_cb_,
153 Call(PacketMatches(header_ + 1, kScoHeaderSize, payload)))
154 .WillOnce(Notify(promise));
155 }
156
157 void WriteInboundScoData(char* payload) {
158 // Use the header_ computed in ExpectInboundScoData
159 ALOGD("%s writing", __func__);
160 TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kScoHeaderSize + 1));
161 TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
162 }
163
164 void ExpectInboundEvent(char* payload, std::promise<void>* promise) {
165 // h4 type[1] + event_code[1] + size[1]
166 header_[0] = static_cast<uint8_t>(PacketType::EVENT);
167 header_[1] = 9;
168 header_[2] = strlen(payload) & 0xFF;
169 EXPECT_CALL(event_cb_,
170 Call(PacketMatches(header_ + 1, kEventHeaderSize, payload)))
171 .WillOnce(Notify(promise));
172 }
173
174 void WriteInboundEvent(char* payload) {
175 // Use the header_ computed in ExpectInboundEvent
176 char preamble[3] = {static_cast<uint8_t>(PacketType::EVENT), 9, 0};
177 preamble[2] = strlen(payload) & 0xFF;
178 ALOGD("%s writing", __func__);
179 TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kEventHeaderSize + 1));
180 TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
181 }
182
183 void ExpectInboundIsoData(char* payload, std::promise<void>* promise) {
184 // h4 type[1] + handle[2] + size[1]
185 header_[0] = static_cast<uint8_t>(PacketType::ISO_DATA);
186 header_[1] = 19;
187 header_[2] = 92;
188 int length = strlen(payload);
189 header_[3] = length & 0xFF;
190 header_[4] = (length >> 8) & 0x3F;
191
192 EXPECT_CALL(iso_cb_,
193 Call(PacketMatches(header_ + 1, kIsoHeaderSize, payload)))
194 .WillOnce(Notify(promise));
195 }
196
197 void WriteInboundIsoData(char* payload) {
198 // Use the header_ computed in ExpectInboundIsoData
199 ALOGD("%s writing", __func__);
200 TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kIsoHeaderSize + 1));
201 TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
202 }
203
204 void WriteAndExpectManyInboundAclDataPackets(char* payload) {
205 size_t kNumPackets = 20;
206 // h4 type[1] + handle[2] + size[2]
207 char preamble[5] = {static_cast<uint8_t>(PacketType::ACL_DATA), 19, 92, 0,
208 0};
209 int length = strlen(payload);
210 preamble[3] = length & 0xFF;
211 preamble[4] = (length >> 8) & 0xFF;
212
213 EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, sizeof(preamble) - 1,
214 payload)))
215 .Times(kNumPackets);
216
217 for (size_t i = 0; i < kNumPackets; i++) {
218 TEMP_FAILURE_RETRY(write(chip_uart_fd_, preamble, sizeof(preamble)));
219 TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
220 }
221
222 CallDataReady();
223 }
224
225 testing::MockFunction<void(const std::vector<uint8_t>&)> cmd_cb_;
226 testing::MockFunction<void(const std::vector<uint8_t>&)> event_cb_;
227 testing::MockFunction<void(const std::vector<uint8_t>&)> acl_cb_;
228 testing::MockFunction<void(const std::vector<uint8_t>&)> sco_cb_;
229 testing::MockFunction<void(const std::vector<uint8_t>&)> iso_cb_;
230 testing::MockFunction<void(void)> disconnect_cb_;
231 std::shared_ptr<H4Protocol> h4_hci_;
232 int chip_uart_fd_;
233 int stack_uart_fd_;
234
235 char header_[5];
236};
237
238// Test sending data sends correct data onto the UART
239TEST_F(H4ProtocolTest, TestSends) {
240 SendAndReadUartOutbound(PacketType::COMMAND, sample_data1);
241 SendAndReadUartOutbound(PacketType::ACL_DATA, sample_data2);
242 SendAndReadUartOutbound(PacketType::SCO_DATA, sample_data3);
243 SendAndReadUartOutbound(PacketType::ISO_DATA, sample_data4);
244}
245
246// Ensure we properly parse data coming from the UART
247TEST_F(H4ProtocolTest, TestReads) {
248 std::promise<void> acl_promise;
249 std::promise<void> sco_promise;
250 std::promise<void> event_promise;
251 std::promise<void> iso_promise;
252
253 ExpectInboundAclData(acl_data, &acl_promise);
254 WriteInboundAclData(acl_data);
255 CallDataReady();
256 ExpectInboundScoData(sco_data, &sco_promise);
257 WriteInboundScoData(sco_data);
258 CallDataReady();
259 ExpectInboundEvent(event_data, &event_promise);
260 WriteInboundEvent(event_data);
261 CallDataReady();
262 ExpectInboundIsoData(iso_data, &iso_promise);
263 WriteInboundIsoData(iso_data);
264 CallDataReady();
265
266 WaitForTimeout(100, &acl_promise);
267 WaitForTimeout(100, &sco_promise);
268 WaitForTimeout(100, &event_promise);
269 WaitForTimeout(100, &iso_promise);
270}
271
272TEST_F(H4ProtocolTest, TestMultiplePackets) {
273 WriteAndExpectManyInboundAclDataPackets(sco_data);
274}
275
276TEST_F(H4ProtocolTest, TestDisconnect) {
277 EXPECT_CALL(disconnect_cb_, Call());
278 close(chip_uart_fd_);
279 CallDataReady();
280}
281
282TEST_F(H4ProtocolTest, TestPartialWrites) {
283 size_t payload_len = strlen(acl_data);
284 const size_t kNumIntervals = payload_len + 1;
285 // h4 type[1] + handle[2] + size[2]
286 header_[0] = static_cast<uint8_t>(PacketType::ACL_DATA);
287 header_[1] = 19;
288 header_[2] = 92;
289 header_[3] = payload_len & 0xFF;
290 header_[4] = (payload_len >> 8) & 0xFF;
291
292 EXPECT_CALL(acl_cb_,
293 Call(PacketMatches(header_ + 1, sizeof(header_) - 1, acl_data)))
294 .Times(kNumIntervals);
295
296 for (size_t interval = 1; interval < kNumIntervals + 1; interval++) {
297 // Use the header_ data that expect already set up.
298 if (interval < kAclHeaderSize) {
299 TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, interval));
300 CallDataReady();
301 TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_ + interval,
302 kAclHeaderSize + 1 - interval));
303 CallDataReady();
304 } else {
305 TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kAclHeaderSize + 1));
306 CallDataReady();
307 }
308
309 for (size_t bytes = 0; bytes + interval <= payload_len; bytes += interval) {
310 TEMP_FAILURE_RETRY(write(chip_uart_fd_, acl_data + bytes, interval));
311 CallDataReady();
312 }
313 size_t extra_bytes = payload_len % interval;
314 if (extra_bytes) {
315 TEMP_FAILURE_RETRY(write(
316 chip_uart_fd_, acl_data + payload_len - extra_bytes, extra_bytes));
317 CallDataReady();
318 }
319 }
320}
321
322class H4ProtocolAsyncTest : public H4ProtocolTest {
323 protected:
324 void SetUp() override {
325 H4ProtocolTest::SetUp();
326 fd_watcher_.WatchFdForNonBlockingReads(
327 stack_uart_fd_, [this](int) { h4_hci_->OnDataReady(); });
328 }
329
330 void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
331
332 void CallDataReady() override {
333 // The Async test can't call data ready.
334 FAIL();
335 }
336
337 void SendAndReadUartOutbound(PacketType type, char* data) {
338 ALOGD("%s sending", __func__);
339 int data_length = strlen(data);
340 h4_hci_->Send(type, (uint8_t*)data, data_length);
341
342 int uart_length = data_length + 1; // + 1 for data type code
343 int i;
344
345 ALOGD("%s reading", __func__);
346 for (i = 0; i < uart_length; i++) {
347 fd_set read_fds;
348 FD_ZERO(&read_fds);
349 FD_SET(chip_uart_fd_, &read_fds);
350 TEMP_FAILURE_RETRY(
351 select(chip_uart_fd_ + 1, &read_fds, nullptr, nullptr, nullptr));
352
353 char byte;
354 TEMP_FAILURE_RETRY(read(chip_uart_fd_, &byte, 1));
355
356 EXPECT_EQ(i == 0 ? static_cast<uint8_t>(type) : data[i - 1], byte);
357 }
358
359 EXPECT_EQ(i, uart_length);
360 }
361
362 void WriteAndExpectInboundAclData(char* payload) {
363 std::promise<void> promise;
364 ExpectInboundAclData(payload, &promise);
365 WriteInboundAclData(payload);
366 WaitForTimeout(100, &promise);
367 }
368
369 void WriteAndExpectInboundScoData(char* payload) {
370 std::promise<void> promise;
371 ExpectInboundScoData(payload, &promise);
372 WriteInboundScoData(payload);
373 WaitForTimeout(100, &promise);
374 }
375
376 void WriteAndExpectInboundEvent(char* payload) {
377 std::promise<void> promise;
378 ExpectInboundEvent(payload, &promise);
379 WriteInboundEvent(payload);
380 WaitForTimeout(100, &promise);
381 }
382
383 void WriteAndExpectInboundIsoData(char* payload) {
384 std::promise<void> promise;
385 ExpectInboundIsoData(payload, &promise);
386 WriteInboundIsoData(payload);
387 WaitForTimeout(100, &promise);
388 }
389
390 void WriteAndExpectManyInboundAclDataPackets(char* payload) {
391 const size_t kNumPackets = 20;
392 // h4 type[1] + handle[2] + size[2]
393 char preamble[5] = {static_cast<uint8_t>(PacketType::ACL_DATA), 19, 92, 0,
394 0};
395 int length = strlen(payload);
396 preamble[3] = length & 0xFF;
397 preamble[4] = (length >> 8) & 0xFF;
398
399 EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, sizeof(preamble) - 1,
400 payload)))
401 .Times(kNumPackets);
402
403 for (size_t i = 0; i < kNumPackets; i++) {
404 TEMP_FAILURE_RETRY(write(chip_uart_fd_, preamble, sizeof(preamble)));
405 TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
406 }
407
408 WriteAndExpectInboundEvent(event_data);
409 }
410
411 AsyncFdWatcher fd_watcher_;
412};
413
414// Test sending data sends correct data onto the UART
415TEST_F(H4ProtocolAsyncTest, TestSends) {
416 SendAndReadUartOutbound(PacketType::COMMAND, sample_data1);
417 SendAndReadUartOutbound(PacketType::ACL_DATA, sample_data2);
418 SendAndReadUartOutbound(PacketType::SCO_DATA, sample_data3);
419 SendAndReadUartOutbound(PacketType::ISO_DATA, sample_data4);
420}
421
422// Ensure we properly parse data coming from the UART
423TEST_F(H4ProtocolAsyncTest, TestReads) {
424 WriteAndExpectInboundAclData(acl_data);
425 WriteAndExpectInboundScoData(sco_data);
426 WriteAndExpectInboundEvent(event_data);
427 WriteAndExpectInboundIsoData(iso_data);
428}
429
430TEST_F(H4ProtocolAsyncTest, TestMultiplePackets) {
431 WriteAndExpectManyInboundAclDataPackets(sco_data);
432}
433
434TEST_F(H4ProtocolAsyncTest, TestDisconnect) {
435 std::promise<void> promise;
436 EXPECT_CALL(disconnect_cb_, Call()).WillOnce(Notify(&promise));
437 close(chip_uart_fd_);
438
439 // Fail if it takes longer than 100 ms.
440 WaitForTimeout(100, &promise);
441}