/*
* 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/core/event_loop_manager.h"
#include "chre/platform/fatal_error.h"
#include "chre_api/chre/version.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;
}
} // 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].sensor = std::move(sensors[i]);
LOGD("Found sensor: %s", getSensorTypeName(sensorType));
}
}
}
}
SensorRequestManager::~SensorRequestManager() {
SensorRequest nullRequest = SensorRequest();
for (size_t i = 0; i < mSensorRequests.size(); i++) {
// Disable sensors that have been enabled previously.
if (mSensorRequests[i].sensor.has_value()) {
mSensorRequests[i].sensor->setRequest(nullRequest);
}
}
}
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].sensor.has_value();
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.sensor.has_value()) {
LOGW("Attempting to configure non-existent sensor");
return false;
}
const Sensor& sensor = requests.sensor.value();
if (!isSensorRequestValid(sensor, sensorRequest)) {
return false;
}
size_t requestIndex;
uint16_t eventType = getSampleEventTypeForSensorType(sensorType);
bool nanoappHasRequest = (requests.find(nanoapp, &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);
}
} 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);
// 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].sensor.has_value()) {
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->unusedFlags = 0;
// Platform-specific properties.
const Sensor& sensor = mSensorRequests[sensorIndex].sensor.value();
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.multiplexer.getRequests()) {
Nanoapp *nanoapp = request.getNanoapp();
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].sensor.has_value()) {
sensorPtr = &mSensorRequests[sensorIndex].sensor.value();
}
}
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].sensor.has_value()) {
success = mSensorRequests[sensorIndex].sensor->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].multiplexer.getRequests();
}
bool SensorRequestManager::logStateToBuffer(char *buffer, size_t *bufferPos,
size_t bufferSize) const {
bool success = 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)) {
uint32_t instanceId = (request.getNanoapp() != nullptr) ?
request.getNanoapp()->getInstanceId() : kInvalidInstanceId;
success &= 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(),
instanceId);
}
}
}
return success;
}
const SensorRequest *SensorRequestManager::SensorRequests::find(
const Nanoapp *nanoapp, size_t *index) const {
CHRE_ASSERT(index);
const auto& requests = multiplexer.getRequests();
for (size_t i = 0; i < requests.size(); i++) {
const SensorRequest& sensorRequest = requests[i];
if (sensorRequest.getNanoapp() == nanoapp) {
*index = i;
return &sensorRequest;
}
}
return nullptr;
}
bool SensorRequestManager::SensorRequests::add(const SensorRequest& request,
bool *requestChanged) {
CHRE_ASSERT(requestChanged != nullptr);
CHRE_ASSERT(sensor.has_value());
size_t addIndex;
bool success = true;
if (!multiplexer.addRequest(request, &addIndex, requestChanged)) {
*requestChanged = false;
success = false;
LOG_OOM();
} else if (*requestChanged) {
success = sensor->setRequest(multiplexer.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.
multiplexer.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(sensor.has_value());
bool success = true;
multiplexer.removeRequest(removeIndex, requestChanged);
if (*requestChanged) {
success = sensor->setRequest(multiplexer.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(sensor.has_value());
bool success = true;
SensorRequest previousRequest = multiplexer.getRequests()[updateIndex];
multiplexer.updateRequest(updateIndex, request, requestChanged);
if (*requestChanged) {
success = sensor->setRequest(multiplexer.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.
multiplexer.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(sensor.has_value());
bool requestChanged;
multiplexer.removeAllRequests(&requestChanged);
bool success = true;
if (requestChanged) {
SensorRequest maximalRequest = multiplexer.getCurrentMaximalRequest();
success = sensor->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;
}
} // namespace chre