Skip ab/6749736 in stage.
Merged-In: I6690e44e88b891558cd18cbd17e161da3eb41f46
Change-Id: I0590b0ce2e4245a471a2aeffa2b194c58d028968
diff --git a/Android.bp b/Android.bp
index e2cb961..3930742 100644
--- a/Android.bp
+++ b/Android.bp
@@ -31,6 +31,12 @@
],
export_include_dirs: ["include"],
local_include_dirs: ["include"],
+ header_libs: [
+ "libfmq-base",
+ ],
+ export_header_lib_headers: [
+ "libfmq-base",
+ ],
srcs: [
"EventFlag.cpp",
"FmqInternal.cpp",
@@ -48,3 +54,18 @@
double_loadable: true,
min_sdk_version: "29",
}
+
+// Header only lib to share type between HIDL and AIDL MQDescriptor
+cc_library_headers {
+ name: "libfmq-base",
+ host_supported: true,
+ vendor_available: true,
+ native_bridge_supported: true,
+ recovery_available: true,
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
+ export_include_dirs: ["base"],
+ min_sdk_version: "29",
+}
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 3973cbe..dfa7071 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "fmq_unit_tests"
+ },
+ {
+ "name": "fmq_test"
}
]
}
diff --git a/base/fmq/MQDescriptorBase.h b/base/fmq/MQDescriptorBase.h
new file mode 100644
index 0000000..21b8e21
--- /dev/null
+++ b/base/fmq/MQDescriptorBase.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <string>
+
+namespace android {
+namespace hardware {
+
+enum MQFlavor : uint32_t {
+ /*
+ * kSynchronizedReadWrite represents the wait-free synchronized flavor of the
+ * FMQ. It is intended to be have a single reader and single writer.
+ * Attempts to overflow/underflow returns a failure.
+ */
+ kSynchronizedReadWrite = 0x01,
+ /*
+ * kUnsynchronizedWrite represents the flavor of FMQ where writes always
+ * succeed. This flavor allows one writer and many readers. A read operation
+ * can detect an overwrite and reset the read counter.
+ */
+ kUnsynchronizedWrite = 0x02
+};
+
+struct GrantorDescriptor {
+ uint32_t flags __attribute__((aligned(4)));
+ uint32_t fdIndex __attribute__((aligned(4)));
+ uint32_t offset __attribute__((aligned(4)));
+ uint64_t extent __attribute__((aligned(8)));
+};
+
+static_assert(offsetof(GrantorDescriptor, flags) == 0, "wrong offset");
+static_assert(offsetof(GrantorDescriptor, fdIndex) == 4, "wrong offset");
+static_assert(offsetof(GrantorDescriptor, offset) == 8, "wrong offset");
+static_assert(offsetof(GrantorDescriptor, extent) == 16, "wrong offset");
+static_assert(sizeof(GrantorDescriptor) == 24, "wrong size");
+static_assert(__alignof(GrantorDescriptor) == 8, "wrong alignment");
+
+namespace details {
+
+void logError(const std::string& message);
+
+typedef uint64_t RingBufferPosition;
+enum GrantorType : int { READPTRPOS = 0, WRITEPTRPOS, DATAPTRPOS, EVFLAGWORDPOS };
+/*
+ * There should at least be GrantorDescriptors for the read counter, write
+ * counter and data buffer. A GrantorDescriptor for an EventFlag word is
+ * not required if there is no need for blocking FMQ operations.
+ */
+static constexpr int32_t kMinGrantorCount = DATAPTRPOS + 1;
+
+/*
+ * Minimum number of GrantorDescriptors required if EventFlag support is
+ * needed for blocking FMQ operations.
+ */
+static constexpr int32_t kMinGrantorCountForEvFlagSupport = EVFLAGWORDPOS + 1;
+
+static inline size_t alignToWordBoundary(size_t length) {
+ constexpr size_t kAlignmentSize = 64;
+ if (kAlignmentSize % __WORDSIZE != 0) {
+#ifdef __BIONIC__
+ __assert(__FILE__, __LINE__, "Incompatible word size");
+#endif
+ }
+
+ /*
+ * Check if alignment to word boundary would cause an overflow.
+ */
+ if (length > SIZE_MAX - kAlignmentSize / 8 + 1) {
+#ifdef __BIONIC__
+ __assert(__FILE__, __LINE__, "Queue size too large");
+#endif
+ }
+
+ return (length + kAlignmentSize / 8 - 1) & ~(kAlignmentSize / 8 - 1U);
+}
+
+static inline size_t isAlignedToWordBoundary(size_t offset) {
+ constexpr size_t kAlignmentSize = 64;
+ return (offset & (kAlignmentSize / 8 - 1)) == 0;
+}
+
+} // namespace details
+} // namespace hardware
+} // namespace android
diff --git a/include/fmq/AidlMQDescriptorShim.h b/include/fmq/AidlMQDescriptorShim.h
new file mode 100644
index 0000000..eb4bbc2
--- /dev/null
+++ b/include/fmq/AidlMQDescriptorShim.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2020 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 <aidl/android/hardware/common/MQDescriptor.h>
+#include <cutils/native_handle.h>
+#include <fmq/MQDescriptorBase.h>
+#include <limits>
+#include <type_traits>
+
+namespace android {
+namespace details {
+
+using aidl::android::hardware::common::GrantorDescriptor;
+using aidl::android::hardware::common::MQDescriptor;
+using aidl::android::hardware::common::SynchronizedReadWrite;
+using aidl::android::hardware::common::UnsynchronizedWrite;
+using android::hardware::MQFlavor;
+
+template <typename T, MQFlavor flavor>
+struct AidlMQDescriptorShim {
+ // Takes ownership of handle
+ AidlMQDescriptorShim(
+ const MQDescriptor<
+ T, typename std::conditional<flavor == hardware::kSynchronizedReadWrite,
+ SynchronizedReadWrite, UnsynchronizedWrite>::type>&
+ desc);
+
+ // Takes ownership of handle
+ AidlMQDescriptorShim(size_t bufferSize, native_handle_t* nHandle, size_t messageSize,
+ bool configureEventFlag = false);
+
+ explicit AidlMQDescriptorShim(const AidlMQDescriptorShim& other)
+ : AidlMQDescriptorShim(0, nullptr, 0) {
+ *this = other;
+ }
+ AidlMQDescriptorShim& operator=(const AidlMQDescriptorShim& other);
+
+ ~AidlMQDescriptorShim();
+
+ size_t getSize() const;
+
+ size_t getQuantum() const;
+
+ uint32_t getFlags() const;
+
+ bool isHandleValid() const { return mHandle != nullptr; }
+ size_t countGrantors() const { return mGrantors.size(); }
+
+ inline const std::vector<android::hardware::GrantorDescriptor>& grantors() const {
+ return mGrantors;
+ }
+
+ inline const ::native_handle_t* handle() const { return mHandle; }
+
+ inline ::native_handle_t* handle() { return mHandle; }
+
+ static const size_t kOffsetOfGrantors;
+ static const size_t kOffsetOfHandle;
+
+ private:
+ std::vector<android::hardware::GrantorDescriptor> mGrantors;
+ native_handle_t* mHandle = nullptr;
+ uint32_t mQuantum = 0;
+ uint32_t mFlags = 0;
+};
+
+template <typename T, MQFlavor flavor>
+AidlMQDescriptorShim<T, flavor>::AidlMQDescriptorShim(
+ const MQDescriptor<T, typename std::conditional<flavor == hardware::kSynchronizedReadWrite,
+ SynchronizedReadWrite,
+ UnsynchronizedWrite>::type>& desc)
+ : mQuantum(desc.quantum), mFlags(desc.flags) {
+ if (desc.quantum < 0 || desc.flags < 0) {
+ // MQDescriptor uses signed integers, but the values must be positive.
+ hardware::details::logError("Invalid MQDescriptor. Values must be positive. quantum: " +
+ std::to_string(desc.quantum) +
+ ". flags: " + std::to_string(desc.flags));
+ return;
+ }
+
+ mGrantors.resize(desc.grantors.size());
+ for (size_t i = 0; i < desc.grantors.size(); ++i) {
+ if (desc.grantors[i].offset < 0 || desc.grantors[i].extent < 0) {
+ // GrantorDescriptor uses signed integers, but the values must be positive.
+ // Return before setting up the native_handle to make this invalid.
+ hardware::details::logError(
+ "Invalid MQDescriptor grantors. Values must be positive. Grantor index: " +
+ std::to_string(i) + ". offset: " + std::to_string(desc.grantors[i].offset) +
+ ". extent: " + std::to_string(desc.grantors[i].extent));
+ return;
+ }
+ mGrantors[i].flags = 0;
+ mGrantors[i].fdIndex = 0;
+ mGrantors[i].offset = desc.grantors[i].offset;
+ mGrantors[i].extent = desc.grantors[i].extent;
+ }
+
+ mHandle = native_handle_create(1 /* num fds */, 0 /* num ints */);
+ if (mHandle == nullptr) {
+ hardware::details::logError("Null native_handle_t");
+ return;
+ }
+ mHandle->data[0] = dup(desc.fileDescriptor.get());
+}
+
+template <typename T, MQFlavor flavor>
+AidlMQDescriptorShim<T, flavor>& AidlMQDescriptorShim<T, flavor>::operator=(
+ const AidlMQDescriptorShim& other) {
+ mGrantors = other.mGrantors;
+ if (mHandle != nullptr) {
+ native_handle_close(mHandle);
+ native_handle_delete(mHandle);
+ mHandle = nullptr;
+ }
+ mQuantum = other.mQuantum;
+ mFlags = other.mFlags;
+
+ if (other.mHandle != nullptr) {
+ mHandle = native_handle_create(other.mHandle->numFds, other.mHandle->numInts);
+
+ for (int i = 0; i < other.mHandle->numFds; ++i) {
+ mHandle->data[i] = dup(other.mHandle->data[i]);
+ }
+
+ memcpy(&mHandle->data[other.mHandle->numFds], &other.mHandle->data[other.mHandle->numFds],
+ static_cast<size_t>(other.mHandle->numInts) * sizeof(int));
+ }
+
+ return *this;
+}
+
+template <typename T, MQFlavor flavor>
+AidlMQDescriptorShim<T, flavor>::AidlMQDescriptorShim(size_t bufferSize, native_handle_t* nHandle,
+ size_t messageSize, bool configureEventFlag) {
+ /*
+ * TODO(b/165674950) Since AIDL does not support unsigned integers, it can only support
+ * The offset of EventFlag word needs to fit into an int32_t in MQDescriptor. This word comes
+ * after the readPtr, writePtr, and dataBuffer.
+ */
+ bool overflow = bufferSize > std::numeric_limits<uint64_t>::max() -
+ (sizeof(hardware::details::RingBufferPosition) +
+ sizeof(hardware::details::RingBufferPosition));
+ uint64_t largestOffset = hardware::details::alignToWordBoundary(
+ sizeof(hardware::details::RingBufferPosition) +
+ sizeof(hardware::details::RingBufferPosition) + bufferSize);
+ if (overflow || largestOffset > std::numeric_limits<int32_t>::max() ||
+ messageSize > std::numeric_limits<int32_t>::max()) {
+ hardware::details::logError(
+ "Queue size is too large. Message size: " + std::to_string(messageSize) +
+ " bytes. Data buffer size: " + std::to_string(bufferSize) + " bytes. Max size: " +
+ std::to_string(std::numeric_limits<int32_t>::max()) + " bytes.");
+ return;
+ }
+
+ mHandle = nHandle;
+ mQuantum = messageSize;
+ mFlags = flavor;
+ /*
+ * If configureEventFlag is true, allocate an additional spot in mGrantor
+ * for containing the fd and offset for mmapping the EventFlag word.
+ */
+ mGrantors.resize(configureEventFlag ? hardware::details::kMinGrantorCountForEvFlagSupport
+ : hardware::details::kMinGrantorCount);
+
+ size_t memSize[] = {
+ sizeof(hardware::details::RingBufferPosition), /* memory to be allocated for read
+ * pointer counter
+ */
+ sizeof(hardware::details::RingBufferPosition), /* memory to be allocated for write
+ pointer counter */
+ bufferSize, /* memory to be allocated for data buffer */
+ sizeof(std::atomic<uint32_t>) /* memory to be allocated for EventFlag word */
+ };
+
+ /*
+ * Create a default grantor descriptor for read, write pointers and
+ * the data buffer. fdIndex parameter is set to 0 by default and
+ * the offset for each grantor is contiguous.
+ */
+ for (size_t grantorPos = 0, offset = 0; grantorPos < mGrantors.size();
+ offset += memSize[grantorPos++]) {
+ mGrantors[grantorPos] = {
+ 0 /* grantor flags */, 0 /* fdIndex */,
+ static_cast<uint32_t>(hardware::details::alignToWordBoundary(offset)),
+ memSize[grantorPos]};
+ }
+}
+
+template <typename T, MQFlavor flavor>
+AidlMQDescriptorShim<T, flavor>::~AidlMQDescriptorShim() {
+ if (mHandle != nullptr) {
+ native_handle_close(mHandle);
+ native_handle_delete(mHandle);
+ }
+}
+
+template <typename T, MQFlavor flavor>
+size_t AidlMQDescriptorShim<T, flavor>::getSize() const {
+ return mGrantors[hardware::details::DATAPTRPOS].extent;
+}
+
+template <typename T, MQFlavor flavor>
+size_t AidlMQDescriptorShim<T, flavor>::getQuantum() const {
+ return mQuantum;
+}
+
+template <typename T, MQFlavor flavor>
+uint32_t AidlMQDescriptorShim<T, flavor>::getFlags() const {
+ return mFlags;
+}
+
+template <typename T, MQFlavor flavor>
+std::string toString(const AidlMQDescriptorShim<T, flavor>& q) {
+ std::string os;
+ if (flavor & hardware::kSynchronizedReadWrite) {
+ os += "fmq_sync";
+ }
+ if (flavor & hardware::kUnsynchronizedWrite) {
+ os += "fmq_unsync";
+ }
+ os += " {" + toString(q.grantors().size()) + " grantor(s), " +
+ "size = " + toString(q.getSize()) + ", .handle = " + toString(q.handle()) +
+ ", .quantum = " + toString(q.getQuantum()) + "}";
+ return os;
+}
+
+} // namespace details
+} // namespace android
diff --git a/include/fmq/AidlMessageQueue.h b/include/fmq/AidlMessageQueue.h
new file mode 100644
index 0000000..b7a33be
--- /dev/null
+++ b/include/fmq/AidlMessageQueue.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/common/MQDescriptor.h>
+#include <aidl/android/hardware/common/SynchronizedReadWrite.h>
+#include <aidl/android/hardware/common/UnsynchronizedWrite.h>
+#include <cutils/native_handle.h>
+#include <fmq/AidlMQDescriptorShim.h>
+#include <fmq/MessageQueueBase.h>
+#include <utils/Log.h>
+#include <type_traits>
+
+namespace android {
+
+using aidl::android::hardware::common::MQDescriptor;
+using aidl::android::hardware::common::SynchronizedReadWrite;
+using aidl::android::hardware::common::UnsynchronizedWrite;
+using android::details::AidlMQDescriptorShim;
+using android::hardware::MQFlavor;
+
+template <typename T>
+struct FlavorTypeToValue;
+
+template <>
+struct FlavorTypeToValue<SynchronizedReadWrite> {
+ static constexpr MQFlavor value = hardware::kSynchronizedReadWrite;
+};
+
+template <>
+struct FlavorTypeToValue<UnsynchronizedWrite> {
+ static constexpr MQFlavor value = hardware::kUnsynchronizedWrite;
+};
+
+typedef uint64_t RingBufferPosition;
+
+/*
+ * AIDL parcelables will have the typedef fixed_size. It is std::true_type when the
+ * parcelable is annotated with @FixedSize, and std::false_type when not. Other types
+ * should not have the fixed_size typedef, so they will always resolve to std::false_type.
+ */
+template <typename T, typename = void>
+struct has_typedef_fixed_size : std::false_type {};
+
+template <typename T>
+struct has_typedef_fixed_size<T, std::void_t<typename T::fixed_size>> : T::fixed_size {};
+
+template <typename T, typename U>
+struct AidlMessageQueue final
+ : public MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value> {
+ static_assert(has_typedef_fixed_size<T>::value == true || std::is_fundamental<T>::value ||
+ std::is_enum<T>::value,
+ "Only fundamental types, enums, and AIDL parcelables annotated with @FixedSize "
+ "and built for the NDK backend are supported as payload types(T).");
+ typedef AidlMQDescriptorShim<T, FlavorTypeToValue<U>::value> Descriptor;
+ /**
+ * This constructor uses the external descriptor used with AIDL interfaces.
+ * It will create an FMQ based on the descriptor that was obtained from
+ * another FMQ instance for communication.
+ *
+ * @param desc Descriptor from another FMQ that contains all of the
+ * information required to create a new instance of that queue.
+ * @param resetPointers Boolean indicating whether the read/write pointers
+ * should be reset or not.
+ */
+ AidlMessageQueue(const MQDescriptor<T, U>& desc, bool resetPointers = true);
+ ~AidlMessageQueue() = default;
+
+ /**
+ * This constructor uses Ashmem shared memory to create an FMQ
+ * that can contain a maximum of 'numElementsInQueue' elements of type T.
+ *
+ * @param numElementsInQueue Capacity of the AidlMessageQueue in terms of T.
+ * @param configureEventFlagWord Boolean that specifies if memory should
+ * also be allocated and mapped for an EventFlag word.
+ */
+ AidlMessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false);
+ MQDescriptor<T, U> dupeDesc();
+
+ private:
+ AidlMessageQueue(const AidlMessageQueue& other) = delete;
+ AidlMessageQueue& operator=(const AidlMessageQueue& other) = delete;
+ AidlMessageQueue() = delete;
+};
+
+template <typename T, typename U>
+AidlMessageQueue<T, U>::AidlMessageQueue(const MQDescriptor<T, U>& desc, bool resetPointers)
+ : MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value>(Descriptor(desc),
+ resetPointers) {}
+
+template <typename T, typename U>
+AidlMessageQueue<T, U>::AidlMessageQueue(size_t numElementsInQueue, bool configureEventFlagWord)
+ : MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value>(
+ numElementsInQueue, configureEventFlagWord) {}
+
+template <typename T, typename U>
+MQDescriptor<T, U> AidlMessageQueue<T, U>::dupeDesc() {
+ auto* shim = MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value>::getDesc();
+ if (shim) {
+ std::vector<aidl::android::hardware::common::GrantorDescriptor> grantors;
+ for (const auto& grantor : shim->grantors()) {
+ grantors.push_back(aidl::android::hardware::common::GrantorDescriptor{
+ .offset = static_cast<int32_t>(grantor.offset),
+ .extent = static_cast<int64_t>(grantor.extent)});
+ }
+ return MQDescriptor<T, U>{
+ .quantum = static_cast<int32_t>(shim->getQuantum()),
+ .grantors = grantors,
+ .flags = static_cast<int32_t>(shim->getFlags()),
+ .fileDescriptor = ndk::ScopedFileDescriptor(dup(shim->handle()->data[0])),
+ };
+ } else {
+ return MQDescriptor<T, U>();
+ }
+}
+
+} // namespace android
diff --git a/include/fmq/MessageQueueBase.h b/include/fmq/MessageQueueBase.h
index cdd7202..0cb83a6 100644
--- a/include/fmq/MessageQueueBase.h
+++ b/include/fmq/MessageQueueBase.h
@@ -24,17 +24,13 @@
#include <atomic>
#include <new>
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::kUnsynchronizedWrite;
+using android::hardware::MQFlavor;
+
namespace android {
-namespace hardware {
-namespace details {
-void check(bool exp);
-void logError(const std::string& message);
-} // namespace details
-} // namespace hardware
-
-template <template <typename, hardware::MQFlavor> class MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> class MQDescriptorType, typename T, MQFlavor flavor>
struct MessageQueueBase {
typedef MQDescriptorType<T, flavor> Descriptor;
@@ -138,7 +134,7 @@
* EventFlag bit mask 'readNotification' is is waited upon.
*
* This method should only be used with a MessageQueue of the flavor
- * 'hardware::kSynchronizedReadWrite'.
+ * 'kSynchronizedReadWrite'.
*
* Upon a successful write, wake is called on 'writeNotification' (if
* non-zero).
@@ -190,7 +186,7 @@
* -If 'count' is greater than the FMQ size.
*
* This method should only be used with a MessageQueue of the flavor
- * 'hardware::kSynchronizedReadWrite'.
+ * 'kSynchronizedReadWrite'.
* If FMQ does not contain 'count' items, the eventFlag bit mask
* 'writeNotification' is waited upon. Upon a successful read from the FMQ,
@@ -448,8 +444,7 @@
android::hardware::EventFlag* mEventFlag = nullptr;
};
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
T* MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getSlot(size_t idx) {
size_t firstRegionLength = first.getLength();
size_t secondRegionLength = second.getLength();
@@ -465,8 +460,7 @@
return second.getAddress() + idx - firstRegionLength;
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getMemRegionInfo(
size_t startIdx, size_t nMessages, size_t& firstCount, size_t& secondCount,
T** firstBaseAddress, T** secondBaseAddress) {
@@ -500,8 +494,7 @@
return true;
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyFrom(T* data,
size_t startIdx,
size_t nMessages) {
@@ -532,8 +525,7 @@
return true;
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyTo(const T* data,
size_t startIdx,
size_t nMessages) {
@@ -564,22 +556,33 @@
return true;
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
void MessageQueueBase<MQDescriptorType, T, flavor>::initMemory(bool resetPointers) {
/*
* Verify that the Descriptor contains the minimum number of grantors
* the native_handle is valid and T matches quantum size.
*/
if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
- (mDesc->countGrantors() < Descriptor::kMinGrantorCount) ||
- (mDesc->getQuantum() != sizeof(T))) {
+ (mDesc->countGrantors() < hardware::details::kMinGrantorCount)) {
+ return;
+ }
+ if (mDesc->getQuantum() != sizeof(T)) {
+ hardware::details::logError(
+ "Payload size differs between the queue instantiation and the "
+ "MQDescriptor.");
return;
}
- if (flavor == hardware::kSynchronizedReadWrite) {
- mReadPtr =
- reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::READPTRPOS));
+ const auto& grantors = mDesc->grantors();
+ for (const auto& grantor : grantors) {
+ if (hardware::details::isAlignedToWordBoundary(grantor.offset) == false) {
+ __assert(__FILE__, __LINE__, "Grantor offsets need to be aligned");
+ }
+ }
+
+ if (flavor == kSynchronizedReadWrite) {
+ mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
+ mapGrantorDescr(hardware::details::READPTRPOS));
} else {
/*
* The unsynchronized write flavor of the FMQ may have multiple readers
@@ -587,31 +590,43 @@
*/
mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
}
+ if (mReadPtr == nullptr) {
+#ifdef __BIONIC__
+ __assert(__FILE__, __LINE__, "mReadPtr is null");
+#endif
+ }
- hardware::details::check(mReadPtr != nullptr);
-
- mWritePtr = reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::WRITEPTRPOS));
- hardware::details::check(mWritePtr != nullptr);
+ mWritePtr = reinterpret_cast<std::atomic<uint64_t>*>(
+ mapGrantorDescr(hardware::details::WRITEPTRPOS));
+ if (mWritePtr == nullptr) {
+#ifdef __BIONIC__
+ __assert(__FILE__, __LINE__, "mWritePtr is null");
+#endif
+ }
if (resetPointers) {
mReadPtr->store(0, std::memory_order_release);
mWritePtr->store(0, std::memory_order_release);
- } else if (flavor != hardware::kSynchronizedReadWrite) {
+ } else if (flavor != kSynchronizedReadWrite) {
// Always reset the read pointer.
mReadPtr->store(0, std::memory_order_release);
}
- mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(Descriptor::DATAPTRPOS));
- hardware::details::check(mRing != nullptr);
+ mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(hardware::details::DATAPTRPOS));
+ if (mRing == nullptr) {
+#ifdef __BIONIC__
+ __assert(__FILE__, __LINE__, "mRing is null");
+#endif
+ }
- mEvFlagWord = static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(Descriptor::EVFLAGWORDPOS));
+ mEvFlagWord =
+ static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(hardware::details::EVFLAGWORDPOS));
if (mEvFlagWord != nullptr) {
android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
}
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(const Descriptor& Desc,
bool resetPointers) {
mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
@@ -622,8 +637,7 @@
initMemory(resetPointers);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(size_t numElementsInQueue,
bool configureEventFlagWord) {
// Check if the buffer size would not overflow size_t
@@ -636,7 +650,7 @@
* we also need to allocate memory for the same/
*/
size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
- size_t kMetaDataSize = 2 * sizeof(android::hardware::RingBufferPosition);
+ size_t kMetaDataSize = 2 * sizeof(android::hardware::details::RingBufferPosition);
if (configureEventFlagWord) {
kMetaDataSize += sizeof(std::atomic<uint32_t>);
@@ -647,9 +661,9 @@
* kQueueSizeBytes needs to be aligned to word boundary so that all offsets
* in the grantorDescriptor will be word aligned.
*/
- size_t kAshmemSizePageAligned =
- (Descriptor::alignToWordBoundary(kQueueSizeBytes) + kMetaDataSize + PAGE_SIZE - 1) &
- ~(PAGE_SIZE - 1);
+ size_t kAshmemSizePageAligned = (hardware::details::alignToWordBoundary(kQueueSizeBytes) +
+ kMetaDataSize + PAGE_SIZE - 1) &
+ ~(PAGE_SIZE - 1);
/*
* Create an ashmem region to map the memory for the ringbuffer,
@@ -675,58 +689,53 @@
initMemory(true);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
MessageQueueBase<MQDescriptorType, T, flavor>::~MessageQueueBase() {
- if (flavor == hardware::kUnsynchronizedWrite) {
+ if (flavor == kUnsynchronizedWrite) {
delete mReadPtr;
} else {
- unmapGrantorDescr(mReadPtr, Descriptor::READPTRPOS);
+ unmapGrantorDescr(mReadPtr, hardware::details::READPTRPOS);
}
if (mWritePtr != nullptr) {
- unmapGrantorDescr(mWritePtr, Descriptor::WRITEPTRPOS);
+ unmapGrantorDescr(mWritePtr, hardware::details::WRITEPTRPOS);
}
if (mRing != nullptr) {
- unmapGrantorDescr(mRing, Descriptor::DATAPTRPOS);
+ unmapGrantorDescr(mRing, hardware::details::DATAPTRPOS);
}
if (mEvFlagWord != nullptr) {
- unmapGrantorDescr(mEvFlagWord, Descriptor::EVFLAGWORDPOS);
+ unmapGrantorDescr(mEvFlagWord, hardware::details::EVFLAGWORDPOS);
android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
}
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data) {
return write(data, 1);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data) {
return read(data, 1);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data, size_t nMessages) {
MemTransaction tx;
return beginWrite(nMessages, &tx) && tx.copyTo(data, 0 /* startIdx */, nMessages) &&
commitWrite(nMessages);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(
const T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
- static_assert(flavor == hardware::kSynchronizedReadWrite,
+ static_assert(flavor == kSynchronizedReadWrite,
"writeBlocking can only be used with the "
- "hardware::kSynchronizedReadWrite flavor.");
+ "kSynchronizedReadWrite flavor.");
/*
* If evFlag is null and the FMQ does not have its own EventFlag object
* return false;
- * If the flavor is hardware::kSynchronizedReadWrite and the readNotification
+ * If the flavor is kSynchronizedReadWrite and the readNotification
* bit mask is zero return false;
* If the count is greater than queue size, return false
* to prevent blocking until timeOut.
@@ -826,21 +835,19 @@
return result;
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(const T* data, size_t count,
int64_t timeOutNanos) {
return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(
T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
- static_assert(flavor == hardware::kSynchronizedReadWrite,
+ static_assert(flavor == kSynchronizedReadWrite,
"readBlocking can only be used with the "
- "hardware::kSynchronizedReadWrite flavor.");
+ "kSynchronizedReadWrite flavor.");
/*
* If evFlag is null and the FMQ does not own its own EventFlag object
@@ -944,33 +951,28 @@
return result;
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(T* data, size_t count,
int64_t timeOutNanos) {
return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWriteBytes() const {
return mDesc->getSize() - availableToReadBytes();
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWrite() const {
return availableToWriteBytes() / sizeof(T);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToRead() const {
return availableToReadBytes() / sizeof(T);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::beginWrite(size_t nMessages,
MemTransaction* result) const {
/*
@@ -978,7 +980,7 @@
* FMQ flavor, if there is not enough space to write nMessages, then return
* result with null addresses.
*/
- if ((flavor == hardware::kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
+ if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
nMessages > getQuantumCount()) {
*result = MemTransaction();
return false;
@@ -1013,8 +1015,7 @@
return true;
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
/*
* Disable integer sanitization since integer overflow here is allowed
* and legal.
@@ -1032,8 +1033,7 @@
return true;
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToReadBytes() const {
/*
* This method is invoked by implementations of both read() and write() and
@@ -1043,16 +1043,14 @@
return mWritePtr->load(std::memory_order_acquire) - mReadPtr->load(std::memory_order_acquire);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data, size_t nMessages) {
MemTransaction tx;
return beginRead(nMessages, &tx) && tx.copyFrom(data, 0 /* startIdx */, nMessages) &&
commitRead(nMessages);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
/*
* Disable integer sanitization since integer overflow here is allowed
* and legal.
@@ -1115,8 +1113,7 @@
return true;
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
/*
* Disable integer sanitization since integer overflow here is allowed
* and legal.
@@ -1141,26 +1138,22 @@
return true;
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumSize() const {
return mDesc->getQuantum();
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumCount() const {
return mDesc->getSize() / mDesc->getQuantum();
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
bool MessageQueueBase<MQDescriptorType, T, flavor>::isValid() const {
return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
void* MessageQueueBase<MQDescriptorType, T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
const native_handle_t* handle = mDesc->handle();
auto grantors = mDesc->grantors();
@@ -1191,8 +1184,7 @@
return reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
}
-template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
- hardware::MQFlavor flavor>
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
void MessageQueueBase<MQDescriptorType, T, flavor>::unmapGrantorDescr(void* address,
uint32_t grantorIdx) {
auto grantors = mDesc->grantors();
diff --git a/tests/Android.bp b/tests/Android.bp
index 1268c2d..0685ff4 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -14,14 +14,29 @@
// limitations under the License.
//
+python_test_host {
+ name: "fmq_test",
+ main: "fmq_test.py",
+ srcs: ["fmq_test.py"],
+ test_config: "fmq_test.xml",
+ target_required: [
+ "android.hardware.tests.msgq@1.0-service-test",
+ "fmq_test_client",
+ ],
+ test_suites: ["general-tests", "vts"],
+}
+
cc_test {
- name: "mq_test_client",
+ name: "fmq_test_client",
srcs: ["msgq_test_client.cpp"],
cflags: [
"-Wall",
"-Werror",
],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
shared_libs: [
"libbase",
@@ -30,15 +45,32 @@
"libhidlbase",
"liblog",
"libutils",
+ "libbinder_ndk",
],
- // Allow dlsym'ing self for statically linked passthrough implementations
- ldflags: ["-rdynamic"],
-
// These are static libs only for testing purposes and portability. Shared
// libs should be used on device.
- static_libs: ["android.hardware.tests.msgq@1.0"],
- whole_static_libs: ["android.hardware.tests.msgq@1.0-impl"],
+ static_libs: [
+ "android.hardware.tests.msgq@1.0",
+ "android.fmq.test-ndk_platform",
+ "android.hardware.common-unstable-ndk_platform",
+ ],
+ whole_static_libs: [
+ "android.hardware.tests.msgq@1.0-impl",
+ "android.fmq.test-impl"
+ ],
+
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+ test_suites: ["general-tests", "vts"],
+ auto_gen_config: false,
}
cc_test {
@@ -53,15 +85,17 @@
"liblog",
"libutils",
],
+ static_libs: [
+ "android.hardware.common-unstable-ndk_platform",
+ ],
cflags: [
"-Wall",
"-Werror",
],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
test_suites: ["general-tests"],
auto_gen_config: true,
}
-
-vts_config {
- name: "VtsFmqUnitTests",
-}
diff --git a/tests/Android.mk b/tests/Android.mk
deleted file mode 100644
index 809ab2b..0000000
--- a/tests/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_MODULE := fmq_test
-LOCAL_MODULE_CLASS := NATIVE_TESTS
-LOCAL_SRC_FILES := fmq_test
-LOCAL_REQUIRED_MODULES := \
- android.hardware.tests.msgq@1.0-service-test \
- mq_test_client \
- hidl_test_helper
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest64
-
-ifneq ($(TARGET_2ND_ARCH),)
-LOCAL_REQUIRED_MODULES += \
- android.hardware.tests.msgq@1.0-service-test:32 \
- mq_test_client:32
-endif
-
-include $(BUILD_PREBUILT)
diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml
deleted file mode 100644
index 9e5df01..0000000
--- a/tests/AndroidTest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<configuration description="Config for VTS FMQ unit tests">
- <option name="config-descriptor:metadata" key="plan" value="vts-library" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
- <option name="push-group" value="HostDrivenTest.push" />
- <option name="cleanup" value="true" />
- <option name="push" value="DATA/nativetest/android.hardware.tests.msgq@1.0-service-test/android.hardware.tests.msgq@1.0-service-test->/data/nativetest/android.hardware.tests.msgq@1.0-service-test/android.hardware.tests.msgq@1.0-service-test" />
- <option name="push" value="DATA/nativetest64/android.hardware.tests.msgq@1.0-service-test/android.hardware.tests.msgq@1.0-service-test->/data/nativetest64/android.hardware.tests.msgq@1.0-service-test/android.hardware.tests.msgq@1.0-service-test" />
- <option name="push" value="DATA/nativetest/mq_test_client/mq_test_client->/data/nativetest/mq_test_client/mq_test_client" />
- <option name="push" value="DATA/nativetest64/mq_test_client/mq_test_client->/data/nativetest64/mq_test_client/mq_test_client" />
- <option name="push" value="DATA/nativetest64/hidl_test_helper->/data/nativetest64/hidl_test_helper" />
- </target_preparer>
- <multi_target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
- <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
- <option name="test-module-name" value="VtsFmqUnitTests" />
- <option name="binary-test-type" value="binary_test" />
- <option name="binary-test-source" value="DATA/nativetest64/fmq_test->/data/nativetest64/fmq_test" />
- <option name="test-timeout" value="1m"/>
- </test>
-</configuration>
diff --git a/tests/aidl/Android.bp b/tests/aidl/Android.bp
new file mode 100644
index 0000000..27b9827
--- /dev/null
+++ b/tests/aidl/Android.bp
@@ -0,0 +1,24 @@
+aidl_interface {
+ name: "android.fmq.test",
+ host_supported: true,
+ vendor_available: true,
+ unstable: true,
+ srcs: [
+ "android/fmq/test/*.aidl",
+ ],
+ imports: [
+ "android.hardware.common",
+ ],
+ gen_trace: true,
+ backend: {
+ java: {
+ enabled: false,
+ },
+ ndk: {
+ enabled: true,
+ },
+ cpp: {
+ enabled: false,
+ }
+ },
+}
diff --git a/tests/aidl/android/fmq/test/EventFlagBits.aidl b/tests/aidl/android/fmq/test/EventFlagBits.aidl
new file mode 100644
index 0000000..202a67c
--- /dev/null
+++ b/tests/aidl/android/fmq/test/EventFlagBits.aidl
@@ -0,0 +1,9 @@
+// FIXME: license file if you have one
+
+package android.fmq.test;
+
+@Backing(type="int")
+enum EventFlagBits {
+ FMQ_NOT_EMPTY = 1 << 0,
+ FMQ_NOT_FULL = 1 << 1,
+}
diff --git a/tests/aidl/android/fmq/test/FixedParcelable.aidl b/tests/aidl/android/fmq/test/FixedParcelable.aidl
new file mode 100644
index 0000000..acb54f2
--- /dev/null
+++ b/tests/aidl/android/fmq/test/FixedParcelable.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2020 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.
+ */
+
+package android.fmq.test;
+
+import android.fmq.test.EventFlagBits;
+
+@FixedSize
+parcelable FixedParcelable {
+ int a;
+ EventFlagBits b;
+}
diff --git a/tests/aidl/android/fmq/test/ITestAidlMsgQ.aidl b/tests/aidl/android/fmq/test/ITestAidlMsgQ.aidl
new file mode 100644
index 0000000..6540ed3
--- /dev/null
+++ b/tests/aidl/android/fmq/test/ITestAidlMsgQ.aidl
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2020 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.
+ */
+
+package android.fmq.test;
+
+import android.hardware.common.MQDescriptor;
+import android.hardware.common.SynchronizedReadWrite;
+import android.hardware.common.UnsynchronizedWrite;
+
+/**
+ * Test interface for MQDescriptor.
+ */
+interface ITestAidlMsgQ {
+ /**
+ * This method requests the service to set up a synchronous read/write
+ * wait-free FMQ using the input descriptor with the client as reader.
+ *
+ * @param mqDesc This structure describes the FMQ that was set up by the
+ * client. Server uses this descriptor to set up a FMQ object at its end.
+ *
+ * @return True if the setup is successful.
+ */
+ boolean configureFmqSyncReadWrite(in MQDescriptor<int, SynchronizedReadWrite> mqDesc);
+
+ /**
+ * This method requests the service to return an MQDescriptor to
+ * an unsynchronized FMQ set up by the server. If 'configureFmq' is
+ * true, then the server sets up a new unsynchronized FMQ. This
+ * method is to be used to test multiple reader processes.
+ *
+ * @param configureFmq The server sets up a new unsynchronized FMQ if
+ * this parameter is true.
+ *
+ * @param out ret True if successful.
+ * @param out mqDesc This structure describes the unsynchronized FMQ that was
+ * set up by the service. Client can use it to set up the FMQ at its end.
+ */
+ boolean getFmqUnsyncWrite(in boolean configureFmq,
+ out MQDescriptor<int, UnsynchronizedWrite> mqDesc);
+
+ /**
+ * This method requests the service to trigger a blocking read.
+ *
+ * @param count Number of messages to read.
+ *
+ */
+ oneway void requestBlockingRead(in int count);
+
+ /**
+ * This method requests the service to trigger a blocking read using
+ * default Event Flag notification bits defined by the MessageQueue class.
+ *
+ * @param count Number of messages to read.
+ *
+ */
+ oneway void requestBlockingReadDefaultEventFlagBits(in int count);
+
+ /**
+ * This method requests the service to repeatedly trigger blocking reads.
+ *
+ * @param count Number of messages to read in a single blocking read.
+ * @param numIter Number of blocking reads to trigger.
+ *
+ */
+ oneway void requestBlockingReadRepeat(in int count, in int numIter);
+
+ /**
+ * This method request the service to read from the synchronized read/write
+ * FMQ.
+ *
+ * @param count Number to messages to read.
+ *
+ * @return True if the read operation was successful.
+ */
+ boolean requestReadFmqSync(in int count);
+
+ /**
+ * This method request the service to read from the unsynchronized flavor of
+ * FMQ.
+ *
+ * @param count Number to messages to read.
+ *
+ * @return Will be True if the read operation was successful.
+ */
+ boolean requestReadFmqUnsync(in int count);
+
+ /**
+ * This method request the service to write into the synchronized read/write
+ * flavor of the FMQ.
+ *
+ * @param count Number to messages to write.
+ *
+ * @return True if the write operation was successful.
+ */
+ boolean requestWriteFmqSync(in int count);
+
+ /**
+ * This method request the service to write into the unsynchronized flavor
+ * of FMQ.
+ *
+ * @param count Number to messages to write.
+ *
+ * @return True if the write operation was successful.
+ */
+ boolean requestWriteFmqUnsync(in int count);
+}
diff --git a/tests/aidl/default/Android.bp b/tests/aidl/default/Android.bp
new file mode 100644
index 0000000..54660e4
--- /dev/null
+++ b/tests/aidl/default/Android.bp
@@ -0,0 +1,16 @@
+cc_library_static {
+ name: "android.fmq.test-impl",
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libfmq",
+ "android.hardware.common-unstable-ndk_platform",
+ ],
+ static_libs: [
+ "android.fmq.test-ndk_platform",
+ ],
+ export_include_dirs: ["."],
+ srcs: [
+ "TestAidlMsgQ.cpp",
+ ],
+}
diff --git a/tests/aidl/default/TestAidlMsgQ.cpp b/tests/aidl/default/TestAidlMsgQ.cpp
new file mode 100644
index 0000000..baec3e6
--- /dev/null
+++ b/tests/aidl/default/TestAidlMsgQ.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2020 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 "TestAidlMsgQ.h"
+
+namespace aidl {
+namespace android {
+namespace fmq {
+namespace test {
+
+// Methods from ::aidl::android::fmq::test::ITestAidlMsgQ follow.
+ndk::ScopedAStatus TestAidlMsgQ::configureFmqSyncReadWrite(
+ const MQDescriptor<int32_t, SynchronizedReadWrite>& mqDesc, bool* _aidl_return) {
+ mFmqSynchronized.reset(new (std::nothrow) TestAidlMsgQ::MessageQueueSync(mqDesc));
+ if ((mFmqSynchronized == nullptr) || (mFmqSynchronized->isValid() == false)) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ /*
+ * Initialize the EventFlag word with bit FMQ_NOT_FULL.
+ */
+ auto evFlagWordPtr = mFmqSynchronized->getEventFlagWord();
+ if (evFlagWordPtr != nullptr) {
+ std::atomic_init(evFlagWordPtr, static_cast<uint32_t>(EventFlagBits::FMQ_NOT_FULL));
+ }
+ *_aidl_return = true;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus TestAidlMsgQ::getFmqUnsyncWrite(
+ bool configureFmq, MQDescriptor<int32_t, UnsynchronizedWrite>* mqDesc, bool* _aidl_return) {
+ if (configureFmq) {
+ static constexpr size_t kNumElementsInQueue = 1024;
+ mFmqUnsynchronized.reset(new (std::nothrow)
+ TestAidlMsgQ::MessageQueueUnsync(kNumElementsInQueue));
+ }
+
+ if ((mFmqUnsynchronized == nullptr) || (mFmqUnsynchronized->isValid() == false) ||
+ (mqDesc == nullptr)) {
+ *_aidl_return = false;
+ } else {
+ *mqDesc = std::move(mFmqUnsynchronized->dupeDesc());
+ *_aidl_return = true;
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus TestAidlMsgQ::requestBlockingRead(int32_t count) {
+ std::vector<int32_t> data(count);
+ bool result = mFmqSynchronized->readBlocking(
+ &data[0], count, static_cast<uint32_t>(EventFlagBits::FMQ_NOT_FULL),
+ static_cast<uint32_t>(EventFlagBits::FMQ_NOT_EMPTY), 5000000000 /* timeOutNanos */);
+
+ if (result == false) {
+ ALOGE("Blocking read fails");
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus TestAidlMsgQ::requestBlockingReadDefaultEventFlagBits(int32_t count) {
+ std::vector<int32_t> data(count);
+ bool result = mFmqSynchronized->readBlocking(&data[0], count);
+
+ if (result == false) {
+ ALOGE("Blocking read fails");
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus TestAidlMsgQ::requestBlockingReadRepeat(int32_t count, int32_t numIter) {
+ std::vector<int32_t> data(count);
+ for (int i = 0; i < numIter; i++) {
+ bool result = mFmqSynchronized->readBlocking(
+ &data[0], count, static_cast<uint32_t>(EventFlagBits::FMQ_NOT_FULL),
+ static_cast<uint32_t>(EventFlagBits::FMQ_NOT_EMPTY), 5000000000 /* timeOutNanos */);
+
+ if (result == false) {
+ ALOGE("Blocking read fails");
+ break;
+ }
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus TestAidlMsgQ::requestReadFmqSync(int32_t count, bool* _aidl_return) {
+ std::vector<int32_t> data(count);
+ bool result = mFmqSynchronized->read(&data[0], count) && verifyData(&data[0], count);
+ *_aidl_return = result;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus TestAidlMsgQ::requestReadFmqUnsync(int32_t count, bool* _aidl_return) {
+ std::vector<int32_t> data(count);
+ bool result = mFmqUnsynchronized->read(&data[0], count) && verifyData(&data[0], count);
+ *_aidl_return = result;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus TestAidlMsgQ::requestWriteFmqSync(int32_t count, bool* _aidl_return) {
+ std::vector<int32_t> data(count);
+ for (int i = 0; i < count; i++) {
+ data[i] = i;
+ }
+ bool result = mFmqSynchronized->write(&data[0], count);
+ *_aidl_return = result;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus TestAidlMsgQ::requestWriteFmqUnsync(int32_t count, bool* _aidl_return) {
+ std::vector<int32_t> data(count);
+ for (int i = 0; i < count; i++) {
+ data[i] = i;
+ }
+ if (!mFmqUnsynchronized) {
+ ALOGE("Unsynchronized queue is not configured.");
+ *_aidl_return = false;
+ return ndk::ScopedAStatus::ok();
+ }
+ bool result = mFmqUnsynchronized->write(&data[0], count);
+ *_aidl_return = result;
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace test
+} // namespace fmq
+} // namespace android
+} // namespace aidl
diff --git a/tests/aidl/default/TestAidlMsgQ.h b/tests/aidl/default/TestAidlMsgQ.h
new file mode 100644
index 0000000..1a65406
--- /dev/null
+++ b/tests/aidl/default/TestAidlMsgQ.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <aidl/android/fmq/test/BnTestAidlMsgQ.h>
+#include <aidl/android/fmq/test/EventFlagBits.h>
+#include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
+
+namespace aidl {
+namespace android {
+namespace fmq {
+namespace test {
+
+using ::aidl::android::fmq::test::EventFlagBits;
+using ::aidl::android::fmq::test::ITestAidlMsgQ;
+
+using ::aidl::android::hardware::common::MQDescriptor;
+using ::aidl::android::hardware::common::SynchronizedReadWrite;
+using ::aidl::android::hardware::common::UnsynchronizedWrite;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::kUnsynchronizedWrite;
+using ::android::hardware::MQFlavor;
+
+using ::android::AidlMessageQueue;
+
+struct TestAidlMsgQ : public BnTestAidlMsgQ {
+ typedef AidlMessageQueue<int32_t, SynchronizedReadWrite> MessageQueueSync;
+ typedef AidlMessageQueue<int32_t, UnsynchronizedWrite> MessageQueueUnsync;
+
+ TestAidlMsgQ() : mFmqSynchronized(nullptr), mFmqUnsynchronized(nullptr) {}
+
+ // Methods from ::aidl::android::fmq::test::ITestAidlMsgQ follow.
+ ndk::ScopedAStatus configureFmqSyncReadWrite(
+ const MQDescriptor<int32_t, SynchronizedReadWrite>& mqDesc,
+ bool* _aidl_return) override;
+ ndk::ScopedAStatus getFmqUnsyncWrite(bool configureFmq,
+ MQDescriptor<int32_t, UnsynchronizedWrite>* mqDesc,
+ bool* _aidl_return) override;
+ ndk::ScopedAStatus requestBlockingRead(int32_t count) override;
+ ndk::ScopedAStatus requestBlockingReadDefaultEventFlagBits(int32_t count) override;
+ ndk::ScopedAStatus requestBlockingReadRepeat(int32_t count, int32_t numIter) override;
+ ndk::ScopedAStatus requestReadFmqSync(int32_t count, bool* _aidl_return) override;
+ ndk::ScopedAStatus requestReadFmqUnsync(int32_t count, bool* _aidl_return) override;
+ ndk::ScopedAStatus requestWriteFmqSync(int32_t count, bool* _aidl_return) override;
+ ndk::ScopedAStatus requestWriteFmqUnsync(int32_t count, bool* _aidl_return) override;
+
+ private:
+ std::unique_ptr<MessageQueueSync> mFmqSynchronized;
+ std::unique_ptr<MessageQueueUnsync> mFmqUnsynchronized;
+
+ /*
+ * Utility function to verify data read from the fast message queue.
+ */
+ bool verifyData(int32_t* data, int count) {
+ for (int i = 0; i < count; i++) {
+ if (data[i] != i) return false;
+ }
+ return true;
+ }
+};
+
+} // namespace test
+} // namespace fmq
+} // namespace android
+} // namespace aidl
diff --git a/tests/fmq_test b/tests/fmq_test
deleted file mode 100644
index 7c5bfbe..0000000
--- a/tests/fmq_test
+++ /dev/null
@@ -1,9 +0,0 @@
-source /data/nativetest64/hidl_test_helper
-
-run_all_tests \
- "/data/nativetest/android.hardware.tests.msgq@1.0-service-test/android.hardware.tests.msgq@1.0-service-test" \
- "/data/nativetest64/android.hardware.tests.msgq@1.0-service-test/android.hardware.tests.msgq@1.0-service-test" \
- "/data/nativetest/mq_test_client/mq_test_client" \
- "/data/nativetest64/mq_test_client/mq_test_client" \
- "fmq_test" \
- "$@"
diff --git a/tests/fmq_test.py b/tests/fmq_test.py
new file mode 100644
index 0000000..68114ad
--- /dev/null
+++ b/tests/fmq_test.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2020 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.
+#
+
+import subprocess
+import unittest
+
+def run_cmd(cmd, ignore_error=False):
+ print("Running command:", cmd)
+ p = subprocess.Popen(cmd, shell=True)
+ p.communicate()
+ if not ignore_error and p.returncode:
+ raise subprocess.CalledProcessError(p.returncode, cmd)
+ return p.returncode
+
+class TestFmq(unittest.TestCase):
+ pass
+
+def make_test(client, server):
+ def test(self):
+ try:
+ run_cmd("adb shell killall %s >/dev/null 2>&1" % client, ignore_error=True)
+ run_cmd("adb shell killall %s >/dev/null 2>&1" % server, ignore_error=True)
+ run_cmd("adb shell \"( %s ) </dev/null >/dev/null 2>&1 &\"" % server)
+ run_cmd("adb shell %s" % client)
+ finally:
+ run_cmd("adb shell killall %s >/dev/null 2>&1" % client, ignore_error=True)
+ run_cmd("adb shell killall %s >/dev/null 2>&1" % server, ignore_error=True)
+ return test
+
+def has_bitness(bitness):
+ return 0 == run_cmd("echo '[[ \"$(getprop ro.product.cpu.abilist%s)\" != \"\" ]]' | adb shell sh" % bitness, ignore_error=True)
+
+if __name__ == '__main__':
+ clients = []
+ servers = []
+
+ if has_bitness(32):
+ clients += ["/data/nativetest/fmq_test_client/fmq_test_client"]
+ servers += ["/data/nativetest/android.hardware.tests.msgq@1.0-service-test/android.hardware.tests.msgq@1.0-service-test"]
+
+ if has_bitness(64):
+ clients += ["/data/nativetest64/fmq_test_client/fmq_test_client"]
+ servers += ["/data/nativetest64/android.hardware.tests.msgq@1.0-service-test/android.hardware.tests.msgq@1.0-service-test"]
+
+ assert len(clients) > 0
+ assert len(servers) > 0
+
+ def short_name(binary):
+ if "64" in binary:
+ return "64"
+ return "32"
+
+ for client in clients:
+ for server in servers:
+ test_name = 'test_%s_to_%s' % (short_name(client), short_name(server))
+ test = make_test(client, server)
+ setattr(TestFmq, test_name, test)
+
+ suite = unittest.TestLoader().loadTestsFromTestCase(TestFmq)
+ unittest.TextTestRunner(verbosity=2).run(suite)
diff --git a/tests/fmq_test.xml b/tests/fmq_test.xml
new file mode 100644
index 0000000..f7b1f16
--- /dev/null
+++ b/tests/fmq_test.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs FMQ on-device integration tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <!-- We would like to abort, but currently there is not a simple way to specify installation of both bitnesses of targets. -->
+ <option name="abort-on-push-failure" value="false"/>
+
+ <option name="push" value="fmq_test_client32->/data/nativetest/fmq_test_client/fmq_test_client" />
+ <option name="push" value="fmq_test_client64->/data/nativetest64/fmq_test_client/fmq_test_client" />
+
+ <option name="push" value="android.hardware.tests.msgq@1.0-service-test32->/data/nativetest/android.hardware.tests.msgq@1.0-service-test/android.hardware.tests.msgq@1.0-service-test" />
+ <option name="push" value="android.hardware.tests.msgq@1.0-service-test64->/data/nativetest64/android.hardware.tests.msgq@1.0-service-test/android.hardware.tests.msgq@1.0-service-test" />
+
+ <option name="cleanup" value="true" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest" >
+ <option name="par-file-name" value="fmq_test" />
+ <option name="test-timeout" value="2m" />
+ </test>
+</configuration>
+
diff --git a/tests/fmq_unit_tests.cpp b/tests/fmq_unit_tests.cpp
index 96528d3..d365054 100644
--- a/tests/fmq_unit_tests.cpp
+++ b/tests/fmq_unit_tests.cpp
@@ -15,70 +15,99 @@
*/
#include <asm-generic/mman.h>
+#include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
#include <gtest/gtest.h>
#include <atomic>
#include <cstdlib>
#include <sstream>
#include <thread>
-#include <fmq/MessageQueue.h>
-#include <fmq/EventFlag.h>
+
+using aidl::android::hardware::common::SynchronizedReadWrite;
+using aidl::android::hardware::common::UnsynchronizedWrite;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::kUnsynchronizedWrite;
enum EventFlagBits : uint32_t {
kFmqNotEmpty = 1 << 0,
kFmqNotFull = 1 << 1,
};
-typedef android::hardware::MessageQueue<uint8_t, android::hardware::kSynchronizedReadWrite>
- MessageQueueSync;
-typedef android::hardware::MessageQueue<uint8_t, android::hardware::kUnsynchronizedWrite>
- MessageQueueUnsync;
+typedef android::AidlMessageQueue<uint8_t, SynchronizedReadWrite> AidlMessageQueueSync;
+typedef android::AidlMessageQueue<uint8_t, UnsynchronizedWrite> AidlMessageQueueUnsync;
+typedef android::hardware::MessageQueue<uint8_t, kSynchronizedReadWrite> MessageQueueSync;
+typedef android::hardware::MessageQueue<uint8_t, kUnsynchronizedWrite> MessageQueueUnsync;
+typedef android::AidlMessageQueue<uint16_t, SynchronizedReadWrite> AidlMessageQueueSync16;
+typedef android::hardware::MessageQueue<uint16_t, kSynchronizedReadWrite> MessageQueueSync16;
-class SynchronizedReadWrites : public ::testing::Test {
-protected:
+// Run everything on both the AIDL and HIDL versions with sync and unsync flavors
+typedef ::testing::Types<AidlMessageQueueSync, MessageQueueSync> SyncTypes;
+typedef ::testing::Types<AidlMessageQueueUnsync, MessageQueueUnsync> UnsyncTypes;
+typedef ::testing::Types<AidlMessageQueueSync16, MessageQueueSync16> BadConfigTypes;
+
+template <typename T>
+class TestBase : public ::testing::Test {
+ public:
+ static void ReaderThreadBlocking(T* fmq, std::atomic<uint32_t>* fwAddr);
+ static void ReaderThreadBlocking2(T* fmq, std::atomic<uint32_t>* fwAddr);
+};
+
+TYPED_TEST_CASE(SynchronizedReadWrites, SyncTypes);
+
+template <typename T>
+class SynchronizedReadWrites : public TestBase<T> {
+ protected:
virtual void TearDown() {
delete mQueue;
}
virtual void SetUp() {
static constexpr size_t kNumElementsInQueue = 2048;
- mQueue = new (std::nothrow) MessageQueueSync(kNumElementsInQueue);
+ mQueue = new (std::nothrow) T(kNumElementsInQueue);
ASSERT_NE(nullptr, mQueue);
ASSERT_TRUE(mQueue->isValid());
mNumMessagesMax = mQueue->getQuantumCount();
ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
}
- MessageQueueSync* mQueue = nullptr;
+ T* mQueue = nullptr;
size_t mNumMessagesMax = 0;
};
-class UnsynchronizedWrite : public ::testing::Test {
-protected:
+TYPED_TEST_CASE(UnsynchronizedWriteTest, UnsyncTypes);
+
+template <typename T>
+class UnsynchronizedWriteTest : public TestBase<T> {
+ protected:
virtual void TearDown() {
delete mQueue;
}
virtual void SetUp() {
static constexpr size_t kNumElementsInQueue = 2048;
- mQueue = new (std::nothrow) MessageQueueUnsync(kNumElementsInQueue);
+ mQueue = new (std::nothrow) T(kNumElementsInQueue);
ASSERT_NE(nullptr, mQueue);
ASSERT_TRUE(mQueue->isValid());
mNumMessagesMax = mQueue->getQuantumCount();
ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
}
- MessageQueueUnsync* mQueue = nullptr;
+ T* mQueue = nullptr;
size_t mNumMessagesMax = 0;
};
-class BlockingReadWrites : public ::testing::Test {
-protected:
+TYPED_TEST_CASE(BlockingReadWrites, SyncTypes);
+
+template <typename T>
+class BlockingReadWrites : public TestBase<T> {
+ protected:
virtual void TearDown() {
delete mQueue;
}
virtual void SetUp() {
static constexpr size_t kNumElementsInQueue = 2048;
- mQueue = new (std::nothrow) MessageQueueSync(kNumElementsInQueue);
+ mQueue = new (std::nothrow) T(kNumElementsInQueue);
ASSERT_NE(nullptr, mQueue);
ASSERT_TRUE(mQueue->isValid());
mNumMessagesMax = mQueue->getQuantumCount();
@@ -89,38 +118,42 @@
std::atomic_init(&mFw, static_cast<uint32_t>(kFmqNotFull));
}
- MessageQueueSync* mQueue;
+ T* mQueue;
std::atomic<uint32_t> mFw;
size_t mNumMessagesMax = 0;
};
-class QueueSizeOdd : public ::testing::Test {
-protected:
- virtual void TearDown() {
- delete mQueue;
- }
- virtual void SetUp() {
- static constexpr size_t kNumElementsInQueue = 2049;
- mQueue = new (std::nothrow) MessageQueueSync(kNumElementsInQueue,
- true /* configureEventFlagWord */);
- ASSERT_NE(nullptr, mQueue);
- ASSERT_TRUE(mQueue->isValid());
- mNumMessagesMax = mQueue->getQuantumCount();
- ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
- auto evFlagWordPtr = mQueue->getEventFlagWord();
- ASSERT_NE(nullptr, evFlagWordPtr);
- /*
- * Initialize the EventFlag word to indicate Queue is not full.
- */
- std::atomic_init(evFlagWordPtr, static_cast<uint32_t>(kFmqNotFull));
- }
+TYPED_TEST_CASE(QueueSizeOdd, SyncTypes);
- MessageQueueSync* mQueue;
- size_t mNumMessagesMax = 0;
+template <typename T>
+class QueueSizeOdd : public TestBase<T> {
+ protected:
+ virtual void TearDown() { delete mQueue; }
+ virtual void SetUp() {
+ static constexpr size_t kNumElementsInQueue = 2049;
+ mQueue = new (std::nothrow) T(kNumElementsInQueue, true /* configureEventFlagWord */);
+ ASSERT_NE(nullptr, mQueue);
+ ASSERT_TRUE(mQueue->isValid());
+ mNumMessagesMax = mQueue->getQuantumCount();
+ ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
+ auto evFlagWordPtr = mQueue->getEventFlagWord();
+ ASSERT_NE(nullptr, evFlagWordPtr);
+ /*
+ * Initialize the EventFlag word to indicate Queue is not full.
+ */
+ std::atomic_init(evFlagWordPtr, static_cast<uint32_t>(kFmqNotFull));
+ }
+
+ T* mQueue;
+ size_t mNumMessagesMax = 0;
};
-class BadQueueConfig: public ::testing::Test {
-};
+TYPED_TEST_CASE(BadQueueConfig, BadConfigTypes);
+
+template <typename T>
+class BadQueueConfig : public TestBase<T> {};
+
+class AidlOnlyBadQueueConfig : public ::testing::Test {};
/*
* Utility function to initialize data to be written to the FMQ
@@ -136,10 +169,8 @@
* it checks if the kFmqNotEmpty bit is actually set.
* If the read is succesful, it signals Wake to kFmqNotFull.
*/
-void ReaderThreadBlocking(
- android::hardware::MessageQueue<uint8_t,
- android::hardware::kSynchronizedReadWrite>* fmq,
- std::atomic<uint32_t>* fwAddr) {
+template <typename T>
+void TestBase<T>::ReaderThreadBlocking(T* fmq, std::atomic<uint32_t>* fwAddr) {
const size_t dataLen = 64;
uint8_t data[dataLen];
android::hardware::EventFlag* efGroup = nullptr;
@@ -171,10 +202,8 @@
* This thread will attempt to read and block using the readBlocking() API and
* passes in a pointer to an EventFlag object.
*/
-void ReaderThreadBlocking2(
- android::hardware::MessageQueue<uint8_t,
- android::hardware::kSynchronizedReadWrite>* fmq,
- std::atomic<uint32_t>* fwAddr) {
+template <typename T>
+void TestBase<T>::ReaderThreadBlocking2(T* fmq, std::atomic<uint32_t>* fwAddr) {
const size_t dataLen = 64;
uint8_t data[dataLen];
android::hardware::EventFlag* efGroup = nullptr;
@@ -192,12 +221,9 @@
ASSERT_EQ(android::NO_ERROR, status);
}
-
-TEST_F(BadQueueConfig, QueueSizeTooLarge) {
- typedef android::hardware::MessageQueue<uint16_t, android::hardware::kSynchronizedReadWrite>
- MessageQueueSync16;
+TYPED_TEST(BadQueueConfig, QueueSizeTooLarge) {
size_t numElementsInQueue = SIZE_MAX / sizeof(uint16_t) + 1;
- MessageQueueSync16 * fmq = new (std::nothrow) MessageQueueSync16(numElementsInQueue);
+ TypeParam* fmq = new (std::nothrow) TypeParam(numElementsInQueue);
ASSERT_NE(nullptr, fmq);
/*
* Should fail due to size being too large to fit into size_t.
@@ -205,16 +231,75 @@
ASSERT_FALSE(fmq->isValid());
}
+// TODO(b/165674950) Since AIDL does not support unsigned integers, it can only support
+// 1/2 the queue size of HIDL. Once support is added to AIDL, this restriction can be
+// lifted. Until then, check against SSIZE_MAX instead of SIZE_MAX.
+TEST_F(AidlOnlyBadQueueConfig, QueueSizeTooLargeForAidl) {
+ size_t numElementsInQueue = SSIZE_MAX / sizeof(uint16_t) + 1;
+ AidlMessageQueueSync16* fmq = new (std::nothrow) AidlMessageQueueSync16(numElementsInQueue);
+ ASSERT_NE(nullptr, fmq);
+ /*
+ * Should fail due to size being too large to fit into size_t.
+ */
+ ASSERT_FALSE(fmq->isValid());
+}
+
+TEST_F(AidlOnlyBadQueueConfig, NegativeAidlDescriptor) {
+ aidl::android::hardware::common::MQDescriptor<uint16_t, SynchronizedReadWrite> desc;
+ desc.quantum = -10;
+ AidlMessageQueueSync16* fmq = new (std::nothrow) AidlMessageQueueSync16(desc);
+ ASSERT_NE(nullptr, fmq);
+ /*
+ * Should fail due to quantum being negative.
+ */
+ ASSERT_FALSE(fmq->isValid());
+}
+
+TEST_F(AidlOnlyBadQueueConfig, NegativeAidlDescriptorGrantor) {
+ aidl::android::hardware::common::MQDescriptor<uint16_t, SynchronizedReadWrite> desc;
+ desc.quantum = 2;
+ desc.flags = 0;
+ desc.grantors.push_back(
+ aidl::android::hardware::common::GrantorDescriptor{.offset = 12, .extent = -10});
+ AidlMessageQueueSync16* fmq = new (std::nothrow) AidlMessageQueueSync16(desc);
+ ASSERT_NE(nullptr, fmq);
+ /*
+ * Should fail due to grantor having negative extent.
+ */
+ ASSERT_FALSE(fmq->isValid());
+}
+
+/*
+ * Test creating a new queue from a modified MQDescriptor of another queue.
+ * If MQDescriptor.quantum doesn't match the size of the payload(T), the queue
+ * should be invalid.
+ */
+TEST_F(AidlOnlyBadQueueConfig, MismatchedPayloadSize) {
+ AidlMessageQueueSync16 fmq = AidlMessageQueueSync16(64);
+ aidl::android::hardware::common::MQDescriptor<uint16_t, SynchronizedReadWrite> desc =
+ fmq.dupeDesc();
+ // This should work fine with the unmodified MQDescriptor
+ AidlMessageQueueSync16 fmq2 = AidlMessageQueueSync16(desc);
+ ASSERT_TRUE(fmq2.isValid());
+
+ // Simulate a difference in payload size between processes handling the queue
+ desc.quantum = 8;
+ AidlMessageQueueSync16 fmq3 = AidlMessageQueueSync16(desc);
+
+ // Should fail due to the quantum not matching the sizeof(uint16_t)
+ ASSERT_FALSE(fmq3.isValid());
+}
+
/*
* Test that basic blocking works. This test uses the non-blocking read()/write()
* APIs.
*/
-TEST_F(BlockingReadWrites, SmallInputTest1) {
+TYPED_TEST(BlockingReadWrites, SmallInputTest1) {
const size_t dataLen = 64;
uint8_t data[dataLen] = {0};
android::hardware::EventFlag* efGroup = nullptr;
- android::status_t status = android::hardware::EventFlag::createEventFlag(&mFw, &efGroup);
+ android::status_t status = android::hardware::EventFlag::createEventFlag(&this->mFw, &efGroup);
ASSERT_EQ(android::NO_ERROR, status);
ASSERT_NE(nullptr, efGroup);
@@ -222,7 +307,8 @@
/*
* Start a thread that will try to read and block on kFmqNotEmpty.
*/
- std::thread Reader(ReaderThreadBlocking, mQueue, &mFw);
+ std::thread Reader(BlockingReadWrites<TypeParam>::ReaderThreadBlocking, this->mQueue,
+ &this->mFw);
struct timespec waitTime = {0, 100 * 1000000};
ASSERT_EQ(0, nanosleep(&waitTime, NULL));
@@ -230,7 +316,7 @@
* After waiting for some time write into the FMQ
* and call Wake on kFmqNotEmpty.
*/
- ASSERT_TRUE(mQueue->write(data, dataLen));
+ ASSERT_TRUE(this->mQueue->write(data, dataLen));
status = efGroup->wake(kFmqNotEmpty);
ASSERT_EQ(android::NO_ERROR, status);
@@ -245,12 +331,12 @@
* Test that basic blocking works. This test uses the
* writeBlocking()/readBlocking() APIs.
*/
-TEST_F(BlockingReadWrites, SmallInputTest2) {
+TYPED_TEST(BlockingReadWrites, SmallInputTest2) {
const size_t dataLen = 64;
uint8_t data[dataLen] = {0};
android::hardware::EventFlag* efGroup = nullptr;
- android::status_t status = android::hardware::EventFlag::createEventFlag(&mFw, &efGroup);
+ android::status_t status = android::hardware::EventFlag::createEventFlag(&this->mFw, &efGroup);
ASSERT_EQ(android::NO_ERROR, status);
ASSERT_NE(nullptr, efGroup);
@@ -259,13 +345,11 @@
* Start a thread that will try to read and block on kFmqNotEmpty. It will
* call wake() on kFmqNotFull when the read is successful.
*/
- std::thread Reader(ReaderThreadBlocking2, mQueue, &mFw);
- bool ret = mQueue->writeBlocking(data,
- dataLen,
- static_cast<uint32_t>(kFmqNotFull),
- static_cast<uint32_t>(kFmqNotEmpty),
- 5000000000 /* timeOutNanos */,
- efGroup);
+ std::thread Reader(BlockingReadWrites<TypeParam>::ReaderThreadBlocking2, this->mQueue,
+ &this->mFw);
+ bool ret = this->mQueue->writeBlocking(data, dataLen, static_cast<uint32_t>(kFmqNotFull),
+ static_cast<uint32_t>(kFmqNotEmpty),
+ 5000000000 /* timeOutNanos */, efGroup);
ASSERT_TRUE(ret);
Reader.join();
@@ -276,9 +360,9 @@
/*
* Test that basic blocking times out as intended.
*/
-TEST_F(BlockingReadWrites, BlockingTimeOutTest) {
+TYPED_TEST(BlockingReadWrites, BlockingTimeOutTest) {
android::hardware::EventFlag* efGroup = nullptr;
- android::status_t status = android::hardware::EventFlag::createEventFlag(&mFw, &efGroup);
+ android::status_t status = android::hardware::EventFlag::createEventFlag(&this->mFw, &efGroup);
ASSERT_EQ(android::NO_ERROR, status);
ASSERT_NE(nullptr, efGroup);
@@ -301,31 +385,29 @@
* Test that odd queue sizes do not cause unaligned error
* on access to EventFlag object.
*/
-TEST_F(QueueSizeOdd, EventFlagTest) {
+TYPED_TEST(QueueSizeOdd, EventFlagTest) {
const size_t dataLen = 64;
uint8_t data[dataLen] = {0};
- bool ret = mQueue->writeBlocking(data,
- dataLen,
- static_cast<uint32_t>(kFmqNotFull),
- static_cast<uint32_t>(kFmqNotEmpty),
- 5000000000 /* timeOutNanos */);
+ bool ret = this->mQueue->writeBlocking(data, dataLen, static_cast<uint32_t>(kFmqNotFull),
+ static_cast<uint32_t>(kFmqNotEmpty),
+ 5000000000 /* timeOutNanos */);
ASSERT_TRUE(ret);
}
/*
* Verify that a few bytes of data can be successfully written and read.
*/
-TEST_F(SynchronizedReadWrites, SmallInputTest1) {
+TYPED_TEST(SynchronizedReadWrites, SmallInputTest1) {
const size_t dataLen = 16;
- ASSERT_LE(dataLen, mNumMessagesMax);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
uint8_t data[dataLen];
initData(data, dataLen);
- ASSERT_TRUE(mQueue->write(data, dataLen));
+ ASSERT_TRUE(this->mQueue->write(data, dataLen));
uint8_t readData[dataLen] = {};
- ASSERT_TRUE(mQueue->read(readData, dataLen));
+ ASSERT_TRUE(this->mQueue->read(readData, dataLen));
ASSERT_EQ(0, memcmp(data, readData, dataLen));
}
@@ -333,27 +415,27 @@
* Verify that a few bytes of data can be successfully written and read using
* beginRead/beginWrite/CommitRead/CommitWrite
*/
-TEST_F(SynchronizedReadWrites, SmallInputTest2) {
+TYPED_TEST(SynchronizedReadWrites, SmallInputTest2) {
const size_t dataLen = 16;
- ASSERT_LE(dataLen, mNumMessagesMax);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
uint8_t data[dataLen];
initData(data, dataLen);
- MessageQueueSync::MemTransaction tx;
- ASSERT_TRUE(mQueue->beginWrite(dataLen, &tx));
+ typename TypeParam::MemTransaction tx;
+ ASSERT_TRUE(this->mQueue->beginWrite(dataLen, &tx));
ASSERT_TRUE(tx.copyTo(data, 0 /* startIdx */, dataLen));
- ASSERT_TRUE(mQueue->commitWrite(dataLen));
+ ASSERT_TRUE(this->mQueue->commitWrite(dataLen));
uint8_t readData[dataLen] = {};
- ASSERT_TRUE(mQueue->beginRead(dataLen, &tx));
+ ASSERT_TRUE(this->mQueue->beginRead(dataLen, &tx));
ASSERT_TRUE(tx.copyFrom(readData, 0 /* startIdx */, dataLen));
- ASSERT_TRUE(mQueue->commitRead(dataLen));
+ ASSERT_TRUE(this->mQueue->commitRead(dataLen));
ASSERT_EQ(0, memcmp(data, readData, dataLen));
}
@@ -362,14 +444,14 @@
* Verify that a few bytes of data can be successfully written and read using
* beginRead/beginWrite/CommitRead/CommitWrite as well as getSlot().
*/
-TEST_F(SynchronizedReadWrites, SmallInputTest3) {
+TYPED_TEST(SynchronizedReadWrites, SmallInputTest3) {
const size_t dataLen = 16;
- ASSERT_LE(dataLen, mNumMessagesMax);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
uint8_t data[dataLen];
initData(data, dataLen);
- MessageQueueSync::MemTransaction tx;
- ASSERT_TRUE(mQueue->beginWrite(dataLen, &tx));
+ typename TypeParam::MemTransaction tx;
+ ASSERT_TRUE(this->mQueue->beginWrite(dataLen, &tx));
auto first = tx.getFirstRegion();
auto second = tx.getSecondRegion();
@@ -380,11 +462,11 @@
*ptr = data[i];
}
- ASSERT_TRUE(mQueue->commitWrite(dataLen));
+ ASSERT_TRUE(this->mQueue->commitWrite(dataLen));
uint8_t readData[dataLen] = {};
- ASSERT_TRUE(mQueue->beginRead(dataLen, &tx));
+ ASSERT_TRUE(this->mQueue->beginRead(dataLen, &tx));
first = tx.getFirstRegion();
second = tx.getSecondRegion();
@@ -396,7 +478,7 @@
readData[i] = *ptr;
}
- ASSERT_TRUE(mQueue->commitRead(dataLen));
+ ASSERT_TRUE(this->mQueue->commitRead(dataLen));
ASSERT_EQ(0, memcmp(data, readData, dataLen));
}
@@ -404,25 +486,25 @@
/*
* Verify that read() returns false when trying to read from an empty queue.
*/
-TEST_F(SynchronizedReadWrites, ReadWhenEmpty1) {
- ASSERT_EQ(0UL, mQueue->availableToRead());
+TYPED_TEST(SynchronizedReadWrites, ReadWhenEmpty1) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
const size_t dataLen = 2;
- ASSERT_LE(dataLen, mNumMessagesMax);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
uint8_t readData[dataLen];
- ASSERT_FALSE(mQueue->read(readData, dataLen));
+ ASSERT_FALSE(this->mQueue->read(readData, dataLen));
}
/*
* Verify that beginRead() returns a MemTransaction object with null pointers when trying
* to read from an empty queue.
*/
-TEST_F(SynchronizedReadWrites, ReadWhenEmpty2) {
- ASSERT_EQ(0UL, mQueue->availableToRead());
+TYPED_TEST(SynchronizedReadWrites, ReadWhenEmpty2) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
const size_t dataLen = 2;
- ASSERT_LE(dataLen, mNumMessagesMax);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
- MessageQueueSync::MemTransaction tx;
- ASSERT_FALSE(mQueue->beginRead(dataLen, &tx));
+ typename TypeParam::MemTransaction tx;
+ ASSERT_FALSE(this->mQueue->beginRead(dataLen, &tx));
auto first = tx.getFirstRegion();
auto second = tx.getSecondRegion();
@@ -435,17 +517,17 @@
* Write the queue until full. Verify that another write is unsuccessful.
* Verify that availableToWrite() returns 0 as expected.
*/
-TEST_F(SynchronizedReadWrites, WriteWhenFull1) {
- ASSERT_EQ(0UL, mQueue->availableToRead());
- std::vector<uint8_t> data(mNumMessagesMax);
+TYPED_TEST(SynchronizedReadWrites, WriteWhenFull1) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
+ std::vector<uint8_t> data(this->mNumMessagesMax);
- initData(&data[0], mNumMessagesMax);
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
- ASSERT_EQ(0UL, mQueue->availableToWrite());
- ASSERT_FALSE(mQueue->write(&data[0], 1));
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ ASSERT_EQ(0UL, this->mQueue->availableToWrite());
+ ASSERT_FALSE(this->mQueue->write(&data[0], 1));
- std::vector<uint8_t> readData(mNumMessagesMax);
- ASSERT_TRUE(mQueue->read(&readData[0], mNumMessagesMax));
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
ASSERT_EQ(data, readData);
}
@@ -453,16 +535,16 @@
* Write the queue until full. Verify that beginWrite() returns
* a MemTransaction object with null base pointers.
*/
-TEST_F(SynchronizedReadWrites, WriteWhenFull2) {
- ASSERT_EQ(0UL, mQueue->availableToRead());
- std::vector<uint8_t> data(mNumMessagesMax);
+TYPED_TEST(SynchronizedReadWrites, WriteWhenFull2) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
+ std::vector<uint8_t> data(this->mNumMessagesMax);
- initData(&data[0], mNumMessagesMax);
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
- ASSERT_EQ(0UL, mQueue->availableToWrite());
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ ASSERT_EQ(0UL, this->mQueue->availableToWrite());
- MessageQueueSync::MemTransaction tx;
- ASSERT_FALSE(mQueue->beginWrite(1, &tx));
+ typename TypeParam::MemTransaction tx;
+ ASSERT_FALSE(this->mQueue->beginWrite(1, &tx));
auto first = tx.getFirstRegion();
auto second = tx.getSecondRegion();
@@ -476,12 +558,12 @@
* Verify that the write is successful and the subsequent read
* returns the expected data.
*/
-TEST_F(SynchronizedReadWrites, LargeInputTest1) {
- std::vector<uint8_t> data(mNumMessagesMax);
- initData(&data[0], mNumMessagesMax);
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
- std::vector<uint8_t> readData(mNumMessagesMax);
- ASSERT_TRUE(mQueue->read(&readData[0], mNumMessagesMax));
+TYPED_TEST(SynchronizedReadWrites, LargeInputTest1) {
+ std::vector<uint8_t> data(this->mNumMessagesMax);
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
ASSERT_EQ(data, readData);
}
@@ -490,18 +572,18 @@
* Verify that it fails. Verify that a subsequent read fails and
* the queue is still empty.
*/
-TEST_F(SynchronizedReadWrites, LargeInputTest2) {
- ASSERT_EQ(0UL, mQueue->availableToRead());
+TYPED_TEST(SynchronizedReadWrites, LargeInputTest2) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
const size_t dataLen = 4096;
- ASSERT_GT(dataLen, mNumMessagesMax);
+ ASSERT_GT(dataLen, this->mNumMessagesMax);
std::vector<uint8_t> data(dataLen);
initData(&data[0], dataLen);
- ASSERT_FALSE(mQueue->write(&data[0], dataLen));
- std::vector<uint8_t> readData(mNumMessagesMax);
- ASSERT_FALSE(mQueue->read(&readData[0], mNumMessagesMax));
+ ASSERT_FALSE(this->mQueue->write(&data[0], dataLen));
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
+ ASSERT_FALSE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
ASSERT_NE(data, readData);
- ASSERT_EQ(0UL, mQueue->availableToRead());
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
}
/*
@@ -509,13 +591,13 @@
* the attempt returns false. Verify that the attempt did not
* affect the pre-existing data in the queue.
*/
-TEST_F(SynchronizedReadWrites, LargeInputTest3) {
- std::vector<uint8_t> data(mNumMessagesMax);
- initData(&data[0], mNumMessagesMax);
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
- ASSERT_FALSE(mQueue->write(&data[0], 1));
- std::vector<uint8_t> readData(mNumMessagesMax);
- ASSERT_TRUE(mQueue->read(&readData[0], mNumMessagesMax));
+TYPED_TEST(SynchronizedReadWrites, LargeInputTest3) {
+ std::vector<uint8_t> data(this->mNumMessagesMax);
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ ASSERT_FALSE(this->mQueue->write(&data[0], 1));
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
ASSERT_EQ(data, readData);
}
@@ -524,13 +606,13 @@
* null base pointers when attempting to write data larger
* than the queue size.
*/
-TEST_F(SynchronizedReadWrites, LargeInputTest4) {
- ASSERT_EQ(0UL, mQueue->availableToRead());
+TYPED_TEST(SynchronizedReadWrites, LargeInputTest4) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
const size_t dataLen = 4096;
- ASSERT_GT(dataLen, mNumMessagesMax);
+ ASSERT_GT(dataLen, this->mNumMessagesMax);
- MessageQueueSync::MemTransaction tx;
- ASSERT_FALSE(mQueue->beginWrite(dataLen, &tx));
+ typename TypeParam::MemTransaction tx;
+ ASSERT_FALSE(this->mQueue->beginWrite(dataLen, &tx));
auto first = tx.getFirstRegion();
auto second = tx.getSecondRegion();
@@ -542,18 +624,18 @@
/*
* Verify that multiple reads one after the other return expected data.
*/
-TEST_F(SynchronizedReadWrites, MultipleRead) {
+TYPED_TEST(SynchronizedReadWrites, MultipleRead) {
const size_t chunkSize = 100;
const size_t chunkNum = 5;
const size_t dataLen = chunkSize * chunkNum;
- ASSERT_LE(dataLen, mNumMessagesMax);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
uint8_t data[dataLen];
initData(data, dataLen);
- ASSERT_TRUE(mQueue->write(data, dataLen));
+ ASSERT_TRUE(this->mQueue->write(data, dataLen));
uint8_t readData[dataLen] = {};
for (size_t i = 0; i < chunkNum; i++) {
- ASSERT_TRUE(mQueue->read(readData + i * chunkSize, chunkSize));
+ ASSERT_TRUE(this->mQueue->read(readData + i * chunkSize, chunkSize));
}
ASSERT_EQ(0, memcmp(readData, data, dataLen));
}
@@ -561,37 +643,37 @@
/*
* Verify that multiple writes one after the other happens correctly.
*/
-TEST_F(SynchronizedReadWrites, MultipleWrite) {
+TYPED_TEST(SynchronizedReadWrites, MultipleWrite) {
const int chunkSize = 100;
const int chunkNum = 5;
const size_t dataLen = chunkSize * chunkNum;
- ASSERT_LE(dataLen, mNumMessagesMax);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
uint8_t data[dataLen];
initData(data, dataLen);
for (unsigned int i = 0; i < chunkNum; i++) {
- ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize));
+ ASSERT_TRUE(this->mQueue->write(data + i * chunkSize, chunkSize));
}
uint8_t readData[dataLen] = {};
- ASSERT_TRUE(mQueue->read(readData, dataLen));
+ ASSERT_TRUE(this->mQueue->read(readData, dataLen));
ASSERT_EQ(0, memcmp(readData, data, dataLen));
}
/*
* 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
+ * Write this->mNumMessagesMax messages into the queue. This will cause a
* wrap around. Read and verify the data.
*/
-TEST_F(SynchronizedReadWrites, ReadWriteWrapAround1) {
- size_t numMessages = mNumMessagesMax - 1;
- std::vector<uint8_t> data(mNumMessagesMax);
- std::vector<uint8_t> readData(mNumMessagesMax);
- initData(&data[0], mNumMessagesMax);
- ASSERT_TRUE(mQueue->write(&data[0], numMessages));
- ASSERT_TRUE(mQueue->read(&readData[0], numMessages));
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
- ASSERT_TRUE(mQueue->read(&readData[0], mNumMessagesMax));
+TYPED_TEST(SynchronizedReadWrites, ReadWriteWrapAround1) {
+ size_t numMessages = this->mNumMessagesMax - 1;
+ std::vector<uint8_t> data(this->mNumMessagesMax);
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], numMessages));
+ ASSERT_TRUE(this->mQueue->read(&readData[0], numMessages));
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ ASSERT_TRUE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
ASSERT_EQ(data, readData);
}
@@ -603,38 +685,38 @@
* Write mNumMessagesMax messages into the queue. This will cause a
* wrap around. Read and verify the data.
*/
-TEST_F(SynchronizedReadWrites, ReadWriteWrapAround2) {
- size_t dataLen = mNumMessagesMax - 1;
- std::vector<uint8_t> data(mNumMessagesMax);
- std::vector<uint8_t> readData(mNumMessagesMax);
- initData(&data[0], mNumMessagesMax);
- ASSERT_TRUE(mQueue->write(&data[0], dataLen));
- ASSERT_TRUE(mQueue->read(&readData[0], dataLen));
+TYPED_TEST(SynchronizedReadWrites, ReadWriteWrapAround2) {
+ size_t dataLen = this->mNumMessagesMax - 1;
+ std::vector<uint8_t> data(this->mNumMessagesMax);
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], dataLen));
+ ASSERT_TRUE(this->mQueue->read(&readData[0], dataLen));
/*
* The next write and read will have to deal with with wrap arounds.
*/
- MessageQueueSync::MemTransaction tx;
- ASSERT_TRUE(mQueue->beginWrite(mNumMessagesMax, &tx));
+ typename TypeParam::MemTransaction tx;
+ ASSERT_TRUE(this->mQueue->beginWrite(this->mNumMessagesMax, &tx));
auto first = tx.getFirstRegion();
auto second = tx.getSecondRegion();
- ASSERT_EQ(first.getLength() + second.getLength(), mNumMessagesMax);
+ ASSERT_EQ(first.getLength() + second.getLength(), this->mNumMessagesMax);
- ASSERT_TRUE(tx.copyTo(&data[0], 0 /* startIdx */, mNumMessagesMax));
+ ASSERT_TRUE(tx.copyTo(&data[0], 0 /* startIdx */, this->mNumMessagesMax));
- ASSERT_TRUE(mQueue->commitWrite(mNumMessagesMax));
+ ASSERT_TRUE(this->mQueue->commitWrite(this->mNumMessagesMax));
- ASSERT_TRUE(mQueue->beginRead(mNumMessagesMax, &tx));
+ ASSERT_TRUE(this->mQueue->beginRead(this->mNumMessagesMax, &tx));
first = tx.getFirstRegion();
second = tx.getSecondRegion();
- ASSERT_EQ(first.getLength() + second.getLength(), mNumMessagesMax);
+ ASSERT_EQ(first.getLength() + second.getLength(), this->mNumMessagesMax);
- ASSERT_TRUE(tx.copyFrom(&readData[0], 0 /* startIdx */, mNumMessagesMax));
- ASSERT_TRUE(mQueue->commitRead(mNumMessagesMax));
+ ASSERT_TRUE(tx.copyFrom(&readData[0], 0 /* startIdx */, this->mNumMessagesMax));
+ ASSERT_TRUE(this->mQueue->commitRead(this->mNumMessagesMax));
ASSERT_EQ(data, readData);
}
@@ -642,44 +724,44 @@
/*
* Verify that a few bytes of data can be successfully written and read.
*/
-TEST_F(UnsynchronizedWrite, SmallInputTest1) {
+TYPED_TEST(UnsynchronizedWriteTest, SmallInputTest1) {
const size_t dataLen = 16;
- ASSERT_LE(dataLen, mNumMessagesMax);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
uint8_t data[dataLen];
initData(data, dataLen);
- ASSERT_TRUE(mQueue->write(data, dataLen));
+ ASSERT_TRUE(this->mQueue->write(data, dataLen));
uint8_t readData[dataLen] = {};
- ASSERT_TRUE(mQueue->read(readData, dataLen));
+ ASSERT_TRUE(this->mQueue->read(readData, dataLen));
ASSERT_EQ(0, memcmp(data, readData, dataLen));
}
/*
* Verify that read() returns false when trying to read from an empty queue.
*/
-TEST_F(UnsynchronizedWrite, ReadWhenEmpty) {
- ASSERT_EQ(0UL, mQueue->availableToRead());
+TYPED_TEST(UnsynchronizedWriteTest, ReadWhenEmpty) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
const size_t dataLen = 2;
- ASSERT_TRUE(dataLen < mNumMessagesMax);
+ ASSERT_TRUE(dataLen < this->mNumMessagesMax);
uint8_t readData[dataLen];
- ASSERT_FALSE(mQueue->read(readData, dataLen));
+ ASSERT_FALSE(this->mQueue->read(readData, dataLen));
}
/*
* Write the queue when full. Verify that a subsequent writes is succesful.
* Verify that availableToWrite() returns 0 as expected.
*/
-TEST_F(UnsynchronizedWrite, WriteWhenFull1) {
- ASSERT_EQ(0UL, mQueue->availableToRead());
- std::vector<uint8_t> data(mNumMessagesMax);
+TYPED_TEST(UnsynchronizedWriteTest, WriteWhenFull1) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
+ std::vector<uint8_t> data(this->mNumMessagesMax);
- initData(&data[0], mNumMessagesMax);
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
- ASSERT_EQ(0UL, mQueue->availableToWrite());
- ASSERT_TRUE(mQueue->write(&data[0], 1));
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ ASSERT_EQ(0UL, this->mQueue->availableToWrite());
+ ASSERT_TRUE(this->mQueue->write(&data[0], 1));
- std::vector<uint8_t> readData(mNumMessagesMax);
- ASSERT_FALSE(mQueue->read(&readData[0], mNumMessagesMax));
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
+ ASSERT_FALSE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
}
/*
@@ -687,22 +769,22 @@
* using beginRead()/commitRead() is succesful.
* Verify that the next read fails as expected for unsynchronized flavor.
*/
-TEST_F(UnsynchronizedWrite, WriteWhenFull2) {
- ASSERT_EQ(0UL, mQueue->availableToRead());
- std::vector<uint8_t> data(mNumMessagesMax);
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
+TYPED_TEST(UnsynchronizedWriteTest, WriteWhenFull2) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
+ std::vector<uint8_t> data(this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
- MessageQueueUnsync::MemTransaction tx;
- ASSERT_TRUE(mQueue->beginWrite(1, &tx));
+ typename TypeParam::MemTransaction tx;
+ ASSERT_TRUE(this->mQueue->beginWrite(1, &tx));
ASSERT_EQ(tx.getFirstRegion().getLength(), 1U);
ASSERT_TRUE(tx.copyTo(&data[0], 0 /* startIdx */));
- ASSERT_TRUE(mQueue->commitWrite(1));
+ ASSERT_TRUE(this->mQueue->commitWrite(1));
- std::vector<uint8_t> readData(mNumMessagesMax);
- ASSERT_FALSE(mQueue->read(&readData[0], mNumMessagesMax));
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
+ ASSERT_FALSE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
}
/*
@@ -710,12 +792,12 @@
* Verify that the write is successful and the subsequent read
* returns the expected data.
*/
-TEST_F(UnsynchronizedWrite, LargeInputTest1) {
- std::vector<uint8_t> data(mNumMessagesMax);
- initData(&data[0], mNumMessagesMax);
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
- std::vector<uint8_t> readData(mNumMessagesMax);
- ASSERT_TRUE(mQueue->read(&readData[0], mNumMessagesMax));
+TYPED_TEST(UnsynchronizedWriteTest, LargeInputTest1) {
+ std::vector<uint8_t> data(this->mNumMessagesMax);
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
ASSERT_EQ(data, readData);
}
@@ -724,17 +806,17 @@
* Verify that it fails. Verify that a subsequent read fails and
* the queue is still empty.
*/
-TEST_F(UnsynchronizedWrite, LargeInputTest2) {
- ASSERT_EQ(0UL, mQueue->availableToRead());
+TYPED_TEST(UnsynchronizedWriteTest, LargeInputTest2) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
const size_t dataLen = 4096;
- ASSERT_GT(dataLen, mNumMessagesMax);
+ ASSERT_GT(dataLen, this->mNumMessagesMax);
std::vector<uint8_t> data(dataLen);
initData(&data[0], dataLen);
- ASSERT_FALSE(mQueue->write(&data[0], dataLen));
- std::vector<uint8_t> readData(mNumMessagesMax);
- ASSERT_FALSE(mQueue->read(&readData[0], mNumMessagesMax));
+ ASSERT_FALSE(this->mQueue->write(&data[0], dataLen));
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
+ ASSERT_FALSE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
ASSERT_NE(data, readData);
- ASSERT_EQ(0UL, mQueue->availableToRead());
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
}
/*
@@ -742,29 +824,29 @@
* the attempt is succesful. Verify that the read fails
* as expected.
*/
-TEST_F(UnsynchronizedWrite, LargeInputTest3) {
- std::vector<uint8_t> data(mNumMessagesMax);
- initData(&data[0], mNumMessagesMax);
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
- ASSERT_TRUE(mQueue->write(&data[0], 1));
- std::vector<uint8_t> readData(mNumMessagesMax);
- ASSERT_FALSE(mQueue->read(&readData[0], mNumMessagesMax));
+TYPED_TEST(UnsynchronizedWriteTest, LargeInputTest3) {
+ std::vector<uint8_t> data(this->mNumMessagesMax);
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ ASSERT_TRUE(this->mQueue->write(&data[0], 1));
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
+ ASSERT_FALSE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
}
/*
* Verify that multiple reads one after the other return expected data.
*/
-TEST_F(UnsynchronizedWrite, MultipleRead) {
+TYPED_TEST(UnsynchronizedWriteTest, MultipleRead) {
const size_t chunkSize = 100;
const size_t chunkNum = 5;
const size_t dataLen = chunkSize * chunkNum;
- ASSERT_LE(dataLen, mNumMessagesMax);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
uint8_t data[dataLen];
initData(data, dataLen);
- ASSERT_TRUE(mQueue->write(data, dataLen));
+ ASSERT_TRUE(this->mQueue->write(data, dataLen));
uint8_t readData[dataLen] = {};
for (size_t i = 0; i < chunkNum; i++) {
- ASSERT_TRUE(mQueue->read(readData + i * chunkSize, chunkSize));
+ ASSERT_TRUE(this->mQueue->read(readData + i * chunkSize, chunkSize));
}
ASSERT_EQ(0, memcmp(readData, data, dataLen));
}
@@ -772,20 +854,20 @@
/*
* Verify that multiple writes one after the other happens correctly.
*/
-TEST_F(UnsynchronizedWrite, MultipleWrite) {
+TYPED_TEST(UnsynchronizedWriteTest, MultipleWrite) {
const size_t chunkSize = 100;
const size_t chunkNum = 5;
const size_t dataLen = chunkSize * chunkNum;
- ASSERT_LE(dataLen, mNumMessagesMax);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
uint8_t data[dataLen];
initData(data, dataLen);
for (size_t i = 0; i < chunkNum; i++) {
- ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize));
+ ASSERT_TRUE(this->mQueue->write(data + i * chunkSize, chunkSize));
}
uint8_t readData[dataLen] = {};
- ASSERT_TRUE(mQueue->read(readData, dataLen));
+ ASSERT_TRUE(this->mQueue->read(readData, dataLen));
ASSERT_EQ(0, memcmp(readData, data, dataLen));
}
@@ -795,15 +877,15 @@
* Write mNumMessagesMax messages into the queue. This will cause a
* wrap around. Read and verify the data.
*/
-TEST_F(UnsynchronizedWrite, ReadWriteWrapAround) {
- size_t numMessages = mNumMessagesMax - 1;
- std::vector<uint8_t> data(mNumMessagesMax);
- std::vector<uint8_t> readData(mNumMessagesMax);
+TYPED_TEST(UnsynchronizedWriteTest, ReadWriteWrapAround) {
+ size_t numMessages = this->mNumMessagesMax - 1;
+ std::vector<uint8_t> data(this->mNumMessagesMax);
+ std::vector<uint8_t> readData(this->mNumMessagesMax);
- initData(&data[0], mNumMessagesMax);
- ASSERT_TRUE(mQueue->write(&data[0], numMessages));
- ASSERT_TRUE(mQueue->read(&readData[0], numMessages));
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
- ASSERT_TRUE(mQueue->read(&readData[0], mNumMessagesMax));
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], numMessages));
+ ASSERT_TRUE(this->mQueue->read(&readData[0], numMessages));
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ ASSERT_TRUE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
ASSERT_EQ(data, readData);
}
diff --git a/tests/msgq_test_client.cpp b/tests/msgq_test_client.cpp
index a3d50a5..b29f198 100644
--- a/tests/msgq_test_client.cpp
+++ b/tests/msgq_test_client.cpp
@@ -19,7 +19,13 @@
#error "GTest did not detect pthread library."
#endif
+#include <aidl/android/fmq/test/FixedParcelable.h>
+#include <aidl/android/fmq/test/ITestAidlMsgQ.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <android/hardware/tests/msgq/1.0/ITestMsgQ.h>
+#include <fmq/AidlMessageQueue.h>
#include <fmq/EventFlag.h>
#include <fmq/MessageQueue.h>
#include <hidl/ServiceManagement.h>
@@ -30,6 +36,9 @@
using android::status_t;
// generated
+using ::aidl::android::fmq::test::EventFlagBits;
+using ::aidl::android::fmq::test::FixedParcelable;
+using ::aidl::android::fmq::test::ITestAidlMsgQ;
using android::hardware::tests::msgq::V1_0::ITestMsgQ;
// libhidl
@@ -40,88 +49,229 @@
using android::hardware::MQDescriptorUnsync;
using android::hardware::details::waitForHwService;
-typedef MessageQueue<uint16_t, kSynchronizedReadWrite> MessageQueueSync;
-typedef MessageQueue<uint16_t, kUnsynchronizedWrite> MessageQueueUnsync;
+using aidl::android::hardware::common::SynchronizedReadWrite;
+using aidl::android::hardware::common::UnsynchronizedWrite;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::kUnsynchronizedWrite;
-static sp<ITestMsgQ> waitGetTestService() {
- android::hardware::details::setTrebleTestingOverride(true);
- // waitForHwService is required because ITestMsgQ is not in manifest.xml.
- // "Real" HALs shouldn't be doing this.
- waitForHwService(ITestMsgQ::descriptor, "default");
- return ITestMsgQ::getService();
-}
+typedef android::AidlMessageQueue<int32_t, SynchronizedReadWrite> AidlMessageQueueSync;
+typedef android::AidlMessageQueue<int32_t, UnsynchronizedWrite> AidlMessageQueueUnsync;
+typedef android::hardware::MessageQueue<int32_t, kSynchronizedReadWrite> MessageQueueSync;
+typedef android::hardware::MessageQueue<int32_t, kUnsynchronizedWrite> MessageQueueUnsync;
+static const std::string kServiceName = "BnTestAidlMsgQ";
+static constexpr size_t kNumElementsInSyncQueue = 1024;
-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);
- });
+// Run everything on both the AIDL and HIDL versions
+typedef ::testing::Types<AidlMessageQueueSync, MessageQueueSync> SyncTypes;
+typedef ::testing::Types<AidlMessageQueueUnsync, MessageQueueUnsync> UnsyncTypes;
+
+template <typename T>
+class ClientSyncTestBase : public ::testing::Test {};
+
+// Specialize for AIDL
+template <>
+class ClientSyncTestBase<AidlMessageQueueSync> : public ::testing::Test {
+ protected:
+ static std::shared_ptr<ITestAidlMsgQ> waitGetTestService() {
+ const std::string instance = std::string() + ITestAidlMsgQ::descriptor + "/default";
+ ndk::SpAIBinder binder(AServiceManager_getService(instance.c_str()));
+ return ITestAidlMsgQ::fromBinder(binder);
}
+ bool configureFmqSyncReadWrite(AidlMessageQueueSync* mq) {
+ bool result = false;
+ auto ret = mService->configureFmqSyncReadWrite(mq->dupeDesc(), &result);
+ return result && ret.isOk();
+ }
+ bool requestReadFmqSync(size_t dataLen) {
+ bool result = false;
+ auto ret = mService->requestReadFmqSync(dataLen, &result);
+ return result && ret.isOk();
+ }
+ bool requestWriteFmqSync(size_t dataLen) {
+ bool result = false;
+ auto ret = mService->requestWriteFmqSync(dataLen, &result);
+ return result && ret.isOk();
+ }
+
+ std::shared_ptr<ITestAidlMsgQ> mService;
};
-class SynchronizedReadWriteClient : public ::testing::Test {
-protected:
+// Specialize for HIDL
+template <>
+class ClientSyncTestBase<MessageQueueSync> : public ::testing::Test {
+ protected:
+ static sp<ITestMsgQ> waitGetTestService() {
+ android::hardware::details::setTrebleTestingOverride(true);
+ // waitForHwService is required because ITestMsgQ is not in manifest.xml.
+ // "Real" HALs shouldn't be doing this.
+ waitForHwService(ITestMsgQ::descriptor, "default");
+ return ITestMsgQ::getService();
+ }
+ bool configureFmqSyncReadWrite(MessageQueueSync* mq) {
+ auto ret = mService->configureFmqSyncReadWrite(*mq->getDesc());
+ return ret && ret.isOk();
+ }
+ bool requestReadFmqSync(size_t dataLen) {
+ auto ret = mService->requestReadFmqSync(dataLen);
+ return ret && ret.isOk();
+ }
+ bool requestWriteFmqSync(size_t dataLen) {
+ auto ret = mService->requestWriteFmqSync(dataLen);
+ return ret && ret.isOk();
+ }
+
+ sp<ITestMsgQ> mService;
+};
+
+template <typename T>
+class ClientUnsyncTestBase : public ::testing::Test {};
+
+// Specialize for AIDL
+template <>
+class ClientUnsyncTestBase<AidlMessageQueueUnsync> : public ::testing::Test {
+ protected:
+ static std::shared_ptr<ITestAidlMsgQ> waitGetTestService() {
+ const std::string instance = std::string() + ITestAidlMsgQ::descriptor + "/default";
+ ndk::SpAIBinder binder(AServiceManager_getService(instance.c_str()));
+ return ITestAidlMsgQ::fromBinder(binder);
+ }
+ bool getFmqUnsyncWrite(bool configureFmq, std::shared_ptr<ITestAidlMsgQ> service,
+ AidlMessageQueueUnsync** queue) {
+ bool result = false;
+ aidl::android::hardware::common::MQDescriptor<int32_t, UnsynchronizedWrite> desc;
+ auto ret = service->getFmqUnsyncWrite(configureFmq, &desc, &result);
+ *queue = new (std::nothrow) AidlMessageQueueUnsync(desc);
+ return result && ret.isOk();
+ }
+
+ std::shared_ptr<ITestAidlMsgQ> getQueue(AidlMessageQueueUnsync** fmq, bool setupQueue) {
+ std::shared_ptr<ITestAidlMsgQ> service = waitGetTestService();
+ if (service == nullptr) return nullptr;
+ getFmqUnsyncWrite(setupQueue, service, fmq);
+ return service;
+ }
+
+ bool requestReadFmqUnsync(size_t dataLen, std::shared_ptr<ITestAidlMsgQ> service) {
+ bool result = false;
+ auto ret = service->requestReadFmqUnsync(dataLen, &result);
+ return result && ret.isOk();
+ }
+ bool requestWriteFmqUnsync(size_t dataLen, std::shared_ptr<ITestAidlMsgQ> service) {
+ bool result = false;
+ auto ret = service->requestWriteFmqUnsync(dataLen, &result);
+ return result && ret.isOk();
+ }
+ AidlMessageQueueUnsync* newQueue() {
+ if (mQueue->isValid())
+ return new (std::nothrow) AidlMessageQueueUnsync(mQueue->dupeDesc());
+ else
+ return nullptr;
+ }
+
+ std::shared_ptr<ITestAidlMsgQ> mService;
+ AidlMessageQueueUnsync* mQueue = nullptr;
+};
+
+// Specialize for HIDL
+template <>
+class ClientUnsyncTestBase<MessageQueueUnsync> : public ::testing::Test {
+ protected:
+ static sp<ITestMsgQ> waitGetTestService() {
+ android::hardware::details::setTrebleTestingOverride(true);
+ // waitForHwService is required because ITestMsgQ is not in manifest.xml.
+ // "Real" HALs shouldn't be doing this.
+ waitForHwService(ITestMsgQ::descriptor, "default");
+ return ITestMsgQ::getService();
+ }
+ bool getFmqUnsyncWrite(bool configureFmq, sp<ITestMsgQ> service, MessageQueueUnsync** queue) {
+ if (!service) {
+ return false;
+ }
+ service->getFmqUnsyncWrite(configureFmq /* configureFmq */,
+ [queue](bool ret, const MQDescriptorUnsync<int32_t>& in) {
+ ASSERT_TRUE(ret);
+ *queue = new (std::nothrow) MessageQueueUnsync(in);
+ });
+ return true;
+ }
+
+ sp<ITestMsgQ> getQueue(MessageQueueUnsync** fmq, bool setupQueue) {
+ sp<ITestMsgQ> service = waitGetTestService();
+ if (service == nullptr) return nullptr;
+ getFmqUnsyncWrite(setupQueue, service, fmq);
+ return service;
+ }
+
+ bool requestReadFmqUnsync(size_t dataLen, sp<ITestMsgQ> service) {
+ auto ret = service->requestReadFmqUnsync(dataLen);
+ return ret && ret.isOk();
+ }
+ bool requestWriteFmqUnsync(size_t dataLen, sp<ITestMsgQ> service) {
+ auto ret = service->requestWriteFmqUnsync(dataLen);
+ return ret && ret.isOk();
+ }
+
+ MessageQueueUnsync* newQueue() {
+ return new (std::nothrow) MessageQueueUnsync(*mQueue->getDesc());
+ }
+
+ sp<ITestMsgQ> mService;
+ MessageQueueUnsync* mQueue = nullptr;
+};
+
+TYPED_TEST_CASE(UnsynchronizedWriteClientMultiProcess, UnsyncTypes);
+template <typename T>
+class UnsynchronizedWriteClientMultiProcess : public ClientUnsyncTestBase<T> {};
+
+TYPED_TEST_CASE(SynchronizedReadWriteClient, SyncTypes);
+template <typename T>
+class SynchronizedReadWriteClient : public ClientSyncTestBase<T> {
+ 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());
+ this->mService = this->waitGetTestService();
+ ASSERT_NE(this->mService, nullptr);
+ ASSERT_TRUE(this->mService->isRemote());
// create a queue on the client side
- mQueue = new (std::nothrow)
- MessageQueueSync(kNumElementsInQueue, true /* configure event flag word */);
+ mQueue =
+ new (std::nothrow) T(kNumElementsInSyncQueue, true /* configure event flag word */);
ASSERT_NE(nullptr, mQueue);
ASSERT_TRUE(mQueue->isValid());
- mNumMessagesMax = mQueue->getQuantumCount();
+ ASSERT_EQ(mQueue->getQuantumCount(), kNumElementsInSyncQueue);
// tell server to set up the queue on its end
- ASSERT_TRUE(mService->configureFmqSyncReadWrite(*mQueue->getDesc()));
+ ASSERT_TRUE(this->configureFmqSyncReadWrite(mQueue));
}
- sp<ITestMsgQ> mService;
- MessageQueueSync* mQueue = nullptr;
- size_t mNumMessagesMax = 0;
+ T* mQueue = nullptr;
};
-class UnsynchronizedWriteClient : public ::testing::Test {
-protected:
- virtual void TearDown() {
- delete mQueue;
- }
+TYPED_TEST_CASE(UnsynchronizedWriteClient, UnsyncTypes);
+template <typename T>
+class UnsynchronizedWriteClient : public ClientUnsyncTestBase<T> {
+ protected:
+ virtual void TearDown() { delete this->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();
+ this->mService = this->waitGetTestService();
+ ASSERT_NE(this->mService, nullptr);
+ ASSERT_TRUE(this->mService->isRemote());
+ this->getFmqUnsyncWrite(true, this->mService, &this->mQueue);
+ ASSERT_NE(nullptr, this->mQueue);
+ ASSERT_TRUE(this->mQueue->isValid());
+ mNumMessagesMax = this->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) {
+bool verifyData(int32_t* data, size_t count) {
for (size_t i = 0; i < count; i++) {
if (data[i] != i) return false;
}
@@ -131,7 +281,7 @@
/*
* Utility function to initialize data to be written to the FMQ
*/
-inline void initData(uint16_t* data, size_t count) {
+inline void initData(int32_t* data, size_t count) {
for (size_t i = 0; i < count; i++) {
data[i] = i;
}
@@ -141,33 +291,30 @@
* Verify that for an unsynchronized flavor of FMQ, multiple readers
* can recover from a write overflow condition.
*/
-TEST_F(UnsynchronizedWriteClientMultiProcess, MultipleReadersAfterOverflow) {
+TYPED_TEST(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());
+ TypeParam* queue = nullptr;
+ auto service = this->getQueue(&queue, true /* setupQueue */);
+ ASSERT_NE(service, nullptr);
+ ASSERT_TRUE(service->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());
+ auto ret = this->requestWriteFmqUnsync(numMessagesMax, service);
ASSERT_TRUE(ret);
- ret = testService->requestWriteFmqUnsync(1);
- ASSERT_TRUE(ret.isOk());
+ ret = this->requestWriteFmqUnsync(1, service);
ASSERT_TRUE(ret);
// The following read should fail due to the overflow.
- std::vector<uint16_t> readData(numMessagesMax);
+ std::vector<int32_t> readData(numMessagesMax);
ASSERT_FALSE(queue->read(&readData[0], numMessagesMax));
/*
@@ -175,8 +322,7 @@
* overflow condition.
*/
ASSERT_LT(dataLen, numMessagesMax);
- ret = testService->requestWriteFmqUnsync(dataLen);
- ASSERT_TRUE(ret.isOk());
+ ret = this->requestWriteFmqUnsync(dataLen, service);
ASSERT_TRUE(ret);
// Verify that the read is successful.
@@ -195,25 +341,22 @@
// 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());
+ TypeParam* queue = nullptr;
+ auto service = this->getQueue(&queue, false /* setupQueue */);
+ ASSERT_NE(service, nullptr);
+ ASSERT_TRUE(service->isRemote());
ASSERT_NE(queue, nullptr);
ASSERT_TRUE(queue->isValid());
// This read should fail due to the write overflow.
- std::vector<uint16_t> readData(dataLen);
+ std::vector<int32_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());
+ auto ret = this->requestWriteFmqUnsync(dataLen, service);
ASSERT_TRUE(ret);
// verify that the read is successful.
@@ -232,26 +375,32 @@
* Test that basic blocking works using readBlocking()/writeBlocking() APIs
* using the EventFlag object owned by FMQ.
*/
-TEST_F(SynchronizedReadWriteClient, BlockingReadWrite1) {
+TYPED_TEST(SynchronizedReadWriteClient, BlockingReadWrite1) {
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.
*/
- 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);
+ this->mService->requestBlockingRead(dataLen);
+ {
+ std::array<int32_t, dataLen> data = {0};
+ ret = this->mQueue->writeBlocking(
+ data.data(), data.size(),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+ 5000000000 /* timeOutNanos */);
+ ASSERT_TRUE(ret);
+ }
+ {
+ std::array<int32_t, kNumElementsInSyncQueue> data = {0};
+ ret = this->mQueue->writeBlocking(
+ data.data(), data.size(),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+ 5000000000 /* timeOutNanos */);
+ ASSERT_TRUE(ret);
+ }
}
/*
@@ -259,30 +408,34 @@
* using the EventFlag object owned by FMQ and using the default EventFlag
* notification bit mask.
*/
-TEST_F(SynchronizedReadWriteClient, BlockingReadWrite2) {
+TYPED_TEST(SynchronizedReadWriteClient, BlockingReadWrite2) {
const size_t dataLen = 64;
- std::vector<uint16_t> data(mNumMessagesMax);
+ bool ret = false;
/*
* Request service to perform a blocking read using default EventFlag
* notification bit mask. This call is oneway and will
* return immediately.
*/
- mService->requestBlockingReadDefaultEventFlagBits(dataLen);
+ this->mService->requestBlockingReadDefaultEventFlagBits(dataLen);
/* Cause a context switch to allow service to block */
sched_yield();
-
- bool ret = mQueue->writeBlocking(&data[0],
- dataLen);
- ASSERT_TRUE(ret);
+ {
+ std::array<int32_t, dataLen> data = {0};
+ ret = this->mQueue->writeBlocking(data.data(), data.size());
+ ASSERT_TRUE(ret);
+ }
/*
* If the blocking read was successful, another write of size
- * mNumMessagesMax will succeed.
+ * kNumElementsInSyncQueue will succeed.
*/
- ret = mQueue->writeBlocking(&data[0], mNumMessagesMax, 5000000000 /* timeOutNanos */);
- ASSERT_TRUE(ret);
+ {
+ std::array<int32_t, kNumElementsInSyncQueue> data = {0};
+ ret = this->mQueue->writeBlocking(data.data(), data.size(), 5000000000 /* timeOutNanos */);
+ ASSERT_TRUE(ret);
+ }
}
/*
@@ -291,32 +444,44 @@
* Each write operation writes the same amount of data as a single read
* operation.
*/
-TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat1) {
+TYPED_TEST(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.
+ * Request service to perform a blocking read of 64 elements. This call is
+ * oneway and will return immediately.
*/
- const size_t writeCount = 1024;
- mService->requestBlockingReadRepeat(dataLen, writeCount);
+ const size_t writeCount = kNumElementsInSyncQueue;
+ this->mService->requestBlockingReadRepeat(dataLen, writeCount);
+ /*
+ * Write 64 elements into the queue for the service to consume
+ */
+ {
+ std::array<int32_t, dataLen> data = {0};
+ for (size_t i = 0; i < writeCount; i++) {
+ ret = this->mQueue->writeBlocking(
+ data.data(), data.size(),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+ 5000000000 /* timeOutNanos */);
+ ASSERT_TRUE(ret);
+ }
+ }
+ /*
+ * The queue should be totally empty now, so filling it up entirely with one
+ * blocking write should be successful.
+ */
+ {
+ std::array<int32_t, kNumElementsInSyncQueue> data = {0};
+ ret = this->mQueue->writeBlocking(
+ data.data(), data.size(),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+ 5000000000 /* timeOutNanos */);
- 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);
}
/*
@@ -325,31 +490,43 @@
* amount of data as a single write.
*
*/
-TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat2) {
+TYPED_TEST(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.
+ * Request service to perform a repeated blocking read. This call is oneway
+ * and will return immediately. It will read 64 * 2 elements with each
+ * blocking read, for a total of writeCount / 2 calls.
*/
- 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 */);
+ const size_t writeCount = kNumElementsInSyncQueue;
+ this->mService->requestBlockingReadRepeat(dataLen * 2, writeCount / 2);
+ /*
+ * Write 64 elements into the queue writeCount times
+ */
+ {
+ std::array<int32_t, dataLen> data = {0};
+ for (size_t i = 0; i < writeCount; i++) {
+ ret = this->mQueue->writeBlocking(
+ data.data(), data.size(),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+ 5000000000 /* timeOutNanos */);
+ ASSERT_TRUE(ret);
+ }
+ }
+ /*
+ * The queue should be totally empty now, so filling it up entirely with one
+ * blocking write should be successful.
+ */
+ {
+ std::array<int32_t, kNumElementsInSyncQueue> data = {0};
+ ret = this->mQueue->writeBlocking(
+ data.data(), data.size(),
+ 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);
}
/*
@@ -357,56 +534,67 @@
* using the EventFlag object owned by FMQ. Each write operation writes twice
* the amount of data as a single read.
*/
-TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat3) {
+TYPED_TEST(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.
+ * Request service to perform a repeated blocking read. This call is oneway
+ * and will return immediately. It will read 64 / 2 elements with each
+ * blocking read, for a total of writeCount * 2 calls.
*/
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 */);
+ this->mService->requestBlockingReadRepeat(dataLen / 2, writeCount * 2);
+ /*
+ * Write 64 elements into the queue writeCount times
+ */
+ {
+ std::array<int32_t, dataLen> data = {0};
+ for (size_t i = 0; i < writeCount; i++) {
+ ret = this->mQueue->writeBlocking(
+ data.data(), data.size(),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+ static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+ 5000000000 /* timeOutNanos */);
+ ASSERT_TRUE(ret);
+ }
+ }
+ /*
+ * The queue should be totally empty now, so filling it up entirely with one
+ * blocking write should be successful.
+ */
+ {
+ std::array<int32_t, kNumElementsInSyncQueue> data = {0};
+ ret = this->mQueue->writeBlocking(
+ data.data(), data.size(),
+ 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;
+TYPED_TEST(SynchronizedReadWriteClient, BlockingReadWriteZeroMessages) {
+ int32_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),
+ bool ret = this->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));
+ ret = this->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);
}
@@ -414,13 +602,13 @@
* Request mService to write a small number of messages
* to the FMQ. Read and verify data.
*/
-TEST_F(SynchronizedReadWriteClient, SmallInputReaderTest1) {
+TYPED_TEST(SynchronizedReadWriteClient, SmallInputReaderTest1) {
const size_t dataLen = 16;
- ASSERT_LE(dataLen, mNumMessagesMax);
- bool ret = mService->requestWriteFmqSync(dataLen);
+ ASSERT_LE(dataLen, kNumElementsInSyncQueue);
+ bool ret = this->requestWriteFmqSync(dataLen);
ASSERT_TRUE(ret);
- uint16_t readData[dataLen] = {};
- ASSERT_TRUE(mQueue->read(readData, dataLen));
+ int32_t readData[dataLen] = {};
+ ASSERT_TRUE(this->mQueue->read(readData, dataLen));
ASSERT_TRUE(verifyData(readData, dataLen));
}
@@ -429,16 +617,16 @@
* to the FMQ. Read and verify each message using
* beginRead/Commit read APIs.
*/
-TEST_F(SynchronizedReadWriteClient, SmallInputReaderTest2) {
+TYPED_TEST(SynchronizedReadWriteClient, SmallInputReaderTest2) {
const size_t dataLen = 16;
- ASSERT_LE(dataLen, mNumMessagesMax);
- auto ret = mService->requestWriteFmqSync(dataLen);
+ ASSERT_LE(dataLen, kNumElementsInSyncQueue);
+ auto ret = this->requestWriteFmqSync(dataLen);
- ASSERT_TRUE(ret.isOk());
+ // ASSERT_TRUE(ret.isOk());
ASSERT_TRUE(ret);
- MessageQueueSync::MemTransaction tx;
- ASSERT_TRUE(mQueue->beginRead(dataLen, &tx));
+ typename TypeParam::MemTransaction tx;
+ ASSERT_TRUE(this->mQueue->beginRead(dataLen, &tx));
auto first = tx.getFirstRegion();
auto second = tx.getSecondRegion();
@@ -452,46 +640,46 @@
}
}
- ASSERT_TRUE(mQueue->commitRead(dataLen));
+ ASSERT_TRUE(this->mQueue->commitRead(dataLen));
}
/*
* Write a small number of messages to FMQ. Request
- * mService to read and verify that the write was succesful.
+ * mService to read and verify that the write was successful.
*/
-TEST_F(SynchronizedReadWriteClient, SmallInputWriterTest1) {
+TYPED_TEST(SynchronizedReadWriteClient, SmallInputWriterTest1) {
const size_t dataLen = 16;
- ASSERT_LE(dataLen, mNumMessagesMax);
- size_t originalCount = mQueue->availableToWrite();
- uint16_t data[dataLen];
+ ASSERT_LE(dataLen, kNumElementsInSyncQueue);
+ size_t originalCount = this->mQueue->availableToWrite();
+ int32_t data[dataLen];
initData(data, dataLen);
- ASSERT_TRUE(mQueue->write(data, dataLen));
- bool ret = mService->requestReadFmqSync(dataLen);
+ ASSERT_TRUE(this->mQueue->write(data, dataLen));
+ bool ret = this->requestReadFmqSync(dataLen);
ASSERT_TRUE(ret);
- size_t availableCount = mQueue->availableToWrite();
+ size_t availableCount = this->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.
+ * APIs. Request mService to read and verify that the write was successful.
*/
-TEST_F(SynchronizedReadWriteClient, SmallInputWriterTest2) {
+TYPED_TEST(SynchronizedReadWriteClient, SmallInputWriterTest2) {
const size_t dataLen = 16;
- ASSERT_LE(dataLen, mNumMessagesMax);
- size_t originalCount = mQueue->availableToWrite();
- uint16_t data[dataLen];
+ ASSERT_LE(dataLen, kNumElementsInSyncQueue);
+ size_t originalCount = this->mQueue->availableToWrite();
+ int32_t data[dataLen];
initData(data, dataLen);
- MessageQueueSync::MemTransaction tx;
- ASSERT_TRUE(mQueue->beginWrite(dataLen, &tx));
+ typename TypeParam::MemTransaction tx;
+ ASSERT_TRUE(this->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();
+ int32_t* firstBaseAddress = first.getAddress();
+ int32_t* secondBaseAddress = second.getAddress();
for (size_t i = 0; i < dataLen; i++) {
if (i < firstRegionLength) {
@@ -501,24 +689,24 @@
}
}
- ASSERT_TRUE(mQueue->commitWrite(dataLen));
+ ASSERT_TRUE(this->mQueue->commitWrite(dataLen));
- auto ret = mService->requestReadFmqSync(dataLen);
- ASSERT_TRUE(ret.isOk());
+ auto ret = this->requestReadFmqSync(dataLen);
+ // ASSERT_TRUE(ret.isOk());
ASSERT_TRUE(ret);
- size_t availableCount = mQueue->availableToWrite();
+ size_t availableCount = this->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());
+TYPED_TEST(SynchronizedReadWriteClient, ReadWhenEmpty) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
const size_t numMessages = 2;
- ASSERT_LE(numMessages, mNumMessagesMax);
- uint16_t readData[numMessages];
- ASSERT_FALSE(mQueue->read(readData, numMessages));
+ ASSERT_LE(numMessages, kNumElementsInSyncQueue);
+ int32_t readData[numMessages];
+ ASSERT_FALSE(this->mQueue->read(readData, numMessages));
}
/*
@@ -526,17 +714,16 @@
* 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
+ * the attempted write was unsuccessful. 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);
+TYPED_TEST(SynchronizedReadWriteClient, WriteWhenFull) {
+ std::array<int32_t, kNumElementsInSyncQueue> data = {0};
+ initData(data.data(), data.size());
+ ASSERT_TRUE(this->mQueue->write(data.data(), data.size()));
+ ASSERT_EQ(0UL, this->mQueue->availableToWrite());
+ ASSERT_FALSE(this->mQueue->write(&data[0], 1));
+ bool ret = this->requestReadFmqSync(data.size());
ASSERT_TRUE(ret);
}
@@ -545,12 +732,12 @@
* Request mService to write data equal to queue size.
* Read and verify data in mQueue.
*/
-TEST_F(SynchronizedReadWriteClient, LargeInputTest1) {
- bool ret = mService->requestWriteFmqSync(mNumMessagesMax);
+TYPED_TEST(SynchronizedReadWriteClient, LargeInputTest1) {
+ bool ret = this->requestWriteFmqSync(kNumElementsInSyncQueue);
ASSERT_TRUE(ret);
- std::vector<uint16_t> readData(mNumMessagesMax);
- ASSERT_TRUE(mQueue->read(&readData[0], mNumMessagesMax));
- ASSERT_TRUE(verifyData(&readData[0], mNumMessagesMax));
+ std::vector<int32_t> readData(kNumElementsInSyncQueue);
+ ASSERT_TRUE(this->mQueue->read(&readData[0], kNumElementsInSyncQueue));
+ ASSERT_TRUE(verifyData(&readData[0], kNumElementsInSyncQueue));
}
/*
@@ -558,15 +745,15 @@
* 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());
+TYPED_TEST(SynchronizedReadWriteClient, LargeInputTest2) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
const size_t numMessages = 2048;
- ASSERT_GT(numMessages, mNumMessagesMax);
- bool ret = mService->requestWriteFmqSync(numMessages);
+ ASSERT_GT(numMessages, kNumElementsInSyncQueue);
+ bool ret = this->requestWriteFmqSync(numMessages);
ASSERT_FALSE(ret);
- uint16_t readData;
- ASSERT_EQ(0UL, mQueue->availableToRead());
- ASSERT_FALSE(mQueue->read(&readData, 1));
+ int32_t readData;
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
+ ASSERT_FALSE(this->mQueue->read(&readData, 1));
}
/*
@@ -577,14 +764,14 @@
* 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));
+TYPED_TEST(SynchronizedReadWriteClient, LargeInputTest3) {
+ std::array<int32_t, kNumElementsInSyncQueue> data = {0};
+ initData(data.data(), data.size());
+ ASSERT_TRUE(this->mQueue->write(data.data(), data.size()));
+ ASSERT_EQ(0UL, this->mQueue->availableToWrite());
+ ASSERT_FALSE(this->mQueue->write(data.data(), 1));
- bool ret = mService->requestReadFmqSync(mNumMessagesMax);
+ bool ret = this->requestReadFmqSync(data.size());
ASSERT_TRUE(ret);
}
@@ -592,19 +779,19 @@
* 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) {
+TYPED_TEST(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();
+ ASSERT_LE(numMessages, kNumElementsInSyncQueue);
+ size_t availableToRead = this->mQueue->availableToRead();
size_t expectedCount = 0;
ASSERT_EQ(expectedCount, availableToRead);
- bool ret = mService->requestWriteFmqSync(numMessages);
+ bool ret = this->requestWriteFmqSync(numMessages);
ASSERT_TRUE(ret);
- uint16_t readData[numMessages] = {};
+ int32_t readData[numMessages] = {};
for (size_t i = 0; i < chunkNum; i++) {
- ASSERT_TRUE(mQueue->read(readData + i * chunkSize, chunkSize));
+ ASSERT_TRUE(this->mQueue->read(readData + i * chunkSize, chunkSize));
}
ASSERT_TRUE(verifyData(readData, numMessages));
}
@@ -613,18 +800,18 @@
* Write to FMQ in bursts.
* Request mService to read data. Verify the read was successful.
*/
-TEST_F(SynchronizedReadWriteClient, MultipleWrite) {
+TYPED_TEST(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];
+ ASSERT_LE(numMessages, kNumElementsInSyncQueue);
+ int32_t data[numMessages];
initData(&data[0], numMessages);
for (size_t i = 0; i < chunkNum; i++) {
- ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize));
+ ASSERT_TRUE(this->mQueue->write(data + i * chunkSize, chunkSize));
}
- bool ret = mService->requestReadFmqSync(numMessages);
+ bool ret = this->requestReadFmqSync(numMessages);
ASSERT_TRUE(ret);
}
@@ -634,15 +821,15 @@
* 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);
+TYPED_TEST(SynchronizedReadWriteClient, ReadWriteWrapAround) {
+ size_t numMessages = kNumElementsInSyncQueue / 2;
+ std::array<int32_t, kNumElementsInSyncQueue> data = {0};
+ initData(data.data(), data.size());
+ ASSERT_TRUE(this->mQueue->write(&data[0], numMessages));
+ bool ret = this->requestReadFmqSync(numMessages);
ASSERT_TRUE(ret);
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
- ret = mService->requestReadFmqSync(mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(data.data(), data.size()));
+ ret = this->requestReadFmqSync(data.size());
ASSERT_TRUE(ret);
}
@@ -654,74 +841,72 @@
* 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);
+TYPED_TEST(SynchronizedReadWriteClient, ReadWriteWrapAround2) {
+ size_t numMessages = kNumElementsInSyncQueue / 2;
+ std::array<int32_t, kNumElementsInSyncQueue> data = {0};
+ initData(data.data(), data.size());
+ ASSERT_TRUE(this->mQueue->write(&data[0], numMessages));
+ auto ret = this->requestReadFmqSync(numMessages);
- ASSERT_TRUE(ret.isOk());
+ // 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));
+ typename TypeParam::MemTransaction tx;
+ ASSERT_TRUE(this->mQueue->beginWrite(data.size(), &tx));
- ASSERT_EQ(tx.getFirstRegion().getLength() + tx.getSecondRegion().getLength(), mNumMessagesMax);
+ ASSERT_EQ(tx.getFirstRegion().getLength() + tx.getSecondRegion().getLength(), data.size());
- for (size_t i = 0; i < mNumMessagesMax; i++) {
- uint16_t* ptr = tx.getSlot(i);
+ for (size_t i = 0; i < data.size(); i++) {
+ int32_t* ptr = tx.getSlot(i);
*ptr = data[i];
}
- ASSERT_TRUE(mQueue->commitWrite(mNumMessagesMax));
+ ASSERT_TRUE(this->mQueue->commitWrite(data.size()));
- ret = mService->requestReadFmqSync(mNumMessagesMax);
-
- ASSERT_TRUE(ret.isOk());
+ ret = this->requestReadFmqSync(data.size());
ASSERT_TRUE(ret);
}
/*
- * Request mService to write a small number of messages
+ * Request this->mService to write a small number of messages
* to the FMQ. Read and verify data.
*/
-TEST_F(UnsynchronizedWriteClient, SmallInputReaderTest1) {
+TYPED_TEST(UnsynchronizedWriteClient, SmallInputReaderTest1) {
const size_t dataLen = 16;
- ASSERT_LE(dataLen, mNumMessagesMax);
- bool ret = mService->requestWriteFmqUnsync(dataLen);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
+ bool ret = this->requestWriteFmqUnsync(dataLen, this->mService);
ASSERT_TRUE(ret);
- uint16_t readData[dataLen] = {};
- ASSERT_TRUE(mQueue->read(readData, dataLen));
+ int32_t readData[dataLen] = {};
+ ASSERT_TRUE(this->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.
+ * this->mService to read and verify that the write was successful.
*/
-TEST_F(UnsynchronizedWriteClient, SmallInputWriterTest1) {
+TYPED_TEST(UnsynchronizedWriteClient, SmallInputWriterTest1) {
const size_t dataLen = 16;
- ASSERT_LE(dataLen, mNumMessagesMax);
- uint16_t data[dataLen];
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
+ int32_t data[dataLen];
initData(data, dataLen);
- ASSERT_TRUE(mQueue->write(data, dataLen));
- bool ret = mService->requestReadFmqUnsync(dataLen);
+ ASSERT_TRUE(this->mQueue->write(data, dataLen));
+ bool ret = this->requestReadFmqUnsync(dataLen, this->mService);
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());
+TYPED_TEST(UnsynchronizedWriteClient, ReadWhenEmpty) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
const size_t numMessages = 2;
- ASSERT_LE(numMessages, mNumMessagesMax);
- uint16_t readData[numMessages];
- ASSERT_FALSE(mQueue->read(readData, numMessages));
+ ASSERT_LE(numMessages, this->mNumMessagesMax);
+ int32_t readData[numMessages];
+ ASSERT_FALSE(this->mQueue->read(readData, numMessages));
}
/*
@@ -729,187 +914,210 @@
* 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.
+ * the attempted write was successful. Request this->mService
+ * to read the messages in the FMQ and verify that it is unsuccessful.
*/
-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);
+TYPED_TEST(UnsynchronizedWriteClient, WriteWhenFull) {
+ std::vector<int32_t> data(this->mNumMessagesMax);
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ ASSERT_EQ(0UL, this->mQueue->availableToWrite());
+ ASSERT_TRUE(this->mQueue->write(&data[0], 1));
+ bool ret = this->requestReadFmqUnsync(this->mNumMessagesMax, this->mService);
ASSERT_FALSE(ret);
}
/*
* Verify FMQ is empty.
- * Request mService to write data equal to queue size.
- * Read and verify data in mQueue.
+ * Request this->mService to write data equal to queue size.
+ * Read and verify data in this->mQueue.
*/
-TEST_F(UnsynchronizedWriteClient, LargeInputTest1) {
- bool ret = mService->requestWriteFmqUnsync(mNumMessagesMax);
+TYPED_TEST(UnsynchronizedWriteClient, LargeInputTest1) {
+ bool ret = this->requestWriteFmqUnsync(this->mNumMessagesMax, this->mService);
ASSERT_TRUE(ret);
- std::vector<uint16_t> data(mNumMessagesMax);
- ASSERT_TRUE(mQueue->read(&data[0], mNumMessagesMax));
- ASSERT_TRUE(verifyData(&data[0], mNumMessagesMax));
+ std::vector<int32_t> data(this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->read(&data[0], this->mNumMessagesMax));
+ ASSERT_TRUE(verifyData(&data[0], this->mNumMessagesMax));
}
/*
- * Request mService to write more than maximum number of messages to the FMQ.
+ * Request this->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);
+TYPED_TEST(UnsynchronizedWriteClient, LargeInputTest2) {
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
+ const size_t numMessages = this->mNumMessagesMax + 1;
+ bool ret = this->requestWriteFmqUnsync(numMessages, this->mService);
ASSERT_FALSE(ret);
- uint16_t readData;
- ASSERT_EQ(0UL, mQueue->availableToRead());
- ASSERT_FALSE(mQueue->read(&readData, 1));
+ int32_t readData;
+ ASSERT_EQ(0UL, this->mQueue->availableToRead());
+ ASSERT_FALSE(this->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
+ * is equal to this->mNumMessagesMax.
+ * Verify that another write attempt is successful.
+ * Request this->mService to read. Verify that read is unsuccessful.
+ * Perform another write and verify that the read is successful
* 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));
+TYPED_TEST(UnsynchronizedWriteClient, LargeInputTest3) {
+ std::vector<int32_t> data(this->mNumMessagesMax);
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ ASSERT_EQ(0UL, this->mQueue->availableToWrite());
+ ASSERT_TRUE(this->mQueue->write(&data[0], 1));
- bool ret = mService->requestReadFmqUnsync(mNumMessagesMax);
+ bool ret = this->requestReadFmqUnsync(this->mNumMessagesMax, this->mService);
ASSERT_FALSE(ret);
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
- ret = mService->requestReadFmqUnsync(mNumMessagesMax);
+ ret = this->requestReadFmqUnsync(this->mNumMessagesMax, this->mService);
ASSERT_TRUE(ret);
}
/*
- * Confirm that the FMQ is empty. Request mService to write to FMQ.
+ * Confirm that the FMQ is empty. Request this->mService to write to FMQ.
* Do multiple reads to empty FMQ and verify data.
*/
-TEST_F(UnsynchronizedWriteClient, MultipleRead) {
+TYPED_TEST(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();
+ ASSERT_LE(numMessages, this->mNumMessagesMax);
+ size_t availableToRead = this->mQueue->availableToRead();
size_t expectedCount = 0;
ASSERT_EQ(expectedCount, availableToRead);
- bool ret = mService->requestWriteFmqUnsync(numMessages);
+ bool ret = this->requestWriteFmqUnsync(numMessages, this->mService);
ASSERT_TRUE(ret);
- uint16_t readData[numMessages] = {};
+ int32_t readData[numMessages] = {};
for (size_t i = 0; i < chunkNum; i++) {
- ASSERT_TRUE(mQueue->read(readData + i * chunkSize, chunkSize));
+ ASSERT_TRUE(this->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.
+ * Request this->mService to read data, verify that it was successful.
*/
-TEST_F(UnsynchronizedWriteClient, MultipleWrite) {
+TYPED_TEST(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];
+ ASSERT_LE(numMessages, this->mNumMessagesMax);
+ int32_t data[numMessages];
initData(data, numMessages);
for (size_t i = 0; i < chunkNum; i++) {
- ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize));
+ ASSERT_TRUE(this->mQueue->write(data + i * chunkSize, chunkSize));
}
- bool ret = mService->requestReadFmqUnsync(numMessages);
+ bool ret = this->requestReadFmqUnsync(numMessages, this->mService);
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.
+ * Request this->mService to read back the same.
+ * Write this->mNumMessagesMax messages into the queue. This should cause a
+ * wrap around. Request this->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);
+TYPED_TEST(UnsynchronizedWriteClient, ReadWriteWrapAround) {
+ size_t numMessages = this->mNumMessagesMax / 2;
+ std::vector<int32_t> data(this->mNumMessagesMax);
+ initData(&data[0], this->mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], numMessages));
+ bool ret = this->requestReadFmqUnsync(numMessages, this->mService);
ASSERT_TRUE(ret);
- ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
- ret = mService->requestReadFmqUnsync(mNumMessagesMax);
+ ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+ ret = this->requestReadFmqUnsync(this->mNumMessagesMax, this->mService);
ASSERT_TRUE(ret);
}
/*
- * Request mService to write a small number of messages
+ * Request this->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());
+TYPED_TEST(UnsynchronizedWriteClient, SmallInputMultipleReaderTest) {
+ TypeParam* mQueue2 = this->newQueue();
+
+ ASSERT_NE(nullptr, mQueue2);
const size_t dataLen = 16;
- ASSERT_LE(dataLen, mNumMessagesMax);
+ ASSERT_LE(dataLen, this->mNumMessagesMax);
- bool ret = mService->requestWriteFmqUnsync(dataLen);
+ bool ret = this->requestWriteFmqUnsync(dataLen, this->mService);
ASSERT_TRUE(ret);
pid_t pid;
if ((pid = fork()) == 0) {
/* child process */
- uint16_t readData[dataLen] = {};
+ int32_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));
+ int32_t readData[dataLen] = {};
+ ASSERT_TRUE(this->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.
+ * Request this->mService to write into the FMQ until it is full.
+ * Request this->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());
+TYPED_TEST(UnsynchronizedWriteClient, OverflowNotificationTest) {
+ TypeParam* mQueue2 = this->newQueue();
+ ASSERT_NE(nullptr, mQueue2);
- bool ret = mService->requestWriteFmqUnsync(mNumMessagesMax);
+ bool ret = this->requestWriteFmqUnsync(this->mNumMessagesMax, this->mService);
ASSERT_TRUE(ret);
- ret = mService->requestWriteFmqUnsync(1);
+ ret = this->requestWriteFmqUnsync(1, this->mService);
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));
+ std::vector<int32_t> readData(this->mNumMessagesMax);
+ ASSERT_FALSE(mQueue2->read(&readData[0], this->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));
+ std::vector<int32_t> readData(this->mNumMessagesMax);
+ ASSERT_FALSE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
}
}
+
+/*
+ * Make sure a valid queue can be created with different supported types.
+ * All fundamental or native types should work. An AIDL parcelable that is
+ * annotated with @FixedSize is supported. A parcelable without it, will cause
+ * a compilation error.
+ */
+typedef ::testing::Types<FixedParcelable, EventFlagBits, bool, int8_t, char, char16_t, int32_t,
+ int64_t, float, double>
+ AidlTypeCheckTypes;
+
+template <typename T>
+class AidlTypeChecks : public ::testing::Test {};
+
+TYPED_TEST_CASE(AidlTypeChecks, AidlTypeCheckTypes);
+
+TYPED_TEST(AidlTypeChecks, FixedSizeParcelableTest) {
+ android::AidlMessageQueue<TypeParam, UnsynchronizedWrite> queue =
+ android::AidlMessageQueue<TypeParam, UnsynchronizedWrite>(64);
+ ASSERT_TRUE(queue.isValid());
+ // Make sure we can do a simple write/read of any value.
+ TypeParam writeData[1];
+ TypeParam readData[1];
+ EXPECT_TRUE(queue.write(writeData, 1));
+ EXPECT_TRUE(queue.read(readData, 1));
+}