Merge RQ3A.210705.001 to aosp-master - DO NOT MERGE

Merged-In: Ifa7a5bf6e485bbadcfcc6fbd6f965d2f82777cf7
Merged-In: I5d8686bc749e9a80e1e7da00e9fba4813c6fbb9f
Merged-In: I5d8686bc749e9a80e1e7da00e9fba4813c6fbb9f
Change-Id: Id48615c78e63d94bc9692da03708a7722ee66432
diff --git a/Android.bp b/Android.bp
index e2cb961..5889a9c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_library {
     name: "libfmq",
     shared_libs: [
@@ -31,6 +35,12 @@
     ],
     export_include_dirs: ["include"],
     local_include_dirs: ["include"],
+    header_libs: [
+        "libfmq-base",
+    ],
+    export_header_lib_headers: [
+        "libfmq-base",
+    ],
     srcs: [
         "EventFlag.cpp",
         "FmqInternal.cpp",
@@ -40,6 +50,7 @@
         "-Werror",
     ],
     vendor_available: true,
+    product_available: true,
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
     vndk: {
@@ -47,4 +58,21 @@
     },
     double_loadable: true,
     min_sdk_version: "29",
+    host_supported: true,
+}
+
+// Header only lib to share type between HIDL and AIDL MQDescriptor
+cc_library_headers {
+    name: "libfmq-base",
+    host_supported: true,
+    vendor_available: true,
+    product_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/EventFlag.cpp b/EventFlag.cpp
index cb101bd..96f9519 100644
--- a/EventFlag.cpp
+++ b/EventFlag.cpp
@@ -22,6 +22,7 @@
 #include <sys/syscall.h>
 #include <unistd.h>
 
+#include <limits>
 #include <new>
 
 #include <fmq/EventFlag.h>
@@ -120,9 +121,9 @@
      * No need to call FUTEX_WAKE_BITSET if there were deferred wakes
      * already available for all set bits from bitmask.
      */
+    constexpr size_t kIntMax = std::numeric_limits<int>::max();
     if ((~old & bitmask) != 0) {
-        int ret = syscall(__NR_futex, mEfWordPtr, FUTEX_WAKE_BITSET,
-                          INT_MAX, NULL, NULL, bitmask);
+        int ret = syscall(__NR_futex, mEfWordPtr, FUTEX_WAKE_BITSET, kIntMax, NULL, NULL, bitmask);
         if (ret == -1) {
             status = -errno;
             ALOGE("Error in event flag wake attempt: %s\n", strerror(errno));
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..dfa7071
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "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/benchmarks/Android.mk b/benchmarks/Android.mk
index d82c0a3..3cae117 100644
--- a/benchmarks/Android.mk
+++ b/benchmarks/Android.mk
@@ -31,10 +31,11 @@
 LOCAL_REQUIRED_MODULES := android.hardware.tests.msgq@1.0-impl
 
 ifneq ($(TARGET_2ND_ARCH),)
-LOCAL_REQUIRED_MODULES += android.hardware.tests.msgq@1.0-impl$(TARGET_2ND_ARCH_MODULE_SUFFIX)
+LOCAL_REQUIRED_MODULES += android.hardware.tests.msgq@1.0-impl:32
 endif
 
 LOCAL_SHARED_LIBRARIES += android.hardware.tests.msgq@1.0 libfmq
 LOCAL_MODULE := mq_benchmark_client
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
 include $(BUILD_NATIVE_TEST)
-
diff --git a/include/fmq/AidlMQDescriptorShim.h b/include/fmq/AidlMQDescriptorShim.h
new file mode 100644
index 0000000..e3d3cb9
--- /dev/null
+++ b/include/fmq/AidlMQDescriptorShim.h
@@ -0,0 +1,262 @@
+/*
+ * 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/fmq/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::fmq::GrantorDescriptor;
+using aidl::android::hardware::common::fmq::MQDescriptor;
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::hardware::common::fmq::UnsynchronizedWrite;
+using android::hardware::MQFlavor;
+
+template <typename T, MQFlavor flavor>
+struct AidlMQDescriptorShim {
+    // Takes ownership of handle
+    AidlMQDescriptorShim(const std::vector<android::hardware::GrantorDescriptor>& grantors,
+                         native_handle_t* nHandle, size_t size);
+
+    // 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 ||
+            desc.grantors[i].fdIndex < 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 = desc.grantors[i].fdIndex;
+        mGrantors[i].offset = desc.grantors[i].offset;
+        mGrantors[i].extent = desc.grantors[i].extent;
+    }
+
+    mHandle = native_handle_create(desc.handle.fds.size() /* num fds */,
+                                   desc.handle.ints.size() /* num ints */);
+    if (mHandle == nullptr) {
+        hardware::details::logError("Null native_handle_t");
+        return;
+    }
+    int data_index = 0;
+    for (const auto& fd : desc.handle.fds) {
+        mHandle->data[data_index] = dup(fd.get());
+        data_index++;
+    }
+    for (const auto& data_int : desc.handle.ints) {
+        mHandle->data[data_index] = data_int;
+        data_index++;
+    }
+}
+
+template <typename T, MQFlavor flavor>
+AidlMQDescriptorShim<T, flavor>::AidlMQDescriptorShim(
+        const std::vector<android::hardware::GrantorDescriptor>& grantors, native_handle_t* nhandle,
+        size_t size)
+    : mGrantors(grantors),
+      mHandle(nhandle),
+      mQuantum(static_cast<uint32_t>(size)),
+      mFlags(flavor) {}
+
+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)
+    : mHandle(nHandle), mQuantum(messageSize), mFlags(flavor) {
+    /*
+     * 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;
+    }
+
+    /*
+     * 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..0536d6a
--- /dev/null
+++ b/include/fmq/AidlMessageQueue.h
@@ -0,0 +1,157 @@
+/*
+ * 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/fmq/MQDescriptor.h>
+#include <aidl/android/hardware/common/fmq/SynchronizedReadWrite.h>
+#include <aidl/android/hardware/common/fmq/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::fmq::MQDescriptor;
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::hardware::common::fmq::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 {};
+
+#define STATIC_AIDL_TYPE_CHECK(T)                                                                  \
+    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).");
+
+template <typename T, typename U>
+struct AidlMessageQueue final
+    : public MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value> {
+    STATIC_AIDL_TYPE_CHECK(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.
+     * @param bufferFd User-supplied file descriptor to map the memory for the ringbuffer
+     * By default, bufferFd=-1 means library will allocate ashmem region for ringbuffer.
+     * MessageQueue takes ownership of the file descriptor.
+     * @param bufferSize size of buffer in bytes that bufferFd represents. This
+     * size must be larger than or equal to (numElementsInQueue * sizeof(T)).
+     * Otherwise, operations will cause out-of-bounds memory access.
+     */
+    AidlMessageQueue(size_t numElementsInQueue, bool configureEventFlagWord,
+                     android::base::unique_fd bufferFd, size_t bufferSize);
+
+    AidlMessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false)
+        : AidlMessageQueue(numElementsInQueue, configureEventFlagWord, android::base::unique_fd(),
+                           0) {}
+
+    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,
+                                         android::base::unique_fd bufferFd, size_t bufferSize)
+    : MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value>(
+              numElementsInQueue, configureEventFlagWord, std::move(bufferFd), bufferSize) {}
+
+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::fmq::GrantorDescriptor> grantors;
+        for (const auto& grantor : shim->grantors()) {
+            grantors.push_back(aidl::android::hardware::common::fmq::GrantorDescriptor{
+                    .fdIndex = static_cast<int32_t>(grantor.fdIndex),
+                    .offset = static_cast<int32_t>(grantor.offset),
+                    .extent = static_cast<int64_t>(grantor.extent)});
+        }
+        std::vector<ndk::ScopedFileDescriptor> fds;
+        std::vector<int> ints;
+        int data_index = 0;
+        for (; data_index < shim->handle()->numFds; data_index++) {
+            fds.push_back(ndk::ScopedFileDescriptor(dup(shim->handle()->data[data_index])));
+        }
+        for (; data_index < shim->handle()->numFds + shim->handle()->numInts; data_index++) {
+            ints.push_back(shim->handle()->data[data_index]);
+        }
+        return MQDescriptor<T, U>{
+                .quantum = static_cast<int32_t>(shim->getQuantum()),
+                .grantors = grantors,
+                .flags = static_cast<int32_t>(shim->getFlags()),
+                .handle = {std::move(fds), std::move(ints)},
+        };
+    } else {
+        return MQDescriptor<T, U>();
+    }
+}
+
+}  // namespace android
diff --git a/include/fmq/ConvertMQDescriptors.h b/include/fmq/ConvertMQDescriptors.h
new file mode 100644
index 0000000..6534ebe
--- /dev/null
+++ b/include/fmq/ConvertMQDescriptors.h
@@ -0,0 +1,121 @@
+/*
+ * 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/fmq/MQDescriptor.h>
+#include <aidl/android/hardware/common/fmq/SynchronizedReadWrite.h>
+#include <aidl/android/hardware/common/fmq/UnsynchronizedWrite.h>
+#include <cutils/native_handle.h>
+#include <fmq/AidlMessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+using aidl::android::hardware::common::fmq::GrantorDescriptor;
+using aidl::android::hardware::common::fmq::MQDescriptor;
+using hardware::details::logError;
+
+/**
+ * This function converts a HIDL hardware::MQDescriptor to an AIDL
+ * aidl::android::hardware::common::fmq::MQDescriptor for Fast
+ * Message Queue.
+ *
+ * This is considered UNSAFE because it is not checking the offsets of each of the
+ * paylod types' fields. In order for these objects to be passed through shared memory safely,
+ * they must have the exact same memory layout. Same size, same alignment, and same
+ * offsets for each field. Make sure this is the case before using this!
+ * Same sized C++ fundamental types and enums with same sized backing types are OK.
+ * Ex 1: uint64_t is compatible with int64_t
+ * Ex 2:
+ * @FixedSize parcelable Foo {
+ *   int a;
+ *   long b;
+ *   MyEnum c; // backed by int32_t
+ * }
+ * struct Bar {
+ *   int a;
+ *   long b;
+ *   YourEnum c; // backed by uint32_t
+ * }
+ * The two types above are compatible with each other as long as the fields have
+ * the same offsets.
+ *
+ * Template params:
+ *    HidlPayload - the type of the payload used for the HIDL MessageQueue
+ *    AidlPayload - the type of the payload used for the AIDL AidlMessageQueue
+ *    AidlFlavor - the flavor of the queues. Either SynchronizedReadWrite,
+ *                 or UnsynchronizedWrite
+ * Function params:
+ *    hidlDesc - reference to the HIDL MQDescriptor to be copied from
+ *    aidlDesc - pointer to the AIDL MQDescriptor to be copied to
+ */
+template <typename HidlPayload, typename AidlPayload, typename AidlFlavor>
+bool unsafeHidlToAidlMQDescriptor(
+        const hardware::MQDescriptor<HidlPayload, FlavorTypeToValue<AidlFlavor>::value>& hidlDesc,
+        MQDescriptor<AidlPayload, AidlFlavor>* aidlDesc) {
+    static_assert(sizeof(HidlPayload) == sizeof(AidlPayload),
+                  "Payload types are definitely incompatible");
+    static_assert(alignof(HidlPayload) == alignof(AidlPayload),
+                  "Payload types are definitely incompatible");
+    STATIC_AIDL_TYPE_CHECK(AidlPayload);
+    if (!aidlDesc->grantors.empty()) {
+        logError("Destination AIDL MQDescriptor should be empty, but already contains grantors.");
+        return false;
+    }
+
+    for (const auto& grantor : hidlDesc.grantors()) {
+        if (static_cast<int32_t>(grantor.offset) < 0 || static_cast<int64_t>(grantor.extent) < 0 ||
+            static_cast<int64_t>(grantor.fdIndex) < 0) {
+            logError(
+                    "Unsafe static_cast of grantor fields. Either the hardware::MQDescriptor is "
+                    "invalid, or the MessageQueue is too large to be described by AIDL.");
+            return false;
+        }
+        aidlDesc->grantors.push_back(
+                GrantorDescriptor{.fdIndex = static_cast<int32_t>(grantor.fdIndex),
+                                  .offset = static_cast<int32_t>(grantor.offset),
+                                  .extent = static_cast<int64_t>(grantor.extent)});
+    }
+
+    std::vector<ndk::ScopedFileDescriptor> fds;
+    std::vector<int> ints;
+    int data_index = 0;
+    for (; data_index < hidlDesc.handle()->numFds; data_index++) {
+        fds.push_back(ndk::ScopedFileDescriptor(dup(hidlDesc.handle()->data[data_index])));
+    }
+    for (; data_index < hidlDesc.handle()->numFds + hidlDesc.handle()->numInts; data_index++) {
+        ints.push_back(hidlDesc.handle()->data[data_index]);
+    }
+
+    aidlDesc->handle = {std::move(fds), std::move(ints)};
+    if (static_cast<int32_t>(hidlDesc.getQuantum()) < 0 ||
+        static_cast<int32_t>(hidlDesc.getFlags()) < 0) {
+        logError(
+                "Unsafe static_cast of quantum or flags. Either the hardware::MQDescriptor is "
+                "invalid, or the MessageQueue is too large to be described by AIDL.");
+        return false;
+    }
+    if (hidlDesc.getFlags() != FlavorTypeToValue<AidlFlavor>::value) {
+        logError("hardware::MQDescriptor hidlDesc is invalid. Unexpected getFlags() value: " +
+                 std::to_string(hidlDesc.getFlags()) +
+                 ". Expected value: " + std::to_string(FlavorTypeToValue<AidlFlavor>::value));
+        return false;
+    }
+    aidlDesc->quantum = static_cast<int32_t>(hidlDesc.getQuantum());
+    aidlDesc->flags = static_cast<int32_t>(hidlDesc.getFlags());
+    return true;
+}
+
+}  // namespace android
diff --git a/include/fmq/MessageQueue.h b/include/fmq/MessageQueue.h
index 97fee0e..8ff0739 100644
--- a/include/fmq/MessageQueue.h
+++ b/include/fmq/MessageQueue.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,38 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef HIDL_MQ_H
-#define HIDL_MQ_H
+#pragma once
 
-#include <atomic>
-#include <cutils/ashmem.h>
-#include <fmq/EventFlag.h>
 #include <hidl/MQDescriptor.h>
-#include <new>
-#include <sys/mman.h>
-#include <utils/Log.h>
-#include <utils/SystemClock.h>
+#include "MessageQueueBase.h"
 
 namespace android {
 namespace hardware {
 
-namespace details {
-void check(bool exp);
-void logError(const std::string &message);
-}  // namespace details
-
 template <typename T, MQFlavor flavor>
-struct MessageQueue {
+struct MessageQueue final : public MessageQueueBase<MQDescriptor, T, flavor> {
     typedef MQDescriptor<T, flavor> Descriptor;
-
-    /**
-     * @param Desc MQDescriptor describing the FMQ.
-     * @param resetPointers bool indicating whether the read/write pointers
-     * should be reset or not.
-     */
-    MessageQueue(const Descriptor& Desc, bool resetPointers = true);
-
-    ~MessageQueue();
+    MessageQueue(const Descriptor& Desc, bool resetPointers = true)
+        : MessageQueueBase<MQDescriptor, T, flavor>(Desc, resetPointers) {}
+    ~MessageQueue() = default;
 
     /**
      * This constructor uses Ashmem shared memory to create an FMQ
@@ -54,1177 +36,27 @@
      * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
      * @param configureEventFlagWord Boolean that specifies if memory should
      * also be allocated and mapped for an EventFlag word.
+     * @param bufferFd User-supplied file descriptor to map the memory for the ringbuffer
+     * By default, bufferFd=-1 means library will allocate ashmem region for ringbuffer.
+     * MessageQueue takes ownership of the file descriptor.
+     * @param bufferSize size of buffer in bytes that bufferFd represents. This
+     * size must be larger than or equal to (numElementsInQueue * sizeof(T)).
+     * Otherwise, operations will cause out-of-bounds memory access.
      */
-    MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false);
+    MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord,
+                 android::base::unique_fd bufferFd, size_t bufferSize)
+        : MessageQueueBase<MQDescriptor, T, flavor>(numElementsInQueue, configureEventFlagWord,
+                                                    std::move(bufferFd), bufferSize) {}
 
-    /**
-     * @return Number of items of type T that can be written into the FMQ
-     * without a read.
-     */
-    size_t availableToWrite() const;
+    MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false)
+        : MessageQueueBase<MQDescriptor, T, flavor>(numElementsInQueue, configureEventFlagWord,
+                                                    android::base::unique_fd(), 0) {}
 
-    /**
-     * @return Number of items of type T that are waiting to be read from the
-     * FMQ.
-     */
-    size_t availableToRead() const;
-
-    /**
-     * Returns the size of type T in bytes.
-     *
-     * @param Size of T.
-     */
-    size_t getQuantumSize() const;
-
-    /**
-     * Returns the size of the FMQ in terms of the size of type T.
-     *
-     * @return Number of items of type T that will fit in the FMQ.
-     */
-    size_t getQuantumCount() const;
-
-    /**
-     * @return Whether the FMQ is configured correctly.
-     */
-    bool isValid() const;
-
-    /**
-     * Non-blocking write to FMQ.
-     *
-     * @param data Pointer to the object of type T to be written into the FMQ.
-     *
-     * @return Whether the write was successful.
-     */
-    bool write(const T* data);
-
-    /**
-     * Non-blocking read from FMQ.
-     *
-     * @param data Pointer to the memory where the object read from the FMQ is
-     * copied to.
-     *
-     * @return Whether the read was successful.
-     */
-    bool read(T* data);
-
-    /**
-     * Write some data into the FMQ without blocking.
-     *
-     * @param data Pointer to the array of items of type T.
-     * @param count Number of items in array.
-     *
-     * @return Whether the write was successful.
-     */
-    __attribute__((noinline)) bool write(const T* data, size_t count);
-
-    /**
-     * Perform a blocking write of 'count' items into the FMQ using EventFlags.
-     * Does not support partial writes.
-     *
-     * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
-     * associated with the FMQ and it is used in that case.
-     *
-     * The application code must ensure that 'evFlag' used by the
-     * reader(s)/writer is based upon the same EventFlag word.
-     *
-     * The method will return false without blocking if any of the following
-     * conditions are true:
-     * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
-     * - If the 'readNotification' bit mask is zero.
-     * - If 'count' is greater than the FMQ size.
-     *
-     * If the there is insufficient space available to write into it, the
-     * EventFlag bit mask 'readNotification' is is waited upon.
-     *
-     * This method should only be used with a MessageQueue of the flavor
-     * 'kSynchronizedReadWrite'.
-     *
-     * Upon a successful write, wake is called on 'writeNotification' (if
-     * non-zero).
-     *
-     * @param data Pointer to the array of items of type T.
-     * @param count Number of items in array.
-     * @param readNotification The EventFlag bit mask to wait on if there is not
-     * enough space in FMQ to write 'count' items.
-     * @param writeNotification The EventFlag bit mask to call wake on
-     * a successful write. No wake is called if 'writeNotification' is zero.
-     * @param timeOutNanos Number of nanoseconds after which the blocking
-     * write attempt is aborted.
-     * @param evFlag The EventFlag object to be used for blocking. If nullptr,
-     * it is checked whether the FMQ owns an EventFlag object and that is used
-     * for blocking instead.
-     *
-     * @return Whether the write was successful.
-     */
-    bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
-                       uint32_t writeNotification, int64_t timeOutNanos = 0,
-                       android::hardware::EventFlag* evFlag = nullptr);
-
-    bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
-
-    /**
-     * Read some data from the FMQ without blocking.
-     *
-     * @param data Pointer to the array to which read data is to be written.
-     * @param count Number of items to be read.
-     *
-     * @return Whether the read was successful.
-     */
-    __attribute__((noinline)) bool read(T* data, size_t count);
-
-    /**
-     * Perform a blocking read operation of 'count' items from the FMQ. Does not
-     * perform a partial read.
-     *
-     * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
-     * associated with the FMQ and it is used in that case.
-     *
-     * The application code must ensure that 'evFlag' used by the
-     * reader(s)/writer is based upon the same EventFlag word.
-     *
-     * The method will return false without blocking if any of the following
-     * conditions are true:
-     * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
-     * -If the 'writeNotification' bit mask is zero.
-     * -If 'count' is greater than the FMQ size.
-     *
-     * This method should only be used with a MessageQueue of the flavor
-     * 'kSynchronizedReadWrite'.
-
-     * If FMQ does not contain 'count' items, the eventFlag bit mask
-     * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
-     * wake is called on 'readNotification' (if non-zero).
-     *
-     * @param data Pointer to the array to which read data is to be written.
-     * @param count Number of items to be read.
-     * @param readNotification The EventFlag bit mask to call wake on after
-     * a successful read. No wake is called if 'readNotification' is zero.
-     * @param writeNotification The EventFlag bit mask to call a wait on
-     * if there is insufficient data in the FMQ to be read.
-     * @param timeOutNanos Number of nanoseconds after which the blocking
-     * read attempt is aborted.
-     * @param evFlag The EventFlag object to be used for blocking.
-     *
-     * @return Whether the read was successful.
-     */
-    bool readBlocking(T* data, size_t count, uint32_t readNotification,
-                      uint32_t writeNotification, int64_t timeOutNanos = 0,
-                      android::hardware::EventFlag* evFlag = nullptr);
-
-    bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
-
-    /**
-     * Get a pointer to the MQDescriptor object that describes this FMQ.
-     *
-     * @return Pointer to the MQDescriptor associated with the FMQ.
-     */
-    const Descriptor* getDesc() const { return mDesc.get(); }
-
-    /**
-     * Get a pointer to the EventFlag word if there is one associated with this FMQ.
-     *
-     * @return Pointer to an EventFlag word, will return nullptr if not
-     * configured. This method does not transfer ownership. The EventFlag
-     * word will be unmapped by the MessageQueue destructor.
-     */
-    std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
-
-    /**
-     * Describes a memory region in the FMQ.
-     */
-    struct MemRegion {
-        MemRegion() : MemRegion(nullptr, 0) {}
-
-        MemRegion(T* base, size_t size) : address(base), length(size) {}
-
-        MemRegion& operator=(const MemRegion &other) {
-            address = other.address;
-            length = other.length;
-            return *this;
-        }
-
-        /**
-         * Gets a pointer to the base address of the MemRegion.
-         */
-        inline T* getAddress() const { return address; }
-
-        /**
-         * Gets the length of the MemRegion. This would equal to the number
-         * of items of type T that can be read from/written into the MemRegion.
-         */
-        inline size_t getLength() const { return length; }
-
-        /**
-         * Gets the length of the MemRegion in bytes.
-         */
-        inline size_t getLengthInBytes() const { return length * sizeof(T); }
-
-    private:
-        /* Base address */
-        T* address;
-
-        /*
-         * Number of items of type T that can be written to/read from the base
-         * address.
-         */
-        size_t length;
-    };
-
-    /**
-     * Describes the memory regions to be used for a read or write.
-     * The struct contains two MemRegion objects since the FMQ is a ring
-     * buffer and a read or write operation can wrap around. A single message
-     * of type T will never be broken between the two MemRegions.
-     */
-    struct MemTransaction {
-        MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
-
-        MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond) :
-            first(regionFirst), second(regionSecond) {}
-
-        MemTransaction& operator=(const MemTransaction &other) {
-            first = other.first;
-            second = other.second;
-            return *this;
-        }
-
-        /**
-         * Helper method to calculate the address for a particular index for
-         * the MemTransaction object.
-         *
-         * @param idx Index of the slot to be read/written. If the
-         * MemTransaction object is representing the memory region to read/write
-         * N items of type T, the valid range of idx is between 0 and N-1.
-         *
-         * @return Pointer to the slot idx. Will be nullptr for an invalid idx.
-         */
-        T* getSlot(size_t idx);
-
-        /**
-         * Helper method to write 'nMessages' items of type T into the memory
-         * regions described by the object starting from 'startIdx'. This method
-         * uses memcpy() and is not to meant to be used for a zero copy operation.
-         * Partial writes are not supported.
-         *
-         * @param data Pointer to the source buffer.
-         * @param nMessages Number of items of type T.
-         * @param startIdx The slot number to begin the write from. If the
-         * MemTransaction object is representing the memory region to read/write
-         * N items of type T, the valid range of startIdx is between 0 and N-1;
-         *
-         * @return Whether the write operation of size 'nMessages' succeeded.
-         */
-        bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
-
-        /*
-         * Helper method to read 'nMessages' items of type T from the memory
-         * regions described by the object starting from 'startIdx'. This method uses
-         * memcpy() and is not meant to be used for a zero copy operation. Partial reads
-         * are not supported.
-         *
-         * @param data Pointer to the destination buffer.
-         * @param nMessages Number of items of type T.
-         * @param startIdx The slot number to begin the read from. If the
-         * MemTransaction object is representing the memory region to read/write
-         * N items of type T, the valid range of startIdx is between 0 and N-1.
-         *
-         * @return Whether the read operation of size 'nMessages' succeeded.
-         */
-        bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
-
-        /**
-         * Returns a const reference to the first MemRegion in the
-         * MemTransaction object.
-         */
-        inline const MemRegion& getFirstRegion() const { return first; }
-
-        /**
-         * Returns a const reference to the second MemRegion in the
-         * MemTransaction object.
-         */
-        inline const MemRegion& getSecondRegion() const { return second; }
-
-    private:
-        /*
-         * Given a start index and the number of messages to be
-         * read/written, this helper method calculates the
-         * number of messages that should should be written to both the first
-         * and second MemRegions and the base addresses to be used for
-         * the read/write operation.
-         *
-         * Returns false if the 'startIdx' and 'nMessages' is
-         * invalid for the MemTransaction object.
-         */
-        bool inline getMemRegionInfo(size_t idx,
-                                     size_t nMessages,
-                                     size_t& firstCount,
-                                     size_t& secondCount,
-                                     T** firstBaseAddress,
-                                     T** secondBaseAddress);
-        MemRegion first;
-        MemRegion second;
-    };
-
-    /**
-     * Get a MemTransaction object to write 'nMessages' items of type T.
-     * Once the write is performed using the information from MemTransaction,
-     * the write operation is to be committed using a call to commitWrite().
-     *
-     * @param nMessages Number of messages of type T.
-     * @param Pointer to MemTransaction struct that describes memory to write 'nMessages'
-     * items of type T. If a write of size 'nMessages' is not possible, the base
-     * addresses in the MemTransaction object would be set to nullptr.
-     *
-     * @return Whether it is possible to write 'nMessages' items of type T
-     * into the FMQ.
-     */
-    __attribute__((always_inline)) bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
-
-    /**
-     * Commit a write of size 'nMessages'. To be only used after a call to beginWrite().
-     *
-     * @param nMessages number of messages of type T to be written.
-     *
-     * @return Whether the write operation of size 'nMessages' succeeded.
-     */
-    bool commitWrite(size_t nMessages);
-
-    /**
-     * Get a MemTransaction object to read 'nMessages' items of type T.
-     * Once the read is performed using the information from MemTransaction,
-     * the read operation is to be committed using a call to commitRead().
-     *
-     * @param nMessages Number of messages of type T.
-     * @param pointer to MemTransaction struct that describes memory to read 'nMessages'
-     * items of type T. If a read of size 'nMessages' is not possible, the base
-     * pointers in the MemTransaction object returned will be set to nullptr.
-     *
-     * @return bool Whether it is possible to read 'nMessages' items of type T
-     * from the FMQ.
-     */
-    __attribute__((always_inline)) bool beginRead(size_t nMessages, MemTransaction* memTx) const;
-
-    /**
-     * Commit a read of size 'nMessages'. To be only used after a call to beginRead().
-     * For the unsynchronized flavor of FMQ, this method will return a failure
-     * if a write overflow happened after beginRead() was invoked.
-     *
-     * @param nMessages number of messages of type T to be read.
-     *
-     * @return bool Whether the read operation of size 'nMessages' succeeded.
-     */
-    bool commitRead(size_t nMessages);
-
-private:
-
-    size_t availableToWriteBytes() const;
-    size_t availableToReadBytes() const;
-
+  private:
     MessageQueue(const MessageQueue& other) = delete;
     MessageQueue& operator=(const MessageQueue& other) = delete;
-    MessageQueue();
-
-    void* mapGrantorDescr(uint32_t grantorIdx);
-    void unmapGrantorDescr(void* address, uint32_t grantorIdx);
-    void initMemory(bool resetPointers);
-
-    enum DefaultEventNotification : uint32_t {
-        /*
-         * These are only used internally by the readBlocking()/writeBlocking()
-         * methods and hence once other bit combinations are not required.
-         */
-        FMQ_NOT_FULL = 0x01,
-        FMQ_NOT_EMPTY = 0x02
-    };
-
-    std::unique_ptr<Descriptor> mDesc;
-    uint8_t* mRing = nullptr;
-    /*
-     * TODO(b/31550092): Change to 32 bit read and write pointer counters.
-     */
-    std::atomic<uint64_t>* mReadPtr = nullptr;
-    std::atomic<uint64_t>* mWritePtr = nullptr;
-
-    std::atomic<uint32_t>* mEvFlagWord = nullptr;
-
-    /*
-     * This EventFlag object will be owned by the FMQ and will have the same
-     * lifetime.
-     */
-    android::hardware::EventFlag* mEventFlag = nullptr;
+    MessageQueue() = delete;
 };
 
-template <typename T, MQFlavor flavor>
-T* MessageQueue<T, flavor>::MemTransaction::getSlot(size_t idx) {
-    size_t firstRegionLength = first.getLength();
-    size_t secondRegionLength = second.getLength();
-
-    if (idx > firstRegionLength + secondRegionLength) {
-        return nullptr;
-    }
-
-    if (idx < firstRegionLength) {
-        return first.getAddress() + idx;
-    }
-
-    return second.getAddress() + idx - firstRegionLength;
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::MemTransaction::getMemRegionInfo(size_t startIdx,
-                                                               size_t nMessages,
-                                                               size_t& firstCount,
-                                                               size_t& secondCount,
-                                                               T** firstBaseAddress,
-                                                               T** secondBaseAddress) {
-    size_t firstRegionLength = first.getLength();
-    size_t secondRegionLength = second.getLength();
-
-    if (startIdx + nMessages > firstRegionLength + secondRegionLength) {
-        /*
-         * Return false if 'nMessages' starting at 'startIdx' cannot be
-         * accomodated by the MemTransaction object.
-         */
-        return false;
-    }
-
-    /* Number of messages to be read/written to the first MemRegion. */
-    firstCount = startIdx < firstRegionLength ?
-            std::min(nMessages, firstRegionLength - startIdx) : 0;
-
-    /* Number of messages to be read/written to the second MemRegion. */
-    secondCount = nMessages - firstCount;
-
-    if (firstCount != 0) {
-        *firstBaseAddress = first.getAddress() + startIdx;
-    }
-
-    if (secondCount != 0) {
-        size_t secondStartIdx = startIdx > firstRegionLength ? startIdx - firstRegionLength : 0;
-        *secondBaseAddress = second.getAddress() + secondStartIdx;
-    }
-
-    return true;
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::MemTransaction::copyFrom(T* data, size_t startIdx, size_t nMessages) {
-    if (data == nullptr) {
-        return false;
-    }
-
-    size_t firstReadCount = 0, secondReadCount = 0;
-    T* firstBaseAddress = nullptr, * secondBaseAddress = nullptr;
-
-    if (getMemRegionInfo(startIdx,
-                         nMessages,
-                         firstReadCount,
-                         secondReadCount,
-                         &firstBaseAddress,
-                         &secondBaseAddress) == false) {
-        /*
-         * Returns false if 'startIdx' and 'nMessages' are invalid for this
-         * MemTransaction object.
-         */
-        return false;
-    }
-
-    if (firstReadCount != 0) {
-        memcpy(data, firstBaseAddress, firstReadCount * sizeof(T));
-    }
-
-    if (secondReadCount != 0) {
-        memcpy(data + firstReadCount,
-               secondBaseAddress,
-               secondReadCount * sizeof(T));
-    }
-
-    return true;
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::MemTransaction::copyTo(const T* data,
-                                                     size_t startIdx,
-                                                     size_t nMessages) {
-    if (data == nullptr) {
-        return false;
-    }
-
-    size_t firstWriteCount = 0, secondWriteCount = 0;
-    T * firstBaseAddress = nullptr, * secondBaseAddress = nullptr;
-
-    if (getMemRegionInfo(startIdx,
-                         nMessages,
-                         firstWriteCount,
-                         secondWriteCount,
-                         &firstBaseAddress,
-                         &secondBaseAddress) == false) {
-        /*
-         * Returns false if 'startIdx' and 'nMessages' are invalid for this
-         * MemTransaction object.
-         */
-        return false;
-    }
-
-    if (firstWriteCount != 0) {
-        memcpy(firstBaseAddress, data, firstWriteCount * sizeof(T));
-    }
-
-    if (secondWriteCount != 0) {
-        memcpy(secondBaseAddress,
-               data + firstWriteCount,
-               secondWriteCount * sizeof(T));
-    }
-
-    return true;
-}
-
-template <typename T, MQFlavor flavor>
-void MessageQueue<T, flavor>::initMemory(bool resetPointers) {
-    /*
-     * Verify that the 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))) {
-        return;
-    }
-
-    if (flavor == kSynchronizedReadWrite) {
-        mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
-                mapGrantorDescr(Descriptor::READPTRPOS));
-    } else {
-        /*
-         * The unsynchronized write flavor of the FMQ may have multiple readers
-         * and each reader would have their own read pointer counter.
-         */
-        mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
-    }
-
-    details::check(mReadPtr != nullptr);
-
-    mWritePtr =
-            reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::WRITEPTRPOS));
-    details::check(mWritePtr != nullptr);
-
-    if (resetPointers) {
-        mReadPtr->store(0, std::memory_order_release);
-        mWritePtr->store(0, std::memory_order_release);
-    } else if (flavor != kSynchronizedReadWrite) {
-        // Always reset the read pointer.
-        mReadPtr->store(0, std::memory_order_release);
-    }
-
-    mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(Descriptor::DATAPTRPOS));
-    details::check(mRing != nullptr);
-
-    mEvFlagWord = static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(Descriptor::EVFLAGWORDPOS));
-    if (mEvFlagWord != nullptr) {
-        android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
-    }
-}
-
-template <typename T, MQFlavor flavor>
-MessageQueue<T, flavor>::MessageQueue(const Descriptor& Desc, bool resetPointers) {
-    mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
-    if (mDesc == nullptr) {
-        return;
-    }
-
-    initMemory(resetPointers);
-}
-
-template <typename T, MQFlavor flavor>
-MessageQueue<T, flavor>::MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord) {
-
-    // Check if the buffer size would not overflow size_t
-    if (numElementsInQueue > SIZE_MAX / sizeof(T)) {
-        return;
-    }
-    /*
-     * The FMQ needs to allocate memory for the ringbuffer as well as for the
-     * read and write pointer counters. If an EventFlag word is to be configured,
-     * we also need to allocate memory for the same/
-     */
-    size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
-    size_t kMetaDataSize = 2 * sizeof(android::hardware::RingBufferPosition);
-
-    if (configureEventFlagWord) {
-        kMetaDataSize+= sizeof(std::atomic<uint32_t>);
-    }
-
-    /*
-     * Ashmem memory region size needs to be specified in page-aligned bytes.
-     * 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);
-
-    /*
-     * Create an ashmem region to map the memory for the ringbuffer,
-     * read counter and write counter.
-     */
-    int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
-    ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
-
-    /*
-     * The native handle will contain the fds to be mapped.
-     */
-    native_handle_t* mqHandle =
-            native_handle_create(1 /* numFds */, 0 /* numInts */);
-    if (mqHandle == nullptr) {
-        return;
-    }
-
-    mqHandle->data[0] = ashmemFd;
-    mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(kQueueSizeBytes,
-                                                                      mqHandle,
-                                                                      sizeof(T),
-                                                                      configureEventFlagWord));
-    if (mDesc == nullptr) {
-        return;
-    }
-    initMemory(true);
-}
-
-template <typename T, MQFlavor flavor>
-MessageQueue<T, flavor>::~MessageQueue() {
-    if (flavor == kUnsynchronizedWrite) {
-        delete mReadPtr;
-    } else {
-        unmapGrantorDescr(mReadPtr, Descriptor::READPTRPOS);
-    }
-    if (mWritePtr != nullptr) {
-        unmapGrantorDescr(mWritePtr, Descriptor::WRITEPTRPOS);
-    }
-    if (mRing != nullptr) {
-        unmapGrantorDescr(mRing, Descriptor::DATAPTRPOS);
-    }
-    if (mEvFlagWord != nullptr) {
-        unmapGrantorDescr(mEvFlagWord, Descriptor::EVFLAGWORDPOS);
-        android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
-    }
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::write(const T* data) {
-    return write(data, 1);
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::read(T* data) {
-    return read(data, 1);
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::write(const T* data, size_t nMessages) {
-    MemTransaction tx;
-    return beginWrite(nMessages, &tx) &&
-            tx.copyTo(data, 0 /* startIdx */, nMessages) &&
-            commitWrite(nMessages);
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<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 == kSynchronizedReadWrite,
-                  "writeBlocking can only be used with the "
-                  "kSynchronizedReadWrite flavor.");
-    /*
-     * If evFlag is null and the FMQ does not have its own EventFlag object
-     * return false;
-     * 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.
-     */
-    if (evFlag == nullptr) {
-        evFlag = mEventFlag;
-        if (evFlag == nullptr) {
-            details::logError(
-                "writeBlocking failed: called on MessageQueue with no Eventflag"
-                "configured or provided");
-            return false;
-        }
-    }
-
-    if (readNotification == 0 || (count > getQuantumCount())) {
-        return false;
-    }
-
-    /*
-     * There is no need to wait for a readNotification if there is sufficient
-     * space to write is already present in the FMQ. The latter would be the case when
-     * read operations read more number of messages than write operations write.
-     * In other words, a single large read may clear the FMQ after multiple small
-     * writes. This would fail to clear a pending readNotification bit since
-     * EventFlag bits can only be cleared by a wait() call, however the bit would
-     * be correctly cleared by the next writeBlocking() call.
-     */
-
-    bool result = write(data, count);
-    if (result) {
-        if (writeNotification) {
-            evFlag->wake(writeNotification);
-        }
-        return result;
-    }
-
-    bool shouldTimeOut = timeOutNanos != 0;
-    int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
-
-    while (true) {
-        /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
-        if (shouldTimeOut) {
-            /*
-             * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
-             * to Nanoseconds)
-             */
-            int64_t currentTimeNs = android::elapsedRealtimeNano();
-            /*
-             * Decrement 'timeOutNanos' to account for the time taken to complete the last
-             * iteration of the while loop.
-             */
-            timeOutNanos -= currentTimeNs - prevTimeNanos;
-            prevTimeNanos = currentTimeNs;
-
-            if (timeOutNanos <= 0) {
-                /*
-                 * Attempt write in case a context switch happened outside of
-                 * evFlag->wait().
-                 */
-                result = write(data, count);
-                break;
-            }
-        }
-
-        /*
-         * wait() will return immediately if there was a pending read
-         * notification.
-         */
-        uint32_t efState = 0;
-        status_t status = evFlag->wait(readNotification,
-                                       &efState,
-                                       timeOutNanos,
-                                       true /* retry on spurious wake */);
-
-        if (status != android::TIMED_OUT && status != android::NO_ERROR) {
-            details::logError("Unexpected error code from EventFlag Wait status " + std::to_string(status));
-            break;
-        }
-
-        if (status == android::TIMED_OUT) {
-            break;
-        }
-
-        /*
-         * If there is still insufficient space to write to the FMQ,
-         * keep waiting for another readNotification.
-         */
-        if ((efState & readNotification) && write(data, count)) {
-            result = true;
-            break;
-        }
-    }
-
-    if (result && writeNotification != 0) {
-        evFlag->wake(writeNotification);
-    }
-
-    return result;
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::writeBlocking(const T* data,
-                   size_t count,
-                   int64_t timeOutNanos) {
-    return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::readBlocking(T* data,
-                                           size_t count,
-                                           uint32_t readNotification,
-                                           uint32_t writeNotification,
-                                           int64_t timeOutNanos,
-                                           android::hardware::EventFlag* evFlag) {
-    static_assert(flavor == kSynchronizedReadWrite,
-                  "readBlocking can only be used with the "
-                  "kSynchronizedReadWrite flavor.");
-
-    /*
-     * If evFlag is null and the FMQ does not own its own EventFlag object
-     * return false;
-     * If the writeNotification bit mask is zero return false;
-     * If the count is greater than queue size, return false to prevent
-     * blocking until timeOut.
-     */
-    if (evFlag == nullptr) {
-        evFlag = mEventFlag;
-        if (evFlag == nullptr) {
-            details::logError(
-                "readBlocking failed: called on MessageQueue with no Eventflag"
-                "configured or provided");
-            return false;
-        }
-    }
-
-    if (writeNotification == 0 || count > getQuantumCount()) {
-        return false;
-    }
-
-    /*
-     * There is no need to wait for a write notification if sufficient
-     * data to read is already present in the FMQ. This would be the
-     * case when read operations read lesser number of messages than
-     * a write operation and multiple reads would be required to clear the queue
-     * after a single write operation. This check would fail to clear a pending
-     * writeNotification bit since EventFlag bits can only be cleared
-     * by a wait() call, however the bit would be correctly cleared by the next
-     * readBlocking() call.
-     */
-
-    bool result = read(data, count);
-    if (result) {
-        if (readNotification) {
-            evFlag->wake(readNotification);
-        }
-        return result;
-    }
-
-    bool shouldTimeOut = timeOutNanos != 0;
-    int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
-
-    while (true) {
-        /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
-        if (shouldTimeOut) {
-            /*
-             * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
-             * to Nanoseconds)
-             */
-            int64_t currentTimeNs = android::elapsedRealtimeNano();
-            /*
-             * Decrement 'timeOutNanos' to account for the time taken to complete the last
-             * iteration of the while loop.
-             */
-            timeOutNanos -= currentTimeNs - prevTimeNanos;
-            prevTimeNanos = currentTimeNs;
-
-            if (timeOutNanos <= 0) {
-                /*
-                 * Attempt read in case a context switch happened outside of
-                 * evFlag->wait().
-                 */
-                result = read(data, count);
-                break;
-            }
-        }
-
-        /*
-         * wait() will return immediately if there was a pending write
-         * notification.
-         */
-        uint32_t efState = 0;
-        status_t status = evFlag->wait(writeNotification,
-                                       &efState,
-                                       timeOutNanos,
-                                       true /* retry on spurious wake */);
-
-        if (status != android::TIMED_OUT && status != android::NO_ERROR) {
-            details::logError("Unexpected error code from EventFlag Wait status " + std::to_string(status));
-            break;
-        }
-
-        if (status == android::TIMED_OUT) {
-            break;
-        }
-
-        /*
-         * If the data in FMQ is still insufficient, go back to waiting
-         * for another write notification.
-         */
-        if ((efState & writeNotification) && read(data, count)) {
-            result = true;
-            break;
-        }
-    }
-
-    if (result && readNotification != 0) {
-        evFlag->wake(readNotification);
-    }
-    return result;
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::readBlocking(T* data, size_t count, int64_t timeOutNanos) {
-    return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
-}
-
-template <typename T, MQFlavor flavor>
-size_t MessageQueue<T, flavor>::availableToWriteBytes() const {
-    return mDesc->getSize() - availableToReadBytes();
-}
-
-template <typename T, MQFlavor flavor>
-size_t MessageQueue<T, flavor>::availableToWrite() const {
-    return availableToWriteBytes() / sizeof(T);
-}
-
-template <typename T, MQFlavor flavor>
-size_t MessageQueue<T, flavor>::availableToRead() const {
-    return availableToReadBytes() / sizeof(T);
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::beginWrite(size_t nMessages, MemTransaction* result) const {
-    /*
-     * If nMessages is greater than size of FMQ or in case of the synchronized
-     * FMQ flavor, if there is not enough space to write nMessages, then return
-     * result with null addresses.
-     */
-    if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
-        nMessages > getQuantumCount()) {
-        *result = MemTransaction();
-        return false;
-    }
-
-    auto writePtr = mWritePtr->load(std::memory_order_relaxed);
-    if (writePtr % sizeof(T) != 0) {
-        hardware::details::logError(
-                "The write pointer has become misaligned. Writing to the queue is no longer "
-                "possible.");
-        return false;
-    }
-    size_t writeOffset = writePtr % mDesc->getSize();
-
-    /*
-     * From writeOffset, the number of messages that can be written
-     * contiguously without wrapping around the ring buffer are calculated.
-     */
-    size_t contiguousMessages = (mDesc->getSize() - writeOffset) / sizeof(T);
-
-    if (contiguousMessages < nMessages) {
-        /*
-         * Wrap around is required. Both result.first and result.second are
-         * populated.
-         */
-        *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset),
-                                           contiguousMessages),
-                                 MemRegion(reinterpret_cast<T*>(mRing),
-                                           nMessages - contiguousMessages));
-    } else {
-        /*
-         * A wrap around is not required to write nMessages. Only result.first
-         * is populated.
-         */
-        *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
-                                 MemRegion());
-    }
-
-    return true;
-}
-
-template <typename T, MQFlavor flavor>
-/*
- * Disable integer sanitization since integer overflow here is allowed
- * and legal.
- */
-__attribute__((no_sanitize("integer")))
-bool MessageQueue<T, flavor>::commitWrite(size_t nMessages) {
-    size_t nBytesWritten = nMessages * sizeof(T);
-    auto writePtr = mWritePtr->load(std::memory_order_relaxed);
-    writePtr += nBytesWritten;
-    mWritePtr->store(writePtr, std::memory_order_release);
-    /*
-     * This method cannot fail now since we are only incrementing the writePtr
-     * counter.
-     */
-    return true;
-}
-
-template <typename T, MQFlavor flavor>
-size_t MessageQueue<T, flavor>::availableToReadBytes() const {
-    /*
-     * This method is invoked by implementations of both read() and write() and
-     * hence requries a memory_order_acquired load for both mReadPtr and
-     * mWritePtr.
-     */
-    return mWritePtr->load(std::memory_order_acquire) -
-            mReadPtr->load(std::memory_order_acquire);
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::read(T* data, size_t nMessages) {
-    MemTransaction tx;
-    return beginRead(nMessages, &tx) &&
-            tx.copyFrom(data, 0 /* startIdx */, nMessages) &&
-            commitRead(nMessages);
-}
-
-template <typename T, MQFlavor flavor>
-/*
- * Disable integer sanitization since integer overflow here is allowed
- * and legal.
- */
-__attribute__((no_sanitize("integer")))
-bool MessageQueue<T, flavor>::beginRead(size_t nMessages, MemTransaction* result) const {
-    *result = MemTransaction();
-    /*
-     * If it is detected that the data in the queue was overwritten
-     * due to the reader process being too slow, the read pointer counter
-     * is set to the same as the write pointer counter to indicate error
-     * and the read returns false;
-     * Need acquire/release memory ordering for mWritePtr.
-     */
-    auto writePtr = mWritePtr->load(std::memory_order_acquire);
-    /*
-     * A relaxed load is sufficient for mReadPtr since there will be no
-     * stores to mReadPtr from a different thread.
-     */
-    auto readPtr = mReadPtr->load(std::memory_order_relaxed);
-    if (writePtr % sizeof(T) != 0 || readPtr % sizeof(T) != 0) {
-        hardware::details::logError(
-                "The write or read pointer has become misaligned. Reading from the queue is no "
-                "longer possible.");
-        return false;
-    }
-
-    if (writePtr - readPtr > mDesc->getSize()) {
-        mReadPtr->store(writePtr, std::memory_order_release);
-        return false;
-    }
-
-    size_t nBytesDesired = nMessages * sizeof(T);
-    /*
-     * Return if insufficient data to read in FMQ.
-     */
-    if (writePtr - readPtr < nBytesDesired) {
-        return false;
-    }
-
-    size_t readOffset = readPtr % mDesc->getSize();
-    /*
-     * From readOffset, the number of messages that can be read contiguously
-     * without wrapping around the ring buffer are calculated.
-     */
-    size_t contiguousMessages = (mDesc->getSize() - readOffset) / sizeof(T);
-
-    if (contiguousMessages < nMessages) {
-        /*
-         * A wrap around is required. Both result.first and result.second
-         * are populated.
-         */
-        *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset),
-                                           contiguousMessages),
-                                 MemRegion(reinterpret_cast<T*>(mRing),
-                                           nMessages - contiguousMessages));
-    } else {
-        /*
-         * A wrap around is not required. Only result.first need to be
-         * populated.
-         */
-        *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
-                                 MemRegion());
-    }
-
-    return true;
-}
-
-template <typename T, MQFlavor flavor>
-/*
- * Disable integer sanitization since integer overflow here is allowed
- * and legal.
- */
-__attribute__((no_sanitize("integer")))
-bool MessageQueue<T, flavor>::commitRead(size_t nMessages) {
-    // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
-    auto readPtr = mReadPtr->load(std::memory_order_relaxed);
-    auto writePtr = mWritePtr->load(std::memory_order_acquire);
-    /*
-     * If the flavor is unsynchronized, it is possible that a write overflow may
-     * have occured between beginRead() and commitRead().
-     */
-    if (writePtr - readPtr > mDesc->getSize()) {
-        mReadPtr->store(writePtr, std::memory_order_release);
-        return false;
-    }
-
-    size_t nBytesRead = nMessages * sizeof(T);
-    readPtr += nBytesRead;
-    mReadPtr->store(readPtr, std::memory_order_release);
-    return true;
-}
-
-template <typename T, MQFlavor flavor>
-size_t MessageQueue<T, flavor>::getQuantumSize() const {
-    return mDesc->getQuantum();
-}
-
-template <typename T, MQFlavor flavor>
-size_t MessageQueue<T, flavor>::getQuantumCount() const {
-    return mDesc->getSize() / mDesc->getQuantum();
-}
-
-template <typename T, MQFlavor flavor>
-bool MessageQueue<T, flavor>::isValid() const {
-    return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
-}
-
-template <typename T, MQFlavor flavor>
-void* MessageQueue<T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
-    const native_handle_t* handle = mDesc->handle();
-    auto grantors = mDesc->grantors();
-    if (handle == nullptr) {
-        details::logError("mDesc->handle is null");
-        return nullptr;
-    }
-
-    if (grantorIdx >= grantors.size()) {
-        details::logError(std::string("grantorIdx must be less than ") +
-                          std::to_string(grantors.size()));
-        return nullptr;
-    }
-
-    int fdIndex = grantors[grantorIdx].fdIndex;
-    /*
-     * Offset for mmap must be a multiple of PAGE_SIZE.
-     */
-    int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
-    int mapLength =
-            grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
-
-    void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED,
-                         handle->data[fdIndex], mapOffset);
-    if (address == MAP_FAILED) {
-        details::logError(std::string("mmap failed: ") + std::to_string(errno));
-        return nullptr;
-    }
-    return reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
-}
-
-template <typename T, MQFlavor flavor>
-void MessageQueue<T, flavor>::unmapGrantorDescr(void* address,
-                                                uint32_t grantorIdx) {
-    auto grantors = mDesc->grantors();
-    if ((address == nullptr) || (grantorIdx >= grantors.size())) {
-        return;
-    }
-
-    int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
-    int mapLength =
-            grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
-    void* baseAddress = reinterpret_cast<uint8_t*>(address) -
-            (grantors[grantorIdx].offset - mapOffset);
-    if (baseAddress) munmap(baseAddress, mapLength);
-}
-
 }  // namespace hardware
 }  // namespace android
-#endif  // HIDL_MQ_H
diff --git a/include/fmq/MessageQueueBase.h b/include/fmq/MessageQueueBase.h
new file mode 100644
index 0000000..2a29937
--- /dev/null
+++ b/include/fmq/MessageQueueBase.h
@@ -0,0 +1,1284 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <cutils/ashmem.h>
+#include <fmq/EventFlag.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+#include <atomic>
+#include <new>
+
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::kUnsynchronizedWrite;
+using android::hardware::MQFlavor;
+
+namespace android {
+
+template <template <typename, MQFlavor> class MQDescriptorType, typename T, MQFlavor flavor>
+struct MessageQueueBase {
+    typedef MQDescriptorType<T, flavor> Descriptor;
+
+    /**
+     * @param Desc MQDescriptor describing the FMQ.
+     * @param resetPointers bool indicating whether the read/write pointers
+     * should be reset or not.
+     */
+    MessageQueueBase(const Descriptor& Desc, bool resetPointers = true);
+
+    ~MessageQueueBase();
+
+    /**
+     * 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 MessageQueue in terms of T.
+     * @param configureEventFlagWord Boolean that specifies if memory should
+     * also be allocated and mapped for an EventFlag word.
+     * @param bufferFd User-supplied file descriptor to map the memory for the ringbuffer
+     * By default, bufferFd=-1 means library will allocate ashmem region for ringbuffer.
+     * MessageQueue takes ownership of the file descriptor.
+     * @param bufferSize size of buffer in bytes that bufferFd represents. This
+     * size must be larger than or equal to (numElementsInQueue * sizeof(T)).
+     * Otherwise, operations will cause out-of-bounds memory access.
+     */
+
+    MessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord,
+                     android::base::unique_fd bufferFd, size_t bufferSize);
+
+    MessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord = false)
+        : MessageQueueBase(numElementsInQueue, configureEventFlagWord, android::base::unique_fd(),
+                           0) {}
+
+    /**
+     * @return Number of items of type T that can be written into the FMQ
+     * without a read.
+     */
+    size_t availableToWrite() const;
+
+    /**
+     * @return Number of items of type T that are waiting to be read from the
+     * FMQ.
+     */
+    size_t availableToRead() const;
+
+    /**
+     * Returns the size of type T in bytes.
+     *
+     * @param Size of T.
+     */
+    size_t getQuantumSize() const;
+
+    /**
+     * Returns the size of the FMQ in terms of the size of type T.
+     *
+     * @return Number of items of type T that will fit in the FMQ.
+     */
+    size_t getQuantumCount() const;
+
+    /**
+     * @return Whether the FMQ is configured correctly.
+     */
+    bool isValid() const;
+
+    /**
+     * Non-blocking write to FMQ.
+     *
+     * @param data Pointer to the object of type T to be written into the FMQ.
+     *
+     * @return Whether the write was successful.
+     */
+    bool write(const T* data);
+
+    /**
+     * Non-blocking read from FMQ.
+     *
+     * @param data Pointer to the memory where the object read from the FMQ is
+     * copied to.
+     *
+     * @return Whether the read was successful.
+     */
+    bool read(T* data);
+
+    /**
+     * Write some data into the FMQ without blocking.
+     *
+     * @param data Pointer to the array of items of type T.
+     * @param count Number of items in array.
+     *
+     * @return Whether the write was successful.
+     */
+    bool write(const T* data, size_t count);
+
+    /**
+     * Perform a blocking write of 'count' items into the FMQ using EventFlags.
+     * Does not support partial writes.
+     *
+     * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
+     * associated with the FMQ and it is used in that case.
+     *
+     * The application code must ensure that 'evFlag' used by the
+     * reader(s)/writer is based upon the same EventFlag word.
+     *
+     * The method will return false without blocking if any of the following
+     * conditions are true:
+     * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
+     * - If the 'readNotification' bit mask is zero.
+     * - If 'count' is greater than the FMQ size.
+     *
+     * If the there is insufficient space available to write into it, the
+     * EventFlag bit mask 'readNotification' is is waited upon.
+     *
+     * This method should only be used with a MessageQueue of the flavor
+     * 'kSynchronizedReadWrite'.
+     *
+     * Upon a successful write, wake is called on 'writeNotification' (if
+     * non-zero).
+     *
+     * @param data Pointer to the array of items of type T.
+     * @param count Number of items in array.
+     * @param readNotification The EventFlag bit mask to wait on if there is not
+     * enough space in FMQ to write 'count' items.
+     * @param writeNotification The EventFlag bit mask to call wake on
+     * a successful write. No wake is called if 'writeNotification' is zero.
+     * @param timeOutNanos Number of nanoseconds after which the blocking
+     * write attempt is aborted.
+     * @param evFlag The EventFlag object to be used for blocking. If nullptr,
+     * it is checked whether the FMQ owns an EventFlag object and that is used
+     * for blocking instead.
+     *
+     * @return Whether the write was successful.
+     */
+    bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
+                       uint32_t writeNotification, int64_t timeOutNanos = 0,
+                       android::hardware::EventFlag* evFlag = nullptr);
+
+    bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
+
+    /**
+     * Read some data from the FMQ without blocking.
+     *
+     * @param data Pointer to the array to which read data is to be written.
+     * @param count Number of items to be read.
+     *
+     * @return Whether the read was successful.
+     */
+    bool read(T* data, size_t count);
+
+    /**
+     * Perform a blocking read operation of 'count' items from the FMQ. Does not
+     * perform a partial read.
+     *
+     * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
+     * associated with the FMQ and it is used in that case.
+     *
+     * The application code must ensure that 'evFlag' used by the
+     * reader(s)/writer is based upon the same EventFlag word.
+     *
+     * The method will return false without blocking if any of the following
+     * conditions are true:
+     * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
+     * -If the 'writeNotification' bit mask is zero.
+     * -If 'count' is greater than the FMQ size.
+     *
+     * This method should only be used with a MessageQueue of the flavor
+     * 'kSynchronizedReadWrite'.
+
+     * If FMQ does not contain 'count' items, the eventFlag bit mask
+     * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
+     * wake is called on 'readNotification' (if non-zero).
+     *
+     * @param data Pointer to the array to which read data is to be written.
+     * @param count Number of items to be read.
+     * @param readNotification The EventFlag bit mask to call wake on after
+     * a successful read. No wake is called if 'readNotification' is zero.
+     * @param writeNotification The EventFlag bit mask to call a wait on
+     * if there is insufficient data in the FMQ to be read.
+     * @param timeOutNanos Number of nanoseconds after which the blocking
+     * read attempt is aborted.
+     * @param evFlag The EventFlag object to be used for blocking.
+     *
+     * @return Whether the read was successful.
+     */
+    bool readBlocking(T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
+                      int64_t timeOutNanos = 0, android::hardware::EventFlag* evFlag = nullptr);
+
+    bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
+
+    /**
+     * Get a pointer to the MQDescriptor object that describes this FMQ.
+     *
+     * @return Pointer to the MQDescriptor associated with the FMQ.
+     */
+    const Descriptor* getDesc() const { return mDesc.get(); }
+
+    /**
+     * Get a pointer to the EventFlag word if there is one associated with this FMQ.
+     *
+     * @return Pointer to an EventFlag word, will return nullptr if not
+     * configured. This method does not transfer ownership. The EventFlag
+     * word will be unmapped by the MessageQueue destructor.
+     */
+    std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
+
+    /**
+     * Describes a memory region in the FMQ.
+     */
+    struct MemRegion {
+        MemRegion() : MemRegion(nullptr, 0) {}
+
+        MemRegion(T* base, size_t size) : address(base), length(size) {}
+
+        MemRegion& operator=(const MemRegion& other) {
+            address = other.address;
+            length = other.length;
+            return *this;
+        }
+
+        /**
+         * Gets a pointer to the base address of the MemRegion.
+         */
+        inline T* getAddress() const { return address; }
+
+        /**
+         * Gets the length of the MemRegion. This would equal to the number
+         * of items of type T that can be read from/written into the MemRegion.
+         */
+        inline size_t getLength() const { return length; }
+
+        /**
+         * Gets the length of the MemRegion in bytes.
+         */
+        inline size_t getLengthInBytes() const { return length * sizeof(T); }
+
+      private:
+        /* Base address */
+        T* address;
+
+        /*
+         * Number of items of type T that can be written to/read from the base
+         * address.
+         */
+        size_t length;
+    };
+
+    /**
+     * Describes the memory regions to be used for a read or write.
+     * The struct contains two MemRegion objects since the FMQ is a ring
+     * buffer and a read or write operation can wrap around. A single message
+     * of type T will never be broken between the two MemRegions.
+     */
+    struct MemTransaction {
+        MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
+
+        MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond)
+            : first(regionFirst), second(regionSecond) {}
+
+        MemTransaction& operator=(const MemTransaction& other) {
+            first = other.first;
+            second = other.second;
+            return *this;
+        }
+
+        /**
+         * Helper method to calculate the address for a particular index for
+         * the MemTransaction object.
+         *
+         * @param idx Index of the slot to be read/written. If the
+         * MemTransaction object is representing the memory region to read/write
+         * N items of type T, the valid range of idx is between 0 and N-1.
+         *
+         * @return Pointer to the slot idx. Will be nullptr for an invalid idx.
+         */
+        T* getSlot(size_t idx);
+
+        /**
+         * Helper method to write 'nMessages' items of type T into the memory
+         * regions described by the object starting from 'startIdx'. This method
+         * uses memcpy() and is not to meant to be used for a zero copy operation.
+         * Partial writes are not supported.
+         *
+         * @param data Pointer to the source buffer.
+         * @param nMessages Number of items of type T.
+         * @param startIdx The slot number to begin the write from. If the
+         * MemTransaction object is representing the memory region to read/write
+         * N items of type T, the valid range of startIdx is between 0 and N-1;
+         *
+         * @return Whether the write operation of size 'nMessages' succeeded.
+         */
+        bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
+
+        /*
+         * Helper method to read 'nMessages' items of type T from the memory
+         * regions described by the object starting from 'startIdx'. This method uses
+         * memcpy() and is not meant to be used for a zero copy operation. Partial reads
+         * are not supported.
+         *
+         * @param data Pointer to the destination buffer.
+         * @param nMessages Number of items of type T.
+         * @param startIdx The slot number to begin the read from. If the
+         * MemTransaction object is representing the memory region to read/write
+         * N items of type T, the valid range of startIdx is between 0 and N-1.
+         *
+         * @return Whether the read operation of size 'nMessages' succeeded.
+         */
+        bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
+
+        /**
+         * Returns a const reference to the first MemRegion in the
+         * MemTransaction object.
+         */
+        inline const MemRegion& getFirstRegion() const { return first; }
+
+        /**
+         * Returns a const reference to the second MemRegion in the
+         * MemTransaction object.
+         */
+        inline const MemRegion& getSecondRegion() const { return second; }
+
+      private:
+        /*
+         * Given a start index and the number of messages to be
+         * read/written, this helper method calculates the
+         * number of messages that should should be written to both the first
+         * and second MemRegions and the base addresses to be used for
+         * the read/write operation.
+         *
+         * Returns false if the 'startIdx' and 'nMessages' is
+         * invalid for the MemTransaction object.
+         */
+        bool inline getMemRegionInfo(size_t idx, size_t nMessages, size_t& firstCount,
+                                     size_t& secondCount, T** firstBaseAddress,
+                                     T** secondBaseAddress);
+        MemRegion first;
+        MemRegion second;
+    };
+
+    /**
+     * Get a MemTransaction object to write 'nMessages' items of type T.
+     * Once the write is performed using the information from MemTransaction,
+     * the write operation is to be committed using a call to commitWrite().
+     *
+     * @param nMessages Number of messages of type T.
+     * @param Pointer to MemTransaction struct that describes memory to write 'nMessages'
+     * items of type T. If a write of size 'nMessages' is not possible, the base
+     * addresses in the MemTransaction object would be set to nullptr.
+     *
+     * @return Whether it is possible to write 'nMessages' items of type T
+     * into the FMQ.
+     */
+    bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
+
+    /**
+     * Commit a write of size 'nMessages'. To be only used after a call to beginWrite().
+     *
+     * @param nMessages number of messages of type T to be written.
+     *
+     * @return Whether the write operation of size 'nMessages' succeeded.
+     */
+    bool commitWrite(size_t nMessages);
+
+    /**
+     * Get a MemTransaction object to read 'nMessages' items of type T.
+     * Once the read is performed using the information from MemTransaction,
+     * the read operation is to be committed using a call to commitRead().
+     *
+     * @param nMessages Number of messages of type T.
+     * @param pointer to MemTransaction struct that describes memory to read 'nMessages'
+     * items of type T. If a read of size 'nMessages' is not possible, the base
+     * pointers in the MemTransaction object returned will be set to nullptr.
+     *
+     * @return bool Whether it is possible to read 'nMessages' items of type T
+     * from the FMQ.
+     */
+    bool beginRead(size_t nMessages, MemTransaction* memTx) const;
+
+    /**
+     * Commit a read of size 'nMessages'. To be only used after a call to beginRead().
+     * For the unsynchronized flavor of FMQ, this method will return a failure
+     * if a write overflow happened after beginRead() was invoked.
+     *
+     * @param nMessages number of messages of type T to be read.
+     *
+     * @return bool Whether the read operation of size 'nMessages' succeeded.
+     */
+    bool commitRead(size_t nMessages);
+
+  private:
+    size_t availableToWriteBytes() const;
+    size_t availableToReadBytes() const;
+
+    MessageQueueBase(const MessageQueueBase& other) = delete;
+    MessageQueueBase& operator=(const MessageQueueBase& other) = delete;
+
+    void* mapGrantorDescr(uint32_t grantorIdx);
+    void unmapGrantorDescr(void* address, uint32_t grantorIdx);
+    void initMemory(bool resetPointers);
+
+    enum DefaultEventNotification : uint32_t {
+        /*
+         * These are only used internally by the readBlocking()/writeBlocking()
+         * methods and hence once other bit combinations are not required.
+         */
+        FMQ_NOT_FULL = 0x01,
+        FMQ_NOT_EMPTY = 0x02
+    };
+    std::unique_ptr<Descriptor> mDesc;
+    uint8_t* mRing = nullptr;
+    /*
+     * TODO(b/31550092): Change to 32 bit read and write pointer counters.
+     */
+    std::atomic<uint64_t>* mReadPtr = nullptr;
+    std::atomic<uint64_t>* mWritePtr = nullptr;
+
+    std::atomic<uint32_t>* mEvFlagWord = nullptr;
+
+    /*
+     * This EventFlag object will be owned by the FMQ and will have the same
+     * lifetime.
+     */
+    android::hardware::EventFlag* mEventFlag = nullptr;
+};
+
+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();
+
+    if (idx > firstRegionLength + secondRegionLength) {
+        return nullptr;
+    }
+
+    if (idx < firstRegionLength) {
+        return first.getAddress() + idx;
+    }
+
+    return second.getAddress() + idx - firstRegionLength;
+}
+
+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) {
+    size_t firstRegionLength = first.getLength();
+    size_t secondRegionLength = second.getLength();
+
+    if (startIdx + nMessages > firstRegionLength + secondRegionLength) {
+        /*
+         * Return false if 'nMessages' starting at 'startIdx' cannot be
+         * accommodated by the MemTransaction object.
+         */
+        return false;
+    }
+
+    /* Number of messages to be read/written to the first MemRegion. */
+    firstCount =
+            startIdx < firstRegionLength ? std::min(nMessages, firstRegionLength - startIdx) : 0;
+
+    /* Number of messages to be read/written to the second MemRegion. */
+    secondCount = nMessages - firstCount;
+
+    if (firstCount != 0) {
+        *firstBaseAddress = first.getAddress() + startIdx;
+    }
+
+    if (secondCount != 0) {
+        size_t secondStartIdx = startIdx > firstRegionLength ? startIdx - firstRegionLength : 0;
+        *secondBaseAddress = second.getAddress() + secondStartIdx;
+    }
+
+    return true;
+}
+
+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) {
+    if (data == nullptr) {
+        return false;
+    }
+
+    size_t firstReadCount = 0, secondReadCount = 0;
+    T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
+
+    if (getMemRegionInfo(startIdx, nMessages, firstReadCount, secondReadCount, &firstBaseAddress,
+                         &secondBaseAddress) == false) {
+        /*
+         * Returns false if 'startIdx' and 'nMessages' are invalid for this
+         * MemTransaction object.
+         */
+        return false;
+    }
+
+    if (firstReadCount != 0) {
+        memcpy(data, firstBaseAddress, firstReadCount * sizeof(T));
+    }
+
+    if (secondReadCount != 0) {
+        memcpy(data + firstReadCount, secondBaseAddress, secondReadCount * sizeof(T));
+    }
+
+    return true;
+}
+
+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) {
+    if (data == nullptr) {
+        return false;
+    }
+
+    size_t firstWriteCount = 0, secondWriteCount = 0;
+    T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
+
+    if (getMemRegionInfo(startIdx, nMessages, firstWriteCount, secondWriteCount, &firstBaseAddress,
+                         &secondBaseAddress) == false) {
+        /*
+         * Returns false if 'startIdx' and 'nMessages' are invalid for this
+         * MemTransaction object.
+         */
+        return false;
+    }
+
+    if (firstWriteCount != 0) {
+        memcpy(firstBaseAddress, data, firstWriteCount * sizeof(T));
+    }
+
+    if (secondWriteCount != 0) {
+        memcpy(secondBaseAddress, data + firstWriteCount, secondWriteCount * sizeof(T));
+    }
+
+    return true;
+}
+
+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() < hardware::details::kMinGrantorCount)) {
+        return;
+    }
+    if (mDesc->getQuantum() != sizeof(T)) {
+        hardware::details::logError(
+                "Payload size differs between the queue instantiation and the "
+                "MQDescriptor.");
+        return;
+    }
+
+    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
+         * and each reader would have their own read pointer counter.
+         */
+        mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
+    }
+    if (mReadPtr == nullptr) {
+#ifdef __BIONIC__
+        __assert(__FILE__, __LINE__, "mReadPtr is null");
+#endif
+    }
+
+    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 != kSynchronizedReadWrite) {
+        // Always reset the read pointer.
+        mReadPtr->store(0, std::memory_order_release);
+    }
+
+    mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(hardware::details::DATAPTRPOS));
+    if (mRing == nullptr) {
+#ifdef __BIONIC__
+        __assert(__FILE__, __LINE__, "mRing is null");
+#endif
+    }
+
+    if (mDesc->countGrantors() > hardware::details::EVFLAGWORDPOS) {
+        mEvFlagWord = static_cast<std::atomic<uint32_t>*>(
+                mapGrantorDescr(hardware::details::EVFLAGWORDPOS));
+        if (mEvFlagWord != nullptr) {
+            android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
+        } else {
+#ifdef __BIONIC__
+            __assert(__FILE__, __LINE__, "mEvFlagWord is null");
+#endif
+        }
+    }
+}
+
+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));
+    if (mDesc == nullptr) {
+        return;
+    }
+
+    initMemory(resetPointers);
+}
+
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
+MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(size_t numElementsInQueue,
+                                                                bool configureEventFlagWord,
+                                                                android::base::unique_fd bufferFd,
+                                                                size_t bufferSize) {
+    // Check if the buffer size would not overflow size_t
+    if (numElementsInQueue > SIZE_MAX / sizeof(T)) {
+        hardware::details::logError("Requested message queue size too large. Size of elements: " +
+                                    std::to_string(sizeof(T)) +
+                                    ". Number of elements: " + std::to_string(numElementsInQueue));
+        return;
+    }
+    if (bufferFd != -1 && numElementsInQueue * sizeof(T) > bufferSize) {
+        hardware::details::logError("The supplied buffer size(" + std::to_string(bufferSize) +
+                                    ") is smaller than the required size(" +
+                                    std::to_string(numElementsInQueue * sizeof(T)) + ").");
+        return;
+    }
+    /*
+     * The FMQ needs to allocate memory for the ringbuffer as well as for the
+     * read and write pointer counters. If an EventFlag word is to be configured,
+     * we also need to allocate memory for the same/
+     */
+    size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
+    size_t kMetaDataSize = 2 * sizeof(android::hardware::details::RingBufferPosition);
+
+    if (configureEventFlagWord) {
+        kMetaDataSize += sizeof(std::atomic<uint32_t>);
+    }
+
+    /*
+     * Ashmem memory region size needs to be specified in page-aligned bytes.
+     * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
+     * in the grantorDescriptor will be word aligned.
+     */
+    size_t kAshmemSizePageAligned;
+    if (bufferFd != -1) {
+        // Allocate read counter and write counter only. User-supplied memory will be used for the
+        // ringbuffer.
+        kAshmemSizePageAligned = (kMetaDataSize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+    } else {
+        // Allocate ringbuffer, read counter and write counter.
+        kAshmemSizePageAligned = (hardware::details::alignToWordBoundary(kQueueSizeBytes) +
+                                  kMetaDataSize + PAGE_SIZE - 1) &
+                                 ~(PAGE_SIZE - 1);
+    }
+
+    /*
+     * The native handle will contain the fds to be mapped.
+     */
+    int numFds = (bufferFd != -1) ? 2 : 1;
+    native_handle_t* mqHandle = native_handle_create(numFds, 0 /* numInts */);
+    if (mqHandle == nullptr) {
+        return;
+    }
+
+    /*
+     * Create an ashmem region to map the memory.
+     */
+    int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
+    ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
+    mqHandle->data[0] = ashmemFd;
+
+    if (bufferFd != -1) {
+        // Use user-supplied file descriptor for fdIndex 1
+        mqHandle->data[1] = bufferFd.get();
+        // release ownership of fd. mqHandle owns it now.
+        if (bufferFd.release() < 0) {
+            hardware::details::logError("Error releasing supplied bufferFd");
+        }
+
+        std::vector<android::hardware::GrantorDescriptor> grantors;
+        grantors.resize(configureEventFlagWord ? 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 */
+                kQueueSizeBytes,              /* memory to be allocated for data buffer */
+                sizeof(std::atomic<uint32_t>) /* memory to be allocated for EventFlag word */
+        };
+
+        for (size_t grantorPos = 0, offset = 0; grantorPos < grantors.size(); grantorPos++) {
+            uint32_t grantorFdIndex;
+            size_t grantorOffset;
+            if (grantorPos == hardware::details::DATAPTRPOS) {
+                grantorFdIndex = 1;
+                grantorOffset = 0;
+            } else {
+                grantorFdIndex = 0;
+                grantorOffset = offset;
+                offset += memSize[grantorPos];
+            }
+            grantors[grantorPos] = {
+                    0 /* grantor flags */, grantorFdIndex,
+                    static_cast<uint32_t>(hardware::details::alignToWordBoundary(grantorOffset)),
+                    memSize[grantorPos]};
+        }
+
+        mDesc = std::unique_ptr<Descriptor>(new (std::nothrow)
+                                                    Descriptor(grantors, mqHandle, sizeof(T)));
+    } else {
+        mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(
+                kQueueSizeBytes, mqHandle, sizeof(T), configureEventFlagWord));
+    }
+    if (mDesc == nullptr) {
+        native_handle_close(mqHandle);
+        native_handle_delete(mqHandle);
+        return;
+    }
+    initMemory(true);
+}
+
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
+MessageQueueBase<MQDescriptorType, T, flavor>::~MessageQueueBase() {
+    if (flavor == kUnsynchronizedWrite && mReadPtr != nullptr) {
+        delete mReadPtr;
+    } else if (mReadPtr != nullptr) {
+        unmapGrantorDescr(mReadPtr, hardware::details::READPTRPOS);
+    }
+    if (mWritePtr != nullptr) {
+        unmapGrantorDescr(mWritePtr, hardware::details::WRITEPTRPOS);
+    }
+    if (mRing != nullptr) {
+        unmapGrantorDescr(mRing, hardware::details::DATAPTRPOS);
+    }
+    if (mEvFlagWord != nullptr) {
+        unmapGrantorDescr(mEvFlagWord, hardware::details::EVFLAGWORDPOS);
+        android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
+    }
+}
+
+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, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
+bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data) {
+    return read(data, 1);
+}
+
+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, 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 == kSynchronizedReadWrite,
+                  "writeBlocking can only be used with the "
+                  "kSynchronizedReadWrite flavor.");
+    /*
+     * If evFlag is null and the FMQ does not have its own EventFlag object
+     * return false;
+     * 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.
+     */
+    if (evFlag == nullptr) {
+        evFlag = mEventFlag;
+        if (evFlag == nullptr) {
+            hardware::details::logError(
+                    "writeBlocking failed: called on MessageQueue with no Eventflag"
+                    "configured or provided");
+            return false;
+        }
+    }
+
+    if (readNotification == 0 || (count > getQuantumCount())) {
+        return false;
+    }
+
+    /*
+     * There is no need to wait for a readNotification if there is sufficient
+     * space to write is already present in the FMQ. The latter would be the case when
+     * read operations read more number of messages than write operations write.
+     * In other words, a single large read may clear the FMQ after multiple small
+     * writes. This would fail to clear a pending readNotification bit since
+     * EventFlag bits can only be cleared by a wait() call, however the bit would
+     * be correctly cleared by the next writeBlocking() call.
+     */
+
+    bool result = write(data, count);
+    if (result) {
+        if (writeNotification) {
+            evFlag->wake(writeNotification);
+        }
+        return result;
+    }
+
+    bool shouldTimeOut = timeOutNanos != 0;
+    int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
+
+    while (true) {
+        /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
+        if (shouldTimeOut) {
+            /*
+             * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
+             * to Nanoseconds)
+             */
+            int64_t currentTimeNs = android::elapsedRealtimeNano();
+            /*
+             * Decrement 'timeOutNanos' to account for the time taken to complete the last
+             * iteration of the while loop.
+             */
+            timeOutNanos -= currentTimeNs - prevTimeNanos;
+            prevTimeNanos = currentTimeNs;
+
+            if (timeOutNanos <= 0) {
+                /*
+                 * Attempt write in case a context switch happened outside of
+                 * evFlag->wait().
+                 */
+                result = write(data, count);
+                break;
+            }
+        }
+
+        /*
+         * wait() will return immediately if there was a pending read
+         * notification.
+         */
+        uint32_t efState = 0;
+        status_t status = evFlag->wait(readNotification, &efState, timeOutNanos,
+                                       true /* retry on spurious wake */);
+
+        if (status != android::TIMED_OUT && status != android::NO_ERROR) {
+            hardware::details::logError("Unexpected error code from EventFlag Wait status " +
+                                        std::to_string(status));
+            break;
+        }
+
+        if (status == android::TIMED_OUT) {
+            break;
+        }
+
+        /*
+         * If there is still insufficient space to write to the FMQ,
+         * keep waiting for another readNotification.
+         */
+        if ((efState & readNotification) && write(data, count)) {
+            result = true;
+            break;
+        }
+    }
+
+    if (result && writeNotification != 0) {
+        evFlag->wake(writeNotification);
+    }
+
+    return result;
+}
+
+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, 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 == kSynchronizedReadWrite,
+                  "readBlocking can only be used with the "
+                  "kSynchronizedReadWrite flavor.");
+
+    /*
+     * If evFlag is null and the FMQ does not own its own EventFlag object
+     * return false;
+     * If the writeNotification bit mask is zero return false;
+     * If the count is greater than queue size, return false to prevent
+     * blocking until timeOut.
+     */
+    if (evFlag == nullptr) {
+        evFlag = mEventFlag;
+        if (evFlag == nullptr) {
+            hardware::details::logError(
+                    "readBlocking failed: called on MessageQueue with no Eventflag"
+                    "configured or provided");
+            return false;
+        }
+    }
+
+    if (writeNotification == 0 || count > getQuantumCount()) {
+        return false;
+    }
+
+    /*
+     * There is no need to wait for a write notification if sufficient
+     * data to read is already present in the FMQ. This would be the
+     * case when read operations read lesser number of messages than
+     * a write operation and multiple reads would be required to clear the queue
+     * after a single write operation. This check would fail to clear a pending
+     * writeNotification bit since EventFlag bits can only be cleared
+     * by a wait() call, however the bit would be correctly cleared by the next
+     * readBlocking() call.
+     */
+
+    bool result = read(data, count);
+    if (result) {
+        if (readNotification) {
+            evFlag->wake(readNotification);
+        }
+        return result;
+    }
+
+    bool shouldTimeOut = timeOutNanos != 0;
+    int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
+
+    while (true) {
+        /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
+        if (shouldTimeOut) {
+            /*
+             * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
+             * to Nanoseconds)
+             */
+            int64_t currentTimeNs = android::elapsedRealtimeNano();
+            /*
+             * Decrement 'timeOutNanos' to account for the time taken to complete the last
+             * iteration of the while loop.
+             */
+            timeOutNanos -= currentTimeNs - prevTimeNanos;
+            prevTimeNanos = currentTimeNs;
+
+            if (timeOutNanos <= 0) {
+                /*
+                 * Attempt read in case a context switch happened outside of
+                 * evFlag->wait().
+                 */
+                result = read(data, count);
+                break;
+            }
+        }
+
+        /*
+         * wait() will return immediately if there was a pending write
+         * notification.
+         */
+        uint32_t efState = 0;
+        status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos,
+                                       true /* retry on spurious wake */);
+
+        if (status != android::TIMED_OUT && status != android::NO_ERROR) {
+            hardware::details::logError("Unexpected error code from EventFlag Wait status " +
+                                        std::to_string(status));
+            break;
+        }
+
+        if (status == android::TIMED_OUT) {
+            break;
+        }
+
+        /*
+         * If the data in FMQ is still insufficient, go back to waiting
+         * for another write notification.
+         */
+        if ((efState & writeNotification) && read(data, count)) {
+            result = true;
+            break;
+        }
+    }
+
+    if (result && readNotification != 0) {
+        evFlag->wake(readNotification);
+    }
+    return result;
+}
+
+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, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
+size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWriteBytes() const {
+    return mDesc->getSize() - availableToReadBytes();
+}
+
+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, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
+size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToRead() const {
+    return availableToReadBytes() / sizeof(T);
+}
+
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
+bool MessageQueueBase<MQDescriptorType, T, flavor>::beginWrite(size_t nMessages,
+                                                               MemTransaction* result) const {
+    /*
+     * If nMessages is greater than size of FMQ or in case of the synchronized
+     * FMQ flavor, if there is not enough space to write nMessages, then return
+     * result with null addresses.
+     */
+    if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
+        nMessages > getQuantumCount()) {
+        *result = MemTransaction();
+        return false;
+    }
+
+    auto writePtr = mWritePtr->load(std::memory_order_relaxed);
+    size_t writeOffset = writePtr % mDesc->getSize();
+
+    /*
+     * From writeOffset, the number of messages that can be written
+     * contiguously without wrapping around the ring buffer are calculated.
+     */
+    size_t contiguousMessages = (mDesc->getSize() - writeOffset) / sizeof(T);
+
+    if (contiguousMessages < nMessages) {
+        /*
+         * Wrap around is required. Both result.first and result.second are
+         * populated.
+         */
+        *result = MemTransaction(
+                MemRegion(reinterpret_cast<T*>(mRing + writeOffset), contiguousMessages),
+                MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
+    } else {
+        /*
+         * A wrap around is not required to write nMessages. Only result.first
+         * is populated.
+         */
+        *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
+                                 MemRegion());
+    }
+
+    return true;
+}
+
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
+/*
+ * Disable integer sanitization since integer overflow here is allowed
+ * and legal.
+ */
+__attribute__((no_sanitize("integer"))) bool
+MessageQueueBase<MQDescriptorType, T, flavor>::commitWrite(size_t nMessages) {
+    size_t nBytesWritten = nMessages * sizeof(T);
+    auto writePtr = mWritePtr->load(std::memory_order_relaxed);
+    writePtr += nBytesWritten;
+    mWritePtr->store(writePtr, std::memory_order_release);
+    /*
+     * This method cannot fail now since we are only incrementing the writePtr
+     * counter.
+     */
+    return true;
+}
+
+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
+     * hence requires a memory_order_acquired load for both mReadPtr and
+     * mWritePtr.
+     */
+    return mWritePtr->load(std::memory_order_acquire) - mReadPtr->load(std::memory_order_acquire);
+}
+
+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, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
+/*
+ * Disable integer sanitization since integer overflow here is allowed
+ * and legal.
+ */
+__attribute__((no_sanitize("integer"))) bool
+MessageQueueBase<MQDescriptorType, T, flavor>::beginRead(size_t nMessages,
+                                                         MemTransaction* result) const {
+    *result = MemTransaction();
+    /*
+     * If it is detected that the data in the queue was overwritten
+     * due to the reader process being too slow, the read pointer counter
+     * is set to the same as the write pointer counter to indicate error
+     * and the read returns false;
+     * Need acquire/release memory ordering for mWritePtr.
+     */
+    auto writePtr = mWritePtr->load(std::memory_order_acquire);
+    /*
+     * A relaxed load is sufficient for mReadPtr since there will be no
+     * stores to mReadPtr from a different thread.
+     */
+    auto readPtr = mReadPtr->load(std::memory_order_relaxed);
+
+    if (writePtr - readPtr > mDesc->getSize()) {
+        mReadPtr->store(writePtr, std::memory_order_release);
+        return false;
+    }
+
+    size_t nBytesDesired = nMessages * sizeof(T);
+    /*
+     * Return if insufficient data to read in FMQ.
+     */
+    if (writePtr - readPtr < nBytesDesired) {
+        return false;
+    }
+
+    size_t readOffset = readPtr % mDesc->getSize();
+    /*
+     * From readOffset, the number of messages that can be read contiguously
+     * without wrapping around the ring buffer are calculated.
+     */
+    size_t contiguousMessages = (mDesc->getSize() - readOffset) / sizeof(T);
+
+    if (contiguousMessages < nMessages) {
+        /*
+         * A wrap around is required. Both result.first and result.second
+         * are populated.
+         */
+        *result = MemTransaction(
+                MemRegion(reinterpret_cast<T*>(mRing + readOffset), contiguousMessages),
+                MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
+    } else {
+        /*
+         * A wrap around is not required. Only result.first need to be
+         * populated.
+         */
+        *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
+                                 MemRegion());
+    }
+
+    return true;
+}
+
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
+/*
+ * Disable integer sanitization since integer overflow here is allowed
+ * and legal.
+ */
+__attribute__((no_sanitize("integer"))) bool
+MessageQueueBase<MQDescriptorType, T, flavor>::commitRead(size_t nMessages) {
+    // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
+    auto readPtr = mReadPtr->load(std::memory_order_relaxed);
+    auto writePtr = mWritePtr->load(std::memory_order_acquire);
+    /*
+     * If the flavor is unsynchronized, it is possible that a write overflow may
+     * have occurred between beginRead() and commitRead().
+     */
+    if (writePtr - readPtr > mDesc->getSize()) {
+        mReadPtr->store(writePtr, std::memory_order_release);
+        return false;
+    }
+
+    size_t nBytesRead = nMessages * sizeof(T);
+    readPtr += nBytesRead;
+    mReadPtr->store(readPtr, std::memory_order_release);
+    return true;
+}
+
+template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
+size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumSize() const {
+    return mDesc->getQuantum();
+}
+
+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, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
+bool MessageQueueBase<MQDescriptorType, T, flavor>::isValid() const {
+    return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
+}
+
+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();
+    if (handle == nullptr) {
+        hardware::details::logError("mDesc->handle is null");
+        return nullptr;
+    }
+
+    if (grantorIdx >= grantors.size()) {
+        hardware::details::logError(std::string("grantorIdx must be less than ") +
+                                    std::to_string(grantors.size()));
+        return nullptr;
+    }
+
+    int fdIndex = grantors[grantorIdx].fdIndex;
+    /*
+     * Offset for mmap must be a multiple of PAGE_SIZE.
+     */
+    int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
+    int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
+
+    void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED, handle->data[fdIndex],
+                         mapOffset);
+    if (address == MAP_FAILED) {
+        hardware::details::logError(std::string("mmap failed: ") + std::to_string(errno));
+        return nullptr;
+    }
+    return reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
+}
+
+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();
+    if ((address == nullptr) || (grantorIdx >= grantors.size())) {
+        return;
+    }
+
+    int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
+    int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
+    void* baseAddress =
+            reinterpret_cast<uint8_t*>(address) - (grantors[grantorIdx].offset - mapOffset);
+    if (baseAddress) munmap(baseAddress, mapLength);
+}
+
+}  // namespace hardware
diff --git a/tests/Android.bp b/tests/Android.bp
index b85aa16..ec38cea 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -14,14 +14,36 @@
 // limitations under the License.
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+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"],
+    test_options: {
+        unit_test: false,
+    },
+}
+
 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,32 +52,58 @@
         "libhidlbase",
         "liblog",
         "libutils",
+        "libbinder_ndk",
+    ],
+
+    // These are static libs only for testing purposes and portability. Shared
+    // libs should be used on device.
+    static_libs: [
+        "android.hardware.common-V2-ndk_platform",
+        "android.hardware.common.fmq-V1-ndk_platform",
+        "android.hardware.tests.msgq@1.0",
+        "android.fmq.test-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 {
+    name: "fmq_unit_tests",
+
+    srcs: ["fmq_unit_tests.cpp"],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libutils",
     ],
-
-    // 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"],
-}
-
-cc_test {
-    name: "mq_test",
-
-    srcs: ["mq_test.cpp"],
-    shared_libs: [
-        "libbase",
-        "libcutils",
-        "libfmq",
-        "libhidlbase",
-        "liblog",
-        "libutils",
+    static_libs: [
+        "android.hardware.common.fmq-V1-ndk_platform",
     ],
 
     cflags: [
         "-Wall",
         "-Werror",
     ],
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
 }
diff --git a/tests/Android.mk b/tests/Android.mk
deleted file mode 100644
index 6efe7c2..0000000
--- a/tests/Android.mk
+++ /dev/null
@@ -1,39 +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 :=                           \
-    mq_test_client                                  \
-    android.hardware.tests.msgq@1.0-service-test    \
-    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$(TARGET_2ND_ARCH_MODULE_SUFFIX)
-LOCAL_REQUIRED_MODULES += mq_test_client$(TARGET_2ND_ARCH_MODULE_SUFFIX)
-endif
-
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := VtsFmqUnitTests
--include test/vts/tools/build/Android.host_config.mk
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..c5010ce
--- /dev/null
+++ b/tests/aidl/Android.bp
@@ -0,0 +1,29 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.fmq.test",
+    host_supported: true,
+    vendor_available: true,
+    unstable: true,
+    srcs: [
+        "android/fmq/test/*.aidl",
+    ],
+    imports: [
+        "android.hardware.common",
+        "android.hardware.common.fmq",
+    ],
+    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..7f1f8b7
--- /dev/null
+++ b/tests/aidl/android/fmq/test/ITestAidlMsgQ.aidl
@@ -0,0 +1,122 @@
+/*
+ * 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.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.hardware.common.fmq.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 userFd True to initialize the message queue with a user supplied
+     * file descriptor for the ring buffer.
+     * False to let the message queue use a single FD for everything.
+     *
+     * @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, in boolean userFd,
+        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..71a5533
--- /dev/null
+++ b/tests/aidl/default/Android.bp
@@ -0,0 +1,19 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
+    name: "android.fmq.test-impl",
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libfmq",
+    ],
+    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..485e75b
--- /dev/null
+++ b/tests/aidl/default/TestAidlMsgQ.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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, bool userFd, MQDescriptor<int32_t, UnsynchronizedWrite>* mqDesc,
+        bool* _aidl_return) {
+    if (configureFmq) {
+        static constexpr size_t kNumElementsInQueue = 1024;
+        static constexpr size_t kElementSizeBytes = sizeof(int32_t);
+        ::android::base::unique_fd ringbufferFd;
+        if (userFd) {
+            ringbufferFd.reset(
+                    ::ashmem_create_region("UnsyncWrite", kNumElementsInQueue * kElementSizeBytes));
+        }
+        mFmqUnsynchronized.reset(new (std::nothrow) TestAidlMsgQ::MessageQueueUnsync(
+                kNumElementsInQueue, false, std::move(ringbufferFd),
+                kNumElementsInQueue * kElementSizeBytes));
+    }
+
+    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..6e7c859
--- /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::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::common::fmq::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, bool userFd,
+                                         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 02683c9..0000000
--- a/tests/fmq_test
+++ /dev/null
@@ -1,9 +0,0 @@
-source /data/nativetest64/hidl_test_helper
-
-TREBLE_TESTING_OVERRIDE=true 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
new file mode 100644
index 0000000..be866ec
--- /dev/null
+++ b/tests/fmq_unit_tests.cpp
@@ -0,0 +1,1147 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <asm-generic/mman.h>
+#include <fmq/AidlMessageQueue.h>
+#include <fmq/ConvertMQDescriptors.h>
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+#include <gtest/gtest-death-test.h>
+#include <gtest/gtest.h>
+#include <sys/resource.h>
+#include <atomic>
+#include <cstdlib>
+#include <sstream>
+#include <thread>
+
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::hardware::common::fmq::UnsynchronizedWrite;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::kUnsynchronizedWrite;
+
+enum EventFlagBits : uint32_t {
+    kFmqNotEmpty = 1 << 0,
+    kFmqNotFull = 1 << 1,
+};
+
+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;
+
+typedef android::hardware::MessageQueue<uint8_t, kSynchronizedReadWrite> MessageQueueSync8;
+typedef android::hardware::MQDescriptor<uint8_t, kSynchronizedReadWrite> HidlMQDescSync8;
+typedef android::AidlMessageQueue<int8_t, SynchronizedReadWrite> AidlMessageQueueSync8;
+typedef aidl::android::hardware::common::fmq::MQDescriptor<int8_t, SynchronizedReadWrite>
+        AidlMQDescSync8;
+typedef android::hardware::MessageQueue<uint8_t, kUnsynchronizedWrite> MessageQueueUnsync8;
+typedef android::hardware::MQDescriptor<uint8_t, kUnsynchronizedWrite> HidlMQDescUnsync8;
+typedef android::AidlMessageQueue<int8_t, UnsynchronizedWrite> AidlMessageQueueUnsync8;
+typedef aidl::android::hardware::common::fmq::MQDescriptor<int8_t, UnsynchronizedWrite>
+        AidlMQDescUnsync8;
+
+enum class SetupType {
+    SINGLE_FD,
+    DOUBLE_FD,
+};
+
+template <typename T, SetupType setupType>
+class TestParamTypes {
+  public:
+    typedef T MQType;
+    static constexpr SetupType Setup = setupType;
+};
+
+// Run everything on both the AIDL and HIDL versions with one and two FDs
+typedef ::testing::Types<TestParamTypes<AidlMessageQueueSync, SetupType::SINGLE_FD>,
+                         TestParamTypes<MessageQueueSync, SetupType::SINGLE_FD>,
+                         TestParamTypes<AidlMessageQueueSync, SetupType::DOUBLE_FD>,
+                         TestParamTypes<MessageQueueSync, SetupType::DOUBLE_FD>>
+        SyncTypes;
+typedef ::testing::Types<TestParamTypes<AidlMessageQueueUnsync, SetupType::SINGLE_FD>,
+                         TestParamTypes<MessageQueueUnsync, SetupType::SINGLE_FD>,
+                         TestParamTypes<AidlMessageQueueUnsync, SetupType::DOUBLE_FD>,
+                         TestParamTypes<MessageQueueUnsync, SetupType::DOUBLE_FD>>
+        UnsyncTypes;
+typedef ::testing::Types<TestParamTypes<AidlMessageQueueSync16, SetupType::SINGLE_FD>,
+                         TestParamTypes<MessageQueueSync16, SetupType::SINGLE_FD>,
+                         TestParamTypes<AidlMessageQueueSync16, SetupType::DOUBLE_FD>,
+                         TestParamTypes<MessageQueueSync16, SetupType::DOUBLE_FD>>
+        BadConfigTypes;
+
+template <typename T>
+class TestBase : public ::testing::Test {
+  public:
+    static void ReaderThreadBlocking(typename T::MQType* fmq, std::atomic<uint32_t>* fwAddr);
+    static void ReaderThreadBlocking2(typename T::MQType* 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;
+        static constexpr size_t kPayloadSizeBytes = 1;
+        if (T::Setup == SetupType::SINGLE_FD) {
+            mQueue = new (std::nothrow) typename T::MQType(kNumElementsInQueue);
+        } else {
+            android::base::unique_fd ringbufferFd(::ashmem_create_region(
+                    "SyncReadWrite", kNumElementsInQueue * kPayloadSizeBytes));
+            mQueue = new (std::nothrow)
+                    typename T::MQType(kNumElementsInQueue, false, std::move(ringbufferFd),
+                                       kNumElementsInQueue * kPayloadSizeBytes);
+        }
+        ASSERT_NE(nullptr, mQueue);
+        ASSERT_TRUE(mQueue->isValid());
+        mNumMessagesMax = mQueue->getQuantumCount();
+        ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
+    }
+
+    typename T::MQType* mQueue = nullptr;
+    size_t mNumMessagesMax = 0;
+};
+
+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;
+        static constexpr size_t kPayloadSizeBytes = 1;
+        if (T::Setup == SetupType::SINGLE_FD) {
+            mQueue = new (std::nothrow) typename T::MQType(kNumElementsInQueue);
+        } else {
+            android::base::unique_fd ringbufferFd(
+                    ::ashmem_create_region("UnsyncWrite", kNumElementsInQueue * kPayloadSizeBytes));
+            mQueue = new (std::nothrow)
+                    typename T::MQType(kNumElementsInQueue, false, std::move(ringbufferFd),
+                                       kNumElementsInQueue * kPayloadSizeBytes);
+        }
+        ASSERT_NE(nullptr, mQueue);
+        ASSERT_TRUE(mQueue->isValid());
+        mNumMessagesMax = mQueue->getQuantumCount();
+        ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
+    }
+
+    typename T::MQType* mQueue = nullptr;
+    size_t mNumMessagesMax = 0;
+};
+
+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;
+        static constexpr size_t kPayloadSizeBytes = 1;
+        if (T::Setup == SetupType::SINGLE_FD) {
+            mQueue = new (std::nothrow) typename T::MQType(kNumElementsInQueue);
+        } else {
+            android::base::unique_fd ringbufferFd(::ashmem_create_region(
+                    "SyncBlockingReadWrite", kNumElementsInQueue * kPayloadSizeBytes));
+            mQueue = new (std::nothrow)
+                    typename T::MQType(kNumElementsInQueue, false, std::move(ringbufferFd),
+                                       kNumElementsInQueue * kPayloadSizeBytes);
+        }
+        ASSERT_NE(nullptr, mQueue);
+        ASSERT_TRUE(mQueue->isValid());
+        mNumMessagesMax = mQueue->getQuantumCount();
+        ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
+        /*
+         * Initialize the EventFlag word to indicate Queue is not full.
+         */
+        std::atomic_init(&mFw, static_cast<uint32_t>(kFmqNotFull));
+    }
+
+    typename T::MQType* mQueue;
+    std::atomic<uint32_t> mFw;
+    size_t mNumMessagesMax = 0;
+};
+
+TYPED_TEST_CASE(QueueSizeOdd, SyncTypes);
+
+template <typename T>
+class QueueSizeOdd : public TestBase<T> {
+  protected:
+    virtual void TearDown() { delete mQueue; }
+    virtual void SetUp() {
+        static constexpr size_t kNumElementsInQueue = 2049;
+        static constexpr size_t kPayloadSizeBytes = 1;
+        if (T::Setup == SetupType::SINGLE_FD) {
+            mQueue = new (std::nothrow)
+                    typename T::MQType(kNumElementsInQueue, true /* configureEventFlagWord */);
+        } else {
+            android::base::unique_fd ringbufferFd(
+                    ::ashmem_create_region("SyncSizeOdd", kNumElementsInQueue * kPayloadSizeBytes));
+            mQueue = new (std::nothrow) typename T::MQType(
+                    kNumElementsInQueue, true /* configureEventFlagWord */, std::move(ringbufferFd),
+                    kNumElementsInQueue * kPayloadSizeBytes);
+        }
+        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));
+    }
+
+    typename T::MQType* mQueue;
+    size_t mNumMessagesMax = 0;
+};
+
+TYPED_TEST_CASE(BadQueueConfig, BadConfigTypes);
+
+template <typename T>
+class BadQueueConfig : public TestBase<T> {};
+
+class AidlOnlyBadQueueConfig : public ::testing::Test {};
+class Hidl2AidlOperation : public ::testing::Test {};
+class DoubleFdFailures : public ::testing::Test {};
+
+/*
+ * Utility function to initialize data to be written to the FMQ
+ */
+inline void initData(uint8_t* data, size_t count) {
+    for (size_t i = 0; i < count; i++) {
+        data[i] = i & 0xFF;
+    }
+}
+
+/*
+ * This thread will attempt to read and block. When wait returns
+ * it checks if the kFmqNotEmpty bit is actually set.
+ * If the read is succesful, it signals Wake to kFmqNotFull.
+ */
+template <typename T>
+void TestBase<T>::ReaderThreadBlocking(typename T::MQType* fmq, std::atomic<uint32_t>* fwAddr) {
+    const size_t dataLen = 64;
+    uint8_t data[dataLen];
+    android::hardware::EventFlag* efGroup = nullptr;
+    android::status_t status = android::hardware::EventFlag::createEventFlag(fwAddr, &efGroup);
+    ASSERT_EQ(android::NO_ERROR, status);
+    ASSERT_NE(nullptr, efGroup);
+
+    while (true) {
+        uint32_t efState = 0;
+        android::status_t ret = efGroup->wait(kFmqNotEmpty,
+                                              &efState,
+                                              5000000000 /* timeoutNanoSeconds */);
+        /*
+         * Wait should not time out here after 5s
+         */
+        ASSERT_NE(android::TIMED_OUT, ret);
+
+        if ((efState & kFmqNotEmpty) && fmq->read(data, dataLen)) {
+            efGroup->wake(kFmqNotFull);
+            break;
+        }
+    }
+
+    status = android::hardware::EventFlag::deleteEventFlag(&efGroup);
+    ASSERT_EQ(android::NO_ERROR, status);
+}
+
+/*
+ * This thread will attempt to read and block using the readBlocking() API and
+ * passes in a pointer to an EventFlag object.
+ */
+template <typename T>
+void TestBase<T>::ReaderThreadBlocking2(typename T::MQType* fmq, std::atomic<uint32_t>* fwAddr) {
+    const size_t dataLen = 64;
+    uint8_t data[dataLen];
+    android::hardware::EventFlag* efGroup = nullptr;
+    android::status_t status = android::hardware::EventFlag::createEventFlag(fwAddr, &efGroup);
+    ASSERT_EQ(android::NO_ERROR, status);
+    ASSERT_NE(nullptr, efGroup);
+    bool ret = fmq->readBlocking(data,
+                                 dataLen,
+                                 static_cast<uint32_t>(kFmqNotFull),
+                                 static_cast<uint32_t>(kFmqNotEmpty),
+                                 5000000000 /* timeOutNanos */,
+                                 efGroup);
+    ASSERT_TRUE(ret);
+    status = android::hardware::EventFlag::deleteEventFlag(&efGroup);
+    ASSERT_EQ(android::NO_ERROR, status);
+}
+
+TYPED_TEST(BadQueueConfig, QueueSizeTooLarge) {
+    size_t numElementsInQueue = SIZE_MAX / sizeof(uint16_t) + 1;
+    typename TypeParam::MQType* fmq =
+            new (std::nothrow) typename TypeParam::MQType(numElementsInQueue);
+    ASSERT_NE(nullptr, fmq);
+    /*
+     * Should fail due to size being too large to fit into size_t.
+     */
+    ASSERT_FALSE(fmq->isValid());
+}
+
+// If this test fails and we do leak FDs, the next test will cause a crash
+TEST_F(AidlOnlyBadQueueConfig, LookForLeakedFds) {
+    size_t numElementsInQueue = SIZE_MAX / sizeof(uint32_t) - PAGE_SIZE - 1;
+    struct rlimit rlim;
+    ASSERT_EQ(getrlimit(RLIMIT_NOFILE, &rlim), 0);
+    for (int i = 0; i <= rlim.rlim_cur + 1; i++) {
+        android::AidlMessageQueue<uint32_t, SynchronizedReadWrite> fmq(numElementsInQueue);
+        ASSERT_FALSE(fmq.isValid());
+    }
+    // try to get another FD
+    int fd = ashmem_create_region("test", 100);
+    ASSERT_NE(fd, -1);
+    close(fd);
+}
+
+TEST_F(Hidl2AidlOperation, ConvertDescriptorsSync) {
+    size_t numElementsInQueue = 64;
+
+    // Create HIDL side and get MQDescriptor
+    MessageQueueSync8* fmq = new (std::nothrow) MessageQueueSync8(numElementsInQueue);
+    ASSERT_NE(nullptr, fmq);
+    ASSERT_TRUE(fmq->isValid());
+    const HidlMQDescSync8* hidlDesc = fmq->getDesc();
+    ASSERT_NE(nullptr, hidlDesc);
+
+    // Create AIDL MQDescriptor to send to another process based off the HIDL MQDescriptor
+    AidlMQDescSync8 aidlDesc;
+    android::unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, SynchronizedReadWrite>(*hidlDesc,
+                                                                                  &aidlDesc);
+
+    // Other process will create the other side of the queue using the AIDL MQDescriptor
+    AidlMessageQueueSync8* aidlFmq = new (std::nothrow) AidlMessageQueueSync8(aidlDesc);
+    ASSERT_NE(nullptr, aidlFmq);
+    ASSERT_TRUE(aidlFmq->isValid());
+
+    // Make sure a write to the HIDL side, will show up for the AIDL side
+    constexpr size_t dataLen = 4;
+    uint8_t data[dataLen] = {12, 11, 10, 9};
+    fmq->write(data, dataLen);
+
+    int8_t readData[dataLen];
+    ASSERT_TRUE(aidlFmq->read(readData, dataLen));
+
+    ASSERT_EQ(data[0], readData[0]);
+    ASSERT_EQ(data[1], readData[1]);
+    ASSERT_EQ(data[2], readData[2]);
+    ASSERT_EQ(data[3], readData[3]);
+}
+
+TEST_F(Hidl2AidlOperation, ConvertDescriptorsUnsync) {
+    size_t numElementsInQueue = 64;
+
+    // Create HIDL side and get MQDescriptor
+    MessageQueueUnsync8* fmq = new (std::nothrow) MessageQueueUnsync8(numElementsInQueue);
+    ASSERT_NE(nullptr, fmq);
+    ASSERT_TRUE(fmq->isValid());
+    const HidlMQDescUnsync8* hidlDesc = fmq->getDesc();
+    ASSERT_NE(nullptr, hidlDesc);
+
+    // Create AIDL MQDescriptor to send to another process based off the HIDL MQDescriptor
+    AidlMQDescUnsync8 aidlDesc;
+    android::unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, UnsynchronizedWrite>(*hidlDesc,
+                                                                                &aidlDesc);
+
+    // Other process will create the other side of the queue using the AIDL MQDescriptor
+    AidlMessageQueueUnsync8* aidlFmq = new (std::nothrow) AidlMessageQueueUnsync8(aidlDesc);
+    ASSERT_NE(nullptr, aidlFmq);
+    ASSERT_TRUE(aidlFmq->isValid());
+
+    // Can have multiple readers with unsync flavor
+    AidlMessageQueueUnsync8* aidlFmq2 = new (std::nothrow) AidlMessageQueueUnsync8(aidlDesc);
+    ASSERT_NE(nullptr, aidlFmq2);
+    ASSERT_TRUE(aidlFmq2->isValid());
+
+    // Make sure a write to the HIDL side, will show up for the AIDL side
+    constexpr size_t dataLen = 4;
+    uint8_t data[dataLen] = {12, 11, 10, 9};
+    fmq->write(data, dataLen);
+
+    int8_t readData[dataLen];
+    ASSERT_TRUE(aidlFmq->read(readData, dataLen));
+    int8_t readData2[dataLen];
+    ASSERT_TRUE(aidlFmq2->read(readData2, dataLen));
+
+    ASSERT_EQ(data[0], readData[0]);
+    ASSERT_EQ(data[1], readData[1]);
+    ASSERT_EQ(data[2], readData[2]);
+    ASSERT_EQ(data[3], readData[3]);
+    ASSERT_EQ(data[0], readData2[0]);
+    ASSERT_EQ(data[1], readData2[1]);
+    ASSERT_EQ(data[2], readData2[2]);
+    ASSERT_EQ(data[3], readData2[3]);
+}
+
+TEST_F(Hidl2AidlOperation, ConvertFdIndex1) {
+    native_handle_t* mqHandle = native_handle_create(2 /* numFds */, 0 /* numInts */);
+    if (mqHandle == nullptr) {
+        return;
+    }
+    mqHandle->data[0] = 12;
+    mqHandle->data[1] = 5;
+    ::android::hardware::hidl_vec<android::hardware::GrantorDescriptor> grantors;
+    grantors.resize(3);
+    grantors[0] = {0, 1 /* fdIndex */, 16, 16};
+    grantors[1] = {0, 1 /* fdIndex */, 16, 16};
+    grantors[2] = {0, 1 /* fdIndex */, 16, 16};
+
+    HidlMQDescUnsync8* hidlDesc = new (std::nothrow) HidlMQDescUnsync8(grantors, mqHandle, 10);
+    ASSERT_TRUE(hidlDesc->isHandleValid());
+
+    AidlMQDescUnsync8 aidlDesc;
+    bool ret = android::unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, UnsynchronizedWrite>(
+            *hidlDesc, &aidlDesc);
+    ASSERT_TRUE(ret);
+}
+
+TEST_F(Hidl2AidlOperation, ConvertMultipleFds) {
+    native_handle_t* mqHandle = native_handle_create(2 /* numFds */, 0 /* numInts */);
+    if (mqHandle == nullptr) {
+        return;
+    }
+    mqHandle->data[0] = ::ashmem_create_region("ConvertMultipleFds", 8);
+    mqHandle->data[1] = ::ashmem_create_region("ConvertMultipleFds2", 8);
+    ::android::hardware::hidl_vec<android::hardware::GrantorDescriptor> grantors;
+    grantors.resize(3);
+    grantors[0] = {0, 1 /* fdIndex */, 16, 16};
+    grantors[1] = {0, 1 /* fdIndex */, 16, 16};
+    grantors[2] = {0, 0 /* fdIndex */, 16, 16};
+
+    HidlMQDescUnsync8* hidlDesc = new (std::nothrow) HidlMQDescUnsync8(grantors, mqHandle, 10);
+    ASSERT_TRUE(hidlDesc->isHandleValid());
+
+    AidlMQDescUnsync8 aidlDesc;
+    bool ret = android::unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, UnsynchronizedWrite>(
+            *hidlDesc, &aidlDesc);
+    ASSERT_TRUE(ret);
+    EXPECT_EQ(aidlDesc.handle.fds.size(), 2);
+    native_handle_close(mqHandle);
+    native_handle_delete(mqHandle);
+}
+
+// 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::fmq::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::fmq::MQDescriptor<uint16_t, SynchronizedReadWrite> desc;
+    desc.quantum = 2;
+    desc.flags = 0;
+    desc.grantors.push_back(
+            aidl::android::hardware::common::fmq::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::fmq::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 creating a new queue with an invalid fd. This should assert with message
+ * "mRing is null".
+ */
+TEST_F(DoubleFdFailures, InvalidFd) {
+    EXPECT_DEATH_IF_SUPPORTED(AidlMessageQueueSync(64, false, android::base::unique_fd(3000), 64),
+                              "mRing is null");
+}
+
+/*
+ * Test creating a new queue with a buffer fd and bufferSize smaller than the
+ * requested queue. This should fail to create a valid message queue.
+ */
+TEST_F(DoubleFdFailures, InvalidFdSize) {
+    constexpr size_t kNumElementsInQueue = 1024;
+    constexpr size_t kRequiredDataBufferSize = kNumElementsInQueue * sizeof(uint16_t);
+    android::base::unique_fd ringbufferFd(
+            ::ashmem_create_region("SyncReadWrite", kRequiredDataBufferSize - 8));
+    AidlMessageQueueSync16 fmq = AidlMessageQueueSync16(
+            kNumElementsInQueue, false, std::move(ringbufferFd), kRequiredDataBufferSize - 8);
+    EXPECT_FALSE(fmq.isValid());
+}
+
+/*
+ * Test creating a new queue with a buffer fd and bufferSize larger than the
+ * requested queue. The message queue should be valid.
+ */
+TEST_F(DoubleFdFailures, LargerFdSize) {
+    constexpr size_t kNumElementsInQueue = 1024;
+    constexpr size_t kRequiredDataBufferSize = kNumElementsInQueue * sizeof(uint16_t);
+    android::base::unique_fd ringbufferFd(
+            ::ashmem_create_region("SyncReadWrite", kRequiredDataBufferSize + 8));
+    AidlMessageQueueSync16 fmq = AidlMessageQueueSync16(
+            kNumElementsInQueue, false, std::move(ringbufferFd), kRequiredDataBufferSize + 8);
+    EXPECT_TRUE(fmq.isValid());
+}
+
+/*
+ * Test that basic blocking works. This test uses the non-blocking read()/write()
+ * APIs.
+ */
+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(&this->mFw, &efGroup);
+
+    ASSERT_EQ(android::NO_ERROR, status);
+    ASSERT_NE(nullptr, efGroup);
+
+    /*
+     * Start a thread that will try to read and block on kFmqNotEmpty.
+     */
+    std::thread Reader(BlockingReadWrites<TypeParam>::ReaderThreadBlocking, this->mQueue,
+                       &this->mFw);
+    struct timespec waitTime = {0, 100 * 1000000};
+    ASSERT_EQ(0, nanosleep(&waitTime, NULL));
+
+    /*
+     * After waiting for some time write into the FMQ
+     * and call Wake on kFmqNotEmpty.
+     */
+    ASSERT_TRUE(this->mQueue->write(data, dataLen));
+    status = efGroup->wake(kFmqNotEmpty);
+    ASSERT_EQ(android::NO_ERROR, status);
+
+    ASSERT_EQ(0, nanosleep(&waitTime, NULL));
+    Reader.join();
+
+    status = android::hardware::EventFlag::deleteEventFlag(&efGroup);
+    ASSERT_EQ(android::NO_ERROR, status);
+}
+
+/*
+ * Test that basic blocking works. This test uses the
+ * writeBlocking()/readBlocking() APIs.
+ */
+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(&this->mFw, &efGroup);
+
+    ASSERT_EQ(android::NO_ERROR, status);
+    ASSERT_NE(nullptr, efGroup);
+
+    /*
+     * 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(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();
+
+    status = android::hardware::EventFlag::deleteEventFlag(&efGroup);
+    ASSERT_EQ(android::NO_ERROR, status);
+}
+
+/*
+ * Test that basic blocking times out as intended.
+ */
+TYPED_TEST(BlockingReadWrites, BlockingTimeOutTest) {
+    android::hardware::EventFlag* efGroup = nullptr;
+    android::status_t status = android::hardware::EventFlag::createEventFlag(&this->mFw, &efGroup);
+
+    ASSERT_EQ(android::NO_ERROR, status);
+    ASSERT_NE(nullptr, efGroup);
+
+    /* Block on an EventFlag bit that no one will wake and time out in 1s */
+    uint32_t efState = 0;
+    android::status_t ret = efGroup->wait(kFmqNotEmpty,
+                                          &efState,
+                                          1000000000 /* timeoutNanoSeconds */);
+    /*
+     * Wait should time out in a second.
+     */
+    EXPECT_EQ(android::TIMED_OUT, ret);
+
+    status = android::hardware::EventFlag::deleteEventFlag(&efGroup);
+    ASSERT_EQ(android::NO_ERROR, status);
+}
+
+/*
+ * Test that odd queue sizes do not cause unaligned error
+ * on access to EventFlag object.
+ */
+TYPED_TEST(QueueSizeOdd, EventFlagTest) {
+    const size_t dataLen = 64;
+    uint8_t data[dataLen] = {0};
+
+    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.
+ */
+TYPED_TEST(SynchronizedReadWrites, SmallInputTest1) {
+    const size_t dataLen = 16;
+    ASSERT_LE(dataLen, this->mNumMessagesMax);
+    uint8_t data[dataLen];
+
+    initData(data, dataLen);
+
+    ASSERT_TRUE(this->mQueue->write(data, dataLen));
+    uint8_t readData[dataLen] = {};
+    ASSERT_TRUE(this->mQueue->read(readData, dataLen));
+    ASSERT_EQ(0, memcmp(data, readData, dataLen));
+}
+
+/*
+ * Verify that a few bytes of data can be successfully written and read using
+ * beginRead/beginWrite/CommitRead/CommitWrite
+ */
+TYPED_TEST(SynchronizedReadWrites, SmallInputTest2) {
+    const size_t dataLen = 16;
+    ASSERT_LE(dataLen, this->mNumMessagesMax);
+    uint8_t data[dataLen];
+
+    initData(data, dataLen);
+
+    typename TypeParam::MQType::MemTransaction tx;
+    ASSERT_TRUE(this->mQueue->beginWrite(dataLen, &tx));
+
+    ASSERT_TRUE(tx.copyTo(data, 0 /* startIdx */, dataLen));
+
+    ASSERT_TRUE(this->mQueue->commitWrite(dataLen));
+
+    uint8_t readData[dataLen] = {};
+
+    ASSERT_TRUE(this->mQueue->beginRead(dataLen, &tx));
+
+    ASSERT_TRUE(tx.copyFrom(readData, 0 /* startIdx */, dataLen));
+
+    ASSERT_TRUE(this->mQueue->commitRead(dataLen));
+
+    ASSERT_EQ(0, memcmp(data, readData, dataLen));
+}
+
+/*
+ * Verify that a few bytes of data can be successfully written and read using
+ * beginRead/beginWrite/CommitRead/CommitWrite as well as getSlot().
+ */
+TYPED_TEST(SynchronizedReadWrites, SmallInputTest3) {
+    const size_t dataLen = 16;
+    ASSERT_LE(dataLen, this->mNumMessagesMax);
+    uint8_t data[dataLen];
+
+    initData(data, dataLen);
+    typename TypeParam::MQType::MemTransaction tx;
+    ASSERT_TRUE(this->mQueue->beginWrite(dataLen, &tx));
+
+    auto first = tx.getFirstRegion();
+    auto second = tx.getSecondRegion();
+
+    ASSERT_EQ(first.getLength() + second.getLength(),  dataLen);
+    for (size_t i = 0; i < dataLen; i++) {
+        uint8_t* ptr = tx.getSlot(i);
+        *ptr = data[i];
+    }
+
+    ASSERT_TRUE(this->mQueue->commitWrite(dataLen));
+
+    uint8_t readData[dataLen] = {};
+
+    ASSERT_TRUE(this->mQueue->beginRead(dataLen, &tx));
+
+    first = tx.getFirstRegion();
+    second = tx.getSecondRegion();
+
+    ASSERT_EQ(first.getLength() + second.getLength(),  dataLen);
+
+    for (size_t i = 0; i < dataLen; i++) {
+        uint8_t* ptr = tx.getSlot(i);
+        readData[i] = *ptr;
+    }
+
+    ASSERT_TRUE(this->mQueue->commitRead(dataLen));
+
+    ASSERT_EQ(0, memcmp(data, readData, dataLen));
+}
+
+/*
+ * Verify that read() returns false when trying to read from an empty queue.
+ */
+TYPED_TEST(SynchronizedReadWrites, ReadWhenEmpty1) {
+    ASSERT_EQ(0UL, this->mQueue->availableToRead());
+    const size_t dataLen = 2;
+    ASSERT_LE(dataLen, this->mNumMessagesMax);
+    uint8_t 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.
+ */
+TYPED_TEST(SynchronizedReadWrites, ReadWhenEmpty2) {
+    ASSERT_EQ(0UL, this->mQueue->availableToRead());
+    const size_t dataLen = 2;
+    ASSERT_LE(dataLen, this->mNumMessagesMax);
+
+    typename TypeParam::MQType::MemTransaction tx;
+    ASSERT_FALSE(this->mQueue->beginRead(dataLen, &tx));
+
+    auto first = tx.getFirstRegion();
+    auto second = tx.getSecondRegion();
+
+    ASSERT_EQ(nullptr, first.getAddress());
+    ASSERT_EQ(nullptr, second.getAddress());
+}
+
+/*
+ * Write the queue until full. Verify that another write is unsuccessful.
+ * Verify that availableToWrite() returns 0 as expected.
+ */
+TYPED_TEST(SynchronizedReadWrites, WriteWhenFull1) {
+    ASSERT_EQ(0UL, this->mQueue->availableToRead());
+    std::vector<uint8_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_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);
+}
+
+/*
+ * Write the queue until full. Verify that beginWrite() returns
+ * a MemTransaction object with null base pointers.
+ */
+TYPED_TEST(SynchronizedReadWrites, WriteWhenFull2) {
+    ASSERT_EQ(0UL, this->mQueue->availableToRead());
+    std::vector<uint8_t> data(this->mNumMessagesMax);
+
+    initData(&data[0], this->mNumMessagesMax);
+    ASSERT_TRUE(this->mQueue->write(&data[0], this->mNumMessagesMax));
+    ASSERT_EQ(0UL, this->mQueue->availableToWrite());
+
+    typename TypeParam::MQType::MemTransaction tx;
+    ASSERT_FALSE(this->mQueue->beginWrite(1, &tx));
+
+    auto first = tx.getFirstRegion();
+    auto second = tx.getSecondRegion();
+
+    ASSERT_EQ(nullptr, first.getAddress());
+    ASSERT_EQ(nullptr, second.getAddress());
+}
+
+/*
+ * Write a chunk of data equal to the queue size.
+ * Verify that the write is successful and the subsequent read
+ * returns the expected data.
+ */
+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);
+}
+
+/*
+ * Attempt to write a chunk of data larger than the queue size.
+ * Verify that it fails. Verify that a subsequent read fails and
+ * the queue is still empty.
+ */
+TYPED_TEST(SynchronizedReadWrites, LargeInputTest2) {
+    ASSERT_EQ(0UL, this->mQueue->availableToRead());
+    const size_t dataLen = 4096;
+    ASSERT_GT(dataLen, this->mNumMessagesMax);
+    std::vector<uint8_t> data(dataLen);
+
+    initData(&data[0], dataLen);
+    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, this->mQueue->availableToRead());
+}
+
+/*
+ * After the queue is full, try to write more data. Verify that
+ * the attempt returns false. Verify that the attempt did not
+ * affect the pre-existing data in the queue.
+ */
+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);
+}
+
+/*
+ * Verify that beginWrite() returns a MemTransaction with
+ * null base pointers when attempting to write data larger
+ * than the queue size.
+ */
+TYPED_TEST(SynchronizedReadWrites, LargeInputTest4) {
+    ASSERT_EQ(0UL, this->mQueue->availableToRead());
+    const size_t dataLen = 4096;
+    ASSERT_GT(dataLen, this->mNumMessagesMax);
+
+    typename TypeParam::MQType::MemTransaction tx;
+    ASSERT_FALSE(this->mQueue->beginWrite(dataLen, &tx));
+
+    auto first = tx.getFirstRegion();
+    auto second = tx.getSecondRegion();
+
+    ASSERT_EQ(nullptr, first.getAddress());
+    ASSERT_EQ(nullptr, second.getAddress());
+}
+
+/*
+ * Verify that multiple reads one after the other return expected data.
+ */
+TYPED_TEST(SynchronizedReadWrites, MultipleRead) {
+    const size_t chunkSize = 100;
+    const size_t chunkNum = 5;
+    const size_t dataLen = chunkSize * chunkNum;
+    ASSERT_LE(dataLen, this->mNumMessagesMax);
+    uint8_t data[dataLen];
+
+    initData(data, dataLen);
+    ASSERT_TRUE(this->mQueue->write(data, dataLen));
+    uint8_t readData[dataLen] = {};
+    for (size_t i = 0; i < chunkNum; i++) {
+        ASSERT_TRUE(this->mQueue->read(readData + i * chunkSize, chunkSize));
+    }
+    ASSERT_EQ(0, memcmp(readData, data, dataLen));
+}
+
+/*
+ * Verify that multiple writes one after the other happens correctly.
+ */
+TYPED_TEST(SynchronizedReadWrites, MultipleWrite) {
+    const int chunkSize = 100;
+    const int chunkNum = 5;
+    const size_t dataLen = chunkSize * chunkNum;
+    ASSERT_LE(dataLen, this->mNumMessagesMax);
+    uint8_t data[dataLen];
+
+    initData(data, dataLen);
+    for (unsigned int i = 0; i < chunkNum; i++) {
+        ASSERT_TRUE(this->mQueue->write(data + i * chunkSize, chunkSize));
+    }
+    uint8_t 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 this->mNumMessagesMax messages into the queue. This will cause a
+ * wrap around. Read and verify the data.
+ */
+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);
+}
+
+/*
+ * Use beginRead/CommitRead/beginWrite/commitWrite APIs
+ * to test wrap arounds are handled correctly.
+ * Write enough messages into the FMQ to fill half of it
+ * and read back the same.
+ * Write mNumMessagesMax messages into the queue. This will cause a
+ * wrap around. Read and verify the data.
+ */
+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.
+     */
+    typename TypeParam::MQType::MemTransaction tx;
+    ASSERT_TRUE(this->mQueue->beginWrite(this->mNumMessagesMax, &tx));
+
+    auto first = tx.getFirstRegion();
+    auto second = tx.getSecondRegion();
+
+    ASSERT_EQ(first.getLength() + second.getLength(), this->mNumMessagesMax);
+
+    ASSERT_TRUE(tx.copyTo(&data[0], 0 /* startIdx */, this->mNumMessagesMax));
+
+    ASSERT_TRUE(this->mQueue->commitWrite(this->mNumMessagesMax));
+
+    ASSERT_TRUE(this->mQueue->beginRead(this->mNumMessagesMax, &tx));
+
+    first = tx.getFirstRegion();
+    second = tx.getSecondRegion();
+
+    ASSERT_EQ(first.getLength() + second.getLength(), this->mNumMessagesMax);
+
+    ASSERT_TRUE(tx.copyFrom(&readData[0], 0 /* startIdx */, this->mNumMessagesMax));
+    ASSERT_TRUE(this->mQueue->commitRead(this->mNumMessagesMax));
+
+    ASSERT_EQ(data, readData);
+}
+
+/*
+ * Verify that a few bytes of data can be successfully written and read.
+ */
+TYPED_TEST(UnsynchronizedWriteTest, SmallInputTest1) {
+    const size_t dataLen = 16;
+    ASSERT_LE(dataLen, this->mNumMessagesMax);
+    uint8_t data[dataLen];
+
+    initData(data, dataLen);
+    ASSERT_TRUE(this->mQueue->write(data, dataLen));
+    uint8_t 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.
+ */
+TYPED_TEST(UnsynchronizedWriteTest, ReadWhenEmpty) {
+    ASSERT_EQ(0UL, this->mQueue->availableToRead());
+    const size_t dataLen = 2;
+    ASSERT_TRUE(dataLen < this->mNumMessagesMax);
+    uint8_t 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.
+ */
+TYPED_TEST(UnsynchronizedWriteTest, WriteWhenFull1) {
+    ASSERT_EQ(0UL, this->mQueue->availableToRead());
+    std::vector<uint8_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));
+
+    std::vector<uint8_t> readData(this->mNumMessagesMax);
+    ASSERT_FALSE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
+}
+
+/*
+ * Write the queue when full. Verify that a subsequent writes
+ * using beginRead()/commitRead() is succesful.
+ * Verify that the next read fails as expected for unsynchronized flavor.
+ */
+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));
+
+    typename TypeParam::MQType::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(this->mQueue->commitWrite(1));
+
+    std::vector<uint8_t> readData(this->mNumMessagesMax);
+    ASSERT_FALSE(this->mQueue->read(&readData[0], this->mNumMessagesMax));
+}
+
+/*
+ * Write a chunk of data equal to the queue size.
+ * Verify that the write is successful and the subsequent read
+ * returns the expected data.
+ */
+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);
+}
+
+/*
+ * Attempt to write a chunk of data larger than the queue size.
+ * Verify that it fails. Verify that a subsequent read fails and
+ * the queue is still empty.
+ */
+TYPED_TEST(UnsynchronizedWriteTest, LargeInputTest2) {
+    ASSERT_EQ(0UL, this->mQueue->availableToRead());
+    const size_t dataLen = 4096;
+    ASSERT_GT(dataLen, this->mNumMessagesMax);
+    std::vector<uint8_t> data(dataLen);
+    initData(&data[0], dataLen);
+    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, this->mQueue->availableToRead());
+}
+
+/*
+ * After the queue is full, try to write more data. Verify that
+ * the attempt is succesful. Verify that the read fails
+ * as expected.
+ */
+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.
+ */
+TYPED_TEST(UnsynchronizedWriteTest, MultipleRead) {
+    const size_t chunkSize = 100;
+    const size_t chunkNum = 5;
+    const size_t dataLen = chunkSize * chunkNum;
+    ASSERT_LE(dataLen, this->mNumMessagesMax);
+    uint8_t data[dataLen];
+    initData(data, dataLen);
+    ASSERT_TRUE(this->mQueue->write(data, dataLen));
+    uint8_t readData[dataLen] = {};
+    for (size_t i = 0; i < chunkNum; i++) {
+        ASSERT_TRUE(this->mQueue->read(readData + i * chunkSize, chunkSize));
+    }
+    ASSERT_EQ(0, memcmp(readData, data, dataLen));
+}
+
+/*
+ * Verify that multiple writes one after the other happens correctly.
+ */
+TYPED_TEST(UnsynchronizedWriteTest, MultipleWrite) {
+    const size_t chunkSize = 100;
+    const size_t chunkNum = 5;
+    const size_t dataLen = chunkSize * chunkNum;
+    ASSERT_LE(dataLen, this->mNumMessagesMax);
+    uint8_t data[dataLen];
+
+    initData(data, dataLen);
+    for (size_t i = 0; i < chunkNum; i++) {
+        ASSERT_TRUE(this->mQueue->write(data + i * chunkSize, chunkSize));
+    }
+
+    uint8_t 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
+ * wrap around. Read and verify the data.
+ */
+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], 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/mq_test.cpp b/tests/mq_test.cpp
deleted file mode 100644
index 96528d3..0000000
--- a/tests/mq_test.cpp
+++ /dev/null
@@ -1,809 +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.
- */
-
-#include <asm-generic/mman.h>
-#include <gtest/gtest.h>
-#include <atomic>
-#include <cstdlib>
-#include <sstream>
-#include <thread>
-#include <fmq/MessageQueue.h>
-#include <fmq/EventFlag.h>
-
-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;
-
-class SynchronizedReadWrites : public ::testing::Test {
-protected:
-    virtual void TearDown() {
-        delete mQueue;
-    }
-
-    virtual void SetUp() {
-        static constexpr size_t kNumElementsInQueue = 2048;
-        mQueue = new (std::nothrow) MessageQueueSync(kNumElementsInQueue);
-        ASSERT_NE(nullptr, mQueue);
-        ASSERT_TRUE(mQueue->isValid());
-        mNumMessagesMax = mQueue->getQuantumCount();
-        ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
-    }
-
-    MessageQueueSync* mQueue = nullptr;
-    size_t mNumMessagesMax = 0;
-};
-
-class UnsynchronizedWrite : public ::testing::Test {
-protected:
-    virtual void TearDown() {
-        delete mQueue;
-    }
-
-    virtual void SetUp() {
-        static constexpr size_t kNumElementsInQueue = 2048;
-        mQueue = new (std::nothrow) MessageQueueUnsync(kNumElementsInQueue);
-        ASSERT_NE(nullptr, mQueue);
-        ASSERT_TRUE(mQueue->isValid());
-        mNumMessagesMax = mQueue->getQuantumCount();
-        ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
-    }
-
-    MessageQueueUnsync* mQueue = nullptr;
-    size_t mNumMessagesMax = 0;
-};
-
-class BlockingReadWrites : public ::testing::Test {
-protected:
-    virtual void TearDown() {
-        delete mQueue;
-    }
-    virtual void SetUp() {
-        static constexpr size_t kNumElementsInQueue = 2048;
-        mQueue = new (std::nothrow) MessageQueueSync(kNumElementsInQueue);
-        ASSERT_NE(nullptr, mQueue);
-        ASSERT_TRUE(mQueue->isValid());
-        mNumMessagesMax = mQueue->getQuantumCount();
-        ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
-        /*
-         * Initialize the EventFlag word to indicate Queue is not full.
-         */
-        std::atomic_init(&mFw, static_cast<uint32_t>(kFmqNotFull));
-    }
-
-    MessageQueueSync* 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));
-  }
-
-  MessageQueueSync* mQueue;
-  size_t mNumMessagesMax = 0;
-};
-
-class BadQueueConfig: public ::testing::Test {
-};
-
-/*
- * Utility function to initialize data to be written to the FMQ
- */
-inline void initData(uint8_t* data, size_t count) {
-    for (size_t i = 0; i < count; i++) {
-        data[i] = i & 0xFF;
-    }
-}
-
-/*
- * This thread will attempt to read and block. When wait returns
- * 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) {
-    const size_t dataLen = 64;
-    uint8_t data[dataLen];
-    android::hardware::EventFlag* efGroup = nullptr;
-    android::status_t status = android::hardware::EventFlag::createEventFlag(fwAddr, &efGroup);
-    ASSERT_EQ(android::NO_ERROR, status);
-    ASSERT_NE(nullptr, efGroup);
-
-    while (true) {
-        uint32_t efState = 0;
-        android::status_t ret = efGroup->wait(kFmqNotEmpty,
-                                              &efState,
-                                              5000000000 /* timeoutNanoSeconds */);
-        /*
-         * Wait should not time out here after 5s
-         */
-        ASSERT_NE(android::TIMED_OUT, ret);
-
-        if ((efState & kFmqNotEmpty) && fmq->read(data, dataLen)) {
-            efGroup->wake(kFmqNotFull);
-            break;
-        }
-    }
-
-    status = android::hardware::EventFlag::deleteEventFlag(&efGroup);
-    ASSERT_EQ(android::NO_ERROR, status);
-}
-
-/*
- * 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) {
-    const size_t dataLen = 64;
-    uint8_t data[dataLen];
-    android::hardware::EventFlag* efGroup = nullptr;
-    android::status_t status = android::hardware::EventFlag::createEventFlag(fwAddr, &efGroup);
-    ASSERT_EQ(android::NO_ERROR, status);
-    ASSERT_NE(nullptr, efGroup);
-    bool ret = fmq->readBlocking(data,
-                                 dataLen,
-                                 static_cast<uint32_t>(kFmqNotFull),
-                                 static_cast<uint32_t>(kFmqNotEmpty),
-                                 5000000000 /* timeOutNanos */,
-                                 efGroup);
-    ASSERT_TRUE(ret);
-    status = android::hardware::EventFlag::deleteEventFlag(&efGroup);
-    ASSERT_EQ(android::NO_ERROR, status);
-}
-
-
-TEST_F(BadQueueConfig, QueueSizeTooLarge) {
-    typedef android::hardware::MessageQueue<uint16_t, android::hardware::kSynchronizedReadWrite>
-            MessageQueueSync16;
-    size_t numElementsInQueue = SIZE_MAX / sizeof(uint16_t) + 1;
-    MessageQueueSync16 * fmq = new (std::nothrow) MessageQueueSync16(numElementsInQueue);
-    ASSERT_NE(nullptr, fmq);
-    /*
-     * Should fail due to size being too large to fit into size_t.
-     */
-    ASSERT_FALSE(fmq->isValid());
-}
-
-/*
- * Test that basic blocking works. This test uses the non-blocking read()/write()
- * APIs.
- */
-TEST_F(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);
-
-    ASSERT_EQ(android::NO_ERROR, status);
-    ASSERT_NE(nullptr, efGroup);
-
-    /*
-     * Start a thread that will try to read and block on kFmqNotEmpty.
-     */
-    std::thread Reader(ReaderThreadBlocking, mQueue, &mFw);
-    struct timespec waitTime = {0, 100 * 1000000};
-    ASSERT_EQ(0, nanosleep(&waitTime, NULL));
-
-    /*
-     * After waiting for some time write into the FMQ
-     * and call Wake on kFmqNotEmpty.
-     */
-    ASSERT_TRUE(mQueue->write(data, dataLen));
-    status = efGroup->wake(kFmqNotEmpty);
-    ASSERT_EQ(android::NO_ERROR, status);
-
-    ASSERT_EQ(0, nanosleep(&waitTime, NULL));
-    Reader.join();
-
-    status = android::hardware::EventFlag::deleteEventFlag(&efGroup);
-    ASSERT_EQ(android::NO_ERROR, status);
-}
-
-/*
- * Test that basic blocking works. This test uses the
- * writeBlocking()/readBlocking() APIs.
- */
-TEST_F(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);
-
-    ASSERT_EQ(android::NO_ERROR, status);
-    ASSERT_NE(nullptr, efGroup);
-
-    /*
-     * 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);
-    ASSERT_TRUE(ret);
-    Reader.join();
-
-    status = android::hardware::EventFlag::deleteEventFlag(&efGroup);
-    ASSERT_EQ(android::NO_ERROR, status);
-}
-
-/*
- * Test that basic blocking times out as intended.
- */
-TEST_F(BlockingReadWrites, BlockingTimeOutTest) {
-    android::hardware::EventFlag* efGroup = nullptr;
-    android::status_t status = android::hardware::EventFlag::createEventFlag(&mFw, &efGroup);
-
-    ASSERT_EQ(android::NO_ERROR, status);
-    ASSERT_NE(nullptr, efGroup);
-
-    /* Block on an EventFlag bit that no one will wake and time out in 1s */
-    uint32_t efState = 0;
-    android::status_t ret = efGroup->wait(kFmqNotEmpty,
-                                          &efState,
-                                          1000000000 /* timeoutNanoSeconds */);
-    /*
-     * Wait should time out in a second.
-     */
-    EXPECT_EQ(android::TIMED_OUT, ret);
-
-    status = android::hardware::EventFlag::deleteEventFlag(&efGroup);
-    ASSERT_EQ(android::NO_ERROR, status);
-}
-
-/*
- * Test that odd queue sizes do not cause unaligned error
- * on access to EventFlag object.
- */
-TEST_F(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 */);
-    ASSERT_TRUE(ret);
-}
-
-/*
- * Verify that a few bytes of data can be successfully written and read.
- */
-TEST_F(SynchronizedReadWrites, SmallInputTest1) {
-    const size_t dataLen = 16;
-    ASSERT_LE(dataLen, mNumMessagesMax);
-    uint8_t data[dataLen];
-
-    initData(data, dataLen);
-
-    ASSERT_TRUE(mQueue->write(data, dataLen));
-    uint8_t readData[dataLen] = {};
-    ASSERT_TRUE(mQueue->read(readData, dataLen));
-    ASSERT_EQ(0, memcmp(data, readData, dataLen));
-}
-
-/*
- * Verify that a few bytes of data can be successfully written and read using
- * beginRead/beginWrite/CommitRead/CommitWrite
- */
-TEST_F(SynchronizedReadWrites, SmallInputTest2) {
-    const size_t dataLen = 16;
-    ASSERT_LE(dataLen, mNumMessagesMax);
-    uint8_t data[dataLen];
-
-    initData(data, dataLen);
-
-    MessageQueueSync::MemTransaction tx;
-    ASSERT_TRUE(mQueue->beginWrite(dataLen, &tx));
-
-    ASSERT_TRUE(tx.copyTo(data, 0 /* startIdx */, dataLen));
-
-    ASSERT_TRUE(mQueue->commitWrite(dataLen));
-
-    uint8_t readData[dataLen] = {};
-
-    ASSERT_TRUE(mQueue->beginRead(dataLen, &tx));
-
-    ASSERT_TRUE(tx.copyFrom(readData, 0 /* startIdx */, dataLen));
-
-    ASSERT_TRUE(mQueue->commitRead(dataLen));
-
-    ASSERT_EQ(0, memcmp(data, readData, dataLen));
-}
-
-/*
- * 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) {
-    const size_t dataLen = 16;
-    ASSERT_LE(dataLen, mNumMessagesMax);
-    uint8_t data[dataLen];
-
-    initData(data, dataLen);
-    MessageQueueSync::MemTransaction tx;
-    ASSERT_TRUE(mQueue->beginWrite(dataLen, &tx));
-
-    auto first = tx.getFirstRegion();
-    auto second = tx.getSecondRegion();
-
-    ASSERT_EQ(first.getLength() + second.getLength(),  dataLen);
-    for (size_t i = 0; i < dataLen; i++) {
-        uint8_t* ptr = tx.getSlot(i);
-        *ptr = data[i];
-    }
-
-    ASSERT_TRUE(mQueue->commitWrite(dataLen));
-
-    uint8_t readData[dataLen] = {};
-
-    ASSERT_TRUE(mQueue->beginRead(dataLen, &tx));
-
-    first = tx.getFirstRegion();
-    second = tx.getSecondRegion();
-
-    ASSERT_EQ(first.getLength() + second.getLength(),  dataLen);
-
-    for (size_t i = 0; i < dataLen; i++) {
-        uint8_t* ptr = tx.getSlot(i);
-        readData[i] = *ptr;
-    }
-
-    ASSERT_TRUE(mQueue->commitRead(dataLen));
-
-    ASSERT_EQ(0, memcmp(data, readData, dataLen));
-}
-
-/*
- * Verify that read() returns false when trying to read from an empty queue.
- */
-TEST_F(SynchronizedReadWrites, ReadWhenEmpty1) {
-    ASSERT_EQ(0UL, mQueue->availableToRead());
-    const size_t dataLen = 2;
-    ASSERT_LE(dataLen, mNumMessagesMax);
-    uint8_t readData[dataLen];
-    ASSERT_FALSE(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());
-    const size_t dataLen = 2;
-    ASSERT_LE(dataLen, mNumMessagesMax);
-
-    MessageQueueSync::MemTransaction tx;
-    ASSERT_FALSE(mQueue->beginRead(dataLen, &tx));
-
-    auto first = tx.getFirstRegion();
-    auto second = tx.getSecondRegion();
-
-    ASSERT_EQ(nullptr, first.getAddress());
-    ASSERT_EQ(nullptr, second.getAddress());
-}
-
-/*
- * 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);
-
-    initData(&data[0], mNumMessagesMax);
-    ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
-    ASSERT_EQ(0UL, mQueue->availableToWrite());
-    ASSERT_FALSE(mQueue->write(&data[0], 1));
-
-    std::vector<uint8_t> readData(mNumMessagesMax);
-    ASSERT_TRUE(mQueue->read(&readData[0], mNumMessagesMax));
-    ASSERT_EQ(data, readData);
-}
-
-/*
- * 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);
-
-    initData(&data[0], mNumMessagesMax);
-    ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
-    ASSERT_EQ(0UL, mQueue->availableToWrite());
-
-    MessageQueueSync::MemTransaction tx;
-    ASSERT_FALSE(mQueue->beginWrite(1, &tx));
-
-    auto first = tx.getFirstRegion();
-    auto second = tx.getSecondRegion();
-
-    ASSERT_EQ(nullptr, first.getAddress());
-    ASSERT_EQ(nullptr, second.getAddress());
-}
-
-/*
- * Write a chunk of data equal to the queue size.
- * 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));
-    ASSERT_EQ(data, readData);
-}
-
-/*
- * Attempt to write a chunk of data larger than the queue size.
- * 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());
-    const size_t dataLen = 4096;
-    ASSERT_GT(dataLen, 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_NE(data, readData);
-    ASSERT_EQ(0UL, mQueue->availableToRead());
-}
-
-/*
- * After the queue is full, try to write more data. Verify that
- * 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));
-    ASSERT_EQ(data, readData);
-}
-
-/*
- * Verify that beginWrite() returns a MemTransaction with
- * null base pointers when attempting to write data larger
- * than the queue size.
- */
-TEST_F(SynchronizedReadWrites, LargeInputTest4) {
-    ASSERT_EQ(0UL, mQueue->availableToRead());
-    const size_t dataLen = 4096;
-    ASSERT_GT(dataLen, mNumMessagesMax);
-
-    MessageQueueSync::MemTransaction tx;
-    ASSERT_FALSE(mQueue->beginWrite(dataLen, &tx));
-
-    auto first = tx.getFirstRegion();
-    auto second = tx.getSecondRegion();
-
-    ASSERT_EQ(nullptr, first.getAddress());
-    ASSERT_EQ(nullptr, second.getAddress());
-}
-
-/*
- * Verify that multiple reads one after the other return expected data.
- */
-TEST_F(SynchronizedReadWrites, MultipleRead) {
-    const size_t chunkSize = 100;
-    const size_t chunkNum = 5;
-    const size_t dataLen = chunkSize * chunkNum;
-    ASSERT_LE(dataLen, mNumMessagesMax);
-    uint8_t data[dataLen];
-
-    initData(data, dataLen);
-    ASSERT_TRUE(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_EQ(0, memcmp(readData, data, dataLen));
-}
-
-/*
- * Verify that multiple writes one after the other happens correctly.
- */
-TEST_F(SynchronizedReadWrites, MultipleWrite) {
-    const int chunkSize = 100;
-    const int chunkNum = 5;
-    const size_t dataLen = chunkSize * chunkNum;
-    ASSERT_LE(dataLen, mNumMessagesMax);
-    uint8_t data[dataLen];
-
-    initData(data, dataLen);
-    for (unsigned int i = 0; i < chunkNum; i++) {
-        ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize));
-    }
-    uint8_t readData[dataLen] = {};
-    ASSERT_TRUE(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
- * 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));
-    ASSERT_EQ(data, readData);
-}
-
-/*
- * Use beginRead/CommitRead/beginWrite/commitWrite APIs
- * to test wrap arounds are handled correctly.
- * Write enough messages into the FMQ to fill half of it
- * and read back the same.
- * Write mNumMessagesMax messages into the queue. This will cause a
- * wrap around. Read and verify the data.
- */
-TEST_F(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));
-
-    /*
-     * The next write and read will have to deal with with wrap arounds.
-     */
-    MessageQueueSync::MemTransaction tx;
-    ASSERT_TRUE(mQueue->beginWrite(mNumMessagesMax, &tx));
-
-    auto first = tx.getFirstRegion();
-    auto second = tx.getSecondRegion();
-
-    ASSERT_EQ(first.getLength() + second.getLength(), mNumMessagesMax);
-
-    ASSERT_TRUE(tx.copyTo(&data[0], 0 /* startIdx */,  mNumMessagesMax));
-
-    ASSERT_TRUE(mQueue->commitWrite(mNumMessagesMax));
-
-    ASSERT_TRUE(mQueue->beginRead(mNumMessagesMax, &tx));
-
-    first = tx.getFirstRegion();
-    second = tx.getSecondRegion();
-
-    ASSERT_EQ(first.getLength() + second.getLength(), mNumMessagesMax);
-
-    ASSERT_TRUE(tx.copyFrom(&readData[0], 0 /* startIdx */, mNumMessagesMax));
-    ASSERT_TRUE(mQueue->commitRead(mNumMessagesMax));
-
-    ASSERT_EQ(data, readData);
-}
-
-/*
- * Verify that a few bytes of data can be successfully written and read.
- */
-TEST_F(UnsynchronizedWrite, SmallInputTest1) {
-    const size_t dataLen = 16;
-    ASSERT_LE(dataLen, mNumMessagesMax);
-    uint8_t data[dataLen];
-
-    initData(data, dataLen);
-    ASSERT_TRUE(mQueue->write(data, dataLen));
-    uint8_t readData[dataLen] = {};
-    ASSERT_TRUE(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());
-    const size_t dataLen = 2;
-    ASSERT_TRUE(dataLen < mNumMessagesMax);
-    uint8_t readData[dataLen];
-    ASSERT_FALSE(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);
-
-    initData(&data[0], mNumMessagesMax);
-    ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
-    ASSERT_EQ(0UL, mQueue->availableToWrite());
-    ASSERT_TRUE(mQueue->write(&data[0], 1));
-
-    std::vector<uint8_t> readData(mNumMessagesMax);
-    ASSERT_FALSE(mQueue->read(&readData[0], mNumMessagesMax));
-}
-
-/*
- * Write the queue when full. Verify that a subsequent writes
- * 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));
-
-    MessageQueueUnsync::MemTransaction tx;
-    ASSERT_TRUE(mQueue->beginWrite(1, &tx));
-
-    ASSERT_EQ(tx.getFirstRegion().getLength(), 1U);
-
-    ASSERT_TRUE(tx.copyTo(&data[0], 0 /* startIdx */));
-
-    ASSERT_TRUE(mQueue->commitWrite(1));
-
-    std::vector<uint8_t> readData(mNumMessagesMax);
-    ASSERT_FALSE(mQueue->read(&readData[0], mNumMessagesMax));
-}
-
-/*
- * Write a chunk of data equal to the queue size.
- * 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));
-    ASSERT_EQ(data, readData);
-}
-
-/*
- * Attempt to write a chunk of data larger than the queue size.
- * 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());
-    const size_t dataLen = 4096;
-    ASSERT_GT(dataLen, 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_NE(data, readData);
-    ASSERT_EQ(0UL, mQueue->availableToRead());
-}
-
-/*
- * After the queue is full, try to write more data. Verify that
- * 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));
-}
-
-/*
- * Verify that multiple reads one after the other return expected data.
- */
-TEST_F(UnsynchronizedWrite, MultipleRead) {
-    const size_t chunkSize = 100;
-    const size_t chunkNum = 5;
-    const size_t dataLen = chunkSize * chunkNum;
-    ASSERT_LE(dataLen, mNumMessagesMax);
-    uint8_t data[dataLen];
-    initData(data, dataLen);
-    ASSERT_TRUE(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_EQ(0, memcmp(readData, data, dataLen));
-}
-
-/*
- * Verify that multiple writes one after the other happens correctly.
- */
-TEST_F(UnsynchronizedWrite, MultipleWrite) {
-    const size_t chunkSize = 100;
-    const size_t chunkNum = 5;
-    const size_t dataLen = chunkSize * chunkNum;
-    ASSERT_LE(dataLen, mNumMessagesMax);
-    uint8_t data[dataLen];
-
-    initData(data, dataLen);
-    for (size_t i = 0; i < chunkNum; i++) {
-        ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize));
-    }
-
-    uint8_t readData[dataLen] = {};
-    ASSERT_TRUE(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
- * 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);
-
-    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));
-    ASSERT_EQ(data, readData);
-}
diff --git a/tests/msgq_test_client.cpp b/tests/msgq_test_client.cpp
index 271586a..a971f7d 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,87 +49,258 @@
 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::fmq::SynchronizedReadWrite;
+using aidl::android::hardware::common::fmq::UnsynchronizedWrite;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::kUnsynchronizedWrite;
 
-static sp<ITestMsgQ> waitGetTestService() {
-    // waitForHwService is required because ITestMsgQ is not in manifest.xml.
-    // "Real" HALs shouldn't be doing this.
-    waitForHwService(ITestMsgQ::descriptor, "default");
-    return ITestMsgQ::getService();
-}
+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);
-                                      });
-    }
+enum class SetupType {
+    SINGLE_FD,
+    DOUBLE_FD,
 };
 
-class SynchronizedReadWriteClient : public ::testing::Test {
-protected:
+template <typename T, SetupType setupType>
+class TestParamTypes {
+  public:
+    typedef T MQType;
+    static constexpr bool UserFd = setupType == SetupType::DOUBLE_FD;
+};
+
+// Run everything on both the AIDL and HIDL versions with one and two FDs
+typedef ::testing::Types<TestParamTypes<AidlMessageQueueSync, SetupType::SINGLE_FD>,
+                         TestParamTypes<MessageQueueSync, SetupType::SINGLE_FD>,
+                         TestParamTypes<AidlMessageQueueSync, SetupType::DOUBLE_FD>,
+                         TestParamTypes<MessageQueueSync, SetupType::DOUBLE_FD>>
+        SyncTypes;
+typedef ::testing::Types<TestParamTypes<AidlMessageQueueUnsync, SetupType::SINGLE_FD>,
+                         TestParamTypes<MessageQueueUnsync, SetupType::SINGLE_FD>,
+                         TestParamTypes<AidlMessageQueueUnsync, SetupType::DOUBLE_FD>,
+                         TestParamTypes<MessageQueueUnsync, SetupType::DOUBLE_FD>>
+        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;
+};
+
+// 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, bool userFd, std::shared_ptr<ITestAidlMsgQ> service,
+                           AidlMessageQueueUnsync** queue) {
+        bool result = false;
+        aidl::android::hardware::common::fmq::MQDescriptor<int32_t, UnsynchronizedWrite> desc;
+        auto ret = service->getFmqUnsyncWrite(configureFmq, userFd, &desc, &result);
+        *queue = new (std::nothrow) AidlMessageQueueUnsync(desc);
+        return result && ret.isOk();
+    }
+
+    std::shared_ptr<ITestAidlMsgQ> getQueue(AidlMessageQueueUnsync** fmq, bool setupQueue,
+                                            bool userFd) {
+        std::shared_ptr<ITestAidlMsgQ> service = waitGetTestService();
+        if (service == nullptr) return nullptr;
+        getFmqUnsyncWrite(setupQueue, userFd, 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, bool userFd, sp<ITestMsgQ> service,
+                           MessageQueueUnsync** queue) {
+        if (!service) {
+            return false;
+        }
+        service->getFmqUnsyncWrite(configureFmq, userFd,
+                                   [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, bool userFd) {
+        sp<ITestMsgQ> service = waitGetTestService();
+        if (service == nullptr) return nullptr;
+        getFmqUnsyncWrite(setupQueue, userFd, 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<typename T::MQType> {};
+
+TYPED_TEST_CASE(SynchronizedReadWriteClient, SyncTypes);
+template <typename T>
+class SynchronizedReadWriteClient : public ClientSyncTestBase<typename T::MQType> {
+  protected:
     virtual void TearDown() {
         delete mQueue;
     }
 
     virtual void SetUp() {
-        static constexpr size_t kNumElementsInQueue = (PAGE_SIZE - 16) / sizeof(uint16_t);
-        mService = waitGetTestService();
-        ASSERT_NE(mService, nullptr);
-        ASSERT_TRUE(mService->isRemote());
+        this->mService = this->waitGetTestService();
+        ASSERT_NE(this->mService, nullptr);
+        ASSERT_TRUE(this->mService->isRemote());
+        static constexpr size_t kSyncElementSizeBytes = sizeof(int32_t);
+        android::base::unique_fd ringbufferFd;
+        if (T::UserFd) {
+            ringbufferFd.reset(::ashmem_create_region(
+                    "SyncReadWrite", kNumElementsInSyncQueue * kSyncElementSizeBytes));
+        }
         // create a queue on the client side
-        mQueue = new (std::nothrow)
-            MessageQueueSync(kNumElementsInQueue, true /* configure event flag word */);
+        mQueue = new (std::nothrow) typename T::MQType(
+                kNumElementsInSyncQueue, true /* configure event flag word */,
+                std::move(ringbufferFd), kNumElementsInSyncQueue * kSyncElementSizeBytes);
         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;
+    typename T::MQType* 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<typename T::MQType> {
+  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, false, 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;
     }
@@ -130,7 +310,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;
     }
@@ -140,33 +320,31 @@
  * 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());
+        typename TypeParam::MQType* queue = nullptr;
+        auto service =
+                this->getQueue(&queue, true /* setupQueue */, TypeParam::UserFd /* userFd */);
+        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));
 
         /*
@@ -174,8 +352,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.
@@ -194,25 +371,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());
+        typename TypeParam::MQType* queue = nullptr;
+        auto service = this->getQueue(&queue, false /* setupQueue */, false /* userFd */);
+        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.
@@ -231,26 +405,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);
+    }
 }
 
 /*
@@ -258,30 +438,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);
+    }
 }
 
 /*
@@ -290,32 +474,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);
 }
 
 /*
@@ -324,31 +520,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);
 }
 
 /*
@@ -356,56 +564,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);
 }
 
@@ -413,66 +632,29 @@
  * 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));
 }
 
 /*
- * Request mService to write a message to the queue followed by a beginRead().
- * Get a pointer to the memory region for the that first message. Set the write
- * counter to the last byte in the ring buffer. Request another write from
- * mService. The write should fail because the write address is misaligned.
- */
-TEST_F(SynchronizedReadWriteClient, MisalignedWriteCounter) {
-    const size_t dataLen = 1;
-    bool ret = mService->requestWriteFmqSync(dataLen);
-    ASSERT_TRUE(ret);
-    // begin read and get a MemTransaction object for the first object in the queue
-    MessageQueueSync::MemTransaction tx;
-    ASSERT_TRUE(mQueue->beginRead(dataLen, &tx));
-    // get a pointer to the beginning of the ring buffer
-    const auto& region = tx.getFirstRegion();
-    uint16_t* firstStart = region.getAddress();
-
-    // because this is the first location in the ring buffer, we can get
-    // access to the read and write pointer stored in the fd. 8 bytes back for the
-    // write counter and 16 bytes back for the read counter
-    uint64_t* writeCntr = (uint64_t*)((uint8_t*)firstStart - 8);
-
-    // set it to point to the very last byte in the ring buffer
-    *(writeCntr) = mQueue->getQuantumCount() * mQueue->getQuantumSize() - 1;
-    ASSERT_TRUE(*writeCntr % sizeof(uint16_t) != 0);
-
-    // this is not actually necessary, but it's the expected the pattern.
-    mQueue->commitRead(dataLen);
-
-    // This next write will be misaligned and will overlap outside of the ring buffer.
-    // The write should fail.
-    ret = mService->requestWriteFmqSync(dataLen);
-    EXPECT_FALSE(ret);
-}
-
-/*
  * Request mService to write a small number of messages
  * to the FMQ. Read and verify each message using
  * beginRead/Commit read APIs.
  */
-TEST_F(SynchronizedReadWriteClient, SmallInputReaderTest2) {
+TYPED_TEST(SynchronizedReadWriteClient, SmallInputReaderTest2) {
     const size_t dataLen = 16;
-    ASSERT_LE(dataLen, mNumMessagesMax);
-    auto ret = mService->requestWriteFmqSync(dataLen);
-
-    ASSERT_TRUE(ret.isOk());
+    ASSERT_LE(dataLen, kNumElementsInSyncQueue);
+    auto ret = this->requestWriteFmqSync(dataLen);
     ASSERT_TRUE(ret);
 
-    MessageQueueSync::MemTransaction tx;
-    ASSERT_TRUE(mQueue->beginRead(dataLen, &tx));
+    typename TypeParam::MQType::MemTransaction tx;
+    ASSERT_TRUE(this->mQueue->beginRead(dataLen, &tx));
 
     auto first = tx.getFirstRegion();
     auto second = tx.getSecondRegion();
@@ -486,46 +668,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::MQType::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) {
@@ -535,24 +717,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));
 }
 
 /*
@@ -560,17 +742,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);
 }
 
@@ -579,12 +760,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));
 }
 
 /*
@@ -592,15 +773,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));
 }
 
 /*
@@ -611,14 +792,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);
 }
 
@@ -626,19 +807,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));
 }
@@ -647,18 +828,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);
 }
 
@@ -668,15 +849,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);
 }
 
@@ -688,74 +869,70 @@
  * Write mNumMessagesMax messages into the queue. This will cause a
  * wrap around. Read and verify the data.
  */
-TEST_F(SynchronizedReadWriteClient, ReadWriteWrapAround2) {
-    size_t numMessages = mNumMessagesMax / 2;
-    std::vector<uint16_t> data(mNumMessagesMax);
-    initData(&data[0], mNumMessagesMax);
-    ASSERT_TRUE(mQueue->write(&data[0], numMessages));
-    auto ret = mService->requestReadFmqSync(numMessages);
-
-    ASSERT_TRUE(ret.isOk());
+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);
 
     /*
      * The next write and read will have to deal with with wrap arounds.
      */
-    MessageQueueSync::MemTransaction tx;
-    ASSERT_TRUE(mQueue->beginWrite(mNumMessagesMax, &tx));
+    typename TypeParam::MQType::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));
 }
 
 /*
@@ -763,187 +940,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) {
+    typename TypeParam::MQType* 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) {
+    typename TypeParam::MQType* 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));
+}