• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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