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