1 //
2 // Copyright 2018 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 #include "fmq_driver/VtsFmqDriver.h"
18 
19 #include <errno.h>
20 #include <limits.h>
21 #include <math.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/wait.h>
26 #include <time.h>
27 #include <unistd.h>
28 
29 #include <fmq/MessageQueue.h>
30 #include <gtest/gtest.h>
31 
32 using android::hardware::kSynchronizedReadWrite;
33 using android::hardware::kUnsynchronizedWrite;
34 using namespace std;
35 
36 namespace android {
37 namespace vts {
38 
39 // A test that initializes a single writer and a single reader.
40 class SyncReadWrites : public ::testing::Test {
41  protected:
SetUp()42   virtual void SetUp() {
43     static constexpr size_t NUM_ELEMS = 2048;
44 
45     // initialize a writer
46     writer_id_ = manager_.CreateFmq<uint16_t, kSynchronizedReadWrite>(
47         "uint16_t", NUM_ELEMS, false);
48     ASSERT_NE(writer_id_, -1);
49 
50     // initialize a reader
51     reader_id_ = manager_.CreateFmq<uint16_t, kSynchronizedReadWrite>(
52         "uint16_t", writer_id_);
53     ASSERT_NE(reader_id_, -1);
54   }
55 
TearDown()56   virtual void TearDown() {}
57 
58   VtsFmqDriver manager_;
59   QueueId writer_id_;
60   QueueId reader_id_;
61 };
62 
63 // A test that initializes a single writer and a single reader.
64 // TODO: add tests for blocking between multiple queues later when there is more
65 // use case.
66 class BlockingReadWrites : public ::testing::Test {
67  protected:
SetUp()68   virtual void SetUp() {
69     static constexpr size_t NUM_ELEMS = 2048;
70 
71     // initialize a writer
72     writer_id_ = manager_.CreateFmq<uint16_t, kSynchronizedReadWrite>(
73         "uint16_t", NUM_ELEMS, true);
74     ASSERT_NE(writer_id_, -1);
75 
76     // initialize a reader
77     reader_id_ = manager_.CreateFmq<uint16_t, kSynchronizedReadWrite>(
78         "uint16_t", writer_id_);
79     ASSERT_NE(reader_id_, -1);
80   }
81 
TearDown()82   virtual void TearDown() {}
83 
84   VtsFmqDriver manager_;
85   QueueId writer_id_;
86   QueueId reader_id_;
87 };
88 
89 // A test that initializes a single writer and two readers.
90 class UnsynchronizedWrites : public ::testing::Test {
91  protected:
SetUp()92   virtual void SetUp() {
93     static constexpr size_t NUM_ELEMS = 2048;
94 
95     // initialize a writer
96     writer_id_ = manager_.CreateFmq<uint16_t, kUnsynchronizedWrite>(
97         "uint16_t", NUM_ELEMS, false);
98     ASSERT_NE(writer_id_, -1);
99 
100     // initialize two readers
101     reader_id1_ = manager_.CreateFmq<uint16_t, kUnsynchronizedWrite>(
102         "uint16_t", writer_id_);
103     reader_id2_ = manager_.CreateFmq<uint16_t, kUnsynchronizedWrite>(
104         "uint16_t", writer_id_);
105     ASSERT_NE(reader_id1_, -1);
106     ASSERT_NE(reader_id2_, -1);
107   }
108 
TearDown()109   virtual void TearDown() {}
110 
111   VtsFmqDriver manager_;
112   QueueId writer_id_;
113   QueueId reader_id1_;
114   QueueId reader_id2_;
115 };
116 
117 // Tests the reader and writer are set up correctly.
TEST_F(SyncReadWrites,SetupBasicTest)118 TEST_F(SyncReadWrites, SetupBasicTest) {
119   static constexpr size_t NUM_ELEMS = 2048;
120 
121   // check if the writer has a valid queue
122   ASSERT_TRUE((manager_.IsValid<uint16_t, kSynchronizedReadWrite>("uint16_t",
123                                                                   writer_id_)));
124 
125   // check queue size on writer side
126   size_t writer_queue_size;
127   ASSERT_TRUE((manager_.GetQuantumCount<uint16_t, kSynchronizedReadWrite>(
128       "uint16_t", writer_id_, &writer_queue_size)));
129   ASSERT_EQ(NUM_ELEMS, writer_queue_size);
130 
131   // check queue element size on writer side
132   size_t writer_elem_size;
133   ASSERT_TRUE((manager_.GetQuantumSize<uint16_t, kSynchronizedReadWrite>(
134       "uint16_t", writer_id_, &writer_elem_size)));
135   ASSERT_EQ(sizeof(uint16_t), writer_elem_size);
136 
137   // check space available for writer
138   size_t writer_available_writes;
139   ASSERT_TRUE((manager_.AvailableToWrite<uint16_t, kSynchronizedReadWrite>(
140       "uint16_t", writer_id_, &writer_available_writes)));
141   ASSERT_EQ(NUM_ELEMS, writer_available_writes);
142 
143   // check if the reader has a valid queue
144   ASSERT_TRUE((manager_.IsValid<uint16_t, kSynchronizedReadWrite>("uint16_t",
145                                                                   reader_id_)));
146 
147   // check queue size on reader side
148   size_t reader_queue_size;
149   ASSERT_TRUE((manager_.GetQuantumCount<uint16_t, kSynchronizedReadWrite>(
150       "uint16_t", reader_id_, &reader_queue_size)));
151   ASSERT_EQ(NUM_ELEMS, reader_queue_size);
152 
153   // check queue element size on reader side
154   size_t reader_elem_size;
155   ASSERT_TRUE((manager_.GetQuantumSize<uint16_t, kSynchronizedReadWrite>(
156       "uint16_t", reader_id_, &reader_elem_size)));
157   ASSERT_EQ(sizeof(uint16_t), reader_elem_size);
158 
159   // check items available for reader
160   size_t reader_available_reads;
161   ASSERT_TRUE((manager_.AvailableToRead<uint16_t, kSynchronizedReadWrite>(
162       "uint16_t", reader_id_, &reader_available_reads)));
163   ASSERT_EQ(0, reader_available_reads);
164 }
165 
166 // util method to initialize data
InitData(uint16_t * data,size_t len)167 void InitData(uint16_t* data, size_t len) {
168   for (size_t i = 0; i < len; i++) {
169     data[i] = rand() % 100 + 1;  // a random value between 1 and 100
170   }
171 }
172 
173 // Tests a basic writer and reader interaction.
174 // Reader reads back data written by the writer correctly.
TEST_F(SyncReadWrites,ReadWriteSuccessTest)175 TEST_F(SyncReadWrites, ReadWriteSuccessTest) {
176   static constexpr size_t DATA_SIZE = 64;
177   uint16_t write_data[DATA_SIZE];
178   uint16_t read_data[DATA_SIZE];
179 
180   // initialize the data to transfer
181   InitData(write_data, DATA_SIZE);
182 
183   // writer should succeed
184   ASSERT_TRUE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
185       "uint16_t", writer_id_, write_data, DATA_SIZE)));
186 
187   // reader should succeed
188   ASSERT_TRUE((manager_.ReadFmq<uint16_t, kSynchronizedReadWrite>(
189       "uint16_t", reader_id_, read_data, DATA_SIZE)));
190 
191   // check if the data is read back correctly
192   ASSERT_EQ(0, memcmp(write_data, read_data, DATA_SIZE * sizeof(uint16_t)));
193 }
194 
195 // Tests reading from an empty queue.
TEST_F(SyncReadWrites,ReadEmpty)196 TEST_F(SyncReadWrites, ReadEmpty) {
197   static constexpr size_t DATA_SIZE = 64;
198   uint16_t read_data[DATA_SIZE];
199 
200   // attempt to read from an empty queue
201   ASSERT_FALSE((manager_.ReadFmq<uint16_t, kSynchronizedReadWrite>(
202       "uint16_t", reader_id_, read_data, DATA_SIZE)));
203 }
204 
205 // Tests writing to a full queue.
TEST_F(SyncReadWrites,WriteFull)206 TEST_F(SyncReadWrites, WriteFull) {
207   static constexpr size_t DATA_SIZE = 2048;
208   uint16_t write_data[DATA_SIZE];
209   uint16_t read_data[DATA_SIZE];
210 
211   // initialize the data to transfer
212   InitData(write_data, DATA_SIZE);
213 
214   // This write succeeds, filling up the queue
215   ASSERT_TRUE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
216       "uint16_t", writer_id_, write_data, DATA_SIZE)));
217 
218   // This write fails, queue is full
219   ASSERT_FALSE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
220       "uint16_t", writer_id_, write_data, DATA_SIZE)));
221 
222   // checks space available is 0
223   size_t writer_available_writes;
224   ASSERT_TRUE((manager_.AvailableToWrite<uint16_t, kSynchronizedReadWrite>(
225       "uint16_t", writer_id_, &writer_available_writes)));
226   ASSERT_EQ(0, writer_available_writes);
227 
228   // reader succeeds, reads the entire queue back correctly
229   ASSERT_TRUE((manager_.ReadFmq<uint16_t, kSynchronizedReadWrite>(
230       "uint16_t", reader_id_, read_data, DATA_SIZE)));
231 
232   ASSERT_EQ(0, memcmp(write_data, read_data, DATA_SIZE * sizeof(uint16_t)));
233 }
234 
235 // Attempt to write more than the size of the queue.
TEST_F(SyncReadWrites,WriteTooLarge)236 TEST_F(SyncReadWrites, WriteTooLarge) {
237   static constexpr size_t LARGE_DATA_SIZE = 2049;
238   uint16_t write_data[LARGE_DATA_SIZE];
239 
240   // initialize data to transfer
241   InitData(write_data, LARGE_DATA_SIZE);
242 
243   // write more than the queue size
244   ASSERT_FALSE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
245       "uint16_t", writer_id_, write_data, LARGE_DATA_SIZE)));
246 }
247 
248 // Pass the wrong type.
TEST_F(SyncReadWrites,WrongType)249 TEST_F(SyncReadWrites, WrongType) {
250   static constexpr size_t DATA_SIZE = 2;
251   uint16_t write_data[DATA_SIZE];
252 
253   // initialize data to transfer
254   InitData(write_data, DATA_SIZE);
255 
256   // attempt to write uint32_t type
257   ASSERT_FALSE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
258       "uint32_t", writer_id_, write_data, DATA_SIZE)));
259 }
260 
261 // Tests consecutive interaction between writer and reader.
262 // Reader immediately reads back what writer writes.
TEST_F(SyncReadWrites,ConsecutiveReadWrite)263 TEST_F(SyncReadWrites, ConsecutiveReadWrite) {
264   static constexpr size_t DATA_SIZE = 64;
265   static constexpr size_t BATCH_SIZE = 10;
266   uint16_t read_data[DATA_SIZE];
267   uint16_t write_data[DATA_SIZE];
268 
269   // 10 consecutive writes and reads
270   for (size_t i = 0; i < BATCH_SIZE; i++) {
271     InitData(write_data, DATA_SIZE);
272     ASSERT_TRUE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
273         "uint16_t", writer_id_, write_data, DATA_SIZE)));
274 
275     ASSERT_TRUE((manager_.ReadFmq<uint16_t, kSynchronizedReadWrite>(
276         "uint16_t", reader_id_, read_data, DATA_SIZE)));
277     ASSERT_EQ(0, memcmp(write_data, read_data, DATA_SIZE * sizeof(uint16_t)));
278   }
279 
280   // no more available to read
281   size_t reader_available_reads;
282   ASSERT_TRUE((manager_.AvailableToRead<uint16_t, kSynchronizedReadWrite>(
283       "uint16_t", reader_id_, &reader_available_reads)));
284   ASSERT_EQ(0, reader_available_reads);
285 }
286 
287 // Tests reader waiting for data to be available.
288 // Writer waits for 0.05s and writes the data.
289 // Reader blocks for at most 0.1s and reads the data if it is available.
TEST_F(BlockingReadWrites,ReadWriteSuccess)290 TEST_F(BlockingReadWrites, ReadWriteSuccess) {
291   static constexpr size_t DATA_SIZE = 64;
292 
293   uint16_t read_data[DATA_SIZE];
294   uint16_t write_data[DATA_SIZE];
295 
296   // initialize data to transfer
297   InitData(write_data, DATA_SIZE);
298 
299   pid_t pid = fork();
300   if (pid == 0) {  // child process is a reader, blocking for at most 0.1s.
301     ASSERT_TRUE((manager_.ReadFmqBlocking<uint16_t, kSynchronizedReadWrite>(
302         "uint16_t", reader_id_, read_data, DATA_SIZE, 100 * 1000000)));
303     ASSERT_EQ(0, memcmp(write_data, read_data, DATA_SIZE * sizeof(uint16_t)));
304     exit(0);
305   } else if (pid > 0) {
306     // parent process is a writer, waits for 0.05s and writes.
307     struct timespec writer_wait_time = {0, 50 * 1000000};
308     nanosleep(&writer_wait_time, NULL);
309     ASSERT_TRUE((manager_.WriteFmqBlocking<uint16_t, kSynchronizedReadWrite>(
310         "uint16_t", writer_id_, write_data, DATA_SIZE, 1000000)));
311   }
312 }
313 
314 // Tests reader blocking times out.
TEST_F(BlockingReadWrites,BlockingTimeOut)315 TEST_F(BlockingReadWrites, BlockingTimeOut) {
316   static constexpr size_t DATA_SIZE = 64;
317   uint16_t read_data[DATA_SIZE];
318 
319   // block for 0.05s, timeout
320   ASSERT_FALSE((manager_.ReadFmqBlocking<uint16_t, kSynchronizedReadWrite>(
321       "uint16_t", reader_id_, read_data, DATA_SIZE, 50 * 1000000)));
322 }
323 
324 // Tests two readers can both read back what writer writes correctly.
TEST_F(UnsynchronizedWrites,ReadWriteSuccess)325 TEST_F(UnsynchronizedWrites, ReadWriteSuccess) {
326   static constexpr size_t DATA_SIZE = 64;
327   uint16_t write_data[DATA_SIZE];
328   uint16_t read_data1[DATA_SIZE];
329   uint16_t read_data2[DATA_SIZE];
330 
331   // initialize data to transfer
332   InitData(write_data, DATA_SIZE);
333 
334   // writer writes 64 items
335   ASSERT_TRUE((manager_.WriteFmq<uint16_t, kUnsynchronizedWrite>(
336       "uint16_t", writer_id_, write_data, DATA_SIZE)));
337 
338   // reader 1 reads back data correctly
339   ASSERT_TRUE((manager_.ReadFmq<uint16_t, kUnsynchronizedWrite>(
340       "uint16_t", reader_id1_, read_data1, DATA_SIZE)));
341   ASSERT_EQ(0, memcmp(write_data, read_data1, DATA_SIZE * sizeof(uint16_t)));
342 
343   // reader 2 reads back data correctly
344   ASSERT_TRUE((manager_.ReadFmq<uint16_t, kUnsynchronizedWrite>(
345       "uint16_t", reader_id2_, read_data2, DATA_SIZE)));
346   ASSERT_EQ(0, memcmp(write_data, read_data2, DATA_SIZE * sizeof(uint16_t)));
347 }
348 
349 // Tests that blocking is not allowed on unsynchronized queue.
TEST_F(UnsynchronizedWrites,IllegalBlocking)350 TEST_F(UnsynchronizedWrites, IllegalBlocking) {
351   static constexpr size_t DATA_SIZE = 64;
352   uint16_t write_data[DATA_SIZE];
353 
354   // initialize data to transfer
355   InitData(write_data, DATA_SIZE);
356 
357   // should fail immediately, instead of blocking
358   ASSERT_FALSE((manager_.WriteFmqBlocking<uint16_t, kUnsynchronizedWrite>(
359       "uint16_t", writer_id_, write_data, DATA_SIZE, 1000000)));
360 }
361 
362 }  // namespace vts
363 }  // namespace android
364