1 //
2 // Copyright 2017 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 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 #include <condition_variable>
23 #include <cstdint>
24 #include <cstring>
25 #include <mutex>
26 #include <vector>
27 
28 #include <log/log.h>
29 #include <sys/socket.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 
33 namespace android {
34 namespace hardware {
35 namespace bluetooth {
36 namespace V1_0 {
37 namespace implementation {
38 
39 using hci::H4Protocol;
40 using ::testing::Eq;
41 
42 static char sample_data1[100] = "A point is that which has no part.";
43 static char sample_data2[100] = "A line is breadthless length.";
44 static char sample_data3[100] = "The ends of a line are points.";
45 static char sample_data4[100] =
46     "A plane surface is a surface which lies evenly with the straight ...";
47 static char acl_data[100] =
48     "A straight line is a line which lies evenly with the points on itself.";
49 static char sco_data[100] =
50     "A surface is that which has length and breadth only.";
51 static char event_data[100] = "The edges of a surface are lines.";
52 static char iso_data[100] =
53     "A plane angle is the inclination to one another of two lines in a ...";
54 
55 MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") {
56   size_t length = strlen(payload) + preamble_length;
57   if (length != arg.size()) {
58     return false;
59   }
60 
61   if (memcmp(preamble, arg.data(), preamble_length) != 0) {
62     return false;
63   }
64 
65   return memcmp(payload, arg.data() + preamble_length,
66                 length - preamble_length) == 0;
67 };
68 
ACTION_P2(Notify,mutex,condition)69 ACTION_P2(Notify, mutex, condition) {
70   ALOGD("%s", __func__);
71   std::unique_lock<std::mutex> lock(*mutex);
72   condition->notify_one();
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     H4Protocol* h4_hci = new H4Protocol(
83         sockfd[0], event_cb_.AsStdFunction(), acl_cb_.AsStdFunction(),
84         sco_cb_.AsStdFunction(), iso_cb_.AsStdFunction());
85     fd_watcher_.WatchFdForNonBlockingReads(
86         sockfd[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
87     protocol_ = h4_hci;
88 
89     fake_uart_ = sockfd[1];
90   }
91 
TearDown()92   void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
93 
SendAndReadUartOutbound(uint8_t type,char * data)94   void SendAndReadUartOutbound(uint8_t type, char* data) {
95     ALOGD("%s sending", __func__);
96     int data_length = strlen(data);
97     protocol_->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(fake_uart_, &read_fds);
107       TEMP_FAILURE_RETRY(select(fake_uart_ + 1, &read_fds, NULL, NULL, NULL));
108 
109       char byte;
110       TEMP_FAILURE_RETRY(read(fake_uart_, &byte, 1));
111 
112       EXPECT_EQ(i == 0 ? type : data[i - 1], byte);
113     }
114 
115     EXPECT_EQ(i, uart_length);
116   }
117 
WriteAndExpectInboundAclData(char * payload)118   void WriteAndExpectInboundAclData(char* payload) {
119     // h4 type[1] + handle[2] + size[2]
120     char preamble[5] = {HCI_PACKET_TYPE_ACL_DATA, 19, 92, 0, 0};
121     int length = strlen(payload);
122     preamble[3] = length & 0xFF;
123     preamble[4] = (length >> 8) & 0xFF;
124 
125     ALOGD("%s writing", __func__);
126     TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
127     TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
128 
129     ALOGD("%s waiting", __func__);
130     std::mutex mutex;
131     std::condition_variable done;
132     EXPECT_CALL(acl_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
133                                              payload)))
134         .WillOnce(Notify(&mutex, &done));
135 
136     // Fail if it takes longer than 100 ms.
137     auto timeout_time =
138         std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
139     {
140       std::unique_lock<std::mutex> lock(mutex);
141       done.wait_until(lock, timeout_time);
142     }
143   }
144 
WriteAndExpectInboundScoData(char * payload)145   void WriteAndExpectInboundScoData(char* payload) {
146     // h4 type[1] + handle[2] + size[1]
147     char preamble[4] = {HCI_PACKET_TYPE_SCO_DATA, 20, 17, 0};
148     preamble[3] = strlen(payload) & 0xFF;
149 
150     ALOGD("%s writing", __func__);
151     TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
152     TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
153 
154     ALOGD("%s waiting", __func__);
155     std::mutex mutex;
156     std::condition_variable done;
157     EXPECT_CALL(sco_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
158                                              payload)))
159         .WillOnce(Notify(&mutex, &done));
160 
161     // Fail if it takes longer than 100 ms.
162     auto timeout_time =
163         std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
164     {
165       std::unique_lock<std::mutex> lock(mutex);
166       done.wait_until(lock, timeout_time);
167     }
168   }
169 
WriteAndExpectInboundEvent(char * payload)170   void WriteAndExpectInboundEvent(char* payload) {
171     // h4 type[1] + event_code[1] + size[1]
172     char preamble[3] = {HCI_PACKET_TYPE_EVENT, 9, 0};
173     preamble[2] = strlen(payload) & 0xFF;
174     ALOGD("%s writing", __func__);
175     TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
176     TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
177 
178     ALOGD("%s waiting", __func__);
179     std::mutex mutex;
180     std::condition_variable done;
181     EXPECT_CALL(event_cb_, Call(HidlVecMatches(preamble + 1,
182                                                sizeof(preamble) - 1, payload)))
183         .WillOnce(Notify(&mutex, &done));
184 
185     {
186       std::unique_lock<std::mutex> lock(mutex);
187       done.wait(lock);
188     }
189   }
190 
WriteAndExpectInboundIsoData(char * payload)191   void WriteAndExpectInboundIsoData(char* payload) {
192     // h4 type[1] + handle[2] + size[1]
193     char preamble[4] = {HCI_PACKET_TYPE_ISO_DATA, 20, 17, 0};
194     preamble[3] = strlen(payload) & 0xFF;
195 
196     ALOGD("%s writing", __func__);
197     TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
198     TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
199 
200     ALOGD("%s waiting", __func__);
201     std::mutex mutex;
202     std::condition_variable done;
203     EXPECT_CALL(iso_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
204                                              payload)))
205         .WillOnce(Notify(&mutex, &done));
206 
207     // Fail if it takes longer than 100 ms.
208     auto timeout_time =
209         std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
210     {
211       std::unique_lock<std::mutex> lock(mutex);
212       done.wait_until(lock, timeout_time);
213     }
214   }
215 
216   testing::MockFunction<void(const hidl_vec<uint8_t>&)> event_cb_;
217   testing::MockFunction<void(const hidl_vec<uint8_t>&)> acl_cb_;
218   testing::MockFunction<void(const hidl_vec<uint8_t>&)> sco_cb_;
219   testing::MockFunction<void(const hidl_vec<uint8_t>&)> iso_cb_;
220   async::AsyncFdWatcher fd_watcher_;
221   H4Protocol* protocol_;
222   int fake_uart_;
223 };
224 
225 // Test sending data sends correct data onto the UART
TEST_F(H4ProtocolTest,TestSends)226 TEST_F(H4ProtocolTest, TestSends) {
227   SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1);
228   SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2);
229   SendAndReadUartOutbound(HCI_PACKET_TYPE_SCO_DATA, sample_data3);
230   SendAndReadUartOutbound(HCI_PACKET_TYPE_ISO_DATA, sample_data4);
231 }
232 
233 // Ensure we properly parse data coming from the UART
TEST_F(H4ProtocolTest,TestReads)234 TEST_F(H4ProtocolTest, TestReads) {
235   WriteAndExpectInboundAclData(acl_data);
236   WriteAndExpectInboundScoData(sco_data);
237   WriteAndExpectInboundEvent(event_data);
238   WriteAndExpectInboundIsoData(iso_data);
239 }
240 
241 }  // namespace implementation
242 }  // namespace V1_0
243 }  // namespace bluetooth
244 }  // namespace hardware
245 }  // namespace android
246