| /* |
| * 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/util/macros.h" |
| #include "chre/util/nested_data_ptr.h" |
| #include "chre/util/system/debug_dump.h" |
| #include "chre/util/system/event_callbacks.h" |
| #include "chre/util/time.h" |
| #include "chre_api/chre/version.h" |
| |
| #define LOG_INVALID_HANDLE(x) \ |
| LOGE("Invalid sensor handle %" PRIu32 ": line %d", x, __LINE__) |
| |
| namespace chre { |
| namespace { |
| |
| bool isSensorRequestValid(const Sensor &sensor, |
| const SensorRequest &sensorRequest) { |
| bool isRequestOneShot = sensorModeIsOneShot(sensorRequest.getMode()); |
| bool isRequestOff = sensorRequest.getMode() == SensorMode::Off; |
| uint64_t requestedInterval = sensorRequest.getInterval().toRawNanoseconds(); |
| bool isRequestPassive = sensorModeIsPassive(sensorRequest.getMode()); |
| |
| bool success = false; |
| if (!isRequestOff && requestedInterval < sensor.getMinInterval()) { |
| LOGE("Requested interval %" PRIu64 " < sensor's minInterval %" PRIu64, |
| requestedInterval, sensor.getMinInterval()); |
| } else if (!isRequestOff && isRequestOneShot != sensor.isOneShot()) { |
| LOGE("Invalid request type for sensor reporting mode"); |
| } else if (isRequestPassive && !sensor.supportsPassiveMode()) { |
| LOGE("Passive mode not supported"); |
| } else { |
| success = true; |
| } |
| return success; |
| } |
| |
| /** |
| * A helper function that updates the last event of a sensor in the main thread. |
| * |
| * @param eventData A non-null pointer to the sensor's CHRE event data. |
| */ |
| void updateLastEvent(void *eventData) { |
| CHRE_ASSERT(eventData); |
| |
| auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) { |
| auto *sensorData = static_cast<ChreSensorData *>(data); |
| Sensor *sensor = |
| EventLoopManagerSingleton::get()->getSensorRequestManager().getSensor( |
| sensorData->header.sensorHandle); |
| |
| // Mark last event as valid only if the sensor is enabled. Event data may |
| // arrive after sensor is disabled. |
| if (sensor != nullptr && |
| sensor->getMaximalRequest().getMode() != SensorMode::Off) { |
| sensor->setLastEvent(sensorData); |
| } |
| }; |
| |
| // Schedule a deferred callback. |
| EventLoopManagerSingleton::get()->deferCallback( |
| SystemCallbackType::SensorLastEventUpdate, eventData, callback); |
| } |
| |
| void sensorDataEventFree(uint16_t eventType, void *eventData) { |
| EventLoopManagerSingleton::get() |
| ->getSensorRequestManager() |
| .releaseSensorDataEvent(eventType, eventData); |
| } |
| |
| /** |
| * Posts a CHRE_EVENT_SENSOR_SAMPLING_CHANGE event to the specified Nanoapp. |
| * |
| * @param instanceId The instance ID of the nanoapp with an open request. |
| * @param sensorHandle The handle of the sensor. |
| * @param status A reference of the sampling status to be posted. |
| */ |
| void postSamplingStatusEvent(uint16_t instanceId, uint32_t sensorHandle, |
| const struct chreSensorSamplingStatus &status) { |
| auto *event = memoryAlloc<struct chreSensorSamplingStatusEvent>(); |
| if (event == nullptr) { |
| LOG_OOM(); |
| } else { |
| event->sensorHandle = sensorHandle; |
| event->status = status; |
| |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_SENSOR_SAMPLING_CHANGE, event, freeEventDataCallback, |
| instanceId); |
| } |
| } |
| |
| /** |
| * Notifies all listening nanoapps of the latest sampling status update. |
| * |
| * @param sensorHandle The handle of the sensor. |
| * @param status A reference of the sampling status to be posted. |
| */ |
| void postSamplingStatus(uint32_t sensorHandle, |
| struct chreSensorSamplingStatus &status) { |
| // Only post to Nanoapps with an open request. |
| const DynamicVector<SensorRequest> &requests = |
| EventLoopManagerSingleton::get()->getSensorRequestManager().getRequests( |
| sensorHandle); |
| for (const auto &req : requests) { |
| postSamplingStatusEvent(req.getInstanceId(), sensorHandle, status); |
| } |
| } |
| |
| } // namespace |
| |
| SensorRequestManager::~SensorRequestManager() { |
| for (size_t i = 0; i < mSensors.size(); i++) { |
| // Disable sensors that have been enabled previously. |
| removeAllRequests(mSensors[i]); |
| } |
| } |
| |
| void SensorRequestManager::init() { |
| // The Platform sensor must be initialized prior to interacting with any |
| // sensors. |
| mPlatformSensorManager.init(); |
| |
| mSensors = mPlatformSensorManager.getSensors(); |
| } |
| |
| bool SensorRequestManager::getSensorHandle(uint8_t sensorType, |
| uint8_t sensorIndex, |
| uint16_t targetGroupId, |
| uint32_t *sensorHandle) const { |
| CHRE_ASSERT(sensorHandle); |
| |
| bool sensorHandleIsValid = false; |
| for (uint32_t i = 0; i < mSensors.size(); i++) { |
| if ((mSensors[i].getSensorType() == sensorType) && |
| (mSensors[i].getSensorIndex() == sensorIndex) && |
| (BITMASK_HAS_VALUE(mSensors[i].getTargetGroupMask(), targetGroupId))) { |
| sensorHandleIsValid = true; |
| *sensorHandle = i; |
| break; |
| } |
| } |
| |
| return sensorHandleIsValid; |
| } |
| |
| bool SensorRequestManager::setSensorRequest( |
| Nanoapp *nanoapp, uint32_t sensorHandle, |
| const SensorRequest &sensorRequest) { |
| CHRE_ASSERT(nanoapp); |
| |
| bool success = false; |
| bool requestChanged = false; |
| |
| if (sensorHandle >= mSensors.size()) { |
| LOG_INVALID_HANDLE(sensorHandle); |
| } else { |
| Sensor &sensor = mSensors[sensorHandle]; |
| if (isSensorRequestValid(sensor, sensorRequest)) { |
| // Copy the request so it can be modified below. |
| SensorRequest request = sensorRequest; |
| if (sensor.isOneShot()) { |
| // Always use a latency value of ASAP for one-shot sensors since |
| // one-shot data is always expected to be delivered immediately. |
| request.setLatency(Nanoseconds(CHRE_SENSOR_LATENCY_ASAP)); |
| } |
| |
| size_t requestIndex; |
| uint8_t sensorType = sensor.getSensorType(); |
| uint16_t eventType = getSampleEventTypeForSensorType(sensorType); |
| bool nanoappHasRequest = |
| sensor.getRequestMultiplexer().findRequest(nanoapp->getInstanceId(), |
| &requestIndex) != nullptr; |
| |
| if (request.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 = removeRequest(sensor, requestIndex, &requestChanged); |
| if (success) { |
| cancelFlushRequests(sensorHandle, nanoapp->getInstanceId()); |
| |
| // Only unregister if nanoapp no longer has an outstanding request |
| // for a sensor + target group mask. |
| uint16_t activeMask = |
| getActiveTargetGroupMask(nanoapp->getInstanceId(), sensorType); |
| uint16_t inactiveMask = sensor.getTargetGroupMask() & ~activeMask; |
| if (inactiveMask != 0) { |
| nanoapp->unregisterForBroadcastEvent(eventType, inactiveMask); |
| |
| uint16_t biasEventType; |
| if (sensor.getBiasEventType(&biasEventType)) { |
| // Per API requirements, turn off bias reporting when |
| // unsubscribing from the sensor. |
| nanoapp->unregisterForBroadcastEvent(biasEventType, |
| inactiveMask); |
| } |
| } |
| } |
| } 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. |
| 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. |
| uint16_t biasEventType; |
| if (sensor.getBiasEventType(&biasEventType) && sensor.isCalibrated()) { |
| // Per API requirements, turn on bias reporting for calibrated sensors |
| // by default when subscribed. |
| request.setBiasUpdatesRequested(true); |
| } |
| |
| success = addRequest(sensor, request, &requestChanged); |
| if (success) { |
| nanoapp->registerForBroadcastEvent(eventType, |
| sensor.getTargetGroupMask()); |
| |
| if (request.getBiasUpdatesRequested()) { |
| nanoapp->registerForBroadcastEvent(biasEventType, |
| sensor.getTargetGroupMask()); |
| } |
| |
| // Deliver last valid event to new clients of on-change sensors |
| if (sensor.getLastEvent() != nullptr) { |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| eventType, sensor.getLastEvent(), nullptr /* freeCallback */, |
| nanoapp->getInstanceId()); |
| } |
| } |
| } else { |
| // Ensure bias events stay requested if they were previously enabled. |
| const SensorRequest &previousRequest = |
| sensor.getRequestMultiplexer().getRequests()[requestIndex]; |
| if (previousRequest.getBiasUpdatesRequested()) { |
| request.setBiasUpdatesRequested(true); |
| } |
| // The request changes the mode to the enabled state and there was an |
| // existing request. The existing request is updated. |
| success = updateRequest(sensor, requestIndex, request, &requestChanged); |
| } |
| |
| // TODO: Allow translating the sensor request |
| |
| if (requestChanged) { |
| // TODO: Send an event to nanoapps to indicate the rate change. |
| } |
| |
| if (success) { |
| addSensorRequestLog(nanoapp->getInstanceId(), sensorHandle, request); |
| } |
| } |
| } |
| |
| return success; |
| } |
| |
| bool SensorRequestManager::getSensorInfo(uint32_t sensorHandle, |
| const Nanoapp &nanoapp, |
| struct chreSensorInfo *info) const { |
| CHRE_ASSERT(info); |
| |
| bool success = false; |
| if (sensorHandle >= mSensors.size()) { |
| LOG_INVALID_HANDLE(sensorHandle); |
| } else { |
| mSensors[sensorHandle].populateSensorInfo(info, |
| nanoapp.getTargetApiVersion()); |
| success = true; |
| } |
| |
| return success; |
| } |
| |
| bool SensorRequestManager::removeAllRequests(uint32_t sensorHandle) { |
| bool success = false; |
| if (sensorHandle >= mSensors.size()) { |
| LOG_INVALID_HANDLE(sensorHandle); |
| } else { |
| Sensor &sensor = mSensors[sensorHandle]; |
| uint8_t sensorType = sensor.getSensorType(); |
| uint16_t eventType = getSampleEventTypeForSensorType(sensorType); |
| for (const SensorRequest &request : sensor.getRequests()) { |
| Nanoapp *nanoapp = EventLoopManagerSingleton::get() |
| ->getEventLoop() |
| .findNanoappByInstanceId(request.getInstanceId()); |
| if (nanoapp != nullptr) { |
| nanoapp->unregisterForBroadcastEvent(eventType, |
| sensor.getTargetGroupMask()); |
| } |
| } |
| |
| cancelFlushRequests(sensorHandle); |
| success = removeAllRequests(sensor); |
| } |
| |
| return success; |
| } |
| |
| Sensor *SensorRequestManager::getSensor(uint32_t sensorHandle) { |
| Sensor *sensorPtr = nullptr; |
| if (sensorHandle < mSensors.size()) { |
| sensorPtr = &mSensors[sensorHandle]; |
| } |
| return sensorPtr; |
| } |
| |
| bool SensorRequestManager::getSensorSamplingStatus( |
| uint32_t sensorHandle, struct chreSensorSamplingStatus *status) const { |
| CHRE_ASSERT(status); |
| |
| bool success = false; |
| if (sensorHandle >= mSensors.size()) { |
| LOG_INVALID_HANDLE(sensorHandle); |
| } else { |
| success = mSensors[sensorHandle].getSamplingStatus(status); |
| } |
| |
| return success; |
| } |
| |
| const DynamicVector<SensorRequest> &SensorRequestManager::getRequests( |
| uint32_t sensorHandle) const { |
| if (sensorHandle >= mSensors.size()) { |
| LOG_INVALID_HANDLE(sensorHandle); |
| sensorHandle = 0; |
| } |
| return mSensors[sensorHandle].getRequests(); |
| } |
| |
| bool SensorRequestManager::configureBiasEvents(Nanoapp *nanoapp, |
| uint32_t sensorHandle, |
| bool enable) { |
| bool success = false; |
| uint16_t eventType; |
| if (sensorHandle >= mSensors.size()) { |
| LOG_INVALID_HANDLE(sensorHandle); |
| } else if (enable && !mSensors[sensorHandle].isSensorEnabled()) { |
| LOGE("Bias events can't be configured for a disabled sensor!"); |
| } else if (mSensors[sensorHandle].getBiasEventType(&eventType)) { |
| Sensor &sensor = mSensors[sensorHandle]; |
| size_t requestIndex; |
| bool nanoappHasRequest = |
| sensor.getRequestMultiplexer().findRequest(nanoapp->getInstanceId(), |
| &requestIndex) != nullptr; |
| if (enable && !nanoappHasRequest) { |
| LOGE("0x%" PRIx64 |
| " configuring bias events without an existing sensor request", |
| nanoapp->getAppId()); |
| } else if (!enable && !nanoappHasRequest) { |
| // Treat configuration request as a success since the nanoapp's request |
| // already has been removed which would result in disabling bias event |
| // updates |
| success = true; |
| } else { |
| SensorRequest previousRequest = |
| sensor.getRequestMultiplexer().getRequests()[requestIndex]; |
| previousRequest.setBiasUpdatesRequested(enable); |
| bool requestChanged; |
| success = |
| updateRequest(sensor, requestIndex, previousRequest, &requestChanged); |
| if (success) { |
| if (enable) { |
| nanoapp->registerForBroadcastEvent(eventType, |
| sensor.getTargetGroupMask()); |
| } else { |
| nanoapp->unregisterForBroadcastEvent(eventType, |
| sensor.getTargetGroupMask()); |
| } |
| } |
| } |
| } |
| |
| return success; |
| } |
| |
| bool SensorRequestManager::getThreeAxisBias( |
| uint32_t sensorHandle, struct chreSensorThreeAxisData *bias) const { |
| CHRE_ASSERT(bias != nullptr); |
| |
| bool success = false; |
| if (bias != nullptr) { |
| if (sensorHandle >= mSensors.size()) { |
| LOG_INVALID_HANDLE(sensorHandle); |
| } else { |
| success = |
| mPlatformSensorManager.getThreeAxisBias(mSensors[sensorHandle], bias); |
| } |
| } |
| |
| return success; |
| } |
| |
| bool SensorRequestManager::flushAsync(Nanoapp *nanoapp, uint32_t sensorHandle, |
| const void *cookie) { |
| bool success = false; |
| |
| uint16_t nanoappInstanceId = nanoapp->getInstanceId(); |
| if (sensorHandle >= mSensors.size()) { |
| LOG_INVALID_HANDLE(sensorHandle); |
| } else if (mSensors[sensorHandle].isOneShot()) { |
| LOGE("Cannot flush a one-shot sensor of type %" PRIu8, |
| mSensors[sensorHandle].getSensorType()); |
| } else if (mFlushRequestQueue.full()) { |
| LOG_OOM(); |
| } else { |
| mFlushRequestQueue.emplace_back(sensorHandle, nanoappInstanceId, cookie); |
| success = makeFlushRequest(mFlushRequestQueue.back()) == CHRE_ERROR_NONE; |
| if (!success) { |
| mFlushRequestQueue.pop_back(); |
| } |
| } |
| |
| return success; |
| } |
| |
| void SensorRequestManager::releaseSensorDataEvent(uint16_t eventType, |
| void *eventData) { |
| // Remove all requests if it's a one-shot sensor and only after data has been |
| // delivered to all clients. |
| mPlatformSensorManager.releaseSensorDataEvent(eventData); |
| uint8_t sensorType = getSensorTypeForSampleEventType(eventType); |
| uint32_t sensorHandle; |
| if (getDefaultSensorHandle(sensorType, &sensorHandle) && |
| mSensors[sensorHandle].isOneShot()) { |
| removeAllRequests(sensorHandle); |
| } |
| } |
| |
| void SensorRequestManager::handleFlushCompleteEvent(uint32_t sensorHandle, |
| uint32_t flushRequestId, |
| uint8_t errorCode) { |
| UNUSED_VAR(flushRequestId); |
| |
| if (sensorHandle < mSensors.size() && |
| mSensors[sensorHandle].isFlushRequestPending()) { |
| // Cancel flush request timer before posting to the event queue to ensure |
| // a timeout event isn't processed by CHRE now that the complete event |
| // has been received. |
| mSensors[sensorHandle].cancelPendingFlushRequestTimer(); |
| |
| auto callback = [](uint16_t /*type*/, void *data, void *extraData) { |
| uint8_t cbErrorCode = NestedDataPtr<uint8_t>(data); |
| uint32_t cbSensorHandle = NestedDataPtr<uint32_t>(extraData); |
| EventLoopManagerSingleton::get() |
| ->getSensorRequestManager() |
| .handleFlushCompleteEventSync(cbErrorCode, cbSensorHandle); |
| }; |
| |
| EventLoopManagerSingleton::get()->deferCallback( |
| SystemCallbackType::SensorFlushComplete, |
| NestedDataPtr<uint8_t>(errorCode), callback, |
| NestedDataPtr<uint32_t>(sensorHandle)); |
| } |
| } |
| |
| void SensorRequestManager::handleSensorDataEvent(uint32_t sensorHandle, |
| void *event) { |
| if (sensorHandle >= mSensors.size()) { |
| LOG_INVALID_HANDLE(sensorHandle); |
| mPlatformSensorManager.releaseSensorDataEvent(event); |
| } else { |
| Sensor &sensor = mSensors[sensorHandle]; |
| if (sensor.isOnChange()) { |
| updateLastEvent(event); |
| } |
| |
| uint16_t eventType = |
| getSampleEventTypeForSensorType(sensor.getSensorType()); |
| |
| // Only allow dropping continuous sensor events since losing one-shot or |
| // on-change events could result in nanoapps stuck in a bad state. |
| if (sensor.isContinuous()) { |
| EventLoopManagerSingleton::get() |
| ->getEventLoop() |
| .postLowPriorityEventOrFree(eventType, event, sensorDataEventFree, |
| kSystemInstanceId, kBroadcastInstanceId, |
| sensor.getTargetGroupMask()); |
| } else { |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| eventType, event, sensorDataEventFree, kBroadcastInstanceId, |
| sensor.getTargetGroupMask()); |
| } |
| } |
| } |
| |
| void SensorRequestManager::handleSamplingStatusUpdate( |
| uint32_t sensorHandle, struct chreSensorSamplingStatus *status) { |
| Sensor *sensor = |
| EventLoopManagerSingleton::get()->getSensorRequestManager().getSensor( |
| sensorHandle); |
| if (sensor == nullptr || sensor->isOneShot()) { |
| releaseSamplingStatusUpdate(status); |
| } else { |
| sensor->setSamplingStatus(*status); |
| |
| auto callback = [](uint16_t /*type*/, void *data, void *extraData) { |
| uint32_t cbSensorHandle = NestedDataPtr<uint32_t>(data); |
| auto *cbStatus = |
| static_cast<struct chreSensorSamplingStatus *>(extraData); |
| postSamplingStatus(cbSensorHandle, *cbStatus); |
| EventLoopManagerSingleton::get() |
| ->getSensorRequestManager() |
| .releaseSamplingStatusUpdate(cbStatus); |
| }; |
| |
| // Schedule a deferred callback to handle sensor status change in the main |
| // thread. |
| EventLoopManagerSingleton::get()->deferCallback( |
| SystemCallbackType::SensorStatusUpdate, |
| NestedDataPtr<uint32_t>(sensorHandle), callback, status); |
| } |
| } |
| |
| void SensorRequestManager::handleBiasEvent(uint32_t sensorHandle, |
| void *biasData) { |
| Sensor *sensor = |
| EventLoopManagerSingleton::get()->getSensorRequestManager().getSensor( |
| sensorHandle); |
| CHRE_ASSERT(sensor != nullptr); |
| |
| if (sensor == nullptr) { |
| releaseBiasData(biasData); |
| } else { |
| uint16_t eventType; |
| if (!sensor->reportsBiasEvents() || !sensor->getBiasEventType(&eventType)) { |
| LOGE("Received bias event for unsupported sensor type %s", |
| sensor->getSensorName()); |
| } else { |
| auto freeCallback = [](uint16_t /* type */, void *data) { |
| EventLoopManagerSingleton::get() |
| ->getSensorRequestManager() |
| .releaseBiasData(data); |
| }; |
| |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| eventType, biasData, freeCallback, kBroadcastInstanceId, |
| sensor->getTargetGroupMask()); |
| } |
| } |
| } |
| |
| void SensorRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const { |
| debugDump.print("\nSensors:\n"); |
| for (uint8_t i = 0; i < mSensors.size(); i++) { |
| for (const auto &request : mSensors[i].getRequests()) { |
| // TODO: Rearrange these prints to be similar to sensor request logs |
| // below |
| debugDump.print( |
| " %s: mode=%d int=%" PRIu64 " lat=%" PRIu64 " nappId=%" PRIu16 "\n", |
| mSensors[i].getSensorTypeName(), static_cast<int>(request.getMode()), |
| request.getInterval().toRawNanoseconds(), |
| request.getLatency().toRawNanoseconds(), request.getInstanceId()); |
| } |
| } |
| debugDump.print("\n Last %zu Sensor Requests:\n", mSensorRequestLogs.size()); |
| static_assert(kMaxSensorRequestLogs <= INT8_MAX, |
| "kMaxSensorRequestLogs must be <= INT8_MAX"); |
| for (int8_t i = static_cast<int8_t>(mSensorRequestLogs.size()) - 1; i >= 0; |
| i--) { |
| const auto &log = mSensorRequestLogs[static_cast<size_t>(i)]; |
| const Sensor &sensor = mSensors[log.sensorHandle]; |
| debugDump.print(" ts=%" PRIu64 " nappId=%" PRIu16 " type=%s idx=%" PRIu8 |
| " mask=%" PRIx16 " mode=%s", |
| log.timestamp.toRawNanoseconds(), log.instanceId, |
| sensor.getSensorTypeName(), sensor.getSensorIndex(), |
| sensor.getTargetGroupMask(), getSensorModeName(log.mode)); |
| |
| if (sensorModeIsContinuous(log.mode)) { |
| debugDump.print(" int=%" PRIu64 " lat=%" PRIu64, |
| log.interval.toRawNanoseconds(), |
| log.latency.toRawNanoseconds()); |
| } |
| debugDump.print("\n"); |
| } |
| } |
| |
| uint32_t SensorRequestManager::disableAllSubscriptions(Nanoapp *nanoapp) { |
| uint32_t numDisabledSubscriptions = 0; |
| |
| const uint32_t numSensors = static_cast<uint32_t>(mSensors.size()); |
| for (uint32_t handle = 0; handle < numSensors; handle++) { |
| Sensor &sensor = mSensors[handle]; |
| bool nanoappHasRequest = |
| sensor.getRequestMultiplexer().findRequest( |
| nanoapp->getInstanceId(), nullptr /*index*/) != nullptr; |
| if (nanoappHasRequest) { |
| numDisabledSubscriptions++; |
| SensorRequest request(SensorMode::Off, Nanoseconds() /*interval*/, |
| Nanoseconds() /*latency*/); |
| setSensorRequest(nanoapp, handle, request); |
| } |
| } |
| |
| return numDisabledSubscriptions; |
| } |
| |
| void SensorRequestManager::postFlushCompleteEvent(uint32_t sensorHandle, |
| uint8_t errorCode, |
| const FlushRequest &request) { |
| auto *event = memoryAlloc<chreSensorFlushCompleteEvent>(); |
| if (event == nullptr) { |
| LOG_OOM(); |
| } else { |
| event->sensorHandle = sensorHandle; |
| event->errorCode = errorCode; |
| event->cookie = request.cookie; |
| memset(event->reserved, 0, sizeof(event->reserved)); |
| |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_SENSOR_FLUSH_COMPLETE, event, freeEventDataCallback, |
| request.nanoappInstanceId); |
| } |
| } |
| |
| void SensorRequestManager::completeFlushRequestAtIndex(size_t index, |
| uint8_t errorCode) { |
| if (index < mFlushRequestQueue.size()) { |
| const FlushRequest &request = mFlushRequestQueue[index]; |
| uint32_t sensorHandle = request.sensorHandle; |
| if (request.isActive) { |
| mSensors[sensorHandle].clearPendingFlushRequest(); |
| } |
| |
| postFlushCompleteEvent(sensorHandle, errorCode, request); |
| mFlushRequestQueue.erase(index); |
| } |
| } |
| |
| void SensorRequestManager::dispatchNextFlushRequest(uint32_t sensorHandle) { |
| for (size_t i = 0; i < mFlushRequestQueue.size(); i++) { |
| FlushRequest &request = mFlushRequestQueue[i]; |
| if (request.sensorHandle == sensorHandle) { |
| uint8_t newRequestErrorCode = makeFlushRequest(request); |
| if (newRequestErrorCode == CHRE_ERROR_NONE) { |
| break; |
| } else { |
| completeFlushRequestAtIndex(i, newRequestErrorCode); |
| i--; |
| } |
| } |
| } |
| } |
| |
| void SensorRequestManager::onFlushTimeout(uint32_t sensorHandle) { |
| if (sensorHandle < mSensors.size()) { |
| Sensor &sensor = mSensors[sensorHandle]; |
| sensor.setFlushRequestTimerHandle(CHRE_TIMER_INVALID); |
| } |
| } |
| |
| void SensorRequestManager::handleFlushCompleteEventSync(uint8_t errorCode, |
| uint32_t sensorHandle) { |
| for (size_t i = 0; i < mFlushRequestQueue.size(); i++) { |
| if (mFlushRequestQueue[i].sensorHandle == sensorHandle) { |
| completeFlushRequestAtIndex(i, errorCode); |
| dispatchNextFlushRequest(sensorHandle); |
| break; |
| } |
| } |
| } |
| |
| void SensorRequestManager::cancelFlushRequests(uint32_t sensorHandle, |
| uint32_t nanoappInstanceId) { |
| bool removeAll = (nanoappInstanceId == kSystemInstanceId); |
| for (size_t i = 0; i < mFlushRequestQueue.size(); i++) { |
| const FlushRequest &request = mFlushRequestQueue[i]; |
| if (request.sensorHandle == sensorHandle && |
| (request.nanoappInstanceId == nanoappInstanceId || removeAll)) { |
| completeFlushRequestAtIndex(i, |
| CHRE_ERROR_FUNCTION_DISABLED /* errorCode */); |
| i--; |
| } |
| } |
| |
| if (!mSensors[sensorHandle].isFlushRequestPending()) { |
| dispatchNextFlushRequest(sensorHandle); |
| } |
| } |
| |
| void SensorRequestManager::addSensorRequestLog( |
| uint16_t nanoappInstanceId, uint32_t sensorHandle, |
| const SensorRequest &sensorRequest) { |
| mSensorRequestLogs.kick_push(SensorRequestLog( |
| SystemTime::getMonotonicTime(), nanoappInstanceId, sensorHandle, |
| sensorRequest.getMode(), sensorRequest.getInterval(), |
| sensorRequest.getLatency())); |
| } |
| |
| bool SensorRequestManager::addRequest(Sensor &sensor, |
| const SensorRequest &request, |
| bool *requestChanged) { |
| CHRE_ASSERT(requestChanged != nullptr); |
| |
| size_t addIndex; |
| bool success = true; |
| SensorRequestMultiplexer &multiplexer = sensor.getRequestMultiplexer(); |
| SensorRequest prevRequest = sensor.getMaximalRequest(); |
| if (!multiplexer.addRequest(request, &addIndex, requestChanged)) { |
| *requestChanged = false; |
| success = false; |
| LOG_OOM(); |
| } else if (*requestChanged) { |
| success = configurePlatformSensor(sensor, prevRequest); |
| 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::updateRequest(Sensor &sensor, size_t updateIndex, |
| const SensorRequest &request, |
| bool *requestChanged) { |
| CHRE_ASSERT(requestChanged != nullptr); |
| |
| bool success = true; |
| SensorRequestMultiplexer &multiplexer = sensor.getRequestMultiplexer(); |
| SensorRequest previousRequest = multiplexer.getRequests()[updateIndex]; |
| SensorRequest prevMaxRequest = sensor.getMaximalRequest(); |
| |
| multiplexer.updateRequest(updateIndex, request, requestChanged); |
| if (*requestChanged) { |
| success = configurePlatformSensor(sensor, prevMaxRequest); |
| 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::removeRequest(Sensor &sensor, size_t removeIndex, |
| bool *requestChanged) { |
| CHRE_ASSERT(requestChanged != nullptr); |
| |
| bool success = true; |
| const SensorRequest prevRequest = sensor.getMaximalRequest(); |
| sensor.getRequestMultiplexer().removeRequest(removeIndex, requestChanged); |
| if (*requestChanged) { |
| success = configurePlatformSensor(sensor, prevRequest); |
| 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::removeAllRequests(Sensor &sensor) { |
| bool requestChanged; |
| SensorRequest prevRequest = sensor.getMaximalRequest(); |
| sensor.getRequestMultiplexer().removeAllRequests(&requestChanged); |
| |
| bool success = true; |
| if (requestChanged) { |
| success = configurePlatformSensor(sensor, prevRequest); |
| |
| if (!success) { |
| LOGE("SensorRequestManager failed to remove all requests"); |
| |
| // 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; |
| } |
| |
| uint8_t SensorRequestManager::makeFlushRequest(FlushRequest &request) { |
| uint8_t errorCode = CHRE_ERROR; |
| Sensor &sensor = mSensors[request.sensorHandle]; |
| if (!sensor.isSensorEnabled()) { |
| LOGE("Cannot flush on disabled sensor"); |
| } else if (!sensor.isFlushRequestPending()) { |
| Nanoseconds now = SystemTime::getMonotonicTime(); |
| Nanoseconds deadline = request.deadlineTimestamp; |
| if (now >= deadline) { |
| LOGE("Flush sensor %s failed for nanoapp ID %" PRIu16 |
| ": deadline exceeded", |
| sensor.getSensorName(), request.nanoappInstanceId); |
| errorCode = CHRE_ERROR_TIMEOUT; |
| } else if (doMakeFlushRequest(sensor)) { |
| errorCode = CHRE_ERROR_NONE; |
| Nanoseconds delay = deadline - now; |
| request.isActive = true; |
| |
| auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) { |
| LOGE("Flush request timed out"); |
| NestedDataPtr<uint32_t> sensorHandle(data); |
| EventLoopManagerSingleton::get() |
| ->getSensorRequestManager() |
| .onFlushTimeout(sensorHandle); |
| |
| // Send a complete event, thus closing out this flush request. If the |
| // request that has just timed out receives a response later, this may |
| // inadvertently close out a new request before it has actually |
| // completed. |
| // TODO: Attach an ID to all flush requests / responses so stale |
| // responses can be properly dropped. |
| EventLoopManagerSingleton::get() |
| ->getSensorRequestManager() |
| .handleFlushCompleteEventSync(CHRE_ERROR_TIMEOUT, sensorHandle); |
| }; |
| |
| sensor.setFlushRequestTimerHandle( |
| EventLoopManagerSingleton::get()->setDelayedCallback( |
| SystemCallbackType::SensorFlushTimeout, |
| NestedDataPtr<uint32_t>(request.sensorHandle), callback, delay)); |
| } |
| } else { |
| // Flush request will be made once the pending request is completed. |
| // Return true so that the nanoapp can wait for a result through the |
| // CHRE_EVENT_SENSOR_FLUSH_COMPLETE event. |
| errorCode = CHRE_ERROR_NONE; |
| } |
| |
| return errorCode; |
| } |
| |
| bool SensorRequestManager::doMakeFlushRequest(Sensor &sensor) { |
| // Set to true before making the request since the request may be a |
| // synchronous request and we may get the complete event before it returns. |
| sensor.setFlushRequestPending(true); |
| // TODO: Refactor code to take the request ID into account so multiple flush |
| // requests can be issued. |
| uint32_t flushRequestId; |
| bool success = mPlatformSensorManager.flush(sensor, &flushRequestId); |
| sensor.setFlushRequestPending(success); |
| return success; |
| } |
| |
| bool SensorRequestManager::configurePlatformSensor( |
| Sensor &sensor, const SensorRequest &prevSensorRequest) { |
| bool success = false; |
| const SensorRequest &request = sensor.getMaximalRequest(); |
| |
| // Ensures that only configureBiasEvents is invoked if that's the only value |
| // that has changed since the previous request since CHRE shouldn't configure |
| // the platform for data events if the sensor data request hasn't changed. |
| bool biasChanged = (request.getBiasUpdatesRequested() != |
| prevSensorRequest.getBiasUpdatesRequested()); |
| bool onlyBiasChanged = request.onlyBiasRequestUpdated(prevSensorRequest); |
| uint64_t currentLatency = 0; |
| bool enable = (request.getMode() != SensorMode::Off); |
| if (enable) { |
| currentLatency = request.getLatency().toRawNanoseconds(); |
| } |
| |
| // Per platform API requirements, an active sensor subscription must exist |
| // before any bias configuration can be done. |
| if (!onlyBiasChanged && |
| !mPlatformSensorManager.configureSensor(sensor, request)) { |
| LOGE("Failed to make platform sensor data request"); |
| } else if (biasChanged && |
| !mPlatformSensorManager.configureBiasEvents( |
| sensor, request.getBiasUpdatesRequested(), currentLatency)) { |
| LOGE("Failed to make platform sensor bias request"); |
| if (!onlyBiasChanged) { |
| mPlatformSensorManager.configureSensor(sensor, prevSensorRequest); |
| } |
| } else { |
| success = true; |
| |
| // Reset last event if an on-change sensor is turned off. |
| if (request.getMode() == SensorMode::Off) { |
| sensor.clearLastEvent(); |
| } |
| } |
| return success; |
| } |
| |
| uint16_t SensorRequestManager::getActiveTargetGroupMask( |
| uint16_t nanoappInstanceId, uint8_t sensorType) { |
| uint16_t mask = 0; |
| for (Sensor &sensor : mSensors) { |
| if (sensor.getSensorType() == sensorType) { |
| size_t index; |
| if (sensor.getRequestMultiplexer().findRequest(nanoappInstanceId, |
| &index) != nullptr) { |
| mask |= sensor.getTargetGroupMask(); |
| break; |
| } |
| } |
| } |
| |
| return mask; |
| } |
| |
| } // namespace chre |