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