blob: 85ee64f9aa66ec617e58621ac8b6b114cfa2ee6f [file] [log] [blame]
/*
* 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 <ITestMsgQ.h>
#include <android-base/logging.h>
#include <asm-generic/mman.h>
#include <cutils/ashmem.h>
#include <gtest/gtest.h>
#include <hwbinder/IServiceManager.h>
#include <utils/String16.h>
#include <utils/StrongPointer.h>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include "common/MessageQueue.h"
// libutils:
using android::OK;
using android::sp;
using android::status_t;
using android::String16;
// libbinder:
using android::hardware::getService;
using android::hardware::hidl_version;
using android::hardware::make_hidl_version;
using android::hardware::gen_ref;
using android::hardware::from_ref;
// generated
using android::hardware::tests::ITestMsgQ;
using std::cerr;
using std::cout;
using std::endl;
static int numMessagesMax;
namespace android {
namespace hardware {
namespace tests {
namespace client {
const char kServiceName[] = "android.hardware.tests.ITestMsgQ";
bool GetService(sp<ITestMsgQ>* service, hidl_version version) {
status_t status = getService(String16(kServiceName), version, service);
if (status != OK) {
cerr << "Failed to get service binder: '" << kServiceName
<< "' status=" << status << endl;
return false;
}
return true;
}
} // namespace client
} // namespace tests
} // namespace hardware
} // namespace android
class MQTestClient : public ::testing::Test {
protected:
virtual void TearDown() {
if (fmsg_queue) {
delete fmsg_queue;
}
}
virtual void SetUp() {
namespace client_tests = android::hardware::tests::client;
hidl_version version = make_hidl_version(4, 0);
if (!client_tests::GetService(&service, version)) return;
service->configure([this](const ITestMsgQ::WireMQDescriptor& in) {
create_mq_from_wiremqdesc(&this->fmsg_queue, &in);
});
ASSERT_TRUE(fmsg_queue != nullptr);
ASSERT_TRUE(fmsg_queue->isValid());
numMessagesMax = fmsg_queue->getQuantumCount();
}
sp<ITestMsgQ> service;
android::hardware::MessageQueue<uint16_t>* fmsg_queue;
private:
void create_mq_from_wiremqdesc(android::hardware::MessageQueue<uint16_t>** rbIn,
const ITestMsgQ::WireMQDescriptor* wmq_desc) {
/*
* Create a copy of the native handle from the WireMQDescriptor.
*/
native_handle_t* mq_handle = native_handle_create(
wmq_desc->mq_handle->numFds, wmq_desc->mq_handle->numInts);
if (mq_handle == nullptr) return;
for (int i = 0; i < wmq_desc->mq_handle->numFds; i++)
mq_handle->data[i] = wmq_desc->mq_handle->data[i];
memcpy(&mq_handle->data[mq_handle->numFds],
&wmq_desc->mq_handle->data[mq_handle->numFds],
mq_handle->numInts * sizeof(int));
/*
* Create the vector of GrantorDescriptors.
*/
std::vector<android::hardware::GrantorDescriptor> Grantors(
MINIMUM_GRANTOR_COUNT);
Grantors[android::hardware::READPTRPOS] = {
0, wmq_desc->grantors.buffer[android::hardware::READPTRPOS].shm.fdIndex,
wmq_desc->grantors.buffer[android::hardware::READPTRPOS].shm.offset,
wmq_desc->grantors.buffer[android::hardware::READPTRPOS].shm.extent};
Grantors[android::hardware::WRITEPTRPOS] = {
0, wmq_desc->grantors.buffer[android::hardware::WRITEPTRPOS].shm.fdIndex,
wmq_desc->grantors.buffer[android::hardware::WRITEPTRPOS].shm.offset,
wmq_desc->grantors.buffer[android::hardware::WRITEPTRPOS].shm.extent};
Grantors[android::hardware::DATAPTRPOS] = {
0, wmq_desc->grantors.buffer[android::hardware::DATAPTRPOS].shm.fdIndex,
wmq_desc->grantors.buffer[android::hardware::DATAPTRPOS].shm.offset,
wmq_desc->grantors.buffer[android::hardware::DATAPTRPOS].shm.extent};
android::hardware::MQDescriptor mq_desc(Grantors, mq_handle, 0,
sizeof(uint16_t));
*rbIn = new android::hardware::MessageQueue<uint16_t>(mq_desc);
}
};
/*
* Utility function to verify data read from the fast message queue.
*/
bool verifyData(uint16_t* data, int count) {
for (int i = 0; i < count; i++) {
if (data[i] != i) return false;
}
return true;
}
/* Request service to write a small number of messages
* to the FMQ. Read and verify data.
*/
TEST_F(MQTestClient, SmallInputReaderTest1) {
const int data_len = 16;
ASSERT_TRUE(data_len <= numMessagesMax);
int write_count = -1;
service->requestWrite(data_len,
[&write_count](auto ret) { write_count = ret; });
ASSERT_EQ(write_count, data_len);
uint16_t read_data[data_len] = {};
ASSERT_TRUE(fmsg_queue->read(read_data, data_len));
ASSERT_TRUE(verifyData(read_data, data_len));
}
/*
* Write a small number of messages to FMQ. Request
* service to read and verify that the write was succesful.
*/
TEST_F(MQTestClient, SmallInputWriterTest1) {
const int data_len = 16;
ASSERT_TRUE(data_len <= numMessagesMax);
size_t original_count = fmsg_queue->availableToWrite();
uint16_t data[data_len];
for (int i = 0; i < data_len; i++) {
data[i] = i;
}
ASSERT_TRUE(fmsg_queue->write(data, data_len));
int read_count = -1;
service->requestRead(data_len, [&read_count](auto ret) { read_count = ret; });
ASSERT_EQ(read_count, data_len);
size_t available_count = fmsg_queue->availableToWrite();
ASSERT_EQ(original_count, available_count);
}
/*
* Verify that the FMQ is empty and read fails when it is empty.
*/
TEST_F(MQTestClient, ReadWhenEmpty) {
ASSERT_TRUE(fmsg_queue->availableToRead() == 0);
const int numMessages = 2;
ASSERT_TRUE(numMessages <= numMessagesMax);
uint16_t read_data[numMessages];
ASSERT_FALSE(fmsg_queue->read(read_data, 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 service
* to read and verify the messages in the FMQ.
*/
TEST_F(MQTestClient, WriteWhenFull) {
uint16_t* data = new uint16_t[numMessagesMax];
for (int i = 0; i < numMessagesMax; i++) {
data[i] = i;
}
ASSERT_TRUE(fmsg_queue->write(data, numMessagesMax));
ASSERT_TRUE(fmsg_queue->availableToWrite() == 0);
ASSERT_FALSE(fmsg_queue->write(data, 1));
int read_count = -1;
service->requestRead(numMessagesMax,
[&read_count](auto ret) { read_count = ret; });
ASSERT_EQ(read_count, numMessagesMax);
delete[] data;
}
/*
* Verify FMQ is empty.
* Request service to write data equal to queue size.
* Read and verify data in fmsg_queue.
*/
TEST_F(MQTestClient, LargeInputTest1) {
int write_count = -1;
service->requestWrite(numMessagesMax,
[&write_count](auto ret) { write_count = ret; });
ASSERT_EQ(write_count, numMessagesMax);
uint16_t* read_data = new uint16_t[numMessagesMax]();
ASSERT_TRUE(fmsg_queue->read(read_data, numMessagesMax));
ASSERT_TRUE(verifyData(read_data, numMessagesMax));
delete[] read_data;
}
/*
* Request service 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(MQTestClient, LargeInputTest2) {
ASSERT_TRUE(fmsg_queue->availableToRead() == 0);
const int numMessages = 2048;
ASSERT_TRUE(numMessages > numMessagesMax);
int write_count = -1, expected_count = 0;
service->requestWrite(numMessages,
[&write_count](auto ret) { write_count = ret; });
ASSERT_EQ(write_count, expected_count);
uint16_t read_data;
ASSERT_TRUE(fmsg_queue->availableToRead() == 0);
ASSERT_FALSE(fmsg_queue->read(&read_data, 1));
}
/*
* Write until FMQ is full.
* Verify that the number of messages available to write
* is equal to numMessagesMax.
* Verify that another write attempt fails.
* Request service to read. Verify read count.
*/
TEST_F(MQTestClient, LargeInputTest3) {
uint16_t* data = new uint16_t[numMessagesMax];
for (int i = 0; i < numMessagesMax; i++) {
data[i] = i;
}
ASSERT_TRUE(fmsg_queue->write(data, numMessagesMax));
ASSERT_TRUE(fmsg_queue->availableToWrite() == 0);
ASSERT_FALSE(fmsg_queue->write(data, 1));
int read_count = -1;
service->requestRead(numMessagesMax,
[&read_count](auto ret) { read_count = ret; });
ASSERT_EQ(read_count, numMessagesMax);
delete[] data;
}
/*
* Confirm that the FMQ is empty. Request service to write to FMQ.
* Do multiple reads to empty FMQ and verify data.
*/
TEST_F(MQTestClient, MultipleRead) {
const int chunkSize = 100;
const int chunkNum = 5;
const int numMessages = chunkSize * chunkNum;
ASSERT_TRUE(numMessages <= numMessagesMax);
int availableToRead = fmsg_queue->availableToRead();
int expected_count = 0;
ASSERT_EQ(availableToRead, expected_count);
int write_count = 0;
service->requestWrite(numMessages,
[&write_count](auto ret) { write_count = ret; });
ASSERT_EQ(write_count, numMessages);
uint16_t read_data[numMessages] = {};
for (int i = 0; i < chunkNum; i++) {
ASSERT_TRUE(fmsg_queue->read(read_data + i * chunkSize, chunkSize));
}
ASSERT_TRUE(verifyData(read_data, numMessages));
}
/*
* Write to FMQ in bursts.
* Request service to read data. Verify read_count.
*/
TEST_F(MQTestClient, MultipleWrite) {
const int chunkSize = 100;
const int chunkNum = 5;
const int numMessages = chunkSize * chunkNum;
ASSERT_TRUE(numMessages <= numMessagesMax);
uint16_t data[numMessages];
for (int i = 0; i < numMessages; i++) {
data[i] = i;
}
for (int i = 0; i < chunkNum; i++) {
ASSERT_TRUE(fmsg_queue->write(data + i * chunkSize, chunkSize));
}
int read_count = -1;
service->requestRead(numMessages,
[&read_count](auto ret) { read_count = ret; });
ASSERT_TRUE(read_count == numMessages);
}
/*
* Write enough messages into the FMQ to fill half of it.
* Request service to read back the same.
* Write numMessagesMax messages into the queue. This should cause a
* wrap around. Request service to read and verify the data.
*/
TEST_F(MQTestClient, ReadWriteWrapAround) {
int numMessages = numMessagesMax / 2;
uint16_t* data = new uint16_t[numMessagesMax];
for (int i = 0; i < numMessagesMax; i++) {
data[i] = i;
}
ASSERT_TRUE(fmsg_queue->write(data, numMessages));
int read_count = -1;
service->requestRead(numMessages,
[&read_count](auto ret) { read_count = ret; });
ASSERT_TRUE(read_count == numMessages);
ASSERT_TRUE(fmsg_queue->write(data, numMessagesMax));
read_count = -1;
service->requestRead(numMessagesMax,
[&read_count](auto ret) { read_count = ret; });
ASSERT_TRUE(read_count == numMessagesMax);
delete[] data;
}