diff options
author | Arthur Ishiguro <arthuri@google.com> | 2019-02-21 13:38:52 -0800 |
---|---|---|
committer | Arthur Ishiguro <arthuri@google.com> | 2019-03-21 18:20:32 -0700 |
commit | acd0cb60e1f439a57bd20ff63931036178e74af7 (patch) | |
tree | eaeb8e5b0bd2da7945ac7573eee92a1dcada0467 | |
parent | 401e7d19a62a553f9f77b01372a5940141121052 (diff) | |
download | chre-acd0cb60e1f439a57bd20ff63931036178e74af7.tar.gz |
Implements SensorRequestManager::flushAsync
Bug: 119269104
Test: Compile only
Change-Id: I2c7e02dd0b0d1afe147aa0f28efb1f9164bce0ce
-rw-r--r-- | chre_api/include/chre_api/chre/sensor.h | 1 | ||||
-rw-r--r-- | core/include/chre/core/event_loop_common.h | 2 | ||||
-rw-r--r-- | core/include/chre/core/sensor_request_manager.h | 102 | ||||
-rw-r--r-- | core/include/chre/core/sensor_type.h | 2 | ||||
-rw-r--r-- | core/sensor_request_manager.cc | 157 | ||||
-rw-r--r-- | platform/include/chre/platform/platform_sensor.h | 10 | ||||
-rw-r--r-- | platform/linux/platform_sensor.cc | 5 | ||||
-rw-r--r-- | platform/slpi/see/platform_sensor.cc | 5 | ||||
-rw-r--r-- | platform/slpi/smgr/platform_sensor.cc | 5 |
9 files changed, 284 insertions, 5 deletions
diff --git a/chre_api/include/chre_api/chre/sensor.h b/chre_api/include/chre_api/chre/sensor.h index e9667848..6e418d2d 100644 --- a/chre_api/include/chre_api/chre/sensor.h +++ b/chre_api/include/chre_api/chre/sensor.h @@ -29,6 +29,7 @@ #include <stdbool.h> #include <stdint.h> +#include <chre/common.h> #include <chre/event.h> #include <chre/sensor_types.h> diff --git a/core/include/chre/core/event_loop_common.h b/core/include/chre/core/event_loop_common.h index abb9ce57..df989775 100644 --- a/core/include/chre/core/event_loop_common.h +++ b/core/include/chre/core/event_loop_common.h @@ -42,6 +42,8 @@ enum class SystemCallbackType : uint16_t { WifiHandleRangingEvent, AudioAvailabilityChange, AudioHandleHostAwake, + SensorFlushComplete, + SensorFlushTimeout, }; //! The function signature of a system callback mirrors the CHRE event free diff --git a/core/include/chre/core/sensor_request_manager.h b/core/include/chre/core/sensor_request_manager.h index e4046131..621421a4 100644 --- a/core/include/chre/core/sensor_request_manager.h +++ b/core/include/chre/core/sensor_request_manager.h @@ -20,6 +20,9 @@ #include "chre/core/request_multiplexer.h" #include "chre/core/sensor.h" #include "chre/core/sensor_request.h" +#include "chre/core/timer_pool.h" +#include "chre/platform/system_time.h" +#include "chre/platform/system_timer.h" #include "chre/util/fixed_size_vector.h" #include "chre/util/non_copyable.h" #include "chre/util/optional.h" @@ -129,6 +132,17 @@ class SensorRequestManager : public NonCopyable { bool flushAsync(Nanoapp *nanoapp, uint32_t sensorHandle, const void *cookie); /** + * Invoked by the PlatformSensor when a flush complete event is received for a + * given sensor for a request done through flushAsync(). This method can be + * invoked from any thread, and defers processing the event to the main CHRE + * event loop. + * + * @param errorCode An error code from enum chreError + * @param sensorType The SensorType of sensor that has completed the flush. + */ + void handleFlushCompleteEvent(uint8_t errorCode, SensorType sensorType); + + /** * Prints state in a string buffer. Must only be called from the context of * the main CHRE thread. * @@ -140,6 +154,25 @@ class SensorRequestManager : public NonCopyable { size_t bufferSize) const; private: + //! An internal structure to store incoming sensor flush requests + struct FlushRequest { + FlushRequest(SensorType type, uint32_t id, const void *cookiePtr) { + sensorType = type; + nanoappInstanceId = id; + cookie = cookiePtr; + } + + //! The sensor type the flush request is for. + SensorType sensorType; + //! The ID of the nanoapp that requested the flush. + uint32_t nanoappInstanceId; + //! The opaque pointer provided in flushAsync(). + const void *cookie; + //! The timestamp at which this request should complete. + Nanoseconds deadlineTimestamp = SystemTime::getMonotonicTime() + + Nanoseconds(CHRE_SENSOR_FLUSH_COMPLETE_TIMEOUT_NS); + }; + /** * This allows tracking the state of a sensor with the various requests for it * and can trigger a change in mode/rate/latency when required. @@ -261,6 +294,22 @@ class SensorRequestManager : public NonCopyable { */ bool removeAll(); + /** + * Makes a specified flush request for this sensor, and sets the timeout + * timer appropriately. If there already is a pending flush request, then + * this method does nothing. + * + * @param request the request to make + * + * @return An error code from enum chreError + */ + uint8_t makeFlushRequest(const FlushRequest& request); + + /** + * Cancels a timeout timer for a pending flush request. + */ + void cancelFlushTimer(); + private: //! The sensor associated with this request multiplexer. If this Optional //! container does not have a value, then the platform does not support this @@ -269,10 +318,61 @@ class SensorRequestManager : public NonCopyable { //! The request multiplexer for this sensor. RequestMultiplexer<SensorRequest> mMultiplexer; + + //! The timeout timer handle for the current flush request. + TimerHandle mFlushRequestTimerHandle = CHRE_TIMER_INVALID; + + /** + * @return true if a flush through makeFlushRequest is pending. + */ + inline bool isFlushRequestPending() const { + return mFlushRequestTimerHandle != CHRE_TIMER_INVALID; + } }; - //! The list of sensor requests + //! The list of sensor requests. FixedSizeVector<SensorRequests, getSensorTypeCount()> mSensorRequests; + + //! A queue of flush requests made by nanoapps. + static constexpr size_t kMaxFlushRequests = 16; + FixedSizeVector<FlushRequest, kMaxFlushRequests> mFlushRequestQueue; + + /** + * Helper function to convert SensorType to SensorRequests. + */ + SensorRequests& getSensorRequests(SensorType sensorType) { + size_t index = getSensorTypeArrayIndex(sensorType); + return mSensorRequests[index]; + } + + /** + * Posts an event to a nanoapp indicating the completion of a flush request. + * + * @param sensorHandle The handle of the sensor for this event. + * @param errorCode An error code from enum chreError + * @param request The corresponding FlushRequest. + */ + void postFlushCompleteEvent( + uint32_t sensorHandle, uint8_t errorCode, const FlushRequest& request); + + /** + * Dispatches the next flush request for the given sensor. If there are no + * more pending flush requests, this method does nothing. + * + * @param sensorHandle The handle of the sensor to apply a request for. + * @param sensorType The corresponding sensor type. + */ + void dispatchNextFlushRequest(uint32_t sensorHandle, SensorType sensorType); + + /** + * Handles a complete event for a sensor flush requested through flushAsync. + * See handleFlushCompleteEvent which may be called from any thread. This + * method is intended to be invoked on the CHRE event loop thread. + * + * @param errorCode An error code from enum chreError + * @param sensorType The SensorType of sensor that has completed the flush. + */ + void handleFlushCompleteEventSync(uint8_t errorCode, SensorType sensorType); }; } // namespace chre diff --git a/core/include/chre/core/sensor_type.h b/core/include/chre/core/sensor_type.h index ed8112f3..30b9f96a 100644 --- a/core/include/chre/core/sensor_type.h +++ b/core/include/chre/core/sensor_type.h @@ -38,7 +38,7 @@ union ChreSensorData { * specification. The details of these sensors are left to the CHRE API * sensor definitions. */ -enum class SensorType { +enum class SensorType : uint8_t { Unknown, Accelerometer, InstantMotion, diff --git a/core/sensor_request_manager.cc b/core/sensor_request_manager.cc index dcd5dcc8..3f9e1115 100644 --- a/core/sensor_request_manager.cc +++ b/core/sensor_request_manager.cc @@ -16,9 +16,9 @@ #include "chre/core/sensor_request_manager.h" +#include "chre_api/chre/version.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 { @@ -51,6 +51,13 @@ bool isSensorRequestValid(const Sensor& sensor, return success; } +void flushTimerCallback(uint16_t /* eventType */, void * /* data */) { + // TODO: Fatal error here since some platforms may not be able to handle + // timeouts gracefully. Modify this implementation to drop flush + // requests and handle stale responses in the future appropriately. + FATAL_ERROR("Flush request timed out"); +} + } // namespace SensorRequestManager::SensorRequestManager() { @@ -296,8 +303,58 @@ const DynamicVector<SensorRequest>& SensorRequestManager::getRequests( bool SensorRequestManager::flushAsync( Nanoapp *nanoapp, uint32_t sensorHandle, const void *cookie) { - // TODO: Implement this - return false; + bool success = false; + + uint32_t nanoappInstanceId = nanoapp->getInstanceId(); + SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle); + // NOTE: One-shot sensors do not support flush per API + if (sensorType == SensorType::Unknown || sensorTypeIsOneShot(sensorType)) { + LOGE("Cannot flush for sensor type %" PRIu32, + static_cast<uint32_t>(sensorType)); + } else if (mFlushRequestQueue.full()) { + LOG_OOM(); + } else { + mFlushRequestQueue.emplace_back(sensorType, nanoappInstanceId, cookie); + size_t sensorIndex = getSensorTypeArrayIndex(sensorType); + success = (mSensorRequests[sensorIndex].makeFlushRequest( + mFlushRequestQueue.back()) == CHRE_ERROR_NONE); + if (!success) { + mFlushRequestQueue.pop_back(); + } + } + + return success; +} + +void SensorRequestManager::handleFlushCompleteEvent( + uint8_t errorCode, SensorType sensorType) { + struct CallbackState { + uint8_t errorCode; + SensorType sensorType; + }; + + // Enables passing data through void pointer to avoid allocation. + union NestedCallbackState { + void *eventData; + CallbackState callbackState; + }; + static_assert(sizeof(NestedCallbackState) == sizeof(void *), + "Size of NestedCallbackState must equal that of void *"); + + NestedCallbackState state = {}; + state.callbackState.errorCode = errorCode; + state.callbackState.sensorType = sensorType; + + auto callback = [](uint16_t /* eventType */, void *eventData) { + NestedCallbackState state; + state.eventData = eventData; + EventLoopManagerSingleton::get()->getSensorRequestManager() + .handleFlushCompleteEventSync(state.callbackState.errorCode, + state.callbackState.sensorType); + }; + + EventLoopManagerSingleton::get()->deferCallback( + SystemCallbackType::SensorFlushComplete, state.eventData, callback); } void SensorRequestManager::logStateToBuffer(char *buffer, size_t *bufferPos, @@ -320,6 +377,61 @@ void SensorRequestManager::logStateToBuffer(char *buffer, size_t *bufferPos, } } +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().postEventOrFree( + CHRE_EVENT_SENSOR_FLUSH_COMPLETE, event, freeEventDataCallback, + kSystemInstanceId, request.nanoappInstanceId); + } +} + +void SensorRequestManager::dispatchNextFlushRequest( + uint32_t sensorHandle, SensorType sensorType) { + SensorRequests& requests = getSensorRequests(sensorType); + + for (size_t i = 0; i < mFlushRequestQueue.size(); i++) { + const FlushRequest& request = mFlushRequestQueue[i]; + if (request.sensorType == sensorType) { + uint8_t newRequestErrorCode = requests.makeFlushRequest(request); + if (newRequestErrorCode == CHRE_ERROR_NONE) { + break; + } else { + postFlushCompleteEvent(sensorHandle, newRequestErrorCode, request); + mFlushRequestQueue.erase(i); + i--; + } + } + } +} + +void SensorRequestManager::handleFlushCompleteEventSync( + uint8_t errorCode, SensorType sensorType) { + for (size_t i = 0; i < mFlushRequestQueue.size(); i++) { + const FlushRequest& request = mFlushRequestQueue[i]; + if (request.sensorType == sensorType) { + uint32_t sensorHandle; + if (getSensorHandle(sensorType, &sensorHandle)) { + SensorRequests& requests = getSensorRequests(sensorType); + requests.cancelFlushTimer(); + + postFlushCompleteEvent(sensorHandle, errorCode, request); + mFlushRequestQueue.erase(i); + dispatchNextFlushRequest(sensorHandle, sensorType); + } + break; + } + } +} + const SensorRequest *SensorRequestManager::SensorRequests::find( uint32_t instanceId, size_t *index) const { CHRE_ASSERT(index); @@ -441,4 +553,43 @@ bool SensorRequestManager::SensorRequests::removeAll() { return success; } +uint8_t SensorRequestManager::SensorRequests::makeFlushRequest( + const FlushRequest& request) { + uint8_t errorCode = CHRE_ERROR; + if (!isSensorSupported()) { + LOGE("Cannot flush on unsupported sensor"); + } else if (mMultiplexer.getRequests().size() == 0) { + LOGE("Cannot flush on disabled sensor"); + } else if (!isFlushRequestPending()) { + Nanoseconds now = SystemTime::getMonotonicTime(); + Nanoseconds deadline = request.deadlineTimestamp; + if (now >= deadline) { + LOGE("Flush sensor %" PRIu32 " failed for nanoapp ID %" PRIu32 + ": deadline exceeded", static_cast<uint32_t>(request.sensorType), + request.nanoappInstanceId); + errorCode = CHRE_ERROR_TIMEOUT; + } else if (mSensor->flushAsync()) { + errorCode = CHRE_ERROR_NONE; + Nanoseconds delay = deadline - now; + mFlushRequestTimerHandle = + EventLoopManagerSingleton::get()->setDelayedCallback( + SystemCallbackType::SensorFlushTimeout, nullptr /* data */, + flushTimerCallback, 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; +} + +void SensorRequestManager::SensorRequests::cancelFlushTimer() { + EventLoopManagerSingleton::get()->cancelDelayedCallback( + mFlushRequestTimerHandle); + mFlushRequestTimerHandle = CHRE_TIMER_INVALID; +} + } // namespace chre diff --git a/platform/include/chre/platform/platform_sensor.h b/platform/include/chre/platform/platform_sensor.h index 87d37ed4..a430b376 100644 --- a/platform/include/chre/platform/platform_sensor.h +++ b/platform/include/chre/platform/platform_sensor.h @@ -95,6 +95,16 @@ class PlatformSensor : public PlatformSensorBase, */ bool getSamplingStatus(struct chreSensorSamplingStatus *status) const; + /** + * Makes a sensor flush request for a nanoapp asynchronously. When a flush + * request made by this method is completed (i.e. all pending samples are + * posted to the CHRE event queue), PlatformSensor should invoke + * SensorRequestManager::handleFlushCompleteEvent(). + * + * @return true if the request was accepted. + */ + bool flushAsync(); + protected: /** * Default constructor that puts this instance in an unspecified state. diff --git a/platform/linux/platform_sensor.cc b/platform/linux/platform_sensor.cc index 83589a32..83bfd303 100644 --- a/platform/linux/platform_sensor.cc +++ b/platform/linux/platform_sensor.cc @@ -50,6 +50,11 @@ bool PlatformSensor::applyRequest(const SensorRequest& request) { return false; } +bool PlatformSensor::flushAsync() { + // TODO: Implement this + return false; +} + SensorType PlatformSensor::getSensorType() const { // TODO: Implement this. return SensorType::Unknown; diff --git a/platform/slpi/see/platform_sensor.cc b/platform/slpi/see/platform_sensor.cc index 5898fe66..3ebeb9af 100644 --- a/platform/slpi/see/platform_sensor.cc +++ b/platform/slpi/see/platform_sensor.cc @@ -700,6 +700,11 @@ bool PlatformSensor::applyRequest(const SensorRequest& request) { return success; } +bool PlatformSensor::flushAsync() { + // TODO: Implement this + return false; +} + SensorType PlatformSensor::getSensorType() const { return mSensorType; } diff --git a/platform/slpi/smgr/platform_sensor.cc b/platform/slpi/smgr/platform_sensor.cc index c8847e13..944301af 100644 --- a/platform/slpi/smgr/platform_sensor.cc +++ b/platform/slpi/smgr/platform_sensor.cc @@ -1451,6 +1451,11 @@ bool PlatformSensor::applyRequest(const SensorRequest& request) { return success; } +bool PlatformSensor::flushAsync() { + // TODO: Implement this + return false; +} + SensorType PlatformSensor::getSensorType() const { return getSensorTypeFromSensorId(this->sensorId, this->dataType, this->calType); |