xref: /aosp_15_r20/system/chre/core/include/chre/core/gnss_manager.h (revision 84e339476a462649f82315436d70fd732297a399)
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