Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1bdafa3a authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add cross process mutex test and upgrade tests"

parents 8bd3f093 ec638f5b
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ cc_test {
    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 @@ cc_test {
    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",
}
+42 −0
Original line number Diff line number Diff line
@@ -120,6 +120,24 @@ struct AllocationDtor {

}

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> &params,
@@ -201,9 +219,33 @@ bool TestBufferPoolAllocator::Verify(const native_handle_t *handle, const unsign
  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));
}
+17 −0
Original line number Diff line number Diff line
@@ -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::
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 @@ class TestBufferPoolAllocator : public BufferPoolAllocator {

  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
+269 −0
Original line number Diff line number Diff line
/*
 * 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;
}
+17 −5
Original line number Diff line number Diff line
@@ -161,11 +161,18 @@ class BufferpoolMultiTest : public ::testing::Test {
          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::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 @@ TEST_F(BufferpoolMultiTest, TransferBuffer) {
    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 @@ TEST_F(BufferpoolMultiTest, TransferBuffer) {
    sendMessage(mCommandPipeFds, message);
  }
  EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
  EXPECT_TRUE(message.data.command == PipeCommand::RECEIVE_OK);
}

}  // anonymous namespace
Loading