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