blob: 02c0fc23ac66c0fb527af84cf0ceb7819a579b3c [file] [log] [blame]
/*
* Copyright (C) 2016 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 "sensor_manager_hidl_hal_test"
#include <android-base/logging.h>
#include <sys/mman.h>
#include <chrono>
#include <thread>
#include <android-base/result.h>
#include <android/frameworks/sensorservice/1.0/ISensorManager.h>
#include <android/frameworks/sensorservice/1.0/types.h>
#include <android/hardware/sensors/1.0/types.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/sensor.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
#include <sensors/convert.h>
using ::android::sp;
using ::android::frameworks::sensorservice::V1_0::ISensorManager;
using ::android::frameworks::sensorservice::V1_0::Result;
using ::android::hardware::hidl_memory;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::sensors::V1_0::Event;
using ::android::hardware::sensors::V1_0::RateLevel;
using ::android::hardware::sensors::V1_0::SensorFlagBits;
using ::android::hardware::sensors::V1_0::SensorFlagShift;
using ::android::hardware::sensors::V1_0::SensorInfo;
using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
using ::android::hardware::sensors::V1_0::SensorType;
using ::android::hardware::sensors::V1_0::toString;
using ::android::hidl::allocator::V1_0::IAllocator;
using ::testing::Contains;
template <typename T>
static inline ::testing::AssertionResult isOk(const Return<T> &ret) {
return (ret.isOk()
? ::testing::AssertionSuccess()
: ::testing::AssertionFailure()) << ret.description();
}
template <>
__attribute__((__unused__))
inline ::testing::AssertionResult isOk(const Return<Result> &ret) {
return ((ret.isOk() && ret == Result::OK)
? ::testing::AssertionSuccess()
: ::testing::AssertionFailure())
<< ret.description() << ", "
<< (ret.isOk() ? toString(static_cast<Result>(ret)) : "");
}
static inline ::testing::AssertionResult isOk(Result result) {
using ::android::frameworks::sensorservice::V1_0::toString;
return (result == Result::OK
? ::testing::AssertionSuccess()
: ::testing::AssertionFailure()) << toString(result);
}
template<typename I, typename F>
static ::testing::AssertionResult isIncreasing(I begin, I end, F getField) {
typename std::iterator_traits<I>::pointer lastValue = nullptr;
I iter;
size_t pos;
for (iter = begin, pos = 0; iter != end; ++iter, ++pos) {
if (iter == begin) {
lastValue = &(*iter);
continue;
}
if (getField(*iter) < getField(*lastValue)) {
return ::testing::AssertionFailure() << "Not an increasing sequence, pos = "
<< pos << ", " << getField(*iter) << " < " << getField(*lastValue);
}
}
return ::testing::AssertionSuccess();
}
#define EXPECT_OK(__ret__) EXPECT_TRUE(isOk(__ret__))
#define ASSERT_OK(__ret__) ASSERT_TRUE(isOk(__ret__))
class SensorManagerTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
manager_ = ISensorManager::getService(GetParam());
ASSERT_NE(manager_, nullptr);
ashmem_ = IAllocator::getService("ashmem");
ASSERT_NE(ashmem_, nullptr);
}
// Call getSensorList. Filter result based on |pred| if it is provided.
android::base::Result<std::vector<SensorInfo>> GetSensorList(
const std::function<bool(SensorInfo)> &pred = nullptr) {
Result out_result = Result::INVALID_OPERATION;
std::vector<SensorInfo> out_info;
auto ret = manager_->getSensorList([&](const auto &list, auto result) {
out_result = result;
if (result == Result::OK) {
for (const auto &info : list) {
if (!pred || pred(info)) {
out_info.push_back(info);
}
}
}
});
if (!ret.isOk()) {
return android::base::Error() << ret.description();
}
if (out_result != Result::OK) {
return android::base::Error() << "getSensorList returns " << toString(out_result);
}
return out_info;
}
sp<ISensorManager> manager_;
sp<IAllocator> ashmem_;
};
using map_region = std::unique_ptr<void, std::function<void(void*)>>;
map_region map(const hidl_memory &mem) {
if (mem.handle() == nullptr || mem.handle()->numFds != 1) {
return nullptr;
}
size_t size = mem.size();
void *buf = mmap(nullptr, size, PROT_READ, MAP_SHARED, mem.handle()->data[0], 0);
return map_region{buf, [size](void *localBuf) {
munmap(localBuf, size);
}};
}
TEST_P(SensorManagerTest, List) {
ASSERT_RESULT_OK(GetSensorList());
}
TEST_P(SensorManagerTest, Ashmem) {
auto ashmem_sensors = GetSensorList(
[](const auto &info) { return info.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM; });
ASSERT_RESULT_OK(ashmem_sensors);
if (ashmem_sensors->empty()) {
GTEST_SKIP() << "DIRECT_CHANNEL_ASHMEM not supported by HAL, skipping";
}
auto testOne = [this](uint64_t memSize, uint64_t intendedSize,
ISensorManager::createAshmemDirectChannel_cb callback) {
ASSERT_OK(ashmem_->allocate(memSize, [&](bool success, const auto &mem) {
ASSERT_TRUE(success);
ASSERT_NE(mem.handle(), nullptr);
ASSERT_OK(manager_->createAshmemDirectChannel(mem, intendedSize, callback));
}));
};
testOne(16, 16, [](const auto &chan, Result result) {
EXPECT_EQ(result, Result::BAD_VALUE) << "unexpected result when memory size is too small";
EXPECT_EQ(chan, nullptr);
});
testOne(1024, 1024, [](const auto &chan, Result result) {
EXPECT_OK(result);
EXPECT_NE(chan, nullptr);
});
testOne(1024, 2048, [](const auto &chan, Result result) {
EXPECT_EQ(result, Result::BAD_VALUE) << "unexpected result when intended size is too big";
EXPECT_EQ(chan, nullptr);
});
testOne(1024, 16, [](const auto &chan, Result result) {
EXPECT_EQ(result, Result::BAD_VALUE) << "unexpected result when intended size is too small";
EXPECT_EQ(chan, nullptr);
});
}
static std::vector<Event> parseEvents(uint8_t *buf, size_t memSize) {
using O = SensorsEventFormatOffset;
using ::android::hardware::sensors::V1_0::implementation::convertFromSensorEvent;
size_t offset = 0;
int64_t lastCounter = -1;
std::vector<Event> events;
Event event;
while(offset + (size_t)O::TOTAL_LENGTH <= memSize) {
uint8_t *start = buf + offset;
int64_t atomicCounter = *reinterpret_cast<uint32_t *>(start + (size_t)O::ATOMIC_COUNTER);
if (atomicCounter <= lastCounter) {
break;
}
int32_t size = *reinterpret_cast<int32_t *>(start + (size_t)O::SIZE_FIELD);
if (size != (size_t)O::TOTAL_LENGTH) {
// unknown error, events parsed may be wrong, remove all
events.clear();
break;
}
convertFromSensorEvent(*reinterpret_cast<const sensors_event_t *>(start), &event);
events.push_back(event);
lastCounter = atomicCounter;
offset += (size_t)O::TOTAL_LENGTH;
}
return events;
}
TEST_P(SensorManagerTest, GetDefaultAccelerometer) {
auto accelerometer_ashmem_sensors =
GetSensorList([](const auto &info) { return info.type == SensorType::ACCELEROMETER; });
ASSERT_RESULT_OK(accelerometer_ashmem_sensors);
ASSERT_OK(
manager_->getDefaultSensor(SensorType::ACCELEROMETER, [&](const auto &info, auto result) {
if (accelerometer_ashmem_sensors->empty()) {
ASSERT_EQ(Result::NOT_EXIST, result);
} else {
ASSERT_OK(result);
ASSERT_THAT(*accelerometer_ashmem_sensors, Contains(info));
}
}));
}
TEST_P(SensorManagerTest, Accelerometer) {
using std::literals::chrono_literals::operator""ms;
using ::android::hardware::sensors::V1_0::implementation::convertFromRateLevel;
auto accelerometer_ashmem_sensors = GetSensorList([](const auto &info) {
if (info.type != SensorType::ACCELEROMETER) return false;
if (!(info.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM)) return false;
int maxLevel =
(info.flags & SensorFlagBits::MASK_DIRECT_REPORT) >> (int)SensorFlagShift::DIRECT_REPORT;
return maxLevel >= convertFromRateLevel(RateLevel::FAST);
});
ASSERT_RESULT_OK(accelerometer_ashmem_sensors);
if (accelerometer_ashmem_sensors->empty()) {
GTEST_SKIP() << "No accelerometer sensor that supports DIRECT_CHANNEL_ASHMEM and fast report "
<< "rate, skipping";
}
for (const auto &info : *accelerometer_ashmem_sensors) {
int32_t handle = info.sensorHandle;
const size_t memSize = (size_t)SensorsEventFormatOffset::TOTAL_LENGTH * 300;
ASSERT_OK(ashmem_->allocate(memSize, [&](bool success, const auto &mem) {
ASSERT_TRUE(success);
map_region buf = map(mem);
ASSERT_NE(buf, nullptr);
ASSERT_OK(
manager_->createAshmemDirectChannel(mem, memSize, [&](const auto &chan, Result result) {
ASSERT_OK(result);
ASSERT_NE(chan, nullptr);
int32_t returnedToken;
ASSERT_OK(chan->configure(handle, RateLevel::FAST, [&](auto token, auto res) {
ASSERT_OK(res);
ASSERT_GT(token, 0);
returnedToken = token;
})); // ~200Hz
std::this_thread::sleep_for(500ms);
ASSERT_OK(chan->configure(handle, RateLevel::STOP, [](auto token, auto res) {
ASSERT_OK(res);
ASSERT_EQ(token, 0);
}));
auto events = parseEvents(static_cast<uint8_t *>(buf.get()), memSize);
EXPECT_TRUE(isIncreasing(events.begin(), events.end(), [](const auto &event) {
return event.timestamp;
})) << "timestamp is not monotonically increasing";
for (const auto &event : events) {
EXPECT_EQ(returnedToken, event.sensorHandle)
<< "configure token and sensor handle don't match.";
}
}));
}));
}
}
INSTANTIATE_TEST_SUITE_P(
PerInstance, SensorManagerTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISensorManager::descriptor)),
android::hardware::PrintInstanceNameToString);