/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "chre/core/sensor_request_manager.h"
#include "chre_api/chre/version.h"
#include "chre/core/event_loop_manager.h"
#include "chre/platform/fatal_error.h"
#include "chre/util/system/debug_dump.h"
namespace chre {
namespace {
bool isSensorRequestValid(const Sensor& sensor,
const SensorRequest& sensorRequest) {
bool isRequestContinuous = sensorModeIsContinuous(
sensorRequest.getMode());
bool isRequestOneShot = sensorModeIsOneShot(sensorRequest.getMode());
uint64_t requestedInterval = sensorRequest.getInterval().toRawNanoseconds();
SensorType sensorType = sensor.getSensorType();
bool success = true;
if (requestedInterval < sensor.getMinInterval()) {
success = false;
LOGE("Requested interval %" PRIu64 " < sensor's minInterval %" PRIu64,
requestedInterval, sensor.getMinInterval());
} else if (isRequestContinuous) {
if (sensorTypeIsOneShot(sensorType)) {
success = false;
LOGE("Invalid continuous request for a one-shot sensor.");
}
} else if (isRequestOneShot) {
if (!sensorTypeIsOneShot(sensorType)) {
success = false;
LOGE("Invalid one-shot request for a continuous sensor.");
}
}
return success;
}
void flushTimerCallback(uint16_t /* eventType */, void * /* data */) {
// TODO: Fatal error here since some platforms may not be able to handle
// timeouts gracefully. Modify this implementation to drop flush
// requests and handle stale responses in the future appropriately.
FATAL_ERROR("Flush request timed out");
}
} // namespace
SensorRequestManager::SensorRequestManager() {
mSensorRequests.resize(mSensorRequests.capacity());
DynamicVector<Sensor> sensors;
sensors.reserve(8); // Avoid some initial reallocation churn
if (!PlatformSensor::getSensors(&sensors)) {
LOGE("Failed to query the platform for sensors");
} else if (sensors.empty()) {
LOGW("Platform returned zero sensors");
} else {
for (size_t i = 0; i < sensors.size(); i++) {
SensorType sensorType = sensors[i].getSensorType();
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
if (sensorType == SensorType::Unknown) {
LOGE("Invalid sensor type");
} else if (sensors[i].getMinInterval() == 0) {
LOGE("Invalid sensor minInterval: %s", getSensorTypeName(sensorType));
} else {
mSensorRequests[sensorIndex].setSensor(std::move(sensors[i]));
LOGD("Found sensor: %s", getSensorTypeName(sensorType));
}
}
}
}
SensorRequestManager::~SensorRequestManager() {
for (size_t i = 0; i < mSensorRequests.size(); i++) {
// Disable sensors that have been enabled previously.
if (mSensorRequests[i].isSensorSupported()) {
mSensorRequests[i].removeAll();
}
}
}
bool SensorRequestManager::getSensorHandle(SensorType sensorType,
uint32_t *sensorHandle) const {
CHRE_ASSERT(sensorHandle);
bool sensorHandleIsValid = false;
if (sensorType == SensorType::Unknown) {
LOGW("Querying for unknown sensor type");
} else {
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
sensorHandleIsValid = mSensorRequests[sensorIndex].isSensorSupported();
if (sensorHandleIsValid) {
*sensorHandle = getSensorHandleFromSensorType(sensorType);
}
}
return sensorHandleIsValid;
}
bool SensorRequestManager::setSensorRequest(Nanoapp *nanoapp,
uint32_t sensorHandle, const SensorRequest& sensorRequest) {
CHRE_ASSERT(nanoapp);
// Validate the input to ensure that a valid handle has been provided.
SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
if (sensorType == SensorType::Unknown) {
LOGW("Attempting to configure an invalid sensor handle");
return false;
}
// Ensure that the runtime is aware of this sensor type.
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
SensorRequests& requests = mSensorRequests[sensorIndex];
if (!requests.isSensorSupported()) {
LOGW("Attempting to configure non-existent sensor");
return false;
}
const Sensor& sensor = requests.getSensor();
if (!isSensorRequestValid(sensor, sensorRequest)) {
return false;
}
size_t requestIndex;
uint16_t eventType = getSampleEventTypeForSensorType(sensorType);
bool nanoappHasRequest = (requests.find(nanoapp->getInstanceId(),
&requestIndex) != nullptr);
bool success;
bool requestChanged;
if (sensorRequest.getMode() == SensorMode::Off) {
if (nanoappHasRequest) {
// The request changes the mode to off and there was an existing request.
// The existing request is removed from the multiplexer. The nanoapp is
// unregistered from events of this type if this request was successful.
success = requests.remove(requestIndex, &requestChanged);
if (success) {
nanoapp->unregisterForBroadcastEvent(eventType);
uint16_t biasEventType;
if (getSensorBiasEventType(sensorType, &biasEventType)) {
// Per API requirements, turn off bias reporting when unsubscribing
// from the sensor.
nanoapp->unregisterForBroadcastEvent(biasEventType);
}
}
} else {
// The sensor is being configured to Off, but is already Off (there is no
// existing request). We assign to success to be true and no other
// operation is required.
requestChanged = false;
success = true;
}
} else if (!nanoappHasRequest) {
// The request changes the mode to the enabled state and there was no
// existing request. The request is newly created and added to the
// multiplexer. The nanoapp is registered for events if this request was
// successful.
success = requests.add(sensorRequest, &requestChanged);
if (success) {
nanoapp->registerForBroadcastEvent(eventType);
// Per API requirements, turn on bias reporting for calibrated sensors
// by default when subscribed.
uint16_t biasEventType;
if (getSensorBiasEventType(sensorType, &biasEventType)
&& sensorTypeIsCalibrated(sensorType)) {
nanoapp->registerForBroadcastEvent(biasEventType);
}
// Deliver last valid event to new clients of on-change sensors
if (sensorTypeIsOnChange(sensor.getSensorType())
&& sensor.getLastEvent() != nullptr) {
EventLoopManagerSingleton::get()->getEventLoop()
.postEvent(getSampleEventTypeForSensorType(sensorType),
sensor.getLastEvent(), nullptr, kSystemInstanceId,
nanoapp->getInstanceId());
}
}
} else {
// The request changes the mode to the enabled state and there was an
// existing request. The existing request is updated.
success = requests.update(requestIndex, sensorRequest, &requestChanged);
}
if (requestChanged) {
// TODO: Send an event to nanoapps to indicate the rate change.
}
return success;
}
bool SensorRequestManager::getSensorInfo(uint32_t sensorHandle,
const Nanoapp& nanoapp,
struct chreSensorInfo *info) const {
CHRE_ASSERT(info);
bool success = false;
// Validate the input to ensure that a valid handle has been provided.
SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
if (sensorType == SensorType::Unknown) {
LOGW("Attempting to access sensor with an invalid handle %" PRIu32,
sensorHandle);
} else {
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
if (!mSensorRequests[sensorIndex].isSensorSupported()) {
LOGW("Attempting to get sensor info for unsupported sensor handle %"
PRIu32, sensorHandle);
} else {
// Platform-independent properties.
info->sensorType = getUnsignedIntFromSensorType(sensorType);
info->isOnChange = sensorTypeIsOnChange(sensorType);
info->isOneShot = sensorTypeIsOneShot(sensorType);
info->reportsBiasEvents = sensorTypeReportsBias(sensorType);
info->unusedFlags = 0;
// Platform-specific properties.
const Sensor& sensor = mSensorRequests[sensorIndex].getSensor();
info->sensorName = sensor.getSensorName();
// minInterval was added in CHRE API v1.1 - do not attempt to populate for
// nanoapps targeting v1.0 as their struct will not be large enough
if (nanoapp.getTargetApiVersion() >= CHRE_API_VERSION_1_1) {
info->minInterval = sensor.getMinInterval();
}
success = true;
}
}
return success;
}
bool SensorRequestManager::removeAllRequests(SensorType sensorType) {
bool success = false;
if (sensorType == SensorType::Unknown) {
LOGW("Attempting to remove all requests of an invalid sensor type");
} else {
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
SensorRequests& requests = mSensorRequests[sensorIndex];
uint16_t eventType = getSampleEventTypeForSensorType(sensorType);
for (const SensorRequest& request : requests.getRequests()) {
Nanoapp *nanoapp = EventLoopManagerSingleton::get()->getEventLoop()
.findNanoappByInstanceId(request.getInstanceId());
if (nanoapp != nullptr) {
nanoapp->unregisterForBroadcastEvent(eventType);
}
}
success = requests.removeAll();
}
return success;
}
Sensor *SensorRequestManager::getSensor(SensorType sensorType) {
Sensor *sensorPtr = nullptr;
if (sensorType == SensorType::Unknown
|| sensorType >= SensorType::SENSOR_TYPE_COUNT) {
LOGW("Attempting to get Sensor of an invalid SensorType %d",
static_cast<int>(sensorType));
} else {
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
if (mSensorRequests[sensorIndex].isSensorSupported()) {
sensorPtr = &mSensorRequests[sensorIndex].getSensor();
}
}
return sensorPtr;
}
bool SensorRequestManager::getSensorSamplingStatus(
uint32_t sensorHandle, struct chreSensorSamplingStatus *status) const {
CHRE_ASSERT(status);
bool success = false;
SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
if (sensorType == SensorType::Unknown) {
LOGW("Attempting to access sensor with an invalid handle %" PRIu32,
sensorHandle);
} else {
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
if (mSensorRequests[sensorIndex].isSensorSupported()) {
success = mSensorRequests[sensorIndex].getSamplingStatus(status);
}
}
return success;
}
const DynamicVector<SensorRequest>& SensorRequestManager::getRequests(
SensorType sensorType) const {
size_t sensorIndex = 0;
if (sensorType == SensorType::Unknown
|| sensorType >= SensorType::SENSOR_TYPE_COUNT) {
LOGW("Attempting to get requests of an invalid SensorType");
} else {
sensorIndex = getSensorTypeArrayIndex(sensorType);
}
return mSensorRequests[sensorIndex].getRequests();
}
bool SensorRequestManager::configureBiasEvents(
Nanoapp *nanoapp, uint32_t sensorHandle, bool enable) {
bool success = false;
uint16_t eventType;
SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
if (getSensorBiasEventType(sensorType, &eventType)) {
if (enable) {
nanoapp->registerForBroadcastEvent(eventType);
} else {
nanoapp->unregisterForBroadcastEvent(eventType);
}
success = true;
}
return success;
}
bool SensorRequestManager::getThreeAxisBias(
uint32_t sensorHandle, struct chreSensorThreeAxisData *bias) const {
CHRE_ASSERT(bias != nullptr);
bool success = false;
if (bias != nullptr) {
SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
if (sensorType == SensorType::Unknown) {
LOGW("Attempting to access sensor with an invalid handle %" PRIu32,
sensorHandle);
} else {
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
if (mSensorRequests[sensorIndex].isSensorSupported()) {
success = mSensorRequests[sensorIndex].getThreeAxisBias(bias);
}
}
}
return success;
}
bool SensorRequestManager::flushAsync(
Nanoapp *nanoapp, uint32_t sensorHandle, const void *cookie) {
bool success = false;
uint32_t nanoappInstanceId = nanoapp->getInstanceId();
SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
// NOTE: One-shot sensors do not support flush per API
if (sensorType == SensorType::Unknown || sensorTypeIsOneShot(sensorType)) {
LOGE("Cannot flush for sensor type %" PRIu32,
static_cast<uint32_t>(sensorType));
} else if (mFlushRequestQueue.full()) {
LOG_OOM();
} else {
mFlushRequestQueue.emplace_back(sensorType, nanoappInstanceId, cookie);
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
success = (mSensorRequests[sensorIndex].makeFlushRequest(
mFlushRequestQueue.back()) == CHRE_ERROR_NONE);
if (!success) {
mFlushRequestQueue.pop_back();
}
}
return success;
}
void SensorRequestManager::handleFlushCompleteEvent(
uint8_t errorCode, SensorType sensorType) {
struct CallbackState {
uint8_t errorCode;
SensorType sensorType;
};
// Enables passing data through void pointer to avoid allocation.
union NestedCallbackState {
void *eventData;
CallbackState callbackState;
};
static_assert(sizeof(NestedCallbackState) == sizeof(void *),
"Size of NestedCallbackState must equal that of void *");
NestedCallbackState state = {};
state.callbackState.errorCode = errorCode;
state.callbackState.sensorType = sensorType;
auto callback = [](uint16_t /* eventType */, void *eventData) {
NestedCallbackState nestedState;
nestedState.eventData = eventData;
EventLoopManagerSingleton::get()->getSensorRequestManager()
.handleFlushCompleteEventSync(nestedState.callbackState.errorCode,
nestedState.callbackState.sensorType);
};
EventLoopManagerSingleton::get()->deferCallback(
SystemCallbackType::SensorFlushComplete, state.eventData, callback);
}
void SensorRequestManager::logStateToBuffer(char *buffer, size_t *bufferPos,
size_t bufferSize) const {
debugDumpPrint(buffer, bufferPos, bufferSize, "\nSensors:\n");
for (uint8_t i = 0; i < static_cast<uint8_t>(SensorType::SENSOR_TYPE_COUNT);
i++) {
SensorType sensor = static_cast<SensorType>(i);
if (sensor != SensorType::Unknown) {
for (const auto& request : getRequests(sensor)) {
debugDumpPrint(buffer, bufferPos, bufferSize, " %s: mode=%d"
" interval(ns)=%" PRIu64 " latency(ns)=%"
PRIu64 " nanoappId=%" PRIu32 "\n",
getSensorTypeName(sensor), request.getMode(),
request.getInterval().toRawNanoseconds(),
request.getLatency().toRawNanoseconds(),
request.getInstanceId());
}
}
}
}
void SensorRequestManager::postFlushCompleteEvent(
uint32_t sensorHandle, uint8_t errorCode, const FlushRequest& request) {
auto *event = memoryAlloc<chreSensorFlushCompleteEvent>();
if (event == nullptr) {
LOG_OOM();
} else {
event->sensorHandle = sensorHandle;
event->errorCode = errorCode;
event->cookie = request.cookie;
memset(event->reserved, 0, sizeof(event->reserved));
EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
CHRE_EVENT_SENSOR_FLUSH_COMPLETE, event, freeEventDataCallback,
kSystemInstanceId, request.nanoappInstanceId);
}
}
void SensorRequestManager::dispatchNextFlushRequest(
uint32_t sensorHandle, SensorType sensorType) {
SensorRequests& requests = getSensorRequests(sensorType);
for (size_t i = 0; i < mFlushRequestQueue.size(); i++) {
const FlushRequest& request = mFlushRequestQueue[i];
if (request.sensorType == sensorType) {
uint8_t newRequestErrorCode = requests.makeFlushRequest(request);
if (newRequestErrorCode == CHRE_ERROR_NONE) {
break;
} else {
postFlushCompleteEvent(sensorHandle, newRequestErrorCode, request);
mFlushRequestQueue.erase(i);
i--;
}
}
}
}
void SensorRequestManager::handleFlushCompleteEventSync(
uint8_t errorCode, SensorType sensorType) {
for (size_t i = 0; i < mFlushRequestQueue.size(); i++) {
const FlushRequest& request = mFlushRequestQueue[i];
if (request.sensorType == sensorType) {
uint32_t sensorHandle;
if (getSensorHandle(sensorType, &sensorHandle)) {
SensorRequests& requests = getSensorRequests(sensorType);
requests.cancelFlushTimer();
postFlushCompleteEvent(sensorHandle, errorCode, request);
mFlushRequestQueue.erase(i);
dispatchNextFlushRequest(sensorHandle, sensorType);
}
break;
}
}
}
const SensorRequest *SensorRequestManager::SensorRequests::find(
uint32_t instanceId, size_t *index) const {
CHRE_ASSERT(index);
const auto& requests = mMultiplexer.getRequests();
for (size_t i = 0; i < requests.size(); i++) {
const SensorRequest& sensorRequest = requests[i];
if (sensorRequest.getInstanceId() == instanceId) {
*index = i;
return &sensorRequest;
}
}
return nullptr;
}
bool SensorRequestManager::SensorRequests::add(const SensorRequest& request,
bool *requestChanged) {
CHRE_ASSERT(requestChanged != nullptr);
CHRE_ASSERT(isSensorSupported());
size_t addIndex;
bool success = true;
if (!mMultiplexer.addRequest(request, &addIndex, requestChanged)) {
*requestChanged = false;
success = false;
LOG_OOM();
} else if (*requestChanged) {
success = mSensor->setRequest(mMultiplexer.getCurrentMaximalRequest());
if (!success) {
// Remove the newly added request since the platform failed to handle it.
// The sensor is expected to maintain the existing request so there is no
// need to reset the platform to the last maximal request.
mMultiplexer.removeRequest(addIndex, requestChanged);
// This is a roll-back operation so the maximal change in the multiplexer
// must not have changed. The request changed state is forced to false.
*requestChanged = false;
}
}
return success;
}
bool SensorRequestManager::SensorRequests::remove(size_t removeIndex,
bool *requestChanged) {
CHRE_ASSERT(requestChanged != nullptr);
CHRE_ASSERT(isSensorSupported());
bool success = true;
mMultiplexer.removeRequest(removeIndex, requestChanged);
if (*requestChanged) {
success = mSensor->setRequest(mMultiplexer.getCurrentMaximalRequest());
if (!success) {
LOGE("SensorRequestManager failed to remove a request");
// If the platform fails to handle this request in a debug build there is
// likely an error in the platform. This is not strictly a programming
// error but it does make sense to use assert semantics when a platform
// fails to handle a request that it had been sent previously.
CHRE_ASSERT(false);
// The request to the platform to set a request when removing has failed
// so the request has not changed.
*requestChanged = false;
}
}
return success;
}
bool SensorRequestManager::SensorRequests::update(size_t updateIndex,
const SensorRequest& request,
bool *requestChanged) {
CHRE_ASSERT(requestChanged != nullptr);
CHRE_ASSERT(isSensorSupported());
bool success = true;
SensorRequest previousRequest = mMultiplexer.getRequests()[updateIndex];
mMultiplexer.updateRequest(updateIndex, request, requestChanged);
if (*requestChanged) {
success = mSensor->setRequest(mMultiplexer.getCurrentMaximalRequest());
if (!success) {
// Roll back the request since sending it to the sensor failed. The
// request will roll back to the previous maximal. The sensor is
// expected to maintain the existing request if a request fails so there
// is no need to reset the platform to the last maximal request.
mMultiplexer.updateRequest(updateIndex, previousRequest, requestChanged);
// This is a roll-back operation so the maximal change in the multiplexer
// must not have changed. The request changed state is forced to false.
*requestChanged = false;
}
}
return success;
}
bool SensorRequestManager::SensorRequests::removeAll() {
CHRE_ASSERT(isSensorSupported());
bool requestChanged;
mMultiplexer.removeAllRequests(&requestChanged);
bool success = true;
if (requestChanged) {
SensorRequest maximalRequest = mMultiplexer.getCurrentMaximalRequest();
success = mSensor->setRequest(maximalRequest);
if (!success) {
LOGE("SensorRequestManager failed to remove all request");
// If the platform fails to handle this request in a debug build there is
// likely an error in the platform. This is not strictly a programming
// error but it does make sense to use assert semantics when a platform
// fails to handle a request that it had been sent previously.
CHRE_ASSERT(false);
}
}
return success;
}
uint8_t SensorRequestManager::SensorRequests::makeFlushRequest(
const FlushRequest& request) {
uint8_t errorCode = CHRE_ERROR;
if (!isSensorSupported()) {
LOGE("Cannot flush on unsupported sensor");
} else if (mMultiplexer.getRequests().size() == 0) {
LOGE("Cannot flush on disabled sensor");
} else if (!isFlushRequestPending()) {
Nanoseconds now = SystemTime::getMonotonicTime();
Nanoseconds deadline = request.deadlineTimestamp;
if (now >= deadline) {
LOGE("Flush sensor %" PRIu32 " failed for nanoapp ID %" PRIu32
": deadline exceeded", static_cast<uint32_t>(request.sensorType),
request.nanoappInstanceId);
errorCode = CHRE_ERROR_TIMEOUT;
} else if (mSensor->flushAsync()) {
errorCode = CHRE_ERROR_NONE;
Nanoseconds delay = deadline - now;
mFlushRequestTimerHandle =
EventLoopManagerSingleton::get()->setDelayedCallback(
SystemCallbackType::SensorFlushTimeout, nullptr /* data */,
flushTimerCallback, delay);
}
} else {
// Flush request will be made once the pending request is completed.
// Return true so that the nanoapp can wait for a result through the
// CHRE_EVENT_SENSOR_FLUSH_COMPLETE event.
errorCode = CHRE_ERROR_NONE;
}
return errorCode;
}
void SensorRequestManager::SensorRequests::cancelFlushTimer() {
EventLoopManagerSingleton::get()->cancelDelayedCallback(
mFlushRequestTimerHandle);
mFlushRequestTimerHandle = CHRE_TIMER_INVALID;
}
} // namespace chre