1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef CHRE_CORE_GNSS_MANAGER_H_ 18 #define CHRE_CORE_GNSS_MANAGER_H_ 19 20 #include <cstdint> 21 22 #include "chre/core/nanoapp.h" 23 #include "chre/core/settings.h" 24 #include "chre/platform/platform_gnss.h" 25 #include "chre/util/non_copyable.h" 26 #include "chre/util/system/debug_dump.h" 27 #include "chre/util/time.h" 28 29 namespace chre { 30 31 class GnssManager; 32 33 /** 34 * A helper class that manages requests for a GNSS location or measurement 35 * session. 36 */ 37 class GnssSession { 38 public: 39 /** 40 * Adds a request to a session asynchronously. The result is delivered 41 * through a CHRE_EVENT_GNSS_ASYNC_RESULT event. 42 * 43 * @param nanoapp The nanoapp adding the request. 44 * @param minInterval The minimum reporting interval for results. 45 * @param timeToNext The amount of time that the GNSS system is allowed to 46 * delay generating a report. 47 * @param cookie A cookie that is round-tripped to provide context to the 48 * nanoapp making the request. 49 * 50 * @return true if the request was accepted for processing. 51 */ 52 bool addRequest(Nanoapp *nanoapp, Milliseconds minInterval, 53 Milliseconds minTimeToNext, const void *cookie); 54 55 /** 56 * Removes a request from a session asynchronously. The result is delivered 57 * through a CHRE_EVENT_GNSS_ASYNC_RESULT event. 58 * 59 * @param nanoapp The nanoapp removing the request. 60 * @param cookie A cookie that is round-tripped to provide context to the 61 * nanoapp making the request. 62 * 63 * @return true if the request was accepted for processing. 64 */ 65 bool removeRequest(Nanoapp *nanoapp, const void *cookie); 66 67 /** 68 * Handles the result of a request to the PlatformGnss to request a change to 69 * the session. 70 * 71 * @param enabled true if the session is currently active. 72 * @param errorCode an error code that is used to indicate success or what 73 * type of error has occured. See chreError enum in the CHRE API for 74 * additional details. 75 */ 76 void handleStatusChange(bool enabled, uint8_t errorCode); 77 78 /** 79 * Handles a CHRE GNSS report (location/data) event. 80 * 81 * @param event The GNSS report event provided to the GNSS session. This 82 * memory is guaranteed not to be modified until it has been explicitly 83 * released through the PlatformGnss instance. 84 */ 85 void handleReportEvent(void *event); 86 87 /** 88 * @return true if an async response is pending from GNSS. This method should 89 * be used to check if a GNSS session request is in flight. 90 */ asyncResponsePending()91 bool asyncResponsePending() const { 92 return !mStateTransitions.empty() || mInternalRequestPending; 93 } 94 95 /** 96 * Invoked when the host notifies CHRE of a settings change. 97 * 98 * @param setting The setting that changed. 99 * @param state The new setting state. 100 */ 101 void onSettingChanged(Setting setting, SettingState state); 102 103 /** 104 * Updates the platform GNSS request according to the current state. It should 105 * be used to synchronize the GNSS to the desired state, e.g. for setting 106 * updates or handling a state resync request. 107 * 108 * @param forceUpdate If true, force the platform GNSS request to be made. 109 * 110 * @return true if the invocation resulted in dispatching an internal 111 * request to control the platform layer 112 */ 113 bool updatePlatformRequest(bool forceUpdate = false); 114 115 /** 116 * Invoked as a result of a requestStateResync() callback from the GNSS PAL. 117 * Runs in the context of the CHRE thread. 118 */ 119 void handleRequestStateResyncCallbackSync(); 120 121 /** 122 * Prints state in a string buffer. Must only be called from the context of 123 * the main CHRE thread. 124 * 125 * @param debugDump The debug dump wrapper where a string can be printed 126 * into one of the buffers. 127 */ 128 void logStateToBuffer(DebugDumpWrapper &debugDump) const; 129 130 private: 131 /** 132 * Tracks a nanoapp that has subscribed to a session and the reporting 133 * interval. 134 */ 135 struct Request { 136 //! The nanoapp instance ID that made this request. 137 uint32_t nanoappInstanceId; 138 139 //! The interval of results requested. 140 Milliseconds minInterval; 141 }; 142 143 //! Internal struct with data needed to log last X session requests 144 struct SessionRequestLog { SessionRequestLogSessionRequestLog145 SessionRequestLog(Nanoseconds timestampIn, uint32_t instanceIdIn, 146 Milliseconds intervalIn, bool startIn) 147 : timestamp(timestampIn), 148 instanceId(instanceIdIn), 149 interval(intervalIn), 150 start(startIn) {} 151 Nanoseconds timestamp; 152 uint32_t instanceId; 153 Milliseconds interval; 154 bool start; 155 }; 156 157 /** 158 * Tracks the state of the GNSS engine. 159 */ 160 struct StateTransition { 161 //! The nanoapp instance ID that prompted the change. 162 uint32_t nanoappInstanceId; 163 164 //! The cookie provided to the CHRE API when the nanoapp requested a 165 //! change to the state of the GNSS engine. 166 const void *cookie; 167 168 //! The target state of the GNSS engine. 169 bool enable; 170 171 //! The target minimum reporting interval for the GNSS engine. This is only 172 //! valid if enable is set to true. 173 Milliseconds minInterval; 174 }; 175 176 //! The event type of the session's report data. 177 const uint16_t kReportEventType; 178 179 //! The request type to start and stop a session. 180 uint8_t mStartRequestType; 181 uint8_t mStopRequestType; 182 183 //! The session name, used in logging state. 184 const char *mName; 185 186 //! The maximum number of pending state transitions allowed. 187 static constexpr size_t kMaxGnssStateTransitions = 8; 188 189 //! The queue of state transitions for the GNSS engine. Only one asynchronous 190 //! state transition can be in flight at one time. Any further requests are 191 //! queued here. 192 ArrayQueue<StateTransition, kMaxGnssStateTransitions> mStateTransitions; 193 194 //! The list of most recent session request logs 195 static constexpr size_t kNumSessionRequestLogs = 10; 196 ArrayQueue<SessionRequestLog, kNumSessionRequestLogs> mSessionRequestLogs; 197 198 //! The request multiplexer for GNSS session requests. 199 DynamicVector<Request> mRequests; 200 201 //! The current report interval being sent to the session. This is only valid 202 //! if the mRequests is non-empty. 203 Milliseconds mCurrentInterval = Milliseconds(UINT64_MAX); 204 205 //! The state of the last successful request to the platform. 206 bool mPlatformEnabled = false; 207 208 //! True if a request from the CHRE framework is currently pending. 209 bool mInternalRequestPending = false; 210 211 //! True if a setting change event is pending to be processed. 212 bool mSettingChangePending = false; 213 214 //! True if a state resync callback is pending to be processed. 215 bool mResyncPending = false; 216 217 // Allows GnssManager to access constructor. 218 friend class GnssManager; 219 220 /** 221 * Constructs a GnssSesson. 222 * 223 * @param reportEventType The report event type of this GNSS session. 224 * Currently, only CHRE_EVENT_GNSS_LOCATION for a location session and 225 * CHRE_EVENT_GNSS_LOCATION for a measurement session are supported. 226 */ 227 GnssSession(uint16_t reportEventType); 228 229 /** 230 * Configures the GNSS engine to be enabled/disabled. If enable is set to true 231 * then the minInterval and minTimeToNext values are valid. 232 * 233 * @param nanoapp The nanoapp requesting the state change for the engine. 234 * @param enable Whether to enable or disable the engine. 235 * @param minInterval The minimum reporting interval requested by the nanoapp. 236 * @param minTimeToNext The minimum time to the next report. 237 * @param cookie The cookie provided by the nanoapp to round-trip for context. 238 * 239 * @return true if the request was accepted. 240 */ 241 bool configure(Nanoapp *nanoapp, bool enable, Milliseconds minInterval, 242 Milliseconds minTimeToNext, const void *cookie); 243 244 /** 245 * Checks if a nanoapp has an open session request. 246 * 247 * @param instanceId The nanoapp instance ID to search for. 248 * @param requestIndex A pointer to an index to populate if the nanoapp has an 249 * open session request. 250 * 251 * @return true if the provided instanceId was found. 252 */ 253 bool nanoappHasRequest(uint32_t instanceId, 254 size_t *requestIndex = nullptr) const; 255 256 /** 257 * Adds a request for a session to the queue of state transitions. 258 * 259 * @param instanceId The nanoapp instance ID requesting a session. 260 * @param enable Whether the session is being enabled or disabled for this 261 * nanoapp. 262 * @param minInterval The minimum interval requested by the nanoapp. 263 * @param cookie A cookie that is round-tripped to the nanoapp for context. 264 * 265 * @return true if the state transition was added to the queue. 266 */ 267 bool addRequestToQueue(uint32_t instanceId, bool enable, 268 Milliseconds minInterval, const void *cookie); 269 270 /** 271 * @return true if the session is currently enabled. 272 */ 273 bool isEnabled() const; 274 275 /** 276 * Determines if a change to the session state is required given a set of 277 * parameters. 278 * 279 * @param requestedState The target state requested by a nanoapp. 280 * @param minInterval The minimum reporting interval. 281 * @param nanoappHasRequest If the nanoapp already has a request. 282 * @param requestIndex The index of the request in the list of open requests 283 * if nanoappHasRequest is set to true. 284 * 285 * @return true if a state transition is required. 286 */ 287 bool stateTransitionIsRequired(bool requestedState, Milliseconds minInterval, 288 bool nanoappHasRequest, 289 size_t requestIndex) const; 290 291 /** 292 * Updates the session requests given a nanoapp and the interval requested. 293 * 294 * @param enable true if enabling the session. 295 * @param minInterval the minimum reporting interval if enable is true. 296 * @param instanceId the nanoapp instance ID that owns the request. 297 * 298 * @return true if the session request list was updated. 299 */ 300 bool updateRequests(bool enable, Milliseconds minInterval, 301 uint32_t instanceId); 302 303 /** 304 * Posts the result of a GNSS session add/remove request. 305 * 306 * @param instanceId The nanoapp instance ID that made the request. 307 * @param success true if the operation was successful. 308 * @param enable true if enabling the session. 309 * @param minInterval the minimum reporting interval. 310 * @param errorCode the error code as a result of this operation. 311 * @param cookie the cookie that the nanoapp is provided for context. 312 * 313 * @return true if the event was successfully posted. 314 */ 315 bool postAsyncResultEvent(uint32_t instanceId, bool success, bool enable, 316 Milliseconds minInterval, uint8_t errorCode, 317 const void *cookie); 318 319 /** 320 * Calls through to postAsyncResultEvent but invokes FATAL_ERROR if the 321 * event is not posted successfully. This is used in asynchronous contexts 322 * where a nanoapp could be stuck waiting for a response but CHRE failed to 323 * enqueue one. For parameter details, 324 * @see postAsyncResultEvent 325 */ 326 void postAsyncResultEventFatal(uint32_t instanceId, bool success, bool enable, 327 Milliseconds minInterval, uint8_t errorCode, 328 const void *cookie); 329 330 /** 331 * Handles the result of a request to PlatformGnss to change the state of 332 * the session. See the handleStatusChange method which may be called from 333 * any thread. This method is intended to be invoked on the CHRE event loop 334 * thread. 335 * 336 * @param enabled true if the session was enabled 337 * @param errorCode an error code that is provided to indicate success. 338 */ 339 void handleStatusChangeSync(bool enabled, uint8_t errorCode); 340 341 /** 342 * Releases a GNSS report event after nanoapps have consumed it. 343 * 344 * @param eventType the type of event being freed. 345 * @param eventData a pointer to the scan event to release. 346 */ 347 static void freeReportEventCallback(uint16_t eventType, void *eventData); 348 349 /** 350 * Configures PlatformGnss based on session settings. 351 * 352 * @return true if PlatformGnss has accepted the setting. 353 */ 354 bool controlPlatform(bool enable, Milliseconds minInterval, 355 Milliseconds minTimeToNext); 356 357 /** 358 * Add a log to list of session logs possibly pushing out the oldest log. 359 * 360 * @param nanoappInstanceId the instance of id of nanoapp requesting 361 * @param interval the interval in milliseconds for request 362 * @param start true if the is a start request, false if a stop request 363 */ 364 void addSessionRequestLog(uint32_t nanoappInstanceId, Milliseconds interval, 365 bool start); 366 367 /** 368 * Dispatches pending state transitions on the queue until the first one 369 * succeeds. 370 */ 371 void dispatchQueuedStateTransitions(); 372 }; 373 374 /** 375 * The GnssManager handles platform init, capability query, and delagates debug 376 * dump and all GNSS request management to GnssSession(s), which includes 377 * multiplexing multiple requests into one for the platform to handle. 378 * 379 * This class is effectively a singleton as there can only be one instance of 380 * the PlatformGnss instance. 381 */ 382 class GnssManager : public NonCopyable { 383 public: 384 /** 385 * Constructs a GnssManager. 386 */ 387 GnssManager(); 388 389 /** 390 * Initializes the underlying platform-specific GNSS module. Must be called 391 * prior to invoking any other methods in this class. 392 */ 393 void init(); 394 395 /** 396 * @return the GNSS capabilities exposed by this platform. 397 */ 398 uint32_t getCapabilities(); 399 getLocationSession()400 GnssSession &getLocationSession() { 401 return mLocationSession; 402 }; 403 getMeasurementSession()404 GnssSession &getMeasurementSession() { 405 return mMeasurementSession; 406 }; 407 408 /** 409 * Invoked when the host notifies CHRE of a settings change. 410 * 411 * @param setting The setting that changed. 412 * @param state The new setting state. 413 */ 414 void onSettingChanged(Setting setting, SettingState state); 415 416 /** 417 * Invoked as a result of a requestStateResync() callback from the GNSS PAL. 418 * Runs asynchronously in the context of the callback immediately. 419 */ 420 void handleRequestStateResyncCallback(); 421 422 /** 423 * Invoked as a result of a requestStateResync() callback from the GNSS PAL. 424 * Runs in the context of the CHRE thread. 425 */ 426 void handleRequestStateResyncCallbackSync(); 427 428 /** 429 * @param nanoapp The nanoapp invoking 430 * chreGnssConfigurePassiveLocationListener. 431 * @param enable true to enable the configuration. 432 * 433 * @return true if the configuration succeeded. 434 */ 435 bool configurePassiveLocationListener(Nanoapp *nanoapp, bool enable); 436 437 /** 438 * Prints state in a string buffer. Must only be called from the context of 439 * the main CHRE thread. 440 * 441 * @param debugDump The debug dump wrapper where a string can be printed 442 * into one of the buffers. 443 */ 444 void logStateToBuffer(DebugDumpWrapper &debugDump) const; 445 446 private: 447 // Allows GnssSession to access mPlatformGnss. 448 friend class GnssSession; 449 450 //! The platform GNSS interface. 451 PlatformGnss mPlatformGnss; 452 453 //! The instance of location session. 454 GnssSession mLocationSession; 455 456 //! The instance of measurement session. 457 GnssSession mMeasurementSession; 458 459 //! The list of instance ID of nanoapps that has a passive location listener 460 //! request. 461 DynamicVector<uint32_t> mPassiveLocationListenerNanoapps; 462 463 //! true if the passive location listener is enabled at the platform. 464 bool mPlatformPassiveLocationListenerEnabled; 465 466 /** 467 * @param nanoappInstanceId The instance ID of the nanoapp to check. 468 * @param index If non-null and this function returns true, stores the index 469 * of mPassiveLocationListenerNanoapps where the instance ID is stored. 470 * 471 * @return true if the nanoapp currently has a passive location listener 472 * request. 473 */ 474 bool nanoappHasPassiveLocationListener(uint32_t nanoappInstanceId, 475 size_t *index = nullptr); 476 477 /** 478 * Helper function to invoke configurePassiveLocationListener at the platform 479 * and handle the result. 480 * 481 * @param enable true to enable the configuration. 482 * 483 * @return true if success. 484 */ 485 bool platformConfigurePassiveLocationListener(bool enable); 486 }; 487 488 } // namespace chre 489 490 #endif // CHRE_CORE_GNSS_MANAGER_H_ 491