/*
* Copyright (C) 2017 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 "SensorTest.h"
#include <errno.h>
namespace android {
namespace SensorTest {
// SensorTest container class
bool SensorTest::SetUp() {
if (mManager == nullptr) {
mManager.reset(
TestSensorManager::getInstanceForPackage("android.hardware.cts.SensorNativeTest"));
}
return mManager == nullptr;
}
void SensorTest::TearDown() {
if (mManager == nullptr) {
mManager.reset(nullptr);
}
}
TestSensorManager::TestSensorManager(const char *package) {
mManager = ASensorManager_getInstanceForPackage(package);
}
TestSensorManager::~TestSensorManager() {
for (int channel : mSensorDirectChannel) {
destroyDirectChannel(channel);
}
mSensorDirectChannel.clear();
}
TestSensorManager * TestSensorManager::getInstanceForPackage(const char *package) {
return new TestSensorManager(package);
}
TestSensor TestSensorManager::getDefaultSensor(int type) {
return TestSensor(ASensorManager_getDefaultSensor(mManager, type));
}
int TestSensorManager::createDirectChannel(const TestSharedMemory &mem) {
if (!isValid()) {
return -EINVAL;
}
switch (mem.getType()) {
case ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY:
return createSharedMemoryDirectChannel(
mem.getSharedMemoryFd(), mem.getSize());
case ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER:
return createHardwareBufferDirectChannel(
mem.getHardwareBuffer(), mem.getSize());
default:
return -1;
}
}
int TestSensorManager::createSharedMemoryDirectChannel(int fd, size_t size) {
int ret = ASensorManager_createSharedMemoryDirectChannel(mManager, fd, size);
if (ret > 0) {
mSensorDirectChannel.insert(ret);
}
return ret;
}
int TestSensorManager::createHardwareBufferDirectChannel(
AHardwareBuffer const *buffer, size_t size) {
int ret = ASensorManager_createHardwareBufferDirectChannel(mManager, buffer, size);
if (ret > 0) {
mSensorDirectChannel.insert(ret);
}
return ret;
}
void TestSensorManager::destroyDirectChannel(int channel) {
if (!isValid()) {
return;
}
ASensorManager_destroyDirectChannel(mManager, channel);
mSensorDirectChannel.erase(channel);
return;
}
int TestSensorManager::configureDirectReport(TestSensor sensor, int channel, int rate) {
if (!isValid()) {
return -EINVAL;
}
return ASensorManager_configureDirectReport(mManager, sensor, channel, rate);
}
char * TestSharedMemory::getBuffer() const {
return mBuffer;
}
std::vector<ASensorEvent> TestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const {
constexpr size_t kEventSize = sizeof(ASensorEvent);
constexpr size_t kOffsetSize = offsetof(ASensorEvent, version);
constexpr size_t kOffsetAtomicCounter = offsetof(ASensorEvent, reserved0);
std::vector<ASensorEvent> events;
while (offset + kEventSize <= mSize) {
int64_t atomicCounter = *reinterpret_cast<uint32_t *>(mBuffer + offset + kOffsetAtomicCounter);
if (atomicCounter <= lastCounter) {
break;
}
int32_t size = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetSize);
if (size != kEventSize) {
// unknown error, events parsed may be wrong, remove all
events.clear();
break;
}
events.push_back(*reinterpret_cast<ASensorEvent *>(mBuffer + offset));
lastCounter = atomicCounter;
offset += kEventSize;
}
return events;
}
TestSharedMemory::TestSharedMemory(int type, size_t size)
: mType(type), mSize(0), mBuffer(nullptr),
mSharedMemoryFd(-1), mHardwareBuffer(nullptr) {
bool success = false;
switch(type) {
case ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY: {
mSharedMemoryFd = ASharedMemory_create("TestSharedMemory", size);
if (mSharedMemoryFd < 0
|| ASharedMemory_getSize(mSharedMemoryFd) != size) {
break;
}
mSize = size;
mBuffer = reinterpret_cast<char *>(::mmap(
nullptr, mSize, PROT_READ | PROT_WRITE,
MAP_SHARED, mSharedMemoryFd, 0));
if (mBuffer == MAP_FAILED) {
mBuffer = nullptr;
break;
}
success = true;
break;
}
case ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER: {
AHardwareBuffer_Desc desc = {
.width = static_cast<uint32_t>(size),
.height = 1,
.layers = 1,
.usage = AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA
| AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
.format = AHARDWAREBUFFER_FORMAT_BLOB
};
// allocate
if (AHardwareBuffer_allocate(&desc, &mHardwareBuffer) == 0) {
// lock
if (AHardwareBuffer_lock(mHardwareBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY,
-1, nullptr, reinterpret_cast<void **>(&mBuffer)) == 0) {
if (mBuffer != nullptr) {
mSize = size;
success = true;
}
}
}
break;
}
default:
break;
}
if (!success) {
release();
}
}
TestSharedMemory::~TestSharedMemory() {
release();
}
void TestSharedMemory::release() {
switch(mType) {
case ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY: {
if (mBuffer != nullptr) {
::munmap(mBuffer, mSize);
mBuffer = nullptr;
}
if (mSharedMemoryFd > 0) {
::close(mSharedMemoryFd);
mSharedMemoryFd = -1;
}
mSize = 0;
break;
}
case ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER: {
if (mHardwareBuffer != nullptr) {
if (mBuffer != nullptr) {
int32_t fence = -1;
AHardwareBuffer_unlock(mHardwareBuffer, &fence);
mBuffer = nullptr;
}
AHardwareBuffer_release(mHardwareBuffer);
mHardwareBuffer = nullptr;
}
mSize = 0;
break;
}
default:
break;
}
if (mSharedMemoryFd > 0 || mSize != 0 || mBuffer != nullptr || mHardwareBuffer != nullptr) {
ALOGE("TestSharedMemory %p not properly destructed: "
"type %d, shared_memory_fd %d, hardware_buffer %p, size %zu, buffer %p",
this, static_cast<int>(mType), mSharedMemoryFd, mHardwareBuffer, mSize, mBuffer);
}
}
TestSharedMemory* TestSharedMemory::create(int type, size_t size) {
constexpr size_t kMaxSize = 128*1024*1024; // sensor test should not need more than 128M
if (size == 0 || size >= kMaxSize) {
return nullptr;
}
auto m = new TestSharedMemory(type, size);
if (m->mSize != size || m->mBuffer == nullptr) {
delete m;
m = nullptr;
}
return m;
}
} // namespace SensorTest
} // namespace android