• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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