Adding AidlMessageQueue

This adds an AIDL compatible version of MessageQueue that returns an
AIDL parcelable to be passed between processes. The returned parcelable
is used to create a new instance of the MessageQueue.

Tests were run on 32-bit Cuttlefish as well as 64-bit Flame device.

Test: atest fmq_unit_tests && system/tools/hidl/test/run_all_device_tests.sh
Bug: 142326204

Change-Id: I0fac5065c6d5d0686aa6fd48ca1109417246718c
diff --git a/tests/aidl/default/Android.bp b/tests/aidl/default/Android.bp
new file mode 100644
index 0000000..54660e4
--- /dev/null
+++ b/tests/aidl/default/Android.bp
@@ -0,0 +1,16 @@
+cc_library_static {
+    name: "android.fmq.test-impl",
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libfmq",
+        "android.hardware.common-unstable-ndk_platform",
+    ],
+    static_libs: [
+        "android.fmq.test-ndk_platform",
+    ],
+    export_include_dirs: ["."],
+    srcs: [
+        "TestAidlMsgQ.cpp",
+    ],
+}
diff --git a/tests/aidl/default/TestAidlMsgQ.cpp b/tests/aidl/default/TestAidlMsgQ.cpp
new file mode 100644
index 0000000..0d6153e
--- /dev/null
+++ b/tests/aidl/default/TestAidlMsgQ.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestAidlMsgQ.h"
+
+namespace aidl {
+namespace android {
+namespace fmq {
+namespace test {
+
+// Methods from ::aidl::android::fmq::test::ITestAidlMsgQ follow.
+ndk::ScopedAStatus TestAidlMsgQ::configureFmqSyncReadWrite(const MQDescriptor& mqDesc,
+                                                           bool* _aidl_return) {
+    mFmqSynchronized.reset(new (std::nothrow) TestAidlMsgQ::MessageQueueSync(mqDesc));
+    if ((mFmqSynchronized == nullptr) || (mFmqSynchronized->isValid() == false)) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    /*
+     * Initialize the EventFlag word with bit FMQ_NOT_FULL.
+     */
+    auto evFlagWordPtr = mFmqSynchronized->getEventFlagWord();
+    if (evFlagWordPtr != nullptr) {
+        std::atomic_init(evFlagWordPtr, static_cast<uint32_t>(EventFlagBits::FMQ_NOT_FULL));
+    }
+    *_aidl_return = true;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus TestAidlMsgQ::getFmqUnsyncWrite(bool configureFmq, MQDescriptor* mqDesc,
+                                                   bool* _aidl_return) {
+    if (configureFmq) {
+        static constexpr size_t kNumElementsInQueue = 1024;
+        mFmqUnsynchronized.reset(new (std::nothrow)
+                                         TestAidlMsgQ::MessageQueueUnsync(kNumElementsInQueue));
+    }
+
+    if ((mFmqUnsynchronized == nullptr) || (mFmqUnsynchronized->isValid() == false) ||
+        (mqDesc == nullptr)) {
+        *_aidl_return = false;
+    } else {
+        *mqDesc = std::move(mFmqUnsynchronized->dupeDesc());
+        *_aidl_return = true;
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus TestAidlMsgQ::requestBlockingRead(int32_t count) {
+    std::vector<uint16_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<uint16_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<uint16_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<uint16_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<uint16_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<uint16_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<uint16_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..92cc956
--- /dev/null
+++ b/tests/aidl/default/TestAidlMsgQ.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/fmq/test/BnTestAidlMsgQ.h>
+#include <aidl/android/fmq/test/EventFlagBits.h>
+#include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
+
+namespace aidl {
+namespace android {
+namespace fmq {
+namespace test {
+
+using ::aidl::android::fmq::test::EventFlagBits;
+using ::aidl::android::fmq::test::ITestAidlMsgQ;
+
+using ::aidl::android::hardware::common::MQDescriptor;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::kUnsynchronizedWrite;
+using ::android::hardware::MQFlavor;
+
+using ::android::AidlMessageQueue;
+
+struct TestAidlMsgQ : public BnTestAidlMsgQ {
+    typedef AidlMessageQueue<uint16_t, kSynchronizedReadWrite> MessageQueueSync;
+    typedef AidlMessageQueue<uint16_t, kUnsynchronizedWrite> MessageQueueUnsync;
+
+    TestAidlMsgQ() : mFmqSynchronized(nullptr), mFmqUnsynchronized(nullptr) {}
+
+    // Methods from ::aidl::android::fmq::test::ITestAidlMsgQ follow.
+    ndk::ScopedAStatus configureFmqSyncReadWrite(const MQDescriptor& mqDesc,
+                                                 bool* _aidl_return) override;
+    ndk::ScopedAStatus getFmqUnsyncWrite(bool configureFmq, MQDescriptor* 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(uint16_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