/*
* 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"
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();
uint64_t requestedLatency = sensorRequest.getLatency().toRawNanoseconds();
SensorType sensorType = sensor.getSensorType();
bool success = true;
if (isRequestContinuous) {
if (sensorTypeIsOneShot(sensorType)) {
success = false;
LOGE("Invalid continuous request for a one-shot sensor.");
} else if (requestedInterval < sensor.getMinInterval()) {
success = false;
LOGE("Invalid requested interval %" PRIu64 " for a continuous sensor"
" with minInterval %" PRIu64,
requestedInterval, sensor.getMinInterval());
}
} else if (isRequestOneShot) {
if (!sensorTypeIsOneShot(sensorType)) {
success = false;
LOGE("Invalid one-shot request for a continuous sensor.");
} else if (requestedInterval != CHRE_SENSOR_INTERVAL_DEFAULT ||
requestedLatency != CHRE_SENSOR_LATENCY_DEFAULT) {
success = false;
LOGE("Invalid interval and/or latency for a one-shot request.");
}
}
return success;
}
} // namespace
SensorRequestManager::SensorRequestManager() {
mSensorRequests.resize(mSensorRequests.capacity());
DynamicVector<PlatformSensor> platformSensors;
if (!PlatformSensor::getSensors(&platformSensors)) {
LOGE("Failed to query the platform for sensors");
return;
}
if (platformSensors.empty()) {
LOGW("Platform returned zero sensors");
}
for (size_t i = 0; i < platformSensors.size(); i++) {
SensorType sensorType = platformSensors[i].getSensorType();
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
LOGD("Found sensor: %s", getSensorTypeName(sensorType));
mSensorRequests[sensorIndex].sensor =
Sensor(std::move(platformSensors[i]));
}
}
SensorRequestManager::~SensorRequestManager() {
SensorRequest nullRequest = SensorRequest();
for (size_t i = 0; i < mSensorRequests.size(); i++) {
// Disable sensors that have been enabled previously.
Sensor& sensor = mSensorRequests[i].sensor;
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.isValid();
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 handle");
return false;
}
// Ensure that the runtime is aware of this sensor type.
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
SensorRequests& requests = mSensorRequests[sensorIndex];
const Sensor& sensor = requests.sensor;
if (!sensor.isValid()) {
LOGW("Attempting to configure non-existent sensor");
return false;
} else 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()->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(nanoapp);
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 {
success = true;
// Platform-independent properties.
info->sensorType = getUnsignedIntFromSensorType(sensorType);
info->isOnChange = sensorTypeIsOnChange(sensorType);
info->isOneShot = sensorTypeIsOneShot(sensorType);
info->unusedFlags = 0;
// Platform-specific properties.
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
const Sensor& sensor = mSensorRequests[sensorIndex].sensor;
info->sensorName = sensor.getSensorName();
// minInterval was added in CHRE API 1.1.
if (nanoapp->getTargetApiVersion() >= CHRE_API_VERSION_1_1) {
info->minInterval = info->isOneShot ? CHRE_SENSOR_INTERVAL_DEFAULT :
sensor.getMinInterval();
}
}
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) {
LOGW("Attempting to get Sensor of an invalid SensorType");
} else {
size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
sensorPtr = &mSensorRequests[sensorIndex].sensor;
}
return sensorPtr;
}
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);
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);
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);
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() {
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