/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <gtest/gtest.h> #ifndef GTEST_IS_THREADSAFE #error "GTest did not detect pthread library." #endif #include <android/hardware/tests/msgq/1.0/ITestMsgQ.h> #include <fmq/EventFlag.h> #include <fmq/MessageQueue.h> #include <hidl/ServiceManagement.h> // libutils: using android::OK; using android::sp; using android::status_t; // generated using android::hardware::tests::msgq::V1_0::ITestMsgQ; // libhidl using android::hardware::kSynchronizedReadWrite; using android::hardware::kUnsynchronizedWrite; using android::hardware::MessageQueue; using android::hardware::MQDescriptorSync; using android::hardware::MQDescriptorUnsync; using android::hardware::details::waitForHwService; typedef MessageQueue<uint16_t, kSynchronizedReadWrite> MessageQueueSync; typedef MessageQueue<uint16_t, kUnsynchronizedWrite> MessageQueueUnsync; static sp<ITestMsgQ> waitGetTestService() { // waitForHwService is required because ITestMsgQ is not in manifest.xml. // "Real" HALs shouldn't be doing this. waitForHwService(ITestMsgQ::descriptor, "default"); return ITestMsgQ::getService(); } class UnsynchronizedWriteClientMultiProcess : public ::testing::Test { protected: void getQueue(MessageQueueUnsync** fmq, sp<ITestMsgQ>* service, bool setupQueue) { *service = waitGetTestService(); *fmq = nullptr; if (*service == nullptr) return; if (!(*service)->isRemote()) return; (*service)->getFmqUnsyncWrite(setupQueue, [fmq](bool ret, const MQDescriptorUnsync<uint16_t>& in) { ASSERT_TRUE(ret); *fmq = new (std::nothrow) MessageQueueUnsync(in); }); } }; class SynchronizedReadWriteClient : public ::testing::Test { protected: virtual void TearDown() { delete mQueue; } virtual void SetUp() { static constexpr size_t kNumElementsInQueue = 1024; mService = waitGetTestService(); ASSERT_NE(mService, nullptr); ASSERT_TRUE(mService->isRemote()); // create a queue on the client side mQueue = new (std::nothrow) MessageQueueSync(kNumElementsInQueue, true /* configure event flag word */); ASSERT_NE(nullptr, mQueue); ASSERT_TRUE(mQueue->isValid()); mNumMessagesMax = mQueue->getQuantumCount(); // tell server to set up the queue on its end ASSERT_TRUE(mService->configureFmqSyncReadWrite(*mQueue->getDesc())); } sp<ITestMsgQ> mService; MessageQueueSync* mQueue = nullptr; size_t mNumMessagesMax = 0; }; class UnsynchronizedWriteClient : public ::testing::Test { protected: virtual void TearDown() { delete mQueue; } virtual void SetUp() { mService = waitGetTestService(); ASSERT_NE(mService, nullptr); ASSERT_TRUE(mService->isRemote()); mService->getFmqUnsyncWrite(true /* configureFmq */, [this](bool ret, const MQDescriptorUnsync<uint16_t>& in) { ASSERT_TRUE(ret); mQueue = new (std::nothrow) MessageQueueUnsync(in); }); ASSERT_NE(nullptr, mQueue); ASSERT_TRUE(mQueue->isValid()); mNumMessagesMax = mQueue->getQuantumCount(); } sp<ITestMsgQ> mService; MessageQueueUnsync* mQueue = nullptr; size_t mNumMessagesMax = 0; }; /* * Utility function to verify data read from the fast message queue. */ bool verifyData(uint16_t* data, size_t count) { for (size_t i = 0; i < count; i++) { if (data[i] != i) return false; } return true; } /* * Utility function to initialize data to be written to the FMQ */ inline void initData(uint16_t* data, size_t count) { for (size_t i = 0; i < count; i++) { data[i] = i; } } /* * Verify that for an unsynchronized flavor of FMQ, multiple readers * can recover from a write overflow condition. */ TEST_F(UnsynchronizedWriteClientMultiProcess, MultipleReadersAfterOverflow) { const size_t dataLen = 16; pid_t pid; /* creating first reader process */ if ((pid = fork()) == 0) { sp<ITestMsgQ> testService; MessageQueueUnsync* queue = nullptr; getQueue(&queue, &testService, true /* setupQueue */); ASSERT_NE(testService, nullptr); ASSERT_TRUE(testService->isRemote()); ASSERT_NE(queue, nullptr); ASSERT_TRUE(queue->isValid()); size_t numMessagesMax = queue->getQuantumCount(); // The following two writes will cause a write overflow. auto ret = testService->requestWriteFmqUnsync(numMessagesMax); ASSERT_TRUE(ret.isOk()); ASSERT_TRUE(ret); ret = testService->requestWriteFmqUnsync(1); ASSERT_TRUE(ret.isOk()); ASSERT_TRUE(ret); // The following read should fail due to the overflow. std::vector<uint16_t> readData(numMessagesMax); ASSERT_FALSE(queue->read(&readData[0], numMessagesMax)); /* * Request another write to verify that the reader can recover from the * overflow condition. */ ASSERT_LT(dataLen, numMessagesMax); ret = testService->requestWriteFmqUnsync(dataLen); ASSERT_TRUE(ret.isOk()); ASSERT_TRUE(ret); // Verify that the read is successful. ASSERT_TRUE(queue->read(&readData[0], dataLen)); ASSERT_TRUE(verifyData(&readData[0], dataLen)); delete queue; exit(0); } ASSERT_GT(pid, 0 /* parent should see PID greater than 0 for a good fork */); int status; // wait for the first reader process to exit. ASSERT_EQ(pid, waitpid(pid, &status, 0 /* options */)); // creating second reader process. if ((pid = fork()) == 0) { sp<ITestMsgQ> testService; MessageQueueUnsync* queue = nullptr; getQueue(&queue, &testService, false /* setupQueue */); ASSERT_NE(testService, nullptr); ASSERT_TRUE(testService->isRemote()); ASSERT_NE(queue, nullptr); ASSERT_TRUE(queue->isValid()); // This read should fail due to the write overflow. std::vector<uint16_t> readData(dataLen); ASSERT_FALSE(queue->read(&readData[0], dataLen)); /* * Request another write to verify that the process that recover from * the overflow condition. */ auto ret = testService->requestWriteFmqUnsync(dataLen); ASSERT_TRUE(ret.isOk()); ASSERT_TRUE(ret); // verify that the read is successful. ASSERT_TRUE(queue->read(&readData[0], dataLen)); ASSERT_TRUE(verifyData(&readData[0], dataLen)); delete queue; exit(0); } ASSERT_GT(pid, 0 /* parent should see PID greater than 0 for a good fork */); ASSERT_EQ(pid, waitpid(pid, &status, 0 /* options */)); } /* * Test that basic blocking works using readBlocking()/writeBlocking() APIs * using the EventFlag object owned by FMQ. */ TEST_F(SynchronizedReadWriteClient, BlockingReadWrite1) { const size_t dataLen = 64; uint16_t data[dataLen] = {0}; /* * Request service to perform a blocking read. This call is oneway and will * return immediately. */ mService->requestBlockingRead(dataLen); bool ret = mQueue->writeBlocking(data, dataLen, static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), 5000000000 /* timeOutNanos */); ASSERT_TRUE(ret); ret = mQueue->writeBlocking(data, mNumMessagesMax, static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), 5000000000 /* timeOutNanos */); ASSERT_TRUE(ret); } /* * Test that basic blocking works using readBlocking()/writeBlocking() APIs * using the EventFlag object owned by FMQ and using the default EventFlag * notification bit mask. */ TEST_F(SynchronizedReadWriteClient, BlockingReadWrite2) { const size_t dataLen = 64; std::vector<uint16_t> data(mNumMessagesMax); /* * Request service to perform a blocking read using default EventFlag * notification bit mask. This call is oneway and will * return immediately. */ mService->requestBlockingReadDefaultEventFlagBits(dataLen); /* Cause a context switch to allow service to block */ sched_yield(); bool ret = mQueue->writeBlocking(&data[0], dataLen); ASSERT_TRUE(ret); /* * If the blocking read was successful, another write of size * mNumMessagesMax will succeed. */ ret = mQueue->writeBlocking(&data[0], mNumMessagesMax, 5000000000 /* timeOutNanos */); ASSERT_TRUE(ret); } /* * Test that repeated blocking reads and writes work using readBlocking()/writeBlocking() APIs * using the EventFlag object owned by FMQ. * Each write operation writes the same amount of data as a single read * operation. */ TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat1) { const size_t dataLen = 64; uint16_t data[dataLen] = {0}; bool ret = false; /* * Request service to perform a blocking read. This call is oneway and will * return immediately. */ const size_t writeCount = 1024; mService->requestBlockingReadRepeat(dataLen, writeCount); for (size_t i = 0; i < writeCount; i++) { ret = mQueue->writeBlocking(data, dataLen, static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), 5000000000 /* timeOutNanos */); ASSERT_TRUE(ret); } ret = mQueue->writeBlocking(data, mNumMessagesMax, static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), 5000000000 /* timeOutNanos */); ASSERT_TRUE(ret); } /* * Test that repeated blocking reads and writes work using readBlocking()/writeBlocking() APIs * using the EventFlag object owned by FMQ. Each read operation reads twice the * amount of data as a single write. * */ TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat2) { const size_t dataLen = 64; uint16_t data[dataLen] = {0}; bool ret = false; /* * Request service to perform a blocking read. This call is oneway and will * return immediately. */ const size_t writeCount = 1024; mService->requestBlockingReadRepeat(dataLen*2, writeCount/2); for (size_t i = 0; i < writeCount; i++) { ret = mQueue->writeBlocking(data, dataLen, static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), 5000000000 /* timeOutNanos */); ASSERT_TRUE(ret); } ret = mQueue->writeBlocking(data, mNumMessagesMax, static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), 5000000000 /* timeOutNanos */); ASSERT_TRUE(ret); } /* * Test that basic blocking works using readBlocking()/writeBlocking() APIs * using the EventFlag object owned by FMQ. Each write operation writes twice * the amount of data as a single read. */ TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat3) { const size_t dataLen = 64; uint16_t data[dataLen] = {0}; bool ret = false; /* * Request service to perform a blocking read. This call is oneway and will * return immediately. */ size_t writeCount = 1024; mService->requestBlockingReadRepeat(dataLen/2, writeCount*2); for (size_t i = 0; i < writeCount; i++) { ret = mQueue->writeBlocking(data, dataLen, static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), 5000000000 /* timeOutNanos */); ASSERT_TRUE(ret); } ret = mQueue->writeBlocking(data, mNumMessagesMax, static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), 5000000000 /* timeOutNanos */); ASSERT_TRUE(ret); } /* * Test that writeBlocking()/readBlocking() APIs do not block on * attempts to write/read 0 messages and return true. */ TEST_F(SynchronizedReadWriteClient, BlockingReadWriteZeroMessages) { uint16_t data = 0; /* * Trigger a blocking write for zero messages with no timeout. */ bool ret = mQueue->writeBlocking( &data, 0, static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY)); ASSERT_TRUE(ret); /* * Trigger a blocking read for zero messages with no timeout. */ ret = mQueue->readBlocking(&data, 0, static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY)); ASSERT_TRUE(ret); } /* * Request mService to write a small number of messages * to the FMQ. Read and verify data. */ TEST_F(SynchronizedReadWriteClient, SmallInputReaderTest1) { const size_t dataLen = 16; ASSERT_LE(dataLen, mNumMessagesMax); bool ret = mService->requestWriteFmqSync(dataLen); ASSERT_TRUE(ret); uint16_t readData[dataLen] = {}; ASSERT_TRUE(mQueue->read(readData, dataLen)); ASSERT_TRUE(verifyData(readData, dataLen)); } /* * Request mService to write a small number of messages * to the FMQ. Read and verify each message using * beginRead/Commit read APIs. */ TEST_F(SynchronizedReadWriteClient, SmallInputReaderTest2) { const size_t dataLen = 16; ASSERT_LE(dataLen, mNumMessagesMax); auto ret = mService->requestWriteFmqSync(dataLen); ASSERT_TRUE(ret.isOk()); ASSERT_TRUE(ret); MessageQueueSync::MemTransaction tx; ASSERT_TRUE(mQueue->beginRead(dataLen, &tx)); auto first = tx.getFirstRegion(); auto second = tx.getSecondRegion(); size_t firstRegionLength = first.getLength(); for (size_t i = 0; i < dataLen; i++) { if (i < firstRegionLength) { ASSERT_EQ(i, *(first.getAddress() + i)); } else { ASSERT_EQ(i, *(second.getAddress() + i - firstRegionLength)); } } ASSERT_TRUE(mQueue->commitRead(dataLen)); } /* * Write a small number of messages to FMQ. Request * mService to read and verify that the write was succesful. */ TEST_F(SynchronizedReadWriteClient, SmallInputWriterTest1) { const size_t dataLen = 16; ASSERT_LE(dataLen, mNumMessagesMax); size_t originalCount = mQueue->availableToWrite(); uint16_t data[dataLen]; initData(data, dataLen); ASSERT_TRUE(mQueue->write(data, dataLen)); bool ret = mService->requestReadFmqSync(dataLen); ASSERT_TRUE(ret); size_t availableCount = mQueue->availableToWrite(); ASSERT_EQ(originalCount, availableCount); } /* * Write a small number of messages to FMQ using the beginWrite()/CommitWrite() * APIs. Request mService to read and verify that the write was succesful. */ TEST_F(SynchronizedReadWriteClient, SmallInputWriterTest2) { const size_t dataLen = 16; ASSERT_LE(dataLen, mNumMessagesMax); size_t originalCount = mQueue->availableToWrite(); uint16_t data[dataLen]; initData(data, dataLen); MessageQueueSync::MemTransaction tx; ASSERT_TRUE(mQueue->beginWrite(dataLen, &tx)); auto first = tx.getFirstRegion(); auto second = tx.getSecondRegion(); size_t firstRegionLength = first.getLength(); uint16_t* firstBaseAddress = first.getAddress(); uint16_t* secondBaseAddress = second.getAddress(); for (size_t i = 0; i < dataLen; i++) { if (i < firstRegionLength) { *(firstBaseAddress + i) = i; } else { *(secondBaseAddress + i - firstRegionLength) = i; } } ASSERT_TRUE(mQueue->commitWrite(dataLen)); auto ret = mService->requestReadFmqSync(dataLen); ASSERT_TRUE(ret.isOk()); ASSERT_TRUE(ret); size_t availableCount = mQueue->availableToWrite(); ASSERT_EQ(originalCount, availableCount); } /* * Verify that the FMQ is empty and read fails when it is empty. */ TEST_F(SynchronizedReadWriteClient, ReadWhenEmpty) { ASSERT_EQ(0UL, mQueue->availableToRead()); const size_t numMessages = 2; ASSERT_LE(numMessages, mNumMessagesMax); uint16_t readData[numMessages]; ASSERT_FALSE(mQueue->read(readData, numMessages)); } /* * Verify FMQ is empty. * Write enough messages to fill it. * Verify availableToWrite() method returns is zero. * Try writing another message and verify that * the attempted write was unsuccesful. Request mService * to read and verify the messages in the FMQ. */ TEST_F(SynchronizedReadWriteClient, WriteWhenFull) { std::vector<uint16_t> data(mNumMessagesMax); initData(&data[0], mNumMessagesMax); ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); ASSERT_EQ(0UL, mQueue->availableToWrite()); ASSERT_FALSE(mQueue->write(&data[0], 1)); bool ret = mService->requestReadFmqSync(mNumMessagesMax); ASSERT_TRUE(ret); } /* * Verify FMQ is empty. * Request mService to write data equal to queue size. * Read and verify data in mQueue. */ TEST_F(SynchronizedReadWriteClient, LargeInputTest1) { bool ret = mService->requestWriteFmqSync(mNumMessagesMax); ASSERT_TRUE(ret); std::vector<uint16_t> readData(mNumMessagesMax); ASSERT_TRUE(mQueue->read(&readData[0], mNumMessagesMax)); ASSERT_TRUE(verifyData(&readData[0], mNumMessagesMax)); } /* * Request mService to write more than maximum number of messages to the FMQ. * Verify that the write fails. Verify that availableToRead() method * still returns 0 and verify that attempt to read fails. */ TEST_F(SynchronizedReadWriteClient, LargeInputTest2) { ASSERT_EQ(0UL, mQueue->availableToRead()); const size_t numMessages = 2048; ASSERT_GT(numMessages, mNumMessagesMax); bool ret = mService->requestWriteFmqSync(numMessages); ASSERT_FALSE(ret); uint16_t readData; ASSERT_EQ(0UL, mQueue->availableToRead()); ASSERT_FALSE(mQueue->read(&readData, 1)); } /* * Write until FMQ is full. * Verify that the number of messages available to write * is equal to mNumMessagesMax. * Verify that another write attempt fails. * Request mService to read. Verify read count. */ TEST_F(SynchronizedReadWriteClient, LargeInputTest3) { std::vector<uint16_t> data(mNumMessagesMax); initData(&data[0], mNumMessagesMax); ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); ASSERT_EQ(0UL, mQueue->availableToWrite()); ASSERT_FALSE(mQueue->write(&data[0], 1)); bool ret = mService->requestReadFmqSync(mNumMessagesMax); ASSERT_TRUE(ret); } /* * Confirm that the FMQ is empty. Request mService to write to FMQ. * Do multiple reads to empty FMQ and verify data. */ TEST_F(SynchronizedReadWriteClient, MultipleRead) { const size_t chunkSize = 100; const size_t chunkNum = 5; const size_t numMessages = chunkSize * chunkNum; ASSERT_LE(numMessages, mNumMessagesMax); size_t availableToRead = mQueue->availableToRead(); size_t expectedCount = 0; ASSERT_EQ(expectedCount, availableToRead); bool ret = mService->requestWriteFmqSync(numMessages); ASSERT_TRUE(ret); uint16_t readData[numMessages] = {}; for (size_t i = 0; i < chunkNum; i++) { ASSERT_TRUE(mQueue->read(readData + i * chunkSize, chunkSize)); } ASSERT_TRUE(verifyData(readData, numMessages)); } /* * Write to FMQ in bursts. * Request mService to read data. Verify the read was successful. */ TEST_F(SynchronizedReadWriteClient, MultipleWrite) { const size_t chunkSize = 100; const size_t chunkNum = 5; const size_t numMessages = chunkSize * chunkNum; ASSERT_LE(numMessages, mNumMessagesMax); uint16_t data[numMessages]; initData(&data[0], numMessages); for (size_t i = 0; i < chunkNum; i++) { ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize)); } bool ret = mService->requestReadFmqSync(numMessages); ASSERT_TRUE(ret); } /* * Write enough messages into the FMQ to fill half of it. * Request mService to read back the same. * Write mNumMessagesMax messages into the queue. This should cause a * wrap around. Request mService to read and verify the data. */ TEST_F(SynchronizedReadWriteClient, ReadWriteWrapAround) { size_t numMessages = mNumMessagesMax / 2; std::vector<uint16_t> data(mNumMessagesMax); initData(&data[0], mNumMessagesMax); ASSERT_TRUE(mQueue->write(&data[0], numMessages)); bool ret = mService->requestReadFmqSync(numMessages); ASSERT_TRUE(ret); ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); ret = mService->requestReadFmqSync(mNumMessagesMax); ASSERT_TRUE(ret); } /* * Use beginWrite/commitWrite/getSlot APIs to test wrap arounds are handled * correctly. * Write enough messages into the FMQ to fill half of it * and read back the same. * Write mNumMessagesMax messages into the queue. This will cause a * wrap around. Read and verify the data. */ TEST_F(SynchronizedReadWriteClient, ReadWriteWrapAround2) { size_t numMessages = mNumMessagesMax / 2; std::vector<uint16_t> data(mNumMessagesMax); initData(&data[0], mNumMessagesMax); ASSERT_TRUE(mQueue->write(&data[0], numMessages)); auto ret = mService->requestReadFmqSync(numMessages); ASSERT_TRUE(ret.isOk()); ASSERT_TRUE(ret); /* * The next write and read will have to deal with with wrap arounds. */ MessageQueueSync::MemTransaction tx; ASSERT_TRUE(mQueue->beginWrite(mNumMessagesMax, &tx)); ASSERT_EQ(tx.getFirstRegion().getLength() + tx.getSecondRegion().getLength(), mNumMessagesMax); for (size_t i = 0; i < mNumMessagesMax; i++) { uint16_t* ptr = tx.getSlot(i); *ptr = data[i]; } ASSERT_TRUE(mQueue->commitWrite(mNumMessagesMax)); ret = mService->requestReadFmqSync(mNumMessagesMax); ASSERT_TRUE(ret.isOk()); ASSERT_TRUE(ret); } /* * Request mService to write a small number of messages * to the FMQ. Read and verify data. */ TEST_F(UnsynchronizedWriteClient, SmallInputReaderTest1) { const size_t dataLen = 16; ASSERT_LE(dataLen, mNumMessagesMax); bool ret = mService->requestWriteFmqUnsync(dataLen); ASSERT_TRUE(ret); uint16_t readData[dataLen] = {}; ASSERT_TRUE(mQueue->read(readData, dataLen)); ASSERT_TRUE(verifyData(readData, dataLen)); } /* * Write a small number of messages to FMQ. Request * mService to read and verify that the write was succesful. */ TEST_F(UnsynchronizedWriteClient, SmallInputWriterTest1) { const size_t dataLen = 16; ASSERT_LE(dataLen, mNumMessagesMax); uint16_t data[dataLen]; initData(data, dataLen); ASSERT_TRUE(mQueue->write(data, dataLen)); bool ret = mService->requestReadFmqUnsync(dataLen); ASSERT_TRUE(ret); } /* * Verify that the FMQ is empty and read fails when it is empty. */ TEST_F(UnsynchronizedWriteClient, ReadWhenEmpty) { ASSERT_EQ(0UL, mQueue->availableToRead()); const size_t numMessages = 2; ASSERT_LE(numMessages, mNumMessagesMax); uint16_t readData[numMessages]; ASSERT_FALSE(mQueue->read(readData, numMessages)); } /* * Verify FMQ is empty. * Write enough messages to fill it. * Verify availableToWrite() method returns is zero. * Try writing another message and verify that * the attempted write was successful. Request mService * to read the messages in the FMQ and verify that it is unsuccesful. */ TEST_F(UnsynchronizedWriteClient, WriteWhenFull) { std::vector<uint16_t> data(mNumMessagesMax); initData(&data[0], mNumMessagesMax); ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); ASSERT_EQ(0UL, mQueue->availableToWrite()); ASSERT_TRUE(mQueue->write(&data[0], 1)); bool ret = mService->requestReadFmqUnsync(mNumMessagesMax); ASSERT_FALSE(ret); } /* * Verify FMQ is empty. * Request mService to write data equal to queue size. * Read and verify data in mQueue. */ TEST_F(UnsynchronizedWriteClient, LargeInputTest1) { bool ret = mService->requestWriteFmqUnsync(mNumMessagesMax); ASSERT_TRUE(ret); std::vector<uint16_t> data(mNumMessagesMax); ASSERT_TRUE(mQueue->read(&data[0], mNumMessagesMax)); ASSERT_TRUE(verifyData(&data[0], mNumMessagesMax)); } /* * Request mService to write more than maximum number of messages to the FMQ. * Verify that the write fails. Verify that availableToRead() method * still returns 0 and verify that attempt to read fails. */ TEST_F(UnsynchronizedWriteClient, LargeInputTest2) { ASSERT_EQ(0UL, mQueue->availableToRead()); const size_t numMessages = mNumMessagesMax + 1; bool ret = mService->requestWriteFmqUnsync(numMessages); ASSERT_FALSE(ret); uint16_t readData; ASSERT_EQ(0UL, mQueue->availableToRead()); ASSERT_FALSE(mQueue->read(&readData, 1)); } /* * Write until FMQ is full. * Verify that the number of messages available to write * is equal to mNumMessagesMax. * Verify that another write attempt is succesful. * Request mService to read. Verify that read is unsuccessful. * Perform another write and verify that the read is succesful * to check if the reader process can recover from the error condition. */ TEST_F(UnsynchronizedWriteClient, LargeInputTest3) { std::vector<uint16_t> data(mNumMessagesMax); initData(&data[0], mNumMessagesMax); ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); ASSERT_EQ(0UL, mQueue->availableToWrite()); ASSERT_TRUE(mQueue->write(&data[0], 1)); bool ret = mService->requestReadFmqUnsync(mNumMessagesMax); ASSERT_FALSE(ret); ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); ret = mService->requestReadFmqUnsync(mNumMessagesMax); ASSERT_TRUE(ret); } /* * Confirm that the FMQ is empty. Request mService to write to FMQ. * Do multiple reads to empty FMQ and verify data. */ TEST_F(UnsynchronizedWriteClient, MultipleRead) { const size_t chunkSize = 100; const size_t chunkNum = 5; const size_t numMessages = chunkSize * chunkNum; ASSERT_LE(numMessages, mNumMessagesMax); size_t availableToRead = mQueue->availableToRead(); size_t expectedCount = 0; ASSERT_EQ(expectedCount, availableToRead); bool ret = mService->requestWriteFmqUnsync(numMessages); ASSERT_TRUE(ret); uint16_t readData[numMessages] = {}; for (size_t i = 0; i < chunkNum; i++) { ASSERT_TRUE(mQueue->read(readData + i * chunkSize, chunkSize)); } ASSERT_TRUE(verifyData(readData, numMessages)); } /* * Write to FMQ in bursts. * Request mService to read data, verify that it was successful. */ TEST_F(UnsynchronizedWriteClient, MultipleWrite) { const size_t chunkSize = 100; const size_t chunkNum = 5; const size_t numMessages = chunkSize * chunkNum; ASSERT_LE(numMessages, mNumMessagesMax); uint16_t data[numMessages]; initData(data, numMessages); for (size_t i = 0; i < chunkNum; i++) { ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize)); } bool ret = mService->requestReadFmqUnsync(numMessages); ASSERT_TRUE(ret); } /* * Write enough messages into the FMQ to fill half of it. * Request mService to read back the same. * Write mNumMessagesMax messages into the queue. This should cause a * wrap around. Request mService to read and verify the data. */ TEST_F(UnsynchronizedWriteClient, ReadWriteWrapAround) { size_t numMessages = mNumMessagesMax / 2; std::vector<uint16_t> data(mNumMessagesMax); initData(&data[0], mNumMessagesMax); ASSERT_TRUE(mQueue->write(&data[0], numMessages)); bool ret = mService->requestReadFmqUnsync(numMessages); ASSERT_TRUE(ret); ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); ret = mService->requestReadFmqUnsync(mNumMessagesMax); ASSERT_TRUE(ret); } /* * Request mService to write a small number of messages * to the FMQ. Read and verify data from two threads configured * as readers to the FMQ. */ TEST_F(UnsynchronizedWriteClient, SmallInputMultipleReaderTest) { auto desc = mQueue->getDesc(); std::unique_ptr<MessageQueue<uint16_t, kUnsynchronizedWrite>> mQueue2( new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>(*desc)); ASSERT_NE(nullptr, mQueue2.get()); const size_t dataLen = 16; ASSERT_LE(dataLen, mNumMessagesMax); bool ret = mService->requestWriteFmqUnsync(dataLen); ASSERT_TRUE(ret); pid_t pid; if ((pid = fork()) == 0) { /* child process */ uint16_t readData[dataLen] = {}; ASSERT_TRUE(mQueue2->read(readData, dataLen)); ASSERT_TRUE(verifyData(readData, dataLen)); exit(0); } else { ASSERT_GT(pid, 0 /* parent should see PID greater than 0 for a good fork */); uint16_t readData[dataLen] = {}; ASSERT_TRUE(mQueue->read(readData, dataLen)); ASSERT_TRUE(verifyData(readData, dataLen)); } } /* * Request mService to write into the FMQ until it is full. * Request mService to do another write and verify it is successful. * Use two reader processes to read and verify that both fail. */ TEST_F(UnsynchronizedWriteClient, OverflowNotificationTest) { auto desc = mQueue->getDesc(); std::unique_ptr<MessageQueue<uint16_t, kUnsynchronizedWrite>> mQueue2( new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>(*desc)); ASSERT_NE(nullptr, mQueue2.get()); bool ret = mService->requestWriteFmqUnsync(mNumMessagesMax); ASSERT_TRUE(ret); ret = mService->requestWriteFmqUnsync(1); ASSERT_TRUE(ret); pid_t pid; if ((pid = fork()) == 0) { /* child process */ std::vector<uint16_t> readData(mNumMessagesMax); ASSERT_FALSE(mQueue2->read(&readData[0], mNumMessagesMax)); exit(0); } else { ASSERT_GT(pid, 0/* parent should see PID greater than 0 for a good fork */); std::vector<uint16_t> readData(mNumMessagesMax); ASSERT_FALSE(mQueue->read(&readData[0], mNumMessagesMax)); } }