/* * 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 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(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& 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(SensorType::SENSOR_TYPE_COUNT); i++) { SensorType sensor = static_cast(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