Merge "Add cross process mutex test and upgrade tests"
diff --git a/media/bufferpool/2.0/tests/Android.bp b/media/bufferpool/2.0/tests/Android.bp
index 8492939..56bda89 100644
--- a/media/bufferpool/2.0/tests/Android.bp
+++ b/media/bufferpool/2.0/tests/Android.bp
@@ -25,7 +25,7 @@
static_libs: [
"android.hardware.media.bufferpool@2.0",
"libcutils",
- "libstagefright_bufferpool@2.0",
+ "libstagefright_bufferpool@2.0.1",
],
shared_libs: [
"libfmq",
@@ -44,10 +44,30 @@
static_libs: [
"android.hardware.media.bufferpool@2.0",
"libcutils",
- "libstagefright_bufferpool@2.0",
+ "libstagefright_bufferpool@2.0.1",
],
shared_libs: [
"libfmq",
],
compile_multilib: "both",
}
+
+cc_test {
+ name: "VtsVndkHidlBufferpoolV2_0TargetCondTest",
+ test_suites: ["device-tests"],
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "allocator.cpp",
+ "cond.cpp",
+ ],
+ static_libs: [
+ "android.hardware.media.bufferpool@2.0",
+ "libcutils",
+ "libstagefright_bufferpool@2.0.1",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libfmq",
+ ],
+ compile_multilib: "both",
+}
diff --git a/media/bufferpool/2.0/tests/allocator.cpp b/media/bufferpool/2.0/tests/allocator.cpp
index 843f7ea..25b08ef 100644
--- a/media/bufferpool/2.0/tests/allocator.cpp
+++ b/media/bufferpool/2.0/tests/allocator.cpp
@@ -120,6 +120,24 @@
}
+void IpcMutex::init() {
+ pthread_mutexattr_t mattr;
+ pthread_mutexattr_init(&mattr);
+ pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
+ pthread_mutex_init(&lock, &mattr);
+ pthread_mutexattr_destroy(&mattr);
+
+ pthread_condattr_t cattr;
+ pthread_condattr_init(&cattr);
+ pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
+ pthread_cond_init(&cond, &cattr);
+ pthread_condattr_destroy(&cattr);
+}
+
+IpcMutex *IpcMutex::Import(void *pMutex) {
+ return reinterpret_cast<IpcMutex *>(pMutex);
+}
+
ResultStatus TestBufferPoolAllocator::allocate(
const std::vector<uint8_t> ¶ms,
@@ -201,9 +219,33 @@
return false;
}
+bool TestBufferPoolAllocator::MapMemoryForMutex(const native_handle_t *handle, void **mem) {
+ if (!HandleAshmem::isValid(handle)) {
+ return false;
+ }
+ const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+ *mem = mmap(
+ NULL, o->size(), PROT_READ|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0);
+ if (*mem == MAP_FAILED || *mem == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+bool TestBufferPoolAllocator::UnmapMemoryForMutex(void *mem) {
+ munmap(mem, sizeof(IpcMutex));
+ return true;
+}
+
void getTestAllocatorParams(std::vector<uint8_t> *params) {
constexpr static int kAllocationSize = 1024 * 10;
Params ashmemParams(kAllocationSize);
params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
}
+
+void getIpcMutexParams(std::vector<uint8_t> *params) {
+ Params ashmemParams(sizeof(IpcMutex));
+
+ params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
+}
diff --git a/media/bufferpool/2.0/tests/allocator.h b/media/bufferpool/2.0/tests/allocator.h
index 5281dc3..862d1a5 100644
--- a/media/bufferpool/2.0/tests/allocator.h
+++ b/media/bufferpool/2.0/tests/allocator.h
@@ -17,6 +17,7 @@
#ifndef VNDK_HIDL_BUFFERPOOL_V2_0_ALLOCATOR_H
#define VNDK_HIDL_BUFFERPOOL_V2_0_ALLOCATOR_H
+#include <pthread.h>
#include <bufferpool/BufferPoolTypes.h>
using android::hardware::media::bufferpool::V2_0::ResultStatus;
@@ -25,6 +26,17 @@
using android::hardware::media::bufferpool::V2_0::implementation::
BufferPoolAllocator;
+struct IpcMutex {
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ int counter = 0;
+ bool signalled = false;
+
+ void init();
+
+ static IpcMutex *Import(void *mem);
+};
+
// buffer allocator for the tests
class TestBufferPoolAllocator : public BufferPoolAllocator {
public:
@@ -43,9 +55,14 @@
static bool Verify(const native_handle_t *handle, const unsigned char val);
+ static bool MapMemoryForMutex(const native_handle_t *handle, void **mem);
+
+ static bool UnmapMemoryForMutex(void *mem);
};
// retrieve buffer allocator paramters
void getTestAllocatorParams(std::vector<uint8_t> *params);
+void getIpcMutexParams(std::vector<uint8_t> *params);
+
#endif // VNDK_HIDL_BUFFERPOOL_V2_0_ALLOCATOR_H
diff --git a/media/bufferpool/2.0/tests/cond.cpp b/media/bufferpool/2.0/tests/cond.cpp
new file mode 100644
index 0000000..21beea8
--- /dev/null
+++ b/media/bufferpool/2.0/tests/cond.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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 <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <bufferpool/ClientManager.h>
+#include <errno.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>
+#include "allocator.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::hidl_handle;
+using android::hardware::media::bufferpool::V2_0::IClientManager;
+using android::hardware::media::bufferpool::V2_0::ResultStatus;
+using android::hardware::media::bufferpool::V2_0::implementation::BufferId;
+using android::hardware::media::bufferpool::V2_0::implementation::ClientManager;
+using android::hardware::media::bufferpool::V2_0::implementation::ConnectionId;
+using android::hardware::media::bufferpool::V2_0::implementation::TransactionId;
+using android::hardware::media::bufferpool::BufferPoolData;
+
+namespace {
+
+// 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];
+};
+
+constexpr int kSignalInt = 200;
+
+// media.bufferpool test setup
+class BufferpoolMultiTest : public ::testing::Test {
+ public:
+ virtual void SetUp() override {
+ ResultStatus status;
+ mReceiverPid = -1;
+ mConnectionValid = false;
+
+ ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
+ ASSERT_TRUE(pipe(mResultPipeFds) == 0);
+
+ mReceiverPid = fork();
+ ASSERT_TRUE(mReceiverPid >= 0);
+
+ if (mReceiverPid == 0) {
+ doReceiver();
+ // In order to ignore gtest behaviour, wait for being killed from
+ // tearDown
+ pause();
+ }
+
+ mManager = ClientManager::getInstance();
+ ASSERT_NE(mManager, nullptr);
+
+ mAllocator = std::make_shared<TestBufferPoolAllocator>();
+ ASSERT_TRUE((bool)mAllocator);
+
+ status = mManager->create(mAllocator, &mConnectionId);
+ ASSERT_TRUE(status == ResultStatus::OK);
+ mConnectionValid = true;
+ }
+
+ virtual void TearDown() override {
+ if (mReceiverPid > 0) {
+ kill(mReceiverPid, SIGKILL);
+ int wstatus;
+ wait(&wstatus);
+ }
+
+ if (mConnectionValid) {
+ mManager->close(mConnectionId);
+ }
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ android::sp<ClientManager> mManager;
+ std::shared_ptr<BufferPoolAllocator> mAllocator;
+ bool mConnectionValid;
+ ConnectionId mConnectionId;
+ pid_t mReceiverPid;
+ int mCommandPipeFds[2];
+ int mResultPipeFds[2];
+
+ 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);
+
+ int val = 0;
+ receiveMessage(mCommandPipeFds, &message);
+ {
+ native_handle_t *rhandle = nullptr;
+ std::shared_ptr<BufferPoolData> rbuffer;
+ void *mem = nullptr;
+ IpcMutex *mutex = nullptr;
+ ResultStatus status = mManager->receive(
+ message.data.connectionId, message.data.transactionId,
+ message.data.bufferId, message.data.timestampUs, &rhandle, &rbuffer);
+ mManager->close(message.data.connectionId);
+ if (status != ResultStatus::OK) {
+ message.data.command = PipeCommand::RECEIVE_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ if (!TestBufferPoolAllocator::MapMemoryForMutex(rhandle, &mem)) {
+ message.data.command = PipeCommand::RECEIVE_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ mutex = IpcMutex::Import(mem);
+ pthread_mutex_lock(&(mutex->lock));
+ while (mutex->signalled != true) {
+ pthread_cond_wait(&(mutex->cond), &(mutex->lock));
+ }
+ val = mutex->counter;
+ pthread_mutex_unlock(&(mutex->lock));
+
+ (void)TestBufferPoolAllocator::UnmapMemoryForMutex(mem);
+ if (rhandle) {
+ native_handle_close(rhandle);
+ native_handle_delete(rhandle);
+ }
+ }
+ if (val == kSignalInt) {
+ message.data.command = PipeCommand::RECEIVE_OK;
+ } else {
+ message.data.command = PipeCommand::RECEIVE_ERROR;
+ }
+ sendMessage(mResultPipeFds, message);
+ }
+};
+
+// 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);
+
+ status = mManager->registerSender(receiver, mConnectionId, &receiverId);
+ ASSERT_TRUE(status == ResultStatus::OK);
+ {
+ native_handle_t *shandle = nullptr;
+ std::shared_ptr<BufferPoolData> sbuffer;
+ TransactionId transactionId;
+ int64_t postUs;
+ std::vector<uint8_t> vecParams;
+ void *mem = nullptr;
+ IpcMutex *mutex = nullptr;
+
+ getIpcMutexParams(&vecParams);
+ status = mManager->allocate(mConnectionId, vecParams, &shandle, &sbuffer);
+ ASSERT_TRUE(status == ResultStatus::OK);
+
+ ASSERT_TRUE(TestBufferPoolAllocator::MapMemoryForMutex(shandle, &mem));
+
+ mutex = new(mem) IpcMutex();
+ mutex->init();
+
+ status = mManager->postSend(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);
+ for (int i=0; i < 200000000; ++i) {
+ // no-op in order to ensure
+ // pthread_cond_wait is called before pthread_cond_signal
+ }
+ pthread_mutex_lock(&(mutex->lock));
+ mutex->counter = kSignalInt;
+ mutex->signalled = true;
+ pthread_cond_signal(&(mutex->cond));
+ pthread_mutex_unlock(&(mutex->lock));
+ (void)TestBufferPoolAllocator::UnmapMemoryForMutex(mem);
+ if (shandle) {
+ native_handle_close(shandle);
+ native_handle_delete(shandle);
+ }
+ }
+ EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
+ EXPECT_TRUE(message.data.command == PipeCommand::RECEIVE_OK);
+}
+
+} // anonymous namespace
+
+int main(int argc, char** argv) {
+ android::hardware::details::setTrebleTestingOverride(true);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/media/bufferpool/2.0/tests/multi.cpp b/media/bufferpool/2.0/tests/multi.cpp
index b40838e..43b0a8c 100644
--- a/media/bufferpool/2.0/tests/multi.cpp
+++ b/media/bufferpool/2.0/tests/multi.cpp
@@ -161,11 +161,18 @@
message.data.bufferId, message.data.timestampUs, &rhandle, &rbuffer);
mManager->close(message.data.connectionId);
if (status != ResultStatus::OK) {
- if (!TestBufferPoolAllocator::Verify(rhandle, 0x77)) {
- message.data.command = PipeCommand::RECEIVE_ERROR;
- sendMessage(mResultPipeFds, message);
- return;
- }
+ message.data.command = PipeCommand::RECEIVE_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ if (!TestBufferPoolAllocator::Verify(rhandle, 0x77)) {
+ message.data.command = PipeCommand::RECEIVE_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ if (rhandle) {
+ native_handle_close(rhandle);
+ native_handle_delete(rhandle);
}
}
message.data.command = PipeCommand::RECEIVE_OK;
@@ -198,6 +205,10 @@
ASSERT_TRUE(status == ResultStatus::OK);
ASSERT_TRUE(TestBufferPoolAllocator::Fill(shandle, 0x77));
+ if (shandle) {
+ native_handle_close(shandle);
+ native_handle_delete(shandle);
+ }
status = mManager->postSend(receiverId, sbuffer, &transactionId, &postUs);
ASSERT_TRUE(status == ResultStatus::OK);
@@ -210,6 +221,7 @@
sendMessage(mCommandPipeFds, message);
}
EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
+ EXPECT_TRUE(message.data.command == PipeCommand::RECEIVE_OK);
}
} // anonymous namespace
diff --git a/media/bufferpool/2.0/tests/single.cpp b/media/bufferpool/2.0/tests/single.cpp
index 777edcf..1e9027b 100644
--- a/media/bufferpool/2.0/tests/single.cpp
+++ b/media/bufferpool/2.0/tests/single.cpp
@@ -102,6 +102,10 @@
for (int i = 0; i < kNumAllocationTest; ++i) {
status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer[i]);
ASSERT_TRUE(status == ResultStatus::OK);
+ if (allocHandle) {
+ native_handle_close(allocHandle);
+ native_handle_delete(allocHandle);
+ }
}
for (int i = 0; i < kNumAllocationTest; ++i) {
for (int j = i + 1; j < kNumAllocationTest; ++j) {
@@ -125,6 +129,10 @@
status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer);
ASSERT_TRUE(status == ResultStatus::OK);
bid[i] = buffer->mId;
+ if (allocHandle) {
+ native_handle_close(allocHandle);
+ native_handle_delete(allocHandle);
+ }
}
for (int i = 1; i < kNumRecycleTest; ++i) {
ASSERT_TRUE(bid[i - 1] == bid[i]);
@@ -154,6 +162,15 @@
&recvHandle, &rbuffer);
EXPECT_TRUE(status == ResultStatus::OK);
ASSERT_TRUE(TestBufferPoolAllocator::Verify(recvHandle, 0x77));
+
+ if (allocHandle) {
+ native_handle_close(allocHandle);
+ native_handle_delete(allocHandle);
+ }
+ if (recvHandle) {
+ native_handle_close(recvHandle);
+ native_handle_delete(recvHandle);
+ }
}
} // anonymous namespace