*/
#define LOG_TAG "sensors_hidl_hal_test"
+#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
#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 <VtsHalHidlTargetTestBase.h>
-#include <hardware/sensors.h> // for sensor type strings
+#include <hardware/sensors.h> // for sensor type strings
+#include <log/log.h>
+#include <utils/SystemClock.h>
#include <algorithm>
#include <cinttypes>
using namespace ::android::hardware::sensors::V1_0;
// Test environment for sensors
+class SensorsHidlTest;
class SensorsHidlEnvironment : public ::testing::Environment {
public:
// get the test environment singleton
return instance;
}
- // sensors hidl service
- sp<ISensors> sensors;
-
virtual void SetUp();
virtual void TearDown();
void setCollection(bool enable);
private:
+ friend SensorsHidlTest;
+ // sensors hidl service
+ sp<ISensors> sensors;
+
SensorsHidlEnvironment() {}
void addEvent(const Event& ev);
void startPollingThread();
+ void resetHal();
static void pollingThread(SensorsHidlEnvironment* env, std::shared_ptr<bool> stop);
bool collectionEnabled;
};
void SensorsHidlEnvironment::SetUp() {
- sensors = ::testing::VtsHalHidlTargetTestBase::getService<ISensors>();
- ALOGI_IF(sensors, "sensors is not nullptr, %p", sensors.get());
- ASSERT_NE(sensors, nullptr);
+ resetHal();
+
+ ASSERT_NE(sensors, nullptr) << "sensors is nullptr, cannot get hidl service";
collectionEnabled = false;
startPollingThread();
}
void SensorsHidlEnvironment::TearDown() {
- ALOGI("TearDown SensorsHidlEnvironement");
-
if (stopThread) {
*stopThread = true;
}
pollThread.detach();
}
+void SensorsHidlEnvironment::resetHal() {
+ // wait upto 100ms * 10 = 1s for hidl service.
+ constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
+
+ std::string step;
+ bool succeed = false;
+ for (size_t retry = 10; retry > 0; --retry) {
+ // this do ... while is for easy error handling
+ do {
+ step = "getService()";
+ sensors = ISensors::getService();
+ if (sensors == nullptr) {
+ break;
+ }
+
+ step = "poll() check";
+ // Poke ISensor service. If it has lingering connection from previous generation of
+ // system server, it will kill itself. There is no intention to handle the poll result,
+ // which will be done since the size is 0.
+ if(!sensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
+ break;
+ }
+
+ step = "getSensorList";
+ std::vector<SensorInfo> sensorList;
+ if (!sensors->getSensorsList(
+ [&] (const ::android::hardware::hidl_vec<SensorInfo> &list) {
+ sensorList.reserve(list.size());
+ for (size_t i = 0; i < list.size(); ++i) {
+ sensorList.push_back(list[i]);
+ }
+ }).isOk()) {
+ break;
+ }
+
+ // stop each sensor individually
+ step = "stop each sensor";
+ bool ok = true;
+ for (const auto &i : sensorList) {
+ if (!sensors->activate(i.sensorHandle, false).isOk()) {
+ ok = false;
+ break;
+ }
+ }
+ if (!ok) {
+ break;
+ }
+
+ // mark it done
+ step = "done";
+ succeed = true;
+ } while(0);
+
+ if (succeed) {
+ return;
+ }
+
+ // Delay 100ms before retry, hidl service is expected to come up in short time after crash.
+ ALOGI("%s unsuccessful, try again soon (remaining retry %zu).", step.c_str(), retry - 1);
+ std::this_thread::sleep_for(RETRY_DELAY);
+ }
+
+ sensors = nullptr;
+}
+
void SensorsHidlEnvironment::catEvents(std::vector<Event>* output) {
std::lock_guard<std::mutex> lock(events_mutex);
if (output) {
bool needExit = *stop;
while(!needExit) {
- env->sensors->poll(1,
- [&](auto result, const auto &events, const auto &dynamicSensorsAdded) {
+ env->sensors->poll(64, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) {
if (result != Result::OK
|| (events.size() == 0 && dynamicSensorsAdded.size() == 0)
|| *stop) {
- needExit = true;
- return;
+ needExit = true;
+ return;
}
- if (events.size() > 0) {
- env->addEvent(events[0]);
+ for (const auto& e : events) {
+ env->addEvent(e);
}
- });
+ });
}
ALOGD("polling thread end");
}
}
break;
}
+ case SharedMemType::GRALLOC: {
+
+ break;
+ }
default:
break;
}
return m;
}
+class SensorEventsChecker {
+ public:
+ virtual bool check(const std::vector<Event> &events, std::string *out) const = 0;
+ virtual ~SensorEventsChecker() {}
+};
+
+class NullChecker : public SensorEventsChecker {
+ public:
+ virtual bool check(const std::vector<Event> &, std::string *) const {
+ return true;
+ }
+};
+
+class SensorEventPerEventChecker : public SensorEventsChecker {
+ public:
+ virtual bool checkEvent(const Event &event, std::string *out) const = 0;
+ virtual bool check(const std::vector<Event> &events, std::string *out) const {
+ for (const auto &e : events) {
+ if (!checkEvent(e, out)) {
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+class Vec3NormChecker : public SensorEventPerEventChecker {
+ public:
+ Vec3NormChecker(float min, float max) : mRange(min, max) {}
+ static Vec3NormChecker byNominal(float nominal, float allowedError) {
+ return Vec3NormChecker(nominal - allowedError, nominal + allowedError);
+ }
+
+ virtual bool checkEvent(const Event &event, std::string *out) const {
+ Vec3 v = event.u.vec3;
+ float norm = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
+ if (norm < mRange.first || norm > mRange.second) {
+ if (out != nullptr) {
+ std::ostringstream ss;
+ ss << "Event @ " << event.timestamp << " (" << v.x << ", " << v.y << ", " << v.z << ")"
+ << " has norm " << norm << ", which is beyond range"
+ << " [" << mRange.first << ", " << mRange.second << "]";
+ *out = ss.str();
+ }
+ return false;
+ }
+ return true;
+ }
+ protected:
+ std::pair<float, float> mRange;
+};
+
// The main test class for SENSORS HIDL HAL.
class SensorsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
protected:
SensorInfo defaultSensorByType(SensorType type);
+ std::vector<SensorInfo> getSensorsList();
std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
bool clearBeforeStart = true, bool changeCollection = true);
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);
+ void testStreamingOperation(SensorType type,
+ std::chrono::nanoseconds samplingPeriod,
+ std::chrono::seconds duration,
+ const SensorEventsChecker &checker);
+ void testSamplingRateHotSwitchOperation(SensorType type);
+ void testBatchingOperation(SensorType type);
+ void testDirectReportOperation(
+ SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker);
+
+ static void assertTypeMatchStringType(SensorType type, const hidl_string& stringType);
+ static void assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode);
+ static void assertDelayMatchReportMode(
+ int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode);
static SensorFlagBits expectedReportModeForType(SensorType type);
+ static bool isDirectReportRateSupported(SensorInfo sensor, RateLevel rate);
+ static bool isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type);
+
+ // checkers
+ static const Vec3NormChecker sAccelNormChecker;
+ static const Vec3NormChecker sGyroNormChecker;
// all sensors and direct channnels used
std::unordered_set<int32_t> mSensorHandles;
std::unordered_set<int32_t> mDirectChannelHandles;
};
+const Vec3NormChecker SensorsHidlTest::sAccelNormChecker(
+ Vec3NormChecker::byNominal(GRAVITY_EARTH, 0.5f/*m/s^2*/));
+const Vec3NormChecker SensorsHidlTest::sGyroNormChecker(
+ Vec3NormChecker::byNominal(0.f, 0.1f/*rad/s*/));
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.
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
+ constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //granularity 100 ms
ALOGI("collect max of %zu events for %d us, clearBeforeStart %d",
nEventLimit, timeLimitUs, clearBeforeStart);
return events;
}
-bool SensorsHidlTest::typeMatchStringType(SensorType type, const hidl_string& stringType) {
+void SensorsHidlTest::assertTypeMatchStringType(SensorType type, const hidl_string& stringType) {
if (type >= SensorType::DEVICE_PRIVATE_BASE) {
- return true;
+ return;
}
- bool res = true;
switch (type) {
#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \
- case SensorType::type: res = stringType == SENSOR_STRING_TYPE_ ## type;\
- break;\
-
+ case SensorType::type: ASSERT_STREQ(SENSOR_STRING_TYPE_ ## type, stringType.c_str()); break;
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
default:
- ALOGW("Type %d is not checked, stringType = %s", (int)type, stringType.c_str());
+ FAIL() << "Type " << static_cast<int>(type) << " in android defined range is not checked, "
+ << "stringType = " << stringType;
#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE
}
- return res;
}
-bool SensorsHidlTest::typeMatchReportMode(SensorType type, SensorFlagBits reportMode) {
+void SensorsHidlTest::assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode) {
if (type >= SensorType::DEVICE_PRIVATE_BASE) {
- return true;
+ return;
}
SensorFlagBits expected = expectedReportModeForType(type);
- return expected == (SensorFlagBits)-1 || expected == reportMode;
+ ASSERT_TRUE(expected == (SensorFlagBits) -1 || expected == reportMode)
+ << "reportMode=" << static_cast<int>(reportMode)
+ << "expected=" << static_cast<int>(expected);
}
-bool SensorsHidlTest::delayMatchReportMode(
+void SensorsHidlTest::assertDelayMatchReportMode(
int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode) {
- bool res = true;
switch(reportMode) {
case SensorFlagBits::CONTINUOUS_MODE:
- res = (minDelay > 0) && (maxDelay >= 0);
+ ASSERT_LT(0, minDelay);
+ ASSERT_LE(0, maxDelay);
break;
case SensorFlagBits::ON_CHANGE_MODE:
- //TODO: current implementation does not satisfy minDelay == 0 on Proximity
- res = (minDelay >= 0) && (maxDelay >= 0);
- //res = (minDelay == 0) && (maxDelay >= 0);
+ ASSERT_LE(0, minDelay);
+ ASSERT_LE(0, maxDelay);
break;
case SensorFlagBits::ONE_SHOT_MODE:
- res = (minDelay == -1) && (maxDelay == 0);
+ ASSERT_EQ(-1, minDelay);
+ ASSERT_EQ(0, maxDelay);
break;
case SensorFlagBits::SPECIAL_REPORTING_MODE:
- res = (minDelay == 0) && (maxDelay == 0);
+ // do not enforce anything for special reporting mode
break;
default:
- res = false;
+ FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked";
}
-
- return res;
}
+// return -1 means no expectation for this type
SensorFlagBits SensorsHidlTest::expectedReportModeForType(SensorType type) {
switch (type) {
case SensorType::ACCELEROMETER:
+ case SensorType::ACCELEROMETER_UNCALIBRATED:
case SensorType::GYROSCOPE:
case SensorType::MAGNETIC_FIELD:
case SensorType::ORIENTATION:
case SensorType::AMBIENT_TEMPERATURE:
case SensorType::HEART_RATE:
case SensorType::DEVICE_ORIENTATION:
- case SensorType::MOTION_DETECT:
case SensorType::STEP_COUNTER:
+ case SensorType::LOW_LATENCY_OFFBODY_DETECT:
return SensorFlagBits::ON_CHANGE_MODE;
case SensorType::SIGNIFICANT_MOTION:
case SensorType::WAKE_GESTURE:
case SensorType::GLANCE_GESTURE:
case SensorType::PICK_UP_GESTURE:
+ case SensorType::MOTION_DETECT:
+ case SensorType::STATIONARY_DETECT:
return SensorFlagBits::ONE_SHOT_MODE;
case SensorType::STEP_DETECTOR:
}
}
+bool SensorsHidlTest::isDirectReportRateSupported(SensorInfo sensor, RateLevel rate) {
+ unsigned int r =
+ static_cast<unsigned int>(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT)
+ >> static_cast<unsigned int>(SensorFlagShift::DIRECT_REPORT);
+ return r >= static_cast<unsigned int>(rate);
+}
+
+bool SensorsHidlTest::isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type) {
+ switch (type) {
+ case SharedMemType::ASHMEM:
+ return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0;
+ case SharedMemType::GRALLOC:
+ return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0;
+ default:
+ return false;
+ }
+}
+
SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) {
SensorInfo ret;
return ret;
}
+std::vector<SensorInfo> SensorsHidlTest::getSensorsList() {
+ std::vector<SensorInfo> ret;
+
+ S()->getSensorsList(
+ [&] (const auto &list) {
+ const size_t count = list.size();
+ ret.reserve(list.size());
+ for (size_t i = 0; i < count; ++i) {
+ ret.push_back(list[i]);
+ }
+ });
+
+ return ret;
+}
+
// Test if sensor list returned is valid
TEST_F(SensorsHidlTest, SensorListValid) {
S()->getSensorsList(
[&] (const auto &list) {
const size_t count = list.size();
for (size_t i = 0; i < count; ++i) {
- auto &s = list[i];
- ALOGV("\t%zu: handle=%#08x type=%d name=%s",
- i, s.sensorHandle, (int)s.type, s.name.c_str());
+ const auto &s = list[i];
+ SCOPED_TRACE(::testing::Message() << i << "/" << count << ": "
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << s.sensorHandle << std::dec
+ << " type=" << static_cast<int>(s.type)
+ << " name=" << s.name);
// Test non-empty type string
- ASSERT_FALSE(s.typeAsString.empty());
+ EXPECT_FALSE(s.typeAsString.empty());
// Test defined type matches defined string type
- ASSERT_TRUE(typeMatchStringType(s.type, s.typeAsString));
+ EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
// Test if all sensor has name and vendor
- ASSERT_FALSE(s.name.empty());
- ASSERT_FALSE(s.vendor.empty());
+ EXPECT_FALSE(s.name.empty());
+ EXPECT_FALSE(s.vendor.empty());
// Test power > 0, maxRange > 0
- ASSERT_GE(s.power, 0);
- ASSERT_GT(s.maxRange, 0);
+ EXPECT_LE(0, s.power);
+ EXPECT_LT(0, s.maxRange);
// Info type, should have no sensor
- ASSERT_FALSE(
+ EXPECT_FALSE(
s.type == SensorType::ADDITIONAL_INFO
|| s.type == SensorType::META_DATA);
// Test fifoMax >= fifoReserved
- ALOGV("max reserve = %d, %d", s.fifoMaxEventCount, s.fifoReservedEventCount);
- ASSERT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount);
+ EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
+ << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
// Test Reporting mode valid
- ASSERT_TRUE(typeMatchReportMode(s.type, extractReportMode(s.flags)));
+ EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
// Test min max are in the right order
- ASSERT_LE(s.minDelay, s.maxDelay);
+ EXPECT_LE(s.minDelay, s.maxDelay);
// Test min/max delay matches reporting mode
- ASSERT_TRUE(delayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
+ EXPECT_NO_FATAL_FAILURE(
+ assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
}
});
}
-// Test if sensor hal can do normal accelerometer streaming properly
-TEST_F(SensorsHidlTest, NormalAccelerometerStreamingOperation) {
+// Test if sensor list returned is valid
+TEST_F(SensorsHidlTest, SetOperationMode) {
+ std::vector<SensorInfo> sensorList = getSensorsList();
+
+ bool needOperationModeSupport =
+ std::any_of(sensorList.begin(), sensorList.end(),
+ [] (const auto& s) {
+ return (s.flags & SensorFlagBits::DATA_INJECTION) != 0;
+ });
+ if (!needOperationModeSupport) {
+ return;
+ }
+
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::DATA_INJECTION));
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+}
+// Test if sensor list returned is valid
+TEST_F(SensorsHidlTest, InjectSensorEventData) {
+ std::vector<SensorInfo> sensorList = getSensorsList();
+ std::vector<SensorInfo> sensorSupportInjection;
+
+ bool needOperationModeSupport =
+ std::any_of(sensorList.begin(), sensorList.end(),
+ [&sensorSupportInjection] (const auto& s) {
+ bool ret = (s.flags & SensorFlagBits::DATA_INJECTION) != 0;
+ if (ret) {
+ sensorSupportInjection.push_back(s);
+ }
+ return ret;
+ });
+ if (!needOperationModeSupport) {
+ return;
+ }
+
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::DATA_INJECTION));
+
+ for (const auto &s : sensorSupportInjection) {
+ switch (s.type) {
+ case SensorType::ACCELEROMETER:
+ case SensorType::GYROSCOPE:
+ case SensorType::MAGNETIC_FIELD: {
+ usleep(100000); // sleep 100ms
+
+ Event dummy;
+ dummy.timestamp = android::elapsedRealtimeNano();
+ dummy.sensorType = s.type;
+ dummy.sensorHandle = s.sensorHandle;
+ Vec3 v = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
+ dummy.u.vec3 = v;
+
+ EXPECT_EQ(Result::OK, S()->injectSensorData(dummy));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+}
+
+void SensorsHidlTest::testStreamingOperation(SensorType type,
+ std::chrono::nanoseconds samplingPeriod,
+ std::chrono::seconds duration,
+ const SensorEventsChecker &checker) {
std::vector<Event> events;
- constexpr int64_t samplingPeriodInNs = 20ull*1000*1000; // 20ms
- constexpr int64_t batchingPeriodInNs = 0; // no batching
- constexpr useconds_t minTimeUs = 5*1000*1000; // 5 s
- constexpr size_t minNEvent = 100; // at lease 100 events
- constexpr SensorType type = SensorType::ACCELEROMETER;
+ const int64_t samplingPeriodInNs = samplingPeriod.count();
+ const int64_t batchingPeriodInNs = 0; // no batching
+ const useconds_t minTimeUs = std::chrono::microseconds(duration).count();
+ const size_t minNEvent = duration / samplingPeriod;
SensorInfo sensor = defaultSensorByType(type);
return;
}
+ if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) {
+ // rate not supported
+ return;
+ }
+
int32_t handle = sensor.sensorHandle;
ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
ASSERT_GT(events.size(), 0u);
size_t nRealEvent = 0;
+ bool handleMismatchReported = false;
+ bool metaSensorTypeErrorReported = false;
for (auto & e : events) {
if (e.sensorType == type) {
-
- ASSERT_EQ(e.sensorHandle, handle);
-
- Vec3 acc = e.u.vec3;
-
- double gravityNorm = std::sqrt(acc.x * acc.x + acc.y * acc.y + acc.z * acc.z);
- ALOGV("Norm = %f", gravityNorm);
-
- // assert this is earth gravity
- ASSERT_TRUE(std::fabs(gravityNorm - GRAVITY_EARTH) < 1);
-
+ // avoid generating hundreds of error
+ if (!handleMismatchReported) {
+ EXPECT_EQ(e.sensorHandle, handle)
+ << (handleMismatchReported = true,
+ "Event of the same type must come from the sensor registered");
+ }
++ nRealEvent;
} else {
- ALOGI("Event type %d, handle %d", (int) e.sensorType, (int) e.sensorHandle);
- // Only meta types are allowed besides the subscribed sensor
- ASSERT_TRUE(isMetaSensorType(e.sensorType));
+ // avoid generating hundreds of error
+ if (!metaSensorTypeErrorReported) {
+ EXPECT_TRUE(isMetaSensorType(e.sensorType))
+ << (metaSensorTypeErrorReported = true,
+ "Only meta types are allowed besides the type registered");
+ }
}
}
- ASSERT_GE(nRealEvent, minNEvent / 2); // make sure returned events are not all meta
-}
-
-// 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
- constexpr int64_t batchingPeriodInNs = 0; // no batching
- constexpr useconds_t minTimeUs = 5*1000*1000; // 5 s
- constexpr size_t minNEvent = 200;
- constexpr SensorType type = SensorType::GYROSCOPE;
-
- SensorInfo sensor = defaultSensorByType(type);
-
- if (!isValidType(sensor.type)) {
- // no default sensor of this type
- return;
- }
-
- int32_t handle = sensor.sensorHandle;
+ std::string s;
+ EXPECT_TRUE(checker.check(events, &s)) << s;
- ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
- ASSERT_EQ(activate(handle, 1), Result::OK);
- events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
- ASSERT_EQ(activate(handle, 0), Result::OK);
+ EXPECT_GE(nRealEvent, minNEvent / 2); // make sure returned events are not all meta
+}
- ALOGI("Collected %zu samples", events.size());
+// Test if sensor hal can do UI speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
+ testStreamingOperation(SensorType::ACCELEROMETER,
+ std::chrono::milliseconds(200),
+ std::chrono::seconds(5),
+ sAccelNormChecker);
+}
- ASSERT_GT(events.size(), 0u);
+// Test if sensor hal can do normal speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
+ testStreamingOperation(SensorType::ACCELEROMETER,
+ std::chrono::milliseconds(20),
+ std::chrono::seconds(5),
+ sAccelNormChecker);
+}
- size_t nRealEvent = 0;
- for (auto & e : events) {
- if (e.sensorType == type) {
+// Test if sensor hal can do game speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationFast) {
+ testStreamingOperation(SensorType::ACCELEROMETER,
+ std::chrono::milliseconds(5),
+ std::chrono::seconds(5),
+ sAccelNormChecker);
+}
- ASSERT_EQ(e.sensorHandle, handle);
+// Test if sensor hal can do UI speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
+ testStreamingOperation(SensorType::GYROSCOPE,
+ std::chrono::milliseconds(200),
+ std::chrono::seconds(5),
+ sGyroNormChecker);
+}
- Vec3 gyro = e.u.vec3;
+// Test if sensor hal can do normal speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
+ testStreamingOperation(SensorType::GYROSCOPE,
+ std::chrono::milliseconds(20),
+ std::chrono::seconds(5),
+ sGyroNormChecker);
+}
- double gyroNorm = std::sqrt(gyro.x * gyro.x + gyro.y * gyro.y + gyro.z * gyro.z);
- ALOGV("Gyro Norm = %f", gyroNorm);
+// Test if sensor hal can do game speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationFast) {
+ testStreamingOperation(SensorType::GYROSCOPE,
+ std::chrono::milliseconds(5),
+ std::chrono::seconds(5),
+ sGyroNormChecker);
+}
- // assert not drifting
- ASSERT_TRUE(gyroNorm < 0.1); // < ~5 degree/s
+// Test if sensor hal can do UI speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD,
+ std::chrono::milliseconds(200),
+ std::chrono::seconds(5),
+ NullChecker());
+}
- ++ nRealEvent;
- } else {
- ALOGI("Event type %d, handle %d", (int) e.sensorType, (int) e.sensorHandle);
- // Only meta types are allowed besides the subscribed sensor
- ASSERT_TRUE(isMetaSensorType(e.sensorType));
- }
- }
+// Test if sensor hal can do normal speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD,
+ std::chrono::milliseconds(20),
+ std::chrono::seconds(5),
+ NullChecker());
+}
- ASSERT_GE(nRealEvent, minNEvent / 2); // make sure returned events are not all meta
+// Test if sensor hal can do game speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationFast) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD,
+ std::chrono::milliseconds(5),
+ std::chrono::seconds(5),
+ NullChecker());
}
-// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+void SensorsHidlTest::testSamplingRateHotSwitchOperation(SensorType type) {
std::vector<Event> events1, events2;
constexpr int64_t batchingPeriodInNs = 0; // no batching
constexpr size_t minNEvent = 50;
- constexpr SensorType type = SensorType::ACCELEROMETER;
SensorInfo sensor = defaultSensorByType(type);
maxDelayAverageInterval = timestampInterval / (nEvent - 1);
// change of rate is significant.
- ASSERT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10);
+ EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10);
// fastest rate sampling time is close to spec
ALOGI("minDelayAverageInterval = %" PRId64, minDelayAverageInterval);
- ASSERT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
+ EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
minSamplingPeriodInNs / 10);
}
-// Test if sensor hal can do normal accelerometer batching properly
-TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
+// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
+}
+
+// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
+}
+
+// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
+}
+
+void SensorsHidlTest::testBatchingOperation(SensorType type) {
std::vector<Event> events;
- constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
- constexpr SensorType type = SensorType::ACCELEROMETER;
constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000;
+ constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
SensorInfo sensor = defaultSensorByType(type);
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
- events = collectEvents(
- batchingPeriodInNs / 1000 * 3 / 10,
- minFifoCount, true /*clearBeforeStart*/, false /*change collection*/);
+ // clean existing collections
+ collectEvents(0 /*timeLimitUs*/, 0/*nEventLimit*/,
+ true /*clearBeforeStart*/, false /*change collection*/);
+ // 0.8 + 0.2 times the batching period
+ usleep(batchingPeriodInNs / 1000 * 8 / 10);
ASSERT_EQ(flush(handle), Result::OK);
+ // plus some time for the event to deliver
events = collectEvents(allowedBatchDeliverTimeNs / 1000,
- minFifoCount, true /*clearBeforeStart*/, false /*change collection*/);
+ minFifoCount, false /*clearBeforeStart*/, false /*change collection*/);
SensorsHidlEnvironment::Instance()->setCollection(false);
ASSERT_EQ(activate(handle, 0), Result::OK);
}
// at least reach 90% of advertised capacity
- ASSERT_GT(nEvent, (size_t)(batchingPeriodInNs / minSamplingPeriodInNs * 9 / 10));
+ ASSERT_GT(nEvent, (size_t)(minFifoCount * 9 / 10));
}
-// Test sensor event direct report with ashmem for gyro sensor
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReport) {
+// Test if sensor hal can do accelerometer batching properly
+TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
+ testBatchingOperation(SensorType::ACCELEROMETER);
+}
+
+// Test if sensor hal can do gyroscope batching properly
+TEST_F(SensorsHidlTest, GyroscopeBatchingOperation) {
+ testBatchingOperation(SensorType::GYROSCOPE);
+}
- constexpr SensorType type = SensorType::GYROSCOPE;
- constexpr size_t kEventSize = 104;
+// Test if sensor hal can do magnetometer batching properly
+TEST_F(SensorsHidlTest, MagnetometerBatchingOperation) {
+ testBatchingOperation(SensorType::MAGNETIC_FIELD);
+}
+
+void SensorsHidlTest::testDirectReportOperation(
+ SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker) {
+ constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
constexpr size_t kNEvent = 500;
constexpr size_t kMemSize = kEventSize * kNEvent;
+ constexpr float kNormalNominal = 50;
+ constexpr float kFastNominal = 200;
+ constexpr float kVeryFastNominal = 800;
+
+ constexpr float kNominalTestTimeSec = 1.f;
+ constexpr float kMaxTestTimeSec = kNominalTestTimeSec + 0.5f; // 0.5 second for initialization
+
SensorInfo sensor = defaultSensorByType(type);
- if (!(sensor.flags | SensorFlagBits::MASK_DIRECT_REPORT)
- || !(sensor.flags | SensorFlagBits::DIRECT_CHANNEL_ASHMEM)) {
- // does not declare support
+ if (!isDirectReportRateSupported(sensor, rate)) {
+ return;
+ }
+
+ if (!isDirectChannelTypeSupported(sensor, memType)) {
return;
}
std::unique_ptr<SensorsTestSharedMemory>
- mem(SensorsTestSharedMemory::create(SharedMemType::ASHMEM, kMemSize));
+ mem(SensorsTestSharedMemory::create(memType, kMemSize));
ASSERT_NE(mem, nullptr);
char* buffer = mem->getBuffer();
}
int32_t eventToken;
- configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::NORMAL,
+ configDirectReport(sensor.sensorHandle, channelHandle, rate,
[&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
+ usleep(static_cast<useconds_t>(kMaxTestTimeSec * 1e6f));
auto events = mem->parseEvents();
- // allowed to be 55% of nominal freq (50Hz)
- ASSERT_GT(events.size(), 50u / 2u);
- ASSERT_LT(events.size(), static_cast<size_t>(110*1.5));
+ // find norminal rate
+ float nominalFreq = 0.f;
+ switch (rate) {
+ case RateLevel::NORMAL:
+ nominalFreq = kNormalNominal;
+ break;
+ case RateLevel::FAST:
+ nominalFreq = kFastNominal;
+ break;
+ case RateLevel::VERY_FAST:
+ nominalFreq = kVeryFastNominal;
+ break;
+ case RateLevel::STOP:
+ FAIL();
+ }
+
+ // allowed to be between 55% and 220% of nominal freq
+ ASSERT_GT(events.size(), static_cast<size_t>(nominalFreq * 0.55f * kNominalTestTimeSec));
+ ASSERT_LT(events.size(), static_cast<size_t>(nominalFreq * 2.2f * kMaxTestTimeSec));
int64_t lastTimestamp = 0;
+ bool typeErrorReported = false;
+ bool tokenErrorReported = false;
+ bool timestampErrorReported = false;
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
-
+ if (!typeErrorReported) {
+ EXPECT_EQ(type, e.sensorType)
+ << (typeErrorReported = true, "Type in event does not match type of sensor registered.");
+ }
+ if (!tokenErrorReported) {
+ EXPECT_EQ(eventToken, e.sensorHandle)
+ << (tokenErrorReported = true,
+ "Event token does not match that retured from configDirectReport");
+ }
+ if (!timestampErrorReported) {
+ EXPECT_GT(e.timestamp, lastTimestamp)
+ << (timestampErrorReported = true, "Timestamp not monotonically increasing");
+ }
lastTimestamp = e.timestamp;
}
+ std::string s;
+ EXPECT_TRUE(checker.check(events, &s)) << s;
+
// stop sensor and unregister channel
configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP,
[&eventToken] (auto result, auto) {
- ASSERT_EQ(result, Result::OK);
+ EXPECT_EQ(result, Result::OK);
});
- ASSERT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
+ EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at normal rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at fast rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at very fast rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at normal rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at fast rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at very fast rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for mag sensor at normal rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ NullChecker());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at fast rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
+ NullChecker());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at very fast rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(
+ SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::VERY_FAST, NullChecker());
}
int main(int argc, char **argv) {