[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
diff --git a/sensors/1.0/default/Sensors.cpp b/sensors/1.0/default/Sensors.cpp
index 8903397..aadf848 100644
--- a/sensors/1.0/default/Sensors.cpp
+++ b/sensors/1.0/default/Sensors.cpp
@@ -42,10 +42,12 @@
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<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 6735e96..acff6ca 100644
--- a/sensors/1.0/default/convert.cpp
+++ b/sensors/1.0/default/convert.cpp
@@ -340,6 +340,50 @@
}
}
+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 d289a81..c3a0125 100644
--- a/sensors/1.0/default/include/sensors/convert.h
+++ b/sensors/1.0/default/include/sensors/convert.h
@@ -33,6 +33,9 @@
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 c8c8dfc..552c997 100644
--- a/sensors/1.0/types.hal
+++ b/sensors/1.0/types.hal
@@ -1224,23 +1224,32 @@
@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 675484a..9ca6230 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -19,10 +19,11 @@
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: [
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 2edc5c3..c7600f3 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 @@
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 @@
}
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 @@
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 @@
break;
case SensorFlagBits::SPECIAL_REPORTING_MODE:
res = (minDelay == 0) && (maxDelay == 0);
+ break;
default:
res = false;
}
@@ -439,10 +683,10 @@
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 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 @@
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 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 @@
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 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 @@
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 @@
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 @@
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 @@
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 2980507..1b48916 100644
--- a/sensors/1.0/vts/types.vts
+++ b/sensors/1.0/vts/types.vts
@@ -374,10 +374,7 @@
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 @@
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: {
+ 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: {