/* * 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