diff options
-rw-r--r-- | sensors/1.0/default/Sensors.cpp | 69 | ||||
-rw-r--r-- | sensors/1.0/default/convert.cpp | 44 | ||||
-rw-r--r-- | sensors/1.0/default/include/sensors/convert.h | 3 | ||||
-rw-r--r-- | sensors/1.0/types.hal | 35 | ||||
-rw-r--r-- | sensors/1.0/vts/functional/Android.bp | 5 | ||||
-rw-r--r-- | sensors/1.0/vts/functional/sensors_hidl_hal_test.cpp | 421 | ||||
-rw-r--r-- | sensors/1.0/vts/types.vts | 66 |
7 files changed, 557 insertions, 86 deletions
diff --git a/sensors/1.0/default/Sensors.cpp b/sensors/1.0/default/Sensors.cpp index e4ef99db16..41eb945167 100644 --- a/sensors/1.0/default/Sensors.cpp +++ b/sensors/1.0/default/Sensors.cpp @@ -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; } @@ -227,27 +229,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(); } diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp index 6735e96890..acff6ca7c1 100644 --- a/sensors/1.0/default/convert.cpp +++ b/sensors/1.0/default/convert.cpp @@ -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 diff --git a/sensors/1.0/default/include/sensors/convert.h b/sensors/1.0/default/include/sensors/convert.h index d289a81275..c3a0125d51 100644 --- a/sensors/1.0/default/include/sensors/convert.h +++ b/sensors/1.0/default/include/sensors/convert.h @@ -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 diff --git a/sensors/1.0/types.hal b/sensors/1.0/types.hal index c8c8dfcde0..552c9970d7 100644 --- a/sensors/1.0/types.hal +++ b/sensors/1.0/types.hal @@ -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 */ diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp index 675484a56b..9ca6230349 100644 --- a/sensors/1.0/vts/functional/Android.bp +++ b/sensors/1.0/vts/functional/Android.bp @@ -19,10 +19,11 @@ cc_test { gtest: true, srcs: ["sensors_hidl_hal_test.cpp"], shared_libs: [ - "liblog", + "android.hardware.sensors@1.0", + "libcutils", "libhidlbase", + "liblog", "libutils", - "android.hardware.sensors@1.0", ], static_libs: ["libgtest"], cflags: [ diff --git a/sensors/1.0/vts/functional/sensors_hidl_hal_test.cpp b/sensors/1.0/vts/functional/sensors_hidl_hal_test.cpp index 2edc5c370f..c7600f3802 100644 --- a/sensors/1.0/vts/functional/sensors_hidl_hal_test.cpp +++ b/sensors/1.0/vts/functional/sensors_hidl_hal_test.cpp @@ -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,51 +317,65 @@ 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: - inline sp<ISensors>& S() { - return SensorsHidlEnvironment::Instance()->sensors; + 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); } - 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 + Return<Result> activate( + int32_t sensorHandle, bool enabled); - ALOGI("collect max of %zu events for %d us, clearBeforeStart %d", - nEventLimit, timeLimitUs, clearBeforeStart); + Return<Result> batch( + int32_t sensorHandle, + int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) { + return S()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } - if (changeCollection) { - SensorsHidlEnvironment::Instance()->setCollection(true); - } - if (clearBeforeStart) { - SensorsHidlEnvironment::Instance()->catEvents(nullptr); - } + Return<Result> flush(int32_t sensorHandle) { + return S()->flush(sensorHandle); + } - while (timeLimitUs > 0) { - useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs); - usleep(duration); - timeLimitUs -= duration; + Return<Result> injectSensorData(const Event& event) { + return S()->injectSensorData(event); + } - SensorsHidlEnvironment::Instance()->catEvents(&events); - if (events.size() >= nEventLimit) { - break; - } - ALOGV("time to go = %d, events to go = %d", - (int)timeLimitUs, (int)(nEventLimit - events.size())); - } + Return<void> registerDirectChannel( + const SharedMemInfo& mem, ISensors::registerDirectChannel_cb _hidl_cb); - if (changeCollection) { - SensorsHidlEnvironment::Instance()->setCollection(false); - } - return events; + Return<Result> unregisterDirectChannel(int32_t channelHandle) { + return S()->unregisterDirectChannel(channelHandle); } - 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); + 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; + } inline static SensorFlagBits extractReportMode(uint64_t flag) { return (SensorFlagBits) (flag @@ -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 diff --git a/sensors/1.0/vts/types.vts b/sensors/1.0/vts/types.vts index 29805079e1..1b489168c5 100644 --- a/sensors/1.0/vts/types.vts +++ b/sensors/1.0/vts/types.vts @@ -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 @@ -817,6 +834,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 struct_value: { |