1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <general_test/basic_sensor_test_base.h> 18 19 #include <cinttypes> 20 #include <cstddef> 21 22 #include <shared/send_message.h> 23 24 #include <chre.h> 25 26 using nanoapp_testing::MessageType; 27 using nanoapp_testing::sendFatalFailureToHost; 28 using nanoapp_testing::sendInternalFailureToHost; 29 using nanoapp_testing::sendStringToHost; 30 using nanoapp_testing::sendSuccessToHost; 31 32 /* 33 * Our general test flow is as follows: 34 * 35 * Constructor: Send startEvent to self to start. 36 * StartEvent: Get default sensor and perform various sanity checks. Configure 37 * the sensor. 38 * 39 * At this point, it depends what kind of sensor we have for how we proceed 40 * with the test. 41 * 42 * One-shot: finishTest() 43 * On-change: Wait for one data event from sensor. Then finishTest(). 44 * Continuous: Wait for two data events from sensor. Then finishTest(). 45 * 46 * We also look for and perform basic sanity checking on sampling status 47 * change events, as well as bias data reports. 48 */ 49 50 51 namespace general_test { 52 53 namespace { 54 constexpr uint16_t kStartEvent = CHRE_EVENT_FIRST_USER_VALUE; 55 constexpr uint16_t kPassiveCompleteEvent = CHRE_EVENT_FIRST_USER_VALUE + 1; 56 constexpr uint64_t kNanosecondsPerSecond = 1000000000; 57 constexpr uint64_t kEventLoopSlack = 100000000; // 100 msec 58 59 uint64_t getEventDuration(const chreSensorThreeAxisData *event) { 60 uint64_t duration = 0; 61 for (size_t i = 0; i < event->header.readingCount; i++) { 62 duration += event->readings[i].timestampDelta; 63 } 64 65 return duration; 66 } 67 } // anonymous namespace 68 69 BasicSensorTestBase::BasicSensorTestBase() 70 : Test(CHRE_API_VERSION_1_0), 71 mInMethod(true), 72 mExternalSamplingStatusChange(false), 73 mDoneWithPassiveConfigure(false), 74 mState(State::kPreStart), 75 mInstanceId(chreGetInstanceId()) 76 /* All other members initialized later */ { 77 } 78 79 void BasicSensorTestBase::setUp(uint32_t messageSize, 80 const void * /* message */) { 81 if (messageSize != 0) { 82 sendFatalFailureToHost( 83 "Beginning message expects 0 additional bytes, got ", 84 &messageSize); 85 } 86 // Most tests start running in the constructor. However, since this 87 // is a base class, and we invoke abstract methods when running our 88 // test, we don't start until after the class has been fully 89 // constructed. 90 if (!chreSendEvent(kStartEvent, nullptr, nullptr, mInstanceId)) { 91 sendFatalFailureToHost("Failed chreSendEvent to begin test"); 92 } 93 mInMethod = false; 94 } 95 96 void BasicSensorTestBase::checkPassiveConfigure() { 97 chreSensorConfigureMode mode = isOneShotSensor() ? 98 CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_ONE_SHOT : 99 CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_CONTINUOUS; 100 101 if (mApiVersion == CHRE_API_VERSION_1_0) { 102 // Any attempt to make a PASSIVE call with a non-default interval 103 // or latency should fail. 104 if (chreSensorConfigure(mSensorHandle, mode, 105 CHRE_SENSOR_INTERVAL_DEFAULT, 999)) { 106 sendFatalFailureToHost("chreSensorConfigure() allowed passive with " 107 "different latency"); 108 } 109 if (chreSensorConfigure(mSensorHandle, mode, 110 999, CHRE_SENSOR_LATENCY_DEFAULT)) { 111 sendFatalFailureToHost("chreSensorConfigure() allowed passive with " 112 "different interval"); 113 } 114 // TODO: In a more in-depth test, we should test passive mode 115 // receiving data. This is somewhat complicated by the fact that 116 // pretty much by definition, we don't control whether a sensor 117 // we're passively listening to is enabled or not. We could try 118 // to control this with an additional test nanoapp toggling sensor 119 // usage, but there's still the complication of other nanoapps in 120 // the system. 121 } else { 122 if (!chreSensorConfigure(mSensorHandle, mode, 123 CHRE_SENSOR_INTERVAL_DEFAULT, 124 kNanosecondsPerSecond)) { 125 sendFatalFailureToHost("chreSensorConfigure() failed passive with " 126 "default interval and non-default latency"); 127 } 128 if (!isOneShotSensor() && !chreSensorConfigure( 129 mSensorHandle, mode, kNanosecondsPerSecond, 130 CHRE_SENSOR_LATENCY_DEFAULT)) { 131 sendFatalFailureToHost("chreSensorConfigure() failed passive with " 132 "non-default interval and default latency"); 133 } 134 if (!isOneShotSensor() && !chreSensorConfigure( 135 mSensorHandle, mode, kNanosecondsPerSecond, 136 kNanosecondsPerSecond)) { 137 sendFatalFailureToHost("chreSensorConfigure() failed passive with " 138 "non-default interval and latency"); 139 } 140 } 141 } 142 143 void BasicSensorTestBase::startTest() { 144 mState = State::kPreConfigure; 145 if (!chreSensorFindDefault(getSensorType(), &mSensorHandle)) { 146 if (isRequiredSensor()) { 147 sendFatalFailureToHost("Sensor is required, but no default found."); 148 } 149 sendStringToHost(MessageType::kSkipped, "No default sensor found for " 150 "optional sensor."); 151 return; 152 } 153 154 chreSensorInfo info; 155 if (!chreGetSensorInfo(mSensorHandle, &info)) { 156 sendFatalFailureToHost("GetSensorInfo() call failed"); 157 } 158 if (info.sensorName == nullptr) { 159 sendFatalFailureToHost("chreSensorInfo::sensorName is NULL"); 160 } 161 if (info.sensorType != getSensorType()) { 162 uint32_t type = info.sensorType; 163 sendFatalFailureToHost("chreSensorInfo::sensorType is not expected " 164 "value, is:", &type); 165 } 166 if (info.isOnChange != isOnChangeSensor()) { 167 sendFatalFailureToHost("chreSensorInfo::isOnChange is opposite of " 168 "what we expected"); 169 } 170 if (info.isOneShot != isOneShotSensor()) { 171 sendFatalFailureToHost("chreSensorInfo::isOneShot is opposite of " 172 "what we expected"); 173 } 174 175 if (!chreGetSensorSamplingStatus(mSensorHandle, &mOriginalStatus)) { 176 sendFatalFailureToHost("chreGetSensorSamplingStatus() failed"); 177 } 178 179 // Nanoapp may start getting events with a passive request. Set the base 180 // timestamp to compare against before configuring the sensor. 181 mPreTimestamp = chreGetTime(); 182 183 checkPassiveConfigure(); 184 if (!chreSendEvent(kPassiveCompleteEvent, nullptr, nullptr, mInstanceId)) { 185 sendFatalFailureToHost("Failed chreSendEvent to complete passive test"); 186 } 187 188 // Default interval/latency must be accepted by all sensors. 189 mNewStatus = { 190 CHRE_SENSOR_INTERVAL_DEFAULT, /* interval */ 191 CHRE_SENSOR_LATENCY_DEFAULT, /* latency */ 192 true /* enabled */ 193 }; 194 chreSensorConfigureMode mode = isOneShotSensor() ? 195 CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT : 196 CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS; 197 198 if (!chreSensorConfigure(mSensorHandle, mode, 199 mNewStatus.interval, mNewStatus.latency)) { 200 sendFatalFailureToHost("chreSensorConfigure() call failed with default" 201 " interval and latency"); 202 } 203 // handleEvent may start getting events, and our testing continues there. 204 // (Note: The CHRE is not allow to call handleEvent() while we're still 205 // in this method, so it's not a race to set this state here.) 206 207 // Set a new request so the test can receive events before test timeout. 208 mNewStatus = { 209 // This will be valid on all required sensors. 210 // TODO: A more in-depth test could try to change this interval 211 // from what it currently is for the sensor, and confirm it 212 // changes back when we're DONE. But that's beyond the current 213 // scope of this 'basic' test. 214 kNanosecondsPerSecond, /* interval */ 215 // We want the test to run as quickly as possible. 216 // TODO: Similar to the interval, we could try to test changes in 217 // this value, but it's beyond our 'basic' scope for now. 218 CHRE_SENSOR_LATENCY_ASAP, /* latency */ 219 true /* enabled */ 220 }; 221 222 // Skip one-shot sensors for non-default interval configurations. 223 if (!isOneShotSensor() && !chreSensorConfigure( 224 mSensorHandle, mode, mNewStatus.interval, mNewStatus.latency)) { 225 sendFatalFailureToHost("chreSensorConfigure() call failed"); 226 } 227 228 if (isOnChangeSensor()) { 229 // We should receive the current state of this sensor after the 230 // configure call. However, we're not assured additional events, 231 // since we don't know if this is going to change. Thus, we jump 232 // our testing state to waiting for the last event. 233 mState = State::kExpectingLastDataEvent; 234 } else if (isOneShotSensor()) { 235 // There's no assurance we'll get any events from a one-shot 236 // sensor, so we'll just skip to the end of the test. 237 finishTest(); 238 } else { 239 mState = State::kExpectingInitialDataEvent; 240 } 241 } 242 243 void BasicSensorTestBase::finishTest() { 244 if (!chreSensorConfigureModeOnly(mSensorHandle, 245 CHRE_SENSOR_CONFIGURE_MODE_DONE)) { 246 sendFatalFailureToHost("Unable to configure sensor mode to DONE"); 247 } 248 mDoneTimestamp = chreGetTime(); 249 chreSensorSamplingStatus status; 250 if (!chreGetSensorSamplingStatus(mSensorHandle, &status)) { 251 sendFatalFailureToHost("Could not get final sensor info"); 252 } 253 if (!mExternalSamplingStatusChange) { 254 // No one else changed this, so it should be what we had before. 255 if (status.enabled != mOriginalStatus.enabled) { 256 sendFatalFailureToHost("SensorInfo.enabled not back to original"); 257 } 258 if (status.interval != mOriginalStatus.interval) { 259 sendFatalFailureToHost("SensorInfo.interval not back to original"); 260 } 261 if (status.latency != mOriginalStatus.latency) { 262 sendFatalFailureToHost("SensorInfo.latency not back to original"); 263 } 264 } 265 mState = State::kFinished; 266 sendSuccessToHost(); 267 } 268 269 void BasicSensorTestBase::sanityCheckHeader(const chreSensorDataHeader* header, 270 bool modifyTimestamps, 271 uint64_t eventDuration) { 272 if (header->sensorHandle != mSensorHandle) { 273 sendFatalFailureToHost("SensorDataHeader for wrong handle", 274 &header->sensorHandle); 275 } 276 277 if (!isOnChangeSensor()) { 278 // An on-change sensor is supposed to send its current state, which 279 // could be timestamped in the past. Everything else should be 280 // getting recent data. 281 uint64_t *minTime = nullptr; 282 uint64_t *timeToUpdate = nullptr; 283 284 if (mState == State::kExpectingInitialDataEvent) { 285 minTime = &mPreTimestamp; 286 timeToUpdate = &mFirstEventTimestamp; 287 } else if (mState == State::kExpectingLastDataEvent) { 288 minTime = &mFirstEventTimestamp; 289 timeToUpdate = &mLastEventTimestamp; 290 } else { // State::kFinished 291 minTime = &mLastEventTimestamp; 292 // Go ahead and update this timestamp again. 293 timeToUpdate = &mLastEventTimestamp; 294 } 295 296 // If there's another CHRE client requesting batched sensor data, 297 // baseTimestamp can be before mPreTimestamp. Also allow 298 // kEventLoopSlack to handle this nanoapp before handling the sensor 299 // event. 300 uint64_t minTimeWithSlack = 301 (*minTime > eventDuration + kEventLoopSlack) ? 302 (*minTime - eventDuration - kEventLoopSlack) : 0; 303 if (header->baseTimestamp < minTimeWithSlack) { 304 chreLog(CHRE_LOG_ERROR, 305 "baseTimestamp %" PRIu64 " < minTimeWithSlack %" PRIu64 306 ": minTime %" PRIu64 " eventDuration %" PRIu64 307 " kEventLoopSlack %" PRIu64, 308 header->baseTimestamp, minTimeWithSlack, 309 *minTime, eventDuration, kEventLoopSlack); 310 sendFatalFailureToHost("SensorDataHeader is in the past"); 311 } 312 if ((mState == State::kFinished) && 313 (header->baseTimestamp > mDoneTimestamp)) { 314 sendFatalFailureToHost("SensorDataHeader is from after DONE"); 315 } 316 if (modifyTimestamps) { 317 *timeToUpdate = header->baseTimestamp; 318 } 319 } 320 if (header->readingCount == 0) { 321 sendFatalFailureToHost("SensorDataHeader has readingCount of 0"); 322 } 323 if ((header->reserved[0] != 0) || (header->reserved[1] != 0)) { 324 sendFatalFailureToHost("SensorDataHeader has non-zero reserved bytes"); 325 } 326 } 327 328 329 void BasicSensorTestBase::handleBiasEvent( 330 uint16_t eventType, const chreSensorThreeAxisData *eventData) { 331 uint8_t expectedSensorType = 0; 332 uint32_t eType = eventType; 333 if (eventType == CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO) { 334 expectedSensorType = CHRE_SENSOR_TYPE_GYROSCOPE; 335 } else if (eventType == CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO) { 336 expectedSensorType = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD; 337 } else { 338 sendInternalFailureToHost("Illegal eventType in handleBiasEvent", 339 &eType); 340 } 341 342 if (expectedSensorType != getSensorType()) { 343 sendFatalFailureToHost("Unexpected bias event:", &eType); 344 } 345 sanityCheckHeader(&eventData->header, false, getEventDuration(eventData)); 346 347 // TODO: Sanity check the eventData. This check is out-of-scope for 348 // Android N testing. 349 } 350 351 void BasicSensorTestBase::handleSamplingChangeEvent( 352 const chreSensorSamplingStatusEvent* eventData) { 353 if (eventData->sensorHandle != mSensorHandle) { 354 sendFatalFailureToHost("SamplingChangeEvent for wrong sensor handle:", 355 &eventData->sensorHandle); 356 } 357 if (mState == State::kFinished) { 358 // TODO: If we strictly define whether this event is or isn't 359 // generated upon being DONE with a sensor, then we can perform 360 // a strict check here. For now, we just let this go. 361 return; 362 } 363 // Passive sensor requests do not guarantee sensors will always be enabled. 364 // Bypass 'enabled' check for passive configurations. 365 if (mDoneWithPassiveConfigure && !eventData->status.enabled) { 366 sendFatalFailureToHost("SamplingChangeEvent disabled the sensor."); 367 } 368 369 if ((mNewStatus.interval != eventData->status.interval) || 370 (mNewStatus.latency != eventData->status.latency)) { 371 // This is from someone other than us. Let's note that so we know 372 // our sanity checks are invalid. 373 mExternalSamplingStatusChange = true; 374 } 375 } 376 377 void BasicSensorTestBase::handleSensorDataEvent(const void* eventData) { 378 if ((mState == State::kPreStart) || (mState == State::kPreConfigure)) { 379 sendFatalFailureToHost("SensorDataEvent sent too early."); 380 } 381 // Note, if mState is kFinished, we could be getting batched data which 382 // hadn't been delivered yet at the time we were DONE. We'll sanity 383 // check it, even though in theory we're done testing. 384 uint64_t eventDuration = getEventDuration( 385 static_cast<const chreSensorThreeAxisData *>(eventData)); 386 sanityCheckHeader(static_cast<const chreSensorDataHeader*>(eventData), 387 true, eventDuration); 388 389 // Send to the sensor itself for any additional checks of actual data. 390 confirmDataIsSane(eventData); 391 if (mState == State::kExpectingInitialDataEvent) { 392 mState = State::kExpectingLastDataEvent; 393 } else if (mState == State::kExpectingLastDataEvent) { 394 finishTest(); 395 } else if (mState != State::kFinished) { 396 uint32_t value = static_cast<uint32_t>(mState); 397 sendInternalFailureToHost("Illegal mState in handleSensorDataEvent:", 398 &value); 399 } 400 } 401 402 void BasicSensorTestBase::handleEvent( 403 uint32_t senderInstanceId, uint16_t eventType, const void* eventData) { 404 if (mInMethod) { 405 sendFatalFailureToHost("handleEvent() invoked while already in " 406 "method."); 407 } 408 mInMethod = true; 409 const uint16_t dataEventType = 410 CHRE_EVENT_SENSOR_DATA_EVENT_BASE + getSensorType(); 411 412 if (senderInstanceId == mInstanceId) { 413 if ((eventType == kStartEvent) && (mState == State::kPreStart)) { 414 startTest(); 415 } else if (eventType == kPassiveCompleteEvent) { 416 mDoneWithPassiveConfigure = true; 417 } 418 419 } else if ((mState == State::kPreStart) || 420 (mState == State::kPreConfigure)) { 421 unexpectedEvent(eventType); 422 423 } else if (senderInstanceId != CHRE_INSTANCE_ID) { 424 sendFatalFailureToHost("Unexpected senderInstanceId:", 425 &senderInstanceId); 426 427 } else if (eventData == nullptr) { 428 uint32_t eType = eventType; 429 sendFatalFailureToHost("Got NULL eventData for event:", &eType); 430 431 } else if (eventType == dataEventType) { 432 handleSensorDataEvent(eventData); 433 434 } else if (eventType == CHRE_EVENT_SENSOR_SAMPLING_CHANGE) { 435 handleSamplingChangeEvent( 436 static_cast<const chreSensorSamplingStatusEvent*>(eventData)); 437 438 } else if ((eventType == CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO) || 439 (eventType == CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO)) { 440 handleBiasEvent(eventType, 441 static_cast<const chreSensorThreeAxisData*>(eventData)); 442 443 } else { 444 unexpectedEvent(eventType); 445 } 446 447 mInMethod = false; 448 } 449 450 } // namespace general_test 451