Merge "media.bufferpool@1.0 unit tests"
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Android.bp b/media/libstagefright/codec2/vndk/bufferpool/Android.bp
index f0588d5..c7aa07b 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/Android.bp
+++ b/media/libstagefright/codec2/vndk/bufferpool/Android.bp
@@ -1,5 +1,5 @@
-cc_library_shared {
-    name: "android.hardware.media.bufferpool@1.0-impl",
+cc_library {
+    name: "libstagefright_bufferpool@1.0",
     vendor_available: true,
     vndk: {
         enabled: true,
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/Android.bp b/media/libstagefright/codec2/vndk/bufferpool/vts/Android.bp
new file mode 100644
index 0000000..074d4bc
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/vts/Android.bp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+cc_test {
+    name: "VtsVndkHidlBufferpoolV1_0TargetSingleTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "single.cpp",
+    ],
+    static_libs: [
+        "android.hardware.media.bufferpool@1.0",
+        "libion",
+        "libstagefright_bufferpool@1.0",
+    ],
+    shared_libs: [
+        "libfmq",
+        "libstagefright_codec2",
+        "libstagefright_codec2_vndk",
+    ],
+    compile_multilib: "both",
+}
+
+cc_test {
+    name: "VtsVndkHidlBufferpoolV1_0TargetMultiTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "multi.cpp",
+    ],
+    static_libs: [
+        "android.hardware.media.bufferpool@1.0",
+        "libion",
+        "libstagefright_bufferpool@1.0",
+    ],
+    shared_libs: [
+        "libfmq",
+        "libstagefright_codec2",
+        "libstagefright_codec2_vndk",
+    ],
+    compile_multilib: "both",
+}
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/OWNERS b/media/libstagefright/codec2/vndk/bufferpool/vts/OWNERS
new file mode 100644
index 0000000..4c3f7a1
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/vts/OWNERS
@@ -0,0 +1,7 @@
+# Media team
+taklee@google.com
+lajos@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/multi.cpp b/media/libstagefright/codec2/vndk/bufferpool/vts/multi.cpp
new file mode 100644
index 0000000..3ad8b6c
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/vts/multi.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <C2AllocatorIon.h>
+#include <C2Buffer.h>
+#include <C2PlatformSupport.h>
+#include <ClientManager.h>
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+#include <hidl/Status.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <iostream>
+#include <memory>
+#include <vector>
+
+using android::C2AllocatorIon;
+using android::C2PlatformAllocatorStore;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::hidl_handle;
+using android::hardware::media::bufferpool::V1_0::IAccessor;
+using android::hardware::media::bufferpool::V1_0::IClientManager;
+using android::hardware::media::bufferpool::V1_0::ResultStatus;
+using android::hardware::media::bufferpool::V1_0::implementation::BufferId;
+using android::hardware::media::bufferpool::V1_0::implementation::ClientManager;
+using android::hardware::media::bufferpool::V1_0::implementation::ConnectionId;
+using android::hardware::media::bufferpool::V1_0::implementation::TransactionId;
+
+namespace {
+
+// Buffer allocation size for tests.
+constexpr static int kAllocationSize = 1024 * 10;
+
+// communication message types between processes.
+enum PipeCommand : int32_t {
+    INIT_OK = 0,
+    INIT_ERROR,
+    SEND,
+    RECEIVE_OK,
+    RECEIVE_ERROR,
+};
+
+// communication message between processes.
+union PipeMessage {
+    struct  {
+        int32_t command;
+        BufferId bufferId;
+        ConnectionId connectionId;
+        TransactionId transactionId;
+        int64_t  timestampUs;
+    } data;
+    char array[0];
+};
+
+// media.bufferpool test setup
+class BufferpoolMultiTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    ResultStatus status;
+    mReceiverPid = -1;
+
+    ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
+    ASSERT_TRUE(pipe(mResultPipeFds) == 0);
+
+    mReceiverPid = fork();
+    ASSERT_TRUE(mReceiverPid >= 0);
+
+    if (mReceiverPid == 0) {
+       doReceiver();
+       return;
+    }
+
+    mManager = ClientManager::getInstance();
+    ASSERT_NE(mManager, nullptr);
+
+    mAllocator =
+        std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
+    ASSERT_TRUE((bool)mAllocator);
+
+    status = mManager->create(mAllocator, true, &mConnectionId);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    status = mManager->getAccessor(mConnectionId, &mAccessor);
+    ASSERT_TRUE(status == ResultStatus::OK && (bool)mAccessor);
+  }
+
+  virtual void TearDown() override {
+      if (mReceiverPid > 0) {
+          kill(mReceiverPid, SIGKILL);
+          int wstatus;
+          wait(&wstatus);
+      }
+  }
+
+ protected:
+  static void description(const std::string& description) {
+    RecordProperty("description", description);
+  }
+
+  android::sp<ClientManager> mManager;
+  android::sp<IAccessor> mAccessor;
+  std::shared_ptr<C2Allocator> mAllocator;
+  ConnectionId mConnectionId;
+  pid_t mReceiverPid;
+  int mCommandPipeFds[2];
+  int mResultPipeFds[2];
+
+  void getAllocationParams(std::vector<uint8_t>* vecParams) {
+    union Params {
+      struct {
+        uint32_t capacity;
+        C2MemoryUsage usage;
+      } data;
+      uint8_t array[0];
+      Params()
+          : data{kAllocationSize,
+                 {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}} {}
+    } params;
+    vecParams->assign(params.array, params.array + sizeof(params));
+  }
+
+  bool sendMessage(int *pipes, const PipeMessage &message) {
+    int ret = write(pipes[1], message.array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  bool receiveMessage(int *pipes, PipeMessage *message) {
+    int ret = read(pipes[0], message->array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  void doReceiver() {
+    configureRpcThreadpool(1, false);
+    PipeMessage message;
+    mManager = ClientManager::getInstance();
+    if (!mManager) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    android::status_t status = mManager->registerAsService();
+    if (status != android::OK) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    message.data.command = PipeCommand::INIT_OK;
+    sendMessage(mResultPipeFds, message);
+
+    receiveMessage(mCommandPipeFds, &message);
+    {
+      std::shared_ptr<_C2BlockPoolData> rbuffer;
+      ResultStatus status = mManager->receive(
+          message.data.connectionId, message.data.transactionId,
+          message.data.bufferId, message.data.timestampUs, &rbuffer);
+      if (status != ResultStatus::OK) {
+        message.data.command = PipeCommand::RECEIVE_ERROR;
+        sendMessage(mResultPipeFds, message);
+        return;
+      }
+    }
+    message.data.command = PipeCommand::RECEIVE_OK;
+    sendMessage(mResultPipeFds, message);
+    while(1); // An easy way to ignore gtest behaviour.
+  }
+};
+
+// Buffer transfer test between processes.
+TEST_F(BufferpoolMultiTest, TransferBuffer) {
+  ResultStatus status;
+  PipeMessage message;
+
+  ASSERT_TRUE(receiveMessage(mResultPipeFds, &message));
+
+  android::sp<IClientManager> receiver = IClientManager::getService();
+  ConnectionId receiverId;
+  ASSERT_TRUE((bool)receiver);
+
+  receiver->registerSender(
+      mAccessor, [&status, &receiverId]
+      (ResultStatus outStatus, ConnectionId outId) {
+        status = outStatus;
+        receiverId = outId;
+      });
+  ASSERT_TRUE(status == ResultStatus::OK);
+  {
+    std::shared_ptr<_C2BlockPoolData> sbuffer;
+    TransactionId transactionId;
+    int64_t postUs;
+    std::vector<uint8_t> vecParams;
+
+    getAllocationParams(&vecParams);
+    status = mManager->allocate(mConnectionId, vecParams, &sbuffer);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    status = mManager->postSend(mConnectionId, receiverId, sbuffer,
+                               &transactionId, &postUs);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    message.data.command = PipeCommand::SEND;
+    message.data.bufferId = sbuffer->mId;
+    message.data.connectionId = receiverId;
+    message.data.transactionId = transactionId;
+    message.data.timestampUs = postUs;
+    sendMessage(mCommandPipeFds, message);
+  }
+  EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/single.cpp b/media/libstagefright/codec2/vndk/bufferpool/vts/single.cpp
new file mode 100644
index 0000000..89eb631
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/vts/single.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <C2AllocatorIon.h>
+#include <C2Buffer.h>
+#include <C2PlatformSupport.h>
+#include <ClientManager.h>
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+#include <hidl/Status.h>
+#include <unistd.h>
+#include <iostream>
+#include <memory>
+#include <vector>
+
+using android::C2AllocatorIon;
+using android::C2PlatformAllocatorStore;
+using android::hardware::hidl_handle;
+using android::hardware::media::bufferpool::V1_0::IAccessor;
+using android::hardware::media::bufferpool::V1_0::ResultStatus;
+using android::hardware::media::bufferpool::V1_0::implementation::BufferId;
+using android::hardware::media::bufferpool::V1_0::implementation::ClientManager;
+using android::hardware::media::bufferpool::V1_0::implementation::ConnectionId;
+using android::hardware::media::bufferpool::V1_0::implementation::TransactionId;
+
+namespace {
+
+// Buffer allocation size for tests.
+constexpr static int kAllocationSize = 1024 * 10;
+
+// Number of iteration for buffer allocation test.
+constexpr static int kNumAllocationTest = 3;
+
+// Number of iteration for buffer recycling test.
+constexpr static int kNumRecycleTest = 3;
+
+// media.bufferpool test setup
+class BufferpoolSingleTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    ResultStatus status;
+
+    mManager = ClientManager::getInstance();
+    ASSERT_NE(mManager, nullptr);
+
+    mAllocator =
+        std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
+    ASSERT_TRUE((bool)mAllocator);
+
+    status = mManager->create(mAllocator, true, &mConnectionId);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    status = mManager->getAccessor(mConnectionId, &mAccessor);
+    ASSERT_TRUE(status == ResultStatus::OK && (bool)mAccessor);
+
+    ConnectionId& receiverId = mReceiverId;
+    mManager->registerSender(
+        mAccessor,
+        [&status, &receiverId](ResultStatus hidlStatus, ConnectionId hidlId) {
+          status = hidlStatus;
+          receiverId = hidlId;
+        });
+    ASSERT_TRUE(status == ResultStatus::ALREADY_EXISTS &&
+                receiverId == mConnectionId);
+  }
+
+ protected:
+  static void description(const std::string& description) {
+    RecordProperty("description", description);
+  }
+
+  android::sp<ClientManager> mManager;
+  android::sp<IAccessor> mAccessor;
+  std::shared_ptr<C2Allocator> mAllocator;
+  ConnectionId mConnectionId;
+  ConnectionId mReceiverId;
+
+  void getAllocationParams(std::vector<uint8_t>* vecParams) {
+    union Params {
+      struct {
+        uint32_t capacity;
+        C2MemoryUsage usage;
+      } data;
+      uint8_t array[0];
+      Params()
+          : data{kAllocationSize,
+                 {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}} {}
+    } params;
+    vecParams->assign(params.array, params.array + sizeof(params));
+  }
+};
+
+// Buffer allocation test.
+// Check whether each buffer allocation is done successfully with
+// unique buffer id.
+TEST_F(BufferpoolSingleTest, AllocateBuffer) {
+  ResultStatus status;
+  std::vector<uint8_t> vecParams;
+  getAllocationParams(&vecParams);
+
+  std::shared_ptr<_C2BlockPoolData> buffer[kNumAllocationTest];
+  for (int i = 0; i < kNumAllocationTest; ++i) {
+    status = mManager->allocate(mConnectionId, vecParams, &buffer[i]);
+    ASSERT_TRUE(status == ResultStatus::OK);
+  }
+  for (int i = 0; i < kNumAllocationTest; ++i) {
+    for (int j = i + 1; j < kNumAllocationTest; ++j) {
+      ASSERT_TRUE(buffer[i]->mId != buffer[j]->mId);
+    }
+  }
+  EXPECT_TRUE(kNumAllocationTest > 1);
+}
+
+// Buffer recycle test.
+// Check whether de-allocated buffers are recycled.
+TEST_F(BufferpoolSingleTest, RecycleBuffer) {
+  ResultStatus status;
+  std::vector<uint8_t> vecParams;
+  getAllocationParams(&vecParams);
+
+  BufferId bid[kNumRecycleTest];
+  for (int i = 0; i < kNumRecycleTest; ++i) {
+    std::shared_ptr<_C2BlockPoolData> buffer;
+    status = mManager->allocate(mConnectionId, vecParams, &buffer);
+    ASSERT_TRUE(status == ResultStatus::OK);
+    bid[i] = buffer->mId;
+  }
+  for (int i = 1; i < kNumRecycleTest; ++i) {
+    ASSERT_TRUE(bid[i - 1] == bid[i]);
+  }
+  EXPECT_TRUE(kNumRecycleTest > 1);
+}
+
+// Buffer transfer test.
+// Check whether buffer is transferred to another client successfully.
+TEST_F(BufferpoolSingleTest, TransferBuffer) {
+  ResultStatus status;
+  std::vector<uint8_t> vecParams;
+  getAllocationParams(&vecParams);
+  std::shared_ptr<_C2BlockPoolData> sbuffer, rbuffer;
+
+  TransactionId transactionId;
+  int64_t postUs;
+
+  status = mManager->allocate(mConnectionId, vecParams, &sbuffer);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  status = mManager->postSend(mConnectionId, mReceiverId, sbuffer,
+                              &transactionId, &postUs);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  status = mManager->receive(mReceiverId, transactionId, sbuffer->mId, postUs,
+                             &rbuffer);
+  EXPECT_TRUE(status == ResultStatus::OK);
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}