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