mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
[sensors] Default implementation and vts of direct report
Added support for newly added HAL function for sensor event direct report feature, replace dummy implementation with funtional ones for the following: * registerDirectChannel * unregisterDirectChannel * configDirectReport Added a vts test case for direct report. Added new offset definition to types.hal. This will not affect existing client/calling code. Bug: 30985702 Bug: 32022776 Test: vts pass Change-Id: Ie5e3cddd7c37664e8c59d69cf70aaa1310fd3f58
This commit is contained in:
@@ -42,10 +42,12 @@ static Result ResultFromStatus(status_t err) {
|
||||
switch (err) {
|
||||
case OK:
|
||||
return Result::OK;
|
||||
case BAD_VALUE:
|
||||
return Result::BAD_VALUE;
|
||||
case PERMISSION_DENIED:
|
||||
return Result::PERMISSION_DENIED;
|
||||
case NO_MEMORY:
|
||||
return Result::NO_MEMORY;
|
||||
case BAD_VALUE:
|
||||
return Result::BAD_VALUE;
|
||||
default:
|
||||
return Result::INVALID_OPERATION;
|
||||
}
|
||||
@@ -226,27 +228,68 @@ Return<Result> Sensors::injectSensorData(const Event& event) {
|
||||
|
||||
Return<void> Sensors::registerDirectChannel(
|
||||
const SharedMemInfo& mem, registerDirectChannel_cb _hidl_cb) {
|
||||
//TODO(b/30985702): finish implementation
|
||||
(void) mem;
|
||||
_hidl_cb(Result::INVALID_OPERATION, -1);
|
||||
if (mSensorDevice->register_direct_channel == nullptr
|
||||
|| mSensorDevice->config_direct_report == nullptr) {
|
||||
// HAL does not support
|
||||
_hidl_cb(Result::INVALID_OPERATION, -1);
|
||||
return Void();
|
||||
}
|
||||
|
||||
sensors_direct_mem_t m;
|
||||
if (!convertFromSharedMemInfo(mem, &m)) {
|
||||
_hidl_cb(Result::BAD_VALUE, -1);
|
||||
return Void();
|
||||
}
|
||||
|
||||
int err = mSensorDevice->register_direct_channel(mSensorDevice, &m, -1);
|
||||
|
||||
if (err < 0) {
|
||||
_hidl_cb(ResultFromStatus(err), -1);
|
||||
} else {
|
||||
int32_t channelHandle = static_cast<int32_t>(err);
|
||||
_hidl_cb(Result::OK, channelHandle);
|
||||
}
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<Result> Sensors::unregisterDirectChannel(int32_t channelHandle) {
|
||||
//TODO(b/30985702): finish implementation
|
||||
(void) channelHandle;
|
||||
return Result::INVALID_OPERATION;
|
||||
if (mSensorDevice->register_direct_channel == nullptr
|
||||
|| mSensorDevice->config_direct_report == nullptr) {
|
||||
// HAL does not support
|
||||
return Result::INVALID_OPERATION;
|
||||
}
|
||||
|
||||
mSensorDevice->register_direct_channel(mSensorDevice, nullptr, channelHandle);
|
||||
|
||||
return Result::OK;
|
||||
}
|
||||
|
||||
Return<void> Sensors::configDirectReport(
|
||||
int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
|
||||
configDirectReport_cb _hidl_cb) {
|
||||
//TODO(b/30985702): finish implementation
|
||||
(void) sensorHandle;
|
||||
(void) channelHandle;
|
||||
(void) rate;
|
||||
if (mSensorDevice->register_direct_channel == nullptr
|
||||
|| mSensorDevice->config_direct_report == nullptr) {
|
||||
// HAL does not support
|
||||
_hidl_cb(Result::INVALID_OPERATION, -1);
|
||||
return Void();
|
||||
}
|
||||
|
||||
_hidl_cb(Result::INVALID_OPERATION, -1);
|
||||
sensors_direct_cfg_t cfg = {
|
||||
.rate_level = convertFromRateLevel(rate)
|
||||
};
|
||||
if (cfg.rate_level < 0) {
|
||||
_hidl_cb(Result::BAD_VALUE, -1);
|
||||
return Void();
|
||||
}
|
||||
|
||||
int err = mSensorDevice->config_direct_report(mSensorDevice,
|
||||
sensorHandle, channelHandle, &cfg);
|
||||
|
||||
if (rate == RateLevel::STOP) {
|
||||
_hidl_cb(ResultFromStatus(err), -1);
|
||||
} else {
|
||||
_hidl_cb(err > 0 ? Result::OK : ResultFromStatus(err), err);
|
||||
}
|
||||
return Void();
|
||||
}
|
||||
|
||||
|
||||
@@ -340,6 +340,50 @@ void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
|
||||
}
|
||||
}
|
||||
|
||||
bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut) {
|
||||
if (memOut == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(memIn.type) {
|
||||
case SharedMemType::ASHMEM:
|
||||
memOut->type = SENSOR_DIRECT_MEM_TYPE_ASHMEM;
|
||||
break;
|
||||
case SharedMemType::GRALLOC:
|
||||
memOut->type = SENSOR_DIRECT_MEM_TYPE_GRALLOC;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(memIn.format) {
|
||||
case SharedMemFormat::SENSORS_EVENT:
|
||||
memOut->format = SENSOR_DIRECT_FMT_SENSORS_EVENT;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
memOut->size = memIn.size;
|
||||
memOut->handle = memIn.memoryHandle;
|
||||
return true;
|
||||
}
|
||||
|
||||
int convertFromRateLevel(RateLevel rate) {
|
||||
switch(rate) {
|
||||
case RateLevel::STOP:
|
||||
return SENSOR_DIRECT_RATE_STOP;
|
||||
case RateLevel::NORMAL:
|
||||
return SENSOR_DIRECT_RATE_NORMAL;
|
||||
case RateLevel::FAST:
|
||||
return SENSOR_DIRECT_RATE_FAST;
|
||||
case RateLevel::VERY_FAST:
|
||||
return SENSOR_DIRECT_RATE_VERY_FAST;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
} // namespace sensors
|
||||
|
||||
@@ -33,6 +33,9 @@ void convertToSensor(const SensorInfo &src, sensor_t *dst);
|
||||
void convertFromSensorEvent(const sensors_event_t &src, Event *dst);
|
||||
void convertToSensorEvent(const Event &src, sensors_event_t *dst);
|
||||
|
||||
bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut);
|
||||
int convertFromRateLevel(RateLevel rate);
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
} // namespace sensors
|
||||
|
||||
@@ -1224,23 +1224,32 @@ enum SharedMemType : int32_t {
|
||||
@export(name="direct_format_t", value_prefix="SENSOR_DIRECT_FMT_")
|
||||
enum SharedMemFormat : int32_t {
|
||||
SENSORS_EVENT = 1, // shared memory is formated as an array of data
|
||||
// elements, each sized 104 bytes. Details of fields:
|
||||
//
|
||||
// offset type name
|
||||
//-----------------------------------
|
||||
// 0x0000 int32_t size (always 104)
|
||||
// 0x0004 int32_t sensor report token
|
||||
// 0x0008 int32_t type (see SensorType)
|
||||
// 0x000C int32_t atomic counter
|
||||
// 0x0010 int64_t timestamp (see Event)
|
||||
// 0x0014 float[16]/ data
|
||||
// int64_t[8]
|
||||
// 0x0058 int32_t[4] reserved
|
||||
//
|
||||
// elements. See SensorsEventFormatOffset for details.
|
||||
// Upon return of channel registration call, the
|
||||
// shared memory space must be formated to all 0 by HAL.
|
||||
};
|
||||
|
||||
enum SensorsEventFormatOffset : uint16_t {
|
||||
// offset type name
|
||||
//-----------------------------------
|
||||
// 0x0000 int32_t size (always 104)
|
||||
// 0x0004 int32_t sensor report token
|
||||
// 0x0008 int32_t type (see SensorType)
|
||||
// 0x000C uint32_t atomic counter
|
||||
// 0x0010 int64_t timestamp (see Event)
|
||||
// 0x0018 float[16]/ data
|
||||
// int64_t[8]
|
||||
// 0x0058 int32_t[4] reserved (set to zero)
|
||||
SIZE_FIELD = 0x0,
|
||||
REPORT_TOKEN = 0x4,
|
||||
SENSOR_TYPE = 0x8,
|
||||
ATOMIC_COUNTER = 0xC,
|
||||
TIMESTAMP = 0x10,
|
||||
DATA = 0x18,
|
||||
RESERVED = 0x58,
|
||||
TOTAL_LENGTH = 0x68
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared memory information for a direct channel
|
||||
*/
|
||||
|
||||
@@ -19,10 +19,11 @@ cc_test {
|
||||
gtest: true,
|
||||
srcs: ["sensors_hidl_hal_test.cpp"],
|
||||
shared_libs: [
|
||||
"liblog",
|
||||
"libhidlbase",
|
||||
"libutils",
|
||||
"android.hardware.sensors@1.0",
|
||||
"libcutils",
|
||||
"libhidlbase",
|
||||
"liblog",
|
||||
"libutils",
|
||||
],
|
||||
static_libs: ["libgtest"],
|
||||
cflags: [
|
||||
|
||||
@@ -19,16 +19,20 @@
|
||||
#include <android/hardware/sensors/1.0/ISensors.h>
|
||||
#include <android/hardware/sensors/1.0/types.h>
|
||||
#include <android/log.h>
|
||||
#include <cutils/ashmem.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <hardware/sensors.h> // for sensor type strings
|
||||
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using ::android::hardware::Return;
|
||||
@@ -148,6 +152,164 @@ void SensorsHidlEnvironment::pollingThread(
|
||||
ALOGD("polling thread end");
|
||||
}
|
||||
|
||||
class SensorsTestSharedMemory {
|
||||
public:
|
||||
static SensorsTestSharedMemory* create(SharedMemType type, size_t size);
|
||||
SharedMemInfo getSharedMemInfo() const;
|
||||
char * getBuffer() const;
|
||||
std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const;
|
||||
virtual ~SensorsTestSharedMemory();
|
||||
private:
|
||||
SensorsTestSharedMemory(SharedMemType type, size_t size);
|
||||
|
||||
SharedMemType mType;
|
||||
native_handle_t* mNativeHandle;
|
||||
size_t mSize;
|
||||
char* mBuffer;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory);
|
||||
};
|
||||
|
||||
SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const {
|
||||
SharedMemInfo mem = {
|
||||
.type = mType,
|
||||
.format = SharedMemFormat::SENSORS_EVENT,
|
||||
.size = static_cast<uint32_t>(mSize),
|
||||
.memoryHandle = mNativeHandle
|
||||
};
|
||||
return mem;
|
||||
}
|
||||
|
||||
char * SensorsTestSharedMemory::getBuffer() const {
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const {
|
||||
|
||||
constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
|
||||
constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD);
|
||||
constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN);
|
||||
constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE);
|
||||
constexpr size_t kOffsetAtomicCounter =
|
||||
static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER);
|
||||
constexpr size_t kOffsetTimestamp = static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP);
|
||||
constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA);
|
||||
|
||||
std::vector<Event> events;
|
||||
std::vector<float> data(16);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int32_t token = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetToken);
|
||||
int32_t type = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetType);
|
||||
int64_t timestamp = *reinterpret_cast<int64_t *>(mBuffer + offset + kOffsetTimestamp);
|
||||
|
||||
ALOGV("offset = %zu, cnt %" PRId32 ", token %" PRId32 ", type %" PRId32 ", timestamp %" PRId64,
|
||||
offset, atomicCounter, token, type, timestamp);
|
||||
|
||||
Event event = {
|
||||
.timestamp = timestamp,
|
||||
.sensorHandle = token,
|
||||
.sensorType = static_cast<SensorType>(type),
|
||||
};
|
||||
event.u.data = android::hardware::hidl_array<float, 16>
|
||||
(reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
|
||||
|
||||
events.push_back(event);
|
||||
|
||||
lastCounter = atomicCounter;
|
||||
offset += kEventSize;
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size)
|
||||
: mType(type), mSize(0), mBuffer(nullptr) {
|
||||
native_handle_t *handle = nullptr;
|
||||
char *buffer = nullptr;
|
||||
switch(type) {
|
||||
case SharedMemType::ASHMEM: {
|
||||
int fd;
|
||||
handle = ::native_handle_create(1 /*nFds*/, 0/*nInts*/);
|
||||
if (handle != nullptr) {
|
||||
handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size);
|
||||
if (handle->data[0] > 0) {
|
||||
// memory is pinned by default
|
||||
buffer = static_cast<char *>
|
||||
(::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
|
||||
break;
|
||||
}
|
||||
::native_handle_close(handle);
|
||||
}
|
||||
::native_handle_delete(handle);
|
||||
handle = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (buffer != nullptr) {
|
||||
mNativeHandle = handle;
|
||||
mSize = size;
|
||||
mBuffer = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
SensorsTestSharedMemory::~SensorsTestSharedMemory() {
|
||||
switch(mType) {
|
||||
case SharedMemType::ASHMEM: {
|
||||
if (mSize != 0) {
|
||||
::munmap(mBuffer, mSize);
|
||||
mBuffer = nullptr;
|
||||
|
||||
::native_handle_close(mNativeHandle);
|
||||
::native_handle_delete(mNativeHandle);
|
||||
|
||||
mNativeHandle = nullptr;
|
||||
mSize = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
|
||||
ALOGE("SensorsTestSharedMemory %p not properly destructed: "
|
||||
"type %d, native handle %p, size %zu, buffer %p",
|
||||
this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType 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 SensorsTestSharedMemory(type, size);
|
||||
if (m->mSize != size || m->mBuffer == nullptr) {
|
||||
delete m;
|
||||
m = nullptr;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
// The main test class for SENSORS HIDL HAL.
|
||||
class SensorsHidlTest : public ::testing::Test {
|
||||
public:
|
||||
@@ -155,52 +317,66 @@ class SensorsHidlTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
virtual void TearDown() override {
|
||||
// stop all sensors
|
||||
for (auto s : mSensorHandles) {
|
||||
S()->activate(s, false);
|
||||
}
|
||||
mSensorHandles.clear();
|
||||
|
||||
// stop all direct report and channels
|
||||
for (auto c : mDirectChannelHandles) {
|
||||
// disable all reports
|
||||
S()->configDirectReport(-1, c, RateLevel::STOP, [] (auto, auto){});
|
||||
S()->unregisterDirectChannel(c);
|
||||
}
|
||||
mDirectChannelHandles.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
SensorInfo defaultSensorByType(SensorType type);
|
||||
std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
|
||||
bool clearBeforeStart = true, bool changeCollection = true);
|
||||
|
||||
// implementation wrapper
|
||||
Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) {
|
||||
return S()->getSensorsList(_hidl_cb);
|
||||
}
|
||||
|
||||
Return<Result> activate(
|
||||
int32_t sensorHandle, bool enabled);
|
||||
|
||||
Return<Result> batch(
|
||||
int32_t sensorHandle,
|
||||
int64_t samplingPeriodNs,
|
||||
int64_t maxReportLatencyNs) {
|
||||
return S()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
|
||||
}
|
||||
|
||||
Return<Result> flush(int32_t sensorHandle) {
|
||||
return S()->flush(sensorHandle);
|
||||
}
|
||||
|
||||
Return<Result> injectSensorData(const Event& event) {
|
||||
return S()->injectSensorData(event);
|
||||
}
|
||||
|
||||
Return<void> registerDirectChannel(
|
||||
const SharedMemInfo& mem, ISensors::registerDirectChannel_cb _hidl_cb);
|
||||
|
||||
Return<Result> unregisterDirectChannel(int32_t channelHandle) {
|
||||
return S()->unregisterDirectChannel(channelHandle);
|
||||
}
|
||||
|
||||
Return<void> configDirectReport(
|
||||
int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
|
||||
ISensors::configDirectReport_cb _hidl_cb) {
|
||||
return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
|
||||
}
|
||||
|
||||
inline sp<ISensors>& S() {
|
||||
return SensorsHidlEnvironment::Instance()->sensors;
|
||||
}
|
||||
|
||||
std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
|
||||
bool clearBeforeStart = true,
|
||||
bool changeCollection = true) {
|
||||
std::vector<Event> events;
|
||||
constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //gradularity 100 ms
|
||||
|
||||
ALOGI("collect max of %zu events for %d us, clearBeforeStart %d",
|
||||
nEventLimit, timeLimitUs, clearBeforeStart);
|
||||
|
||||
if (changeCollection) {
|
||||
SensorsHidlEnvironment::Instance()->setCollection(true);
|
||||
}
|
||||
if (clearBeforeStart) {
|
||||
SensorsHidlEnvironment::Instance()->catEvents(nullptr);
|
||||
}
|
||||
|
||||
while (timeLimitUs > 0) {
|
||||
useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs);
|
||||
usleep(duration);
|
||||
timeLimitUs -= duration;
|
||||
|
||||
SensorsHidlEnvironment::Instance()->catEvents(&events);
|
||||
if (events.size() >= nEventLimit) {
|
||||
break;
|
||||
}
|
||||
ALOGV("time to go = %d, events to go = %d",
|
||||
(int)timeLimitUs, (int)(nEventLimit - events.size()));
|
||||
}
|
||||
|
||||
if (changeCollection) {
|
||||
SensorsHidlEnvironment::Instance()->setCollection(false);
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
static bool typeMatchStringType(SensorType type, const hidl_string& stringType);
|
||||
static bool typeMatchReportMode(SensorType type, SensorFlagBits reportMode);
|
||||
static bool delayMatchReportMode(int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode);
|
||||
|
||||
inline static SensorFlagBits extractReportMode(uint64_t flag) {
|
||||
return (SensorFlagBits) (flag
|
||||
& ((uint64_t) SensorFlagBits::CONTINUOUS_MODE
|
||||
@@ -219,10 +395,77 @@ class SensorsHidlTest : public ::testing::Test {
|
||||
return (int32_t) type > 0;
|
||||
}
|
||||
|
||||
static bool typeMatchStringType(SensorType type, const hidl_string& stringType);
|
||||
static bool typeMatchReportMode(SensorType type, SensorFlagBits reportMode);
|
||||
static bool delayMatchReportMode(int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode);
|
||||
static SensorFlagBits expectedReportModeForType(SensorType type);
|
||||
SensorInfo defaultSensorByType(SensorType type);
|
||||
|
||||
// all sensors and direct channnels used
|
||||
std::unordered_set<int32_t> mSensorHandles;
|
||||
std::unordered_set<int32_t> mDirectChannelHandles;
|
||||
};
|
||||
|
||||
|
||||
Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
|
||||
// If activating a sensor, add the handle in a set so that when test fails it can be turned off.
|
||||
// The handle is not removed when it is deactivating on purpose so that it is not necessary to
|
||||
// check the return value of deactivation. Deactivating a sensor more than once does not have
|
||||
// negative effect.
|
||||
if (enabled) {
|
||||
mSensorHandles.insert(sensorHandle);
|
||||
}
|
||||
return S()->activate(sensorHandle, enabled);
|
||||
}
|
||||
|
||||
Return<void> SensorsHidlTest::registerDirectChannel(
|
||||
const SharedMemInfo& mem, ISensors::registerDirectChannel_cb cb) {
|
||||
// If registeration of a channel succeeds, add the handle of channel to a set so that it can be
|
||||
// unregistered when test fails. Unregister a channel does not remove the handle on purpose.
|
||||
// Unregistering a channel more than once should not have negative effect.
|
||||
S()->registerDirectChannel(mem,
|
||||
[&] (auto result, auto channelHandle) {
|
||||
if (result == Result::OK) {
|
||||
mDirectChannelHandles.insert(channelHandle);
|
||||
}
|
||||
cb(result, channelHandle);
|
||||
});
|
||||
return Void();
|
||||
}
|
||||
|
||||
std::vector<Event> SensorsHidlTest::collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
|
||||
bool clearBeforeStart, bool changeCollection) {
|
||||
std::vector<Event> events;
|
||||
constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //gradularity 100 ms
|
||||
|
||||
ALOGI("collect max of %zu events for %d us, clearBeforeStart %d",
|
||||
nEventLimit, timeLimitUs, clearBeforeStart);
|
||||
|
||||
if (changeCollection) {
|
||||
SensorsHidlEnvironment::Instance()->setCollection(true);
|
||||
}
|
||||
if (clearBeforeStart) {
|
||||
SensorsHidlEnvironment::Instance()->catEvents(nullptr);
|
||||
}
|
||||
|
||||
while (timeLimitUs > 0) {
|
||||
useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs);
|
||||
usleep(duration);
|
||||
timeLimitUs -= duration;
|
||||
|
||||
SensorsHidlEnvironment::Instance()->catEvents(&events);
|
||||
if (events.size() >= nEventLimit) {
|
||||
break;
|
||||
}
|
||||
ALOGV("time to go = %d, events to go = %d",
|
||||
(int)timeLimitUs, (int)(nEventLimit - events.size()));
|
||||
}
|
||||
|
||||
if (changeCollection) {
|
||||
SensorsHidlEnvironment::Instance()->setCollection(false);
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
bool SensorsHidlTest::typeMatchStringType(SensorType type, const hidl_string& stringType) {
|
||||
|
||||
if (type >= SensorType::DEVICE_PRIVATE_BASE) {
|
||||
@@ -303,6 +546,7 @@ bool SensorsHidlTest::delayMatchReportMode(
|
||||
break;
|
||||
case SensorFlagBits::SPECIAL_REPORTING_MODE:
|
||||
res = (minDelay == 0) && (maxDelay == 0);
|
||||
break;
|
||||
default:
|
||||
res = false;
|
||||
}
|
||||
@@ -439,10 +683,10 @@ TEST_F(SensorsHidlTest, NormalAccelerometerStreamingOperation) {
|
||||
|
||||
int32_t handle = sensor.sensorHandle;
|
||||
|
||||
S()->batch(handle, samplingPeriodInNs, batchingPeriodInNs);
|
||||
S()->activate(handle, 1);
|
||||
ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
|
||||
ASSERT_EQ(activate(handle, 1), Result::OK);
|
||||
events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
|
||||
S()->activate(handle, 0);
|
||||
ASSERT_EQ(activate(handle, 0), Result::OK);
|
||||
|
||||
ALOGI("Collected %zu samples", events.size());
|
||||
|
||||
@@ -475,7 +719,6 @@ TEST_F(SensorsHidlTest, NormalAccelerometerStreamingOperation) {
|
||||
|
||||
// Test if sensor hal can do gyroscope streaming properly
|
||||
TEST_F(SensorsHidlTest, NormalGyroscopeStreamingOperation) {
|
||||
|
||||
std::vector<Event> events;
|
||||
|
||||
constexpr int64_t samplingPeriodInNs = 10ull*1000*1000; // 10ms
|
||||
@@ -493,10 +736,10 @@ TEST_F(SensorsHidlTest, NormalGyroscopeStreamingOperation) {
|
||||
|
||||
int32_t handle = sensor.sensorHandle;
|
||||
|
||||
S()->batch(handle, samplingPeriodInNs, batchingPeriodInNs);
|
||||
S()->activate(handle, 1);
|
||||
ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
|
||||
ASSERT_EQ(activate(handle, 1), Result::OK);
|
||||
events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
|
||||
S()->activate(handle, 0);
|
||||
ASSERT_EQ(activate(handle, 0), Result::OK);
|
||||
|
||||
ALOGI("Collected %zu samples", events.size());
|
||||
|
||||
@@ -529,7 +772,6 @@ TEST_F(SensorsHidlTest, NormalGyroscopeStreamingOperation) {
|
||||
|
||||
// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
|
||||
TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
|
||||
|
||||
std::vector<Event> events1, events2;
|
||||
|
||||
constexpr int64_t batchingPeriodInNs = 0; // no batching
|
||||
@@ -553,18 +795,18 @@ TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
|
||||
return;
|
||||
}
|
||||
|
||||
S()->batch(handle, minSamplingPeriodInNs, batchingPeriodInNs);
|
||||
S()->activate(handle, 1);
|
||||
ASSERT_EQ(batch(handle, minSamplingPeriodInNs, batchingPeriodInNs), Result::OK);
|
||||
ASSERT_EQ(activate(handle, 1), Result::OK);
|
||||
|
||||
usleep(500000); // sleep 0.5 sec to wait for change rate to happen
|
||||
events1 = collectEvents(sensor.minDelay * minNEvent, minNEvent, true /*clearBeforeStart*/);
|
||||
|
||||
S()->batch(handle, maxSamplingPeriodInNs, batchingPeriodInNs);
|
||||
ASSERT_EQ(batch(handle, maxSamplingPeriodInNs, batchingPeriodInNs), Result::OK);
|
||||
|
||||
usleep(500000); // sleep 0.5 sec to wait for change rate to happen
|
||||
events2 = collectEvents(sensor.maxDelay * minNEvent, minNEvent, true /*clearBeforeStart*/);
|
||||
|
||||
S()->activate(handle, 0);
|
||||
ASSERT_EQ(activate(handle, 0), Result::OK);
|
||||
|
||||
ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size());
|
||||
|
||||
@@ -616,7 +858,6 @@ TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
|
||||
|
||||
// Test if sensor hal can do normal accelerometer batching properly
|
||||
TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
|
||||
|
||||
std::vector<Event> events;
|
||||
|
||||
constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
|
||||
@@ -649,18 +890,17 @@ TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
|
||||
int64_t allowedBatchDeliverTimeNs =
|
||||
std::max(oneSecondInNs, batchingPeriodInNs / 10);
|
||||
|
||||
S()->batch(handle, minSamplingPeriodInNs, INT64_MAX);
|
||||
S()->activate(handle, 1);
|
||||
ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK);
|
||||
ASSERT_EQ(activate(handle, 1), Result::OK);
|
||||
|
||||
usleep(500000); // sleep 0.5 sec to wait for initialization
|
||||
S()->flush(handle);
|
||||
ASSERT_EQ(flush(handle), Result::OK);
|
||||
|
||||
// wait for 80% of the reserved batching period
|
||||
// there should not be any significant amount of events
|
||||
// since collection is not enabled all events will go down the drain
|
||||
usleep(batchingPeriodInNs / 1000 * 8 / 10);
|
||||
|
||||
|
||||
SensorsHidlEnvironment::Instance()->setCollection(true);
|
||||
// 0.8 + 0.3 times the batching period
|
||||
// plus some time for the event to deliver
|
||||
@@ -668,13 +908,13 @@ TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
|
||||
batchingPeriodInNs / 1000 * 3 / 10,
|
||||
minFifoCount, true /*clearBeforeStart*/, false /*change collection*/);
|
||||
|
||||
S()->flush(handle);
|
||||
ASSERT_EQ(flush(handle), Result::OK);
|
||||
|
||||
events = collectEvents(allowedBatchDeliverTimeNs / 1000,
|
||||
minFifoCount, true /*clearBeforeStart*/, false /*change collection*/);
|
||||
|
||||
SensorsHidlEnvironment::Instance()->setCollection(false);
|
||||
S()->activate(handle, 0);
|
||||
ASSERT_EQ(activate(handle, 0), Result::OK);
|
||||
|
||||
size_t nEvent = 0;
|
||||
for (auto & e : events) {
|
||||
@@ -687,6 +927,79 @@ TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
|
||||
ASSERT_GT(nEvent, (size_t)(batchingPeriodInNs / minSamplingPeriodInNs * 9 / 10));
|
||||
}
|
||||
|
||||
// Test sensor event direct report with ashmem for gyro sensor
|
||||
TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReport) {
|
||||
|
||||
constexpr SensorType type = SensorType::GYROSCOPE;
|
||||
constexpr size_t kEventSize = 104;
|
||||
constexpr size_t kNEvent = 500;
|
||||
constexpr size_t kMemSize = kEventSize * kNEvent;
|
||||
|
||||
SensorInfo sensor = defaultSensorByType(type);
|
||||
|
||||
if (!(sensor.flags | SensorFlagBits::MASK_DIRECT_REPORT)
|
||||
|| !(sensor.flags | SensorFlagBits::DIRECT_CHANNEL_ASHMEM)) {
|
||||
// does not declare support
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<SensorsTestSharedMemory>
|
||||
mem(SensorsTestSharedMemory::create(SharedMemType::ASHMEM, kMemSize));
|
||||
ASSERT_NE(mem, nullptr);
|
||||
|
||||
char* buffer = mem->getBuffer();
|
||||
// fill memory with data
|
||||
for (size_t i = 0; i < kMemSize; ++i) {
|
||||
buffer[i] = '\xcc';
|
||||
}
|
||||
|
||||
int32_t channelHandle;
|
||||
registerDirectChannel(mem->getSharedMemInfo(),
|
||||
[&channelHandle] (auto result, auto channelHandle_) {
|
||||
ASSERT_EQ(result, Result::OK);
|
||||
channelHandle = channelHandle_;
|
||||
});
|
||||
|
||||
// check memory is zeroed
|
||||
for (size_t i = 0; i < kMemSize; ++i) {
|
||||
ASSERT_EQ(buffer[i], '\0');
|
||||
}
|
||||
|
||||
int32_t eventToken;
|
||||
configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::NORMAL,
|
||||
[&eventToken] (auto result, auto token) {
|
||||
ASSERT_EQ(result, Result::OK);
|
||||
eventToken = token;
|
||||
});
|
||||
|
||||
usleep(1500000); // sleep 1 sec for data, plus 0.5 sec for initialization
|
||||
auto events = mem->parseEvents();
|
||||
|
||||
// allowed to be 55% of nominal freq (50Hz)
|
||||
ASSERT_GT(events.size(), 50 / 2);
|
||||
ASSERT_LT(events.size(), static_cast<size_t>(110*1.5));
|
||||
|
||||
int64_t lastTimestamp = 0;
|
||||
for (auto &e : events) {
|
||||
ASSERT_EQ(e.sensorType, type);
|
||||
ASSERT_EQ(e.sensorHandle, eventToken);
|
||||
ASSERT_GT(e.timestamp, lastTimestamp);
|
||||
|
||||
Vec3 gyro = e.u.vec3;
|
||||
double gyroNorm = std::sqrt(gyro.x * gyro.x + gyro.y * gyro.y + gyro.z * gyro.z);
|
||||
// assert not drifting
|
||||
ASSERT_TRUE(gyroNorm < 0.1); // < ~5 degree/sa
|
||||
|
||||
lastTimestamp = e.timestamp;
|
||||
}
|
||||
|
||||
// stop sensor and unregister channel
|
||||
configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP,
|
||||
[&eventToken] (auto result, auto) {
|
||||
ASSERT_EQ(result, Result::OK);
|
||||
});
|
||||
ASSERT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::AddGlobalTestEnvironment(SensorsHidlEnvironment::Instance());
|
||||
@@ -695,4 +1008,4 @@ int main(int argc, char **argv) {
|
||||
ALOGI("Test result = %d", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
// vim: set ts=2 sw=2
|
||||
|
||||
@@ -374,10 +374,7 @@ attribute: {
|
||||
struct_value: {
|
||||
name: "flags"
|
||||
type: TYPE_MASK
|
||||
enum_value: {
|
||||
type: TYPE_ENUM
|
||||
predefined_type: "::android::hardware::sensors::V1_0::SensorFlagBits"
|
||||
}
|
||||
predefined_type: "::android::hardware::sensors::V1_0::SensorFlagBits"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,6 +612,26 @@ attribute: {
|
||||
scalar_value: {
|
||||
uint32_t: 131077
|
||||
}
|
||||
enumerator: "AINFO_LOCAL_GEOMAGNETIC_FIELD"
|
||||
scalar_value: {
|
||||
uint32_t: 196608
|
||||
}
|
||||
enumerator: "AINFO_LOCAL_GRAVITY"
|
||||
scalar_value: {
|
||||
uint32_t: 196609
|
||||
}
|
||||
enumerator: "AINFO_DOCK_STATE"
|
||||
scalar_value: {
|
||||
uint32_t: 196610
|
||||
}
|
||||
enumerator: "AINFO_HIGH_PERFORMANCE_MODE"
|
||||
scalar_value: {
|
||||
uint32_t: 196611
|
||||
}
|
||||
enumerator: "AINFO_MAGNETIC_FIELD_CALIBRATION"
|
||||
scalar_value: {
|
||||
uint32_t: 196612
|
||||
}
|
||||
enumerator: "AINFO_CUSTOM_START"
|
||||
scalar_value: {
|
||||
uint32_t: 268435456
|
||||
@@ -816,6 +833,47 @@ attribute: {
|
||||
}
|
||||
}
|
||||
|
||||
attribute: {
|
||||
name: "::android::hardware::sensors::V1_0::SensorsEventFormatOffset"
|
||||
type: TYPE_ENUM
|
||||
enum_value: {
|
||||
scalar_type: "uint16_t"
|
||||
|
||||
enumerator: "SIZE_FIELD"
|
||||
scalar_value: {
|
||||
uint16_t: 0
|
||||
}
|
||||
enumerator: "REPORT_TOKEN"
|
||||
scalar_value: {
|
||||
uint16_t: 4
|
||||
}
|
||||
enumerator: "SENSOR_TYPE"
|
||||
scalar_value: {
|
||||
uint16_t: 8
|
||||
}
|
||||
enumerator: "ATOMIC_COUNTER"
|
||||
scalar_value: {
|
||||
uint16_t: 12
|
||||
}
|
||||
enumerator: "TIMESTAMP"
|
||||
scalar_value: {
|
||||
uint16_t: 16
|
||||
}
|
||||
enumerator: "DATA"
|
||||
scalar_value: {
|
||||
uint16_t: 24
|
||||
}
|
||||
enumerator: "RESERVED"
|
||||
scalar_value: {
|
||||
uint16_t: 88
|
||||
}
|
||||
enumerator: "TOTAL_LENGTH"
|
||||
scalar_value: {
|
||||
uint16_t: 104
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attribute: {
|
||||
name: "::android::hardware::sensors::V1_0::SharedMemInfo"
|
||||
type: TYPE_STRUCT
|
||||
|
||||
Reference in New Issue
Block a user