xref: /aosp_15_r20/hardware/interfaces/bluetooth/hci/test/h4_protocol_unittest.cc (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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 
35 using android::hardware::bluetooth::async::AsyncFdWatcher;
36 using namespace android::hardware::bluetooth::hci;
37 using ::testing::Eq;
38 
39 static char sample_data1[100] = "A point is that which has no part.";
40 static char sample_data2[100] = "A line is breadthless length.";
41 static char sample_data3[100] = "The ends of a line are points.";
42 static char sample_data4[100] =
43     "A plane surface is a surface which lies evenly with the straight ...";
44 static char acl_data[100] =
45     "A straight line is a line which lies evenly with the points on itself.";
46 static char sco_data[100] =
47     "A surface is that which has length and breadth only.";
48 static char event_data[100] = "The edges of a surface are lines.";
49 static char iso_data[100] =
50     "A plane angle is the inclination to one another of two lines in a ...";
51 static char short_payload[10] = "12345";
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_, cmd_cb_.AsStdFunction(), acl_cb_.AsStdFunction(),
86         sco_cb_.AsStdFunction(), event_cb_.AsStdFunction(),
87         iso_cb_.AsStdFunction(), 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(); }
96 
SendAndReadUartOutbound(PacketType type,char * data)97   void SendAndReadUartOutbound(PacketType 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>(PacketType::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_,
133                 Call(PacketMatches(header_ + 1, kAclHeaderSize, 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(write(chip_uart_fd_, header_, kAclHeaderSize + 1));
146     TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
147   }
148 
ExpectInboundScoData(char * payload,std::promise<void> * promise)149   void ExpectInboundScoData(char* payload, std::promise<void>* promise) {
150     // h4 type[1] + handle[2] + size[1]
151     header_[0] = static_cast<uint8_t>(PacketType::SCO_DATA);
152     header_[1] = 20;
153     header_[2] = 17;
154     header_[3] = strlen(payload) & 0xFF;
155     EXPECT_CALL(sco_cb_,
156                 Call(PacketMatches(header_ + 1, kScoHeaderSize, payload)))
157         .WillOnce(Notify(promise));
158   }
159 
WriteInboundScoData(char * payload)160   void WriteInboundScoData(char* payload) {
161     // Use the header_ computed in ExpectInboundScoData
162     ALOGD("%s writing", __func__);
163     TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kScoHeaderSize + 1));
164     TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
165   }
166 
ExpectInboundEvent(char * payload,std::promise<void> * promise)167   void ExpectInboundEvent(char* payload, std::promise<void>* promise) {
168     // h4 type[1] + event_code[1] + size[1]
169     header_[0] = static_cast<uint8_t>(PacketType::EVENT);
170     header_[1] = 9;
171     header_[2] = strlen(payload) & 0xFF;
172     EXPECT_CALL(event_cb_,
173                 Call(PacketMatches(header_ + 1, kEventHeaderSize, payload)))
174         .WillOnce(Notify(promise));
175   }
176 
WriteInboundEvent(char * payload)177   void WriteInboundEvent(char* payload) {
178     // Use the header_ computed in ExpectInboundEvent
179     char preamble[3] = {static_cast<uint8_t>(PacketType::EVENT), 9, 0};
180     preamble[2] = strlen(payload) & 0xFF;
181     ALOGD("%s writing", __func__);
182     TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kEventHeaderSize + 1));
183     TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
184   }
185 
ExpectInboundIsoData(char * payload,std::promise<void> * promise)186   void ExpectInboundIsoData(char* payload, std::promise<void>* promise) {
187     // h4 type[1] + handle[2] + size[1]
188     header_[0] = static_cast<uint8_t>(PacketType::ISO_DATA);
189     header_[1] = 19;
190     header_[2] = 92;
191     int length = strlen(payload);
192     header_[3] = length & 0xFF;
193     header_[4] = (length >> 8) & 0x3F;
194 
195     EXPECT_CALL(iso_cb_,
196                 Call(PacketMatches(header_ + 1, kIsoHeaderSize, payload)))
197         .WillOnce(Notify(promise));
198   }
199 
WriteInboundIsoData(char * payload)200   void WriteInboundIsoData(char* payload) {
201     // Use the header_ computed in ExpectInboundIsoData
202     ALOGD("%s writing", __func__);
203     TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kIsoHeaderSize + 1));
204     TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
205   }
206 
WriteAndExpectManyInboundAclDataPackets(char * payload)207   void WriteAndExpectManyInboundAclDataPackets(char* payload) {
208     size_t kNumPackets = 20;
209     // h4 type[1] + handle[2] + size[2]
210     char preamble[5] = {static_cast<uint8_t>(PacketType::ACL_DATA), 19, 92, 0,
211                         0};
212     int length = strlen(payload);
213     preamble[3] = length & 0xFF;
214     preamble[4] = (length >> 8) & 0xFF;
215 
216     EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, sizeof(preamble) - 1,
217                                             payload)))
218         .Times(kNumPackets);
219 
220     for (size_t i = 0; i < kNumPackets; i++) {
221       TEMP_FAILURE_RETRY(write(chip_uart_fd_, preamble, sizeof(preamble)));
222       TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
223     }
224 
225     CallDataReady();
226   }
227 
WriteAndExpectManyAclDataPacketsDifferentOffsetsShort()228   void WriteAndExpectManyAclDataPacketsDifferentOffsetsShort() {
229     std::promise<void> last_packet_promise;
230     size_t kNumPackets = 30;
231     // h4 type[1] + handle[2] + size[2]
232     char preamble[5] = {static_cast<uint8_t>(PacketType::ACL_DATA), 19, 92, 0,
233                         0};
234     int length = strlen(short_payload);
235     preamble[3] = length & 0xFF;
236     preamble[4] = 0;
237 
238     EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, kAclHeaderSize,
239                                             short_payload)))
240         .Times(kNumPackets);
241     ExpectInboundEvent(event_data, &last_packet_promise);
242 
243     char all_packets[kNumPackets * 10];
244     size_t total_bytes = 0;
245 
246     for (size_t packet = 0; packet < kNumPackets; packet++) {
247       for (size_t i = 0; i < sizeof(preamble); i++) {
248         all_packets[total_bytes++] = preamble[i];
249       }
250       for (size_t i = 0; i < length; i++) {
251         all_packets[total_bytes++] = short_payload[i];
252       }
253     }
254 
255     size_t written_bytes = 0;
256     size_t partial_size = 1;
257     while (written_bytes < total_bytes) {
258       size_t to_write = std::min(partial_size, total_bytes - written_bytes);
259       TEMP_FAILURE_RETRY(
260           write(chip_uart_fd_, all_packets + written_bytes, to_write));
261       written_bytes += to_write;
262       CallDataReady();
263       partial_size++;
264       partial_size = partial_size % 5 + 1;
265     }
266     WriteInboundEvent(event_data);
267     CallDataReady();
268     WaitForTimeout(&last_packet_promise);
269   }
270 
271   testing::MockFunction<void(const std::vector<uint8_t>&)> cmd_cb_;
272   testing::MockFunction<void(const std::vector<uint8_t>&)> event_cb_;
273   testing::MockFunction<void(const std::vector<uint8_t>&)> acl_cb_;
274   testing::MockFunction<void(const std::vector<uint8_t>&)> sco_cb_;
275   testing::MockFunction<void(const std::vector<uint8_t>&)> iso_cb_;
276   testing::MockFunction<void(void)> disconnect_cb_;
277   std::shared_ptr<H4Protocol> h4_hci_;
278   int chip_uart_fd_;
279   int stack_uart_fd_;
280 
281   char header_[5];
282 };
283 
284 // Test sending data sends correct data onto the UART
TEST_F(H4ProtocolTest,TestSends)285 TEST_F(H4ProtocolTest, TestSends) {
286   SendAndReadUartOutbound(PacketType::COMMAND, sample_data1);
287   SendAndReadUartOutbound(PacketType::ACL_DATA, sample_data2);
288   SendAndReadUartOutbound(PacketType::SCO_DATA, sample_data3);
289   SendAndReadUartOutbound(PacketType::ISO_DATA, sample_data4);
290 }
291 
292 // Ensure we properly parse data coming from the UART
TEST_F(H4ProtocolTest,TestReads)293 TEST_F(H4ProtocolTest, TestReads) {
294   std::promise<void> acl_promise;
295   std::promise<void> sco_promise;
296   std::promise<void> event_promise;
297   std::promise<void> iso_promise;
298 
299   ExpectInboundAclData(acl_data, &acl_promise);
300   WriteInboundAclData(acl_data);
301   CallDataReady();
302   ExpectInboundScoData(sco_data, &sco_promise);
303   WriteInboundScoData(sco_data);
304   CallDataReady();
305   ExpectInboundEvent(event_data, &event_promise);
306   WriteInboundEvent(event_data);
307   CallDataReady();
308   ExpectInboundIsoData(iso_data, &iso_promise);
309   WriteInboundIsoData(iso_data);
310   CallDataReady();
311 
312   WaitForTimeout(&acl_promise);
313   WaitForTimeout(&sco_promise);
314   WaitForTimeout(&event_promise);
315   WaitForTimeout(&iso_promise);
316 }
317 
TEST_F(H4ProtocolTest,TestMultiplePackets)318 TEST_F(H4ProtocolTest, TestMultiplePackets) {
319   WriteAndExpectManyInboundAclDataPackets(sco_data);
320 }
321 
TEST_F(H4ProtocolTest,TestMultipleWritesPacketsShortWrites)322 TEST_F(H4ProtocolTest, TestMultipleWritesPacketsShortWrites) {
323   WriteAndExpectManyAclDataPacketsDifferentOffsetsShort();
324 }
325 
TEST_F(H4ProtocolTest,TestDisconnect)326 TEST_F(H4ProtocolTest, TestDisconnect) {
327   EXPECT_CALL(disconnect_cb_, Call());
328   close(chip_uart_fd_);
329   CallDataReady();
330 }
331 
TEST_F(H4ProtocolTest,TestPartialWrites)332 TEST_F(H4ProtocolTest, TestPartialWrites) {
333   size_t payload_len = strlen(acl_data);
334   const size_t kNumIntervals = payload_len + 1;
335   // h4 type[1] + handle[2] + size[2]
336   header_[0] = static_cast<uint8_t>(PacketType::ACL_DATA);
337   header_[1] = 19;
338   header_[2] = 92;
339   header_[3] = payload_len & 0xFF;
340   header_[4] = (payload_len >> 8) & 0xFF;
341 
342   EXPECT_CALL(acl_cb_,
343               Call(PacketMatches(header_ + 1, sizeof(header_) - 1, acl_data)))
344       .Times(kNumIntervals);
345 
346   for (size_t interval = 1; interval < kNumIntervals + 1; interval++) {
347     // Use the header_ data that expect already set up.
348     if (interval < kAclHeaderSize) {
349       TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, interval));
350       CallDataReady();
351       TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_ + interval,
352                                kAclHeaderSize + 1 - interval));
353       CallDataReady();
354     } else {
355       TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kAclHeaderSize + 1));
356       CallDataReady();
357     }
358 
359     for (size_t bytes = 0; bytes + interval <= payload_len; bytes += interval) {
360       TEMP_FAILURE_RETRY(write(chip_uart_fd_, acl_data + bytes, interval));
361       CallDataReady();
362     }
363     size_t extra_bytes = payload_len % interval;
364     if (extra_bytes) {
365       TEMP_FAILURE_RETRY(write(
366           chip_uart_fd_, acl_data + payload_len - extra_bytes, extra_bytes));
367       CallDataReady();
368     }
369   }
370 }
371 
372 class H4ProtocolAsyncTest : public H4ProtocolTest {
373  protected:
SetUp()374   void SetUp() override {
375     H4ProtocolTest::SetUp();
376     fd_watcher_.WatchFdForNonBlockingReads(
377         stack_uart_fd_, [this](int) { h4_hci_->OnDataReady(); });
378   }
379 
TearDown()380   void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
381 
382   // Calling CallDataReady() has no effect in the AsyncTest
CallDataReady()383   void CallDataReady() override {}
384 
SendAndReadUartOutbound(PacketType type,char * data)385   void SendAndReadUartOutbound(PacketType type, char* data) {
386     ALOGD("%s sending", __func__);
387     int data_length = strlen(data);
388     h4_hci_->Send(type, (uint8_t*)data, data_length);
389 
390     int uart_length = data_length + 1;  // + 1 for data type code
391     int i;
392 
393     ALOGD("%s reading", __func__);
394     for (i = 0; i < uart_length; i++) {
395       fd_set read_fds;
396       FD_ZERO(&read_fds);
397       FD_SET(chip_uart_fd_, &read_fds);
398       TEMP_FAILURE_RETRY(
399           select(chip_uart_fd_ + 1, &read_fds, nullptr, nullptr, nullptr));
400 
401       char byte;
402       TEMP_FAILURE_RETRY(read(chip_uart_fd_, &byte, 1));
403 
404       EXPECT_EQ(i == 0 ? static_cast<uint8_t>(type) : data[i - 1], byte);
405     }
406 
407     EXPECT_EQ(i, uart_length);
408   }
409 
WriteAndExpectInboundAclData(char * payload)410   void WriteAndExpectInboundAclData(char* payload) {
411     std::promise<void> promise;
412     ExpectInboundAclData(payload, &promise);
413     WriteInboundAclData(payload);
414     WaitForTimeout(&promise);
415   }
416 
WriteAndExpectInboundScoData(char * payload)417   void WriteAndExpectInboundScoData(char* payload) {
418     std::promise<void> promise;
419     ExpectInboundScoData(payload, &promise);
420     WriteInboundScoData(payload);
421     WaitForTimeout(&promise);
422   }
423 
WriteAndExpectInboundEvent(char * payload)424   void WriteAndExpectInboundEvent(char* payload) {
425     std::promise<void> promise;
426     ExpectInboundEvent(payload, &promise);
427     WriteInboundEvent(payload);
428     WaitForTimeout(&promise);
429   }
430 
WriteAndExpectInboundIsoData(char * payload)431   void WriteAndExpectInboundIsoData(char* payload) {
432     std::promise<void> promise;
433     ExpectInboundIsoData(payload, &promise);
434     WriteInboundIsoData(payload);
435     WaitForTimeout(&promise);
436   }
437 
WriteAndExpectManyInboundAclDataPackets(char * payload)438   void WriteAndExpectManyInboundAclDataPackets(char* payload) {
439     const size_t kNumPackets = 20;
440     // h4 type[1] + handle[2] + size[2]
441     char preamble[5] = {static_cast<uint8_t>(PacketType::ACL_DATA), 19, 92, 0,
442                         0};
443     int length = strlen(payload);
444     preamble[3] = length & 0xFF;
445     preamble[4] = (length >> 8) & 0xFF;
446 
447     EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, sizeof(preamble) - 1,
448                                             payload)))
449         .Times(kNumPackets);
450 
451     for (size_t i = 0; i < kNumPackets; i++) {
452       TEMP_FAILURE_RETRY(write(chip_uart_fd_, preamble, sizeof(preamble)));
453       TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
454     }
455 
456     WriteAndExpectInboundEvent(event_data);
457   }
458 
459   AsyncFdWatcher fd_watcher_;
460 };
461 
462 // Test sending data sends correct data onto the UART
TEST_F(H4ProtocolAsyncTest,TestSends)463 TEST_F(H4ProtocolAsyncTest, TestSends) {
464   SendAndReadUartOutbound(PacketType::COMMAND, sample_data1);
465   SendAndReadUartOutbound(PacketType::ACL_DATA, sample_data2);
466   SendAndReadUartOutbound(PacketType::SCO_DATA, sample_data3);
467   SendAndReadUartOutbound(PacketType::ISO_DATA, sample_data4);
468 }
469 
470 // Ensure we properly parse data coming from the UART
TEST_F(H4ProtocolAsyncTest,TestReads)471 TEST_F(H4ProtocolAsyncTest, TestReads) {
472   WriteAndExpectInboundAclData(acl_data);
473   WriteAndExpectInboundScoData(sco_data);
474   WriteAndExpectInboundEvent(event_data);
475   WriteAndExpectInboundIsoData(iso_data);
476 }
477 
TEST_F(H4ProtocolAsyncTest,TestMultiplePackets)478 TEST_F(H4ProtocolAsyncTest, TestMultiplePackets) {
479   WriteAndExpectManyInboundAclDataPackets(sco_data);
480 }
481 
TEST_F(H4ProtocolAsyncTest,TestMultipleWritesPacketsShortWrites)482 TEST_F(H4ProtocolAsyncTest, TestMultipleWritesPacketsShortWrites) {
483   WriteAndExpectManyAclDataPacketsDifferentOffsetsShort();
484 }
485 
TEST_F(H4ProtocolAsyncTest,TestDisconnect)486 TEST_F(H4ProtocolAsyncTest, TestDisconnect) {
487   std::promise<void> promise;
488   EXPECT_CALL(disconnect_cb_, Call()).WillOnce(Notify(&promise));
489   close(chip_uart_fd_);
490 
491   WaitForTimeout(&promise);
492 }
493