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/platform/platform_gnss.h"
24 #include "chre/util/non_copyable.h"
25 #include "chre/util/time.h"
26 
27 namespace chre {
28 
29 class GnssManager;
30 
31 /**
32  * A helper class that manages requests for a GNSS location or measurement
33  * session.
34  */
35 class GnssSession {
36  public:
37   /**
38    * Adds a request to a session asynchronously. The result is delivered
39    * through a CHRE_EVENT_GNSS_ASYNC_RESULT event.
40    *
41    * @param nanoapp The nanoapp adding the request.
42    * @param minInterval The minimum reporting interval for results.
43    * @param timeToNext The amount of time that the GNSS system is allowed to
44    *        delay generating a report.
45    * @param cookie A cookie that is round-tripped to provide context to the
46    *        nanoapp making the request.
47    *
48    * @return true if the request was accepted for processing.
49    */
50   bool addRequest(Nanoapp *nanoapp, Milliseconds minInterval,
51                   Milliseconds minTimeToNext, const void *cookie);
52 
53   /**
54    * Removes a request from a session asynchronously. The result is delivered
55    * through a CHRE_EVENT_GNSS_ASYNC_RESULT event.
56    *
57    * @param nanoapp The nanoapp removing the request.
58    * @param cookie A cookie that is round-tripped to provide context to the
59    *        nanoapp making the request.
60    *
61    * @return true if the request was accepted for processing.
62    */
63   bool removeRequest(Nanoapp *nanoapp, const void *cookie);
64 
65   /**
66    * Handles the result of a request to the PlatformGnss to request a change to
67    * the session.
68    *
69    * @param enabled true if the session is currently active.
70    * @param errorCode an error code that is used to indicate success or what
71    *        type of error has occured. See chreError enum in the CHRE API for
72    *        additional details.
73    */
74   void handleStatusChange(bool enabled, uint8_t errorCode);
75 
76   /**
77    * Handles a CHRE GNSS report (location/data) event.
78    *
79    * @param event The GNSS report event provided to the GNSS session. This
80    *        memory is guaranteed not to be modified until it has been explicitly
81    *        released through the PlatformGnss instance.
82    */
83   void handleReportEvent(void *event);
84 
85   /**
86    * Prints state in a string buffer. Must only be called from the context of
87    * the main CHRE thread.
88    *
89    * @see GnssManager::logStateToBuffer
90    */
91   void logStateToBuffer(char *buffer, size_t *bufferPos, size_t bufferSize)
92       const;
93 
94  private:
95   /**
96    * Tracks a nanoapp that has subscribed to a session and the reporting
97    * interval.
98    */
99   struct Request {
100     //! The nanoapp instance ID that made this request.
101     uint32_t nanoappInstanceId;
102 
103     //! The interval of results requested.
104     Milliseconds minInterval;
105   };
106 
107   /**
108    * Tracks the state of the GNSS engine.
109    */
110   struct StateTransition {
111     //! The nanoapp instance ID that prompted the change.
112     uint32_t nanoappInstanceId;
113 
114     //! The cookie provided to the CHRE API when the nanoapp requested a
115     //! change to the state of the GNSS engine.
116     const void *cookie;
117 
118     //! The target state of the GNSS engine.
119     bool enable;
120 
121     //! The target minimum reporting interval for the GNSS engine. This is only
122     //! valid if enable is set to true.
123     Milliseconds minInterval;
124   };
125 
126   //! The event type of the session's report data.
127   uint16_t mReportEventType;
128 
129   //! The request type to start and stop a session.
130   uint8_t mStartRequestType;
131   uint8_t mStopRequestType;
132 
133   //! The session name, used in logging state.
134   const char *mName;
135 
136   //! The maximum number of pending state transitions allowed.
137   static constexpr size_t kMaxGnssStateTransitions = 8;
138 
139   //! The queue of state transitions for the GNSS engine. Only one asynchronous
140   //! state transition can be in flight at one time. Any further requests are
141   //! queued here.
142   ArrayQueue<StateTransition, kMaxGnssStateTransitions> mStateTransitions;
143 
144   //! The request multiplexer for GNSS session requests.
145   DynamicVector<Request> mRequests;
146 
147   //! The current report interval being sent to the session. This is only valid
148   //! if the mRequests is non-empty.
149   Milliseconds mCurrentInterval = Milliseconds(UINT64_MAX);
150 
151   // Allows GnssManager to access constructor.
152   friend class GnssManager;
153 
154   /**
155    * Constructs a GnssSesson.
156    *
157    * @param reportEventType The report event type of this GNSS session.
158    *        Currently, only CHRE_EVENT_GNSS_LOCATION for a location session and
159    *        CHRE_EVENT_GNSS_LOCATION for a measurement session are supported.
160    */
161   GnssSession(uint16_t reportEventType);
162 
163   /**
164    * Configures the GNSS engine to be enabled/disabled. If enable is set to true
165    * then the minInterval and minTimeToNext values are valid.
166    *
167    * @param nanoapp The nanoapp requesting the state change for the engine.
168    * @param enable Whether to enable or disable the engine.
169    * @param minInterval The minimum reporting interval requested by the nanoapp.
170    * @param minTimeToNext The minimum time to the next report.
171    * @param cookie The cookie provided by the nanoapp to round-trip for context.
172    *
173    * @return true if the request was accepted.
174    */
175   bool configure(Nanoapp *nanoapp, bool enable, Milliseconds minInterval,
176                  Milliseconds minTimeToNext, const void *cookie);
177 
178   /**
179    * Checks if a nanoapp has an open session request.
180    *
181    * @param instanceId The nanoapp instance ID to search for.
182    * @param requestIndex A pointer to an index to populate if the nanoapp has an
183    *        open session request.
184    *
185    * @return true if the provided instanceId was found.
186    */
187   bool nanoappHasRequest(uint32_t instanceId, size_t *requestIndex = nullptr)
188       const;
189 
190   /**
191    * Adds a request for a session to the queue of state transitions.
192    *
193    * @param instanceId The nanoapp instance ID requesting a session.
194    * @param enable Whether the session is being enabled or disabled for this
195    *        nanoapp.
196    * @param minInterval The minimum interval requested by the nanoapp.
197    * @param cookie A cookie that is round-tripped to the nanoapp for context.
198    *
199    * @return true if the state transition was added to the queue.
200    */
201   bool addRequestToQueue(uint32_t instanceId, bool enable,
202                          Milliseconds minInterval, const void *cookie);
203 
204   /**
205    * @return true if the session is currently enabled.
206    */
207   bool isEnabled() const;
208 
209   /**
210    * Determines if a change to the session state is required given a set of
211    * parameters.
212    *
213    * @param requestedState The target state requested by a nanoapp.
214    * @param minInterval The minimum reporting interval.
215    * @param nanoappHasRequest If the nanoapp already has a request.
216    * @param requestIndex The index of the request in the list of open requests
217    *        if nanoappHasRequest is set to true.
218    *
219    * @return true if a state transition is required.
220    */
221   bool stateTransitionIsRequired(
222       bool requestedState, Milliseconds minInterval, bool nanoappHasRequest,
223       size_t requestIndex) const;
224 
225   /**
226    * Updates the session requests given a nanoapp and the interval requested.
227    *
228    * @param enable true if enabling the session.
229    * @param minInterval the minimum reporting interval if enable is true.
230    * @param instanceId the nanoapp instance ID that owns the request.
231    *
232    * @return true if the session request list was updated.
233    */
234   bool updateRequests(bool enable, Milliseconds minInterval,
235                       uint32_t instanceId);
236 
237   /**
238    * Posts the result of a GNSS session add/remove request.
239    *
240    * @param instanceId The nanoapp instance ID that made the request.
241    * @param success true if the operation was successful.
242    * @param enable true if enabling the session.
243    * @param minInterval the minimum reporting interval.
244    * @param errorCode the error code as a result of this operation.
245    * @param cookie the cookie that the nanoapp is provided for context.
246    *
247    * @return true if the event was successfully posted.
248    */
249   bool postAsyncResultEvent(
250       uint32_t instanceId, bool success, bool enable,
251       Milliseconds minInterval, uint8_t errorCode, const void *cookie);
252 
253   /**
254    * Calls through to postAsyncResultEvent but invokes FATAL_ERROR if the
255    * event is not posted successfully. This is used in asynchronous contexts
256    * where a nanoapp could be stuck waiting for a response but CHRE failed to
257    * enqueue one. For parameter details,
258    * @see postAsyncResultEvent
259    */
260   void postAsyncResultEventFatal(
261       uint32_t instanceId, bool success, bool enable,
262       Milliseconds minInterval, uint8_t errorCode, const void *cookie);
263 
264   /**
265    * Handles the result of a request to PlatformGnss to change the state of
266    * the session. See the handleStatusChange method which may be called from
267    * any thread. This method is intended to be invoked on the CHRE event loop
268    * thread.
269    *
270    * @param enabled true if the session was enabled
271    * @param errorCode an error code that is provided to indicate success.
272    */
273   void handleStatusChangeSync(bool enabled, uint8_t errorCode);
274 
275   /**
276    * Releases a GNSS report event after nanoapps have consumed it.
277    *
278    * @param eventType the type of event being freed.
279    * @param eventData a pointer to the scan event to release.
280    */
281   static void freeReportEventCallback(uint16_t eventType, void *eventData);
282 
283   /**
284    * Configures PlatformGnss based on session settings.
285    *
286    * @return true if PlatformGnss has accepted the setting.
287    */
288   bool controlPlatform(bool enable, Milliseconds minInterval,
289                        Milliseconds minTimeToNext);
290 };
291 
292 /**
293  * The GnssManager handles platform init, capability query, and delagates debug
294  * dump and all GNSS request management to GnssSession(s), which includes
295  * multiplexing multiple requests into one for the platform to handle.
296  *
297  * This class is effectively a singleton as there can only be one instance of
298  * the PlatformGnss instance.
299  */
300 class GnssManager : public NonCopyable {
301  public:
302   /**
303    * Constructs a GnssManager.
304    */
305   GnssManager();
306 
307   /**
308    * Initializes the underlying platform-specific GNSS module. Must be called
309    * prior to invoking any other methods in this class.
310    */
311   void init();
312 
313   /**
314    * @return the GNSS capabilities exposed by this platform.
315    */
316   uint32_t getCapabilities();
317 
getLocationSession()318   GnssSession& getLocationSession() {
319     return mLocationSession;
320   };
321 
getMeasurementSession()322   GnssSession& getMeasurementSession() {
323     return mMeasurementSession;
324   };
325 
326   /**
327    * Prints state in a string buffer. Must only be called from the context of
328    * the main CHRE thread.
329    *
330    * @param buffer Pointer to the start of the buffer.
331    * @param bufferPos Pointer to buffer position to start the print (in-out).
332    * @param size Size of the buffer in bytes.
333    *
334    * @return true if entire log printed, false if overflow or error.
335    */
336   void logStateToBuffer(char *buffer, size_t *bufferPos,
337                         size_t bufferSize) const;
338 
339  private:
340   // Allows GnssSession to access mPlatformGnss.
341   friend class GnssSession;
342 
343   //! The platform GNSS interface.
344   PlatformGnss mPlatformGnss;
345 
346   //! The instance of location session.
347   GnssSession mLocationSession;
348 
349   //! The instance of measurement session.
350   GnssSession mMeasurementSession;
351 };
352 
353 }  // namespace chre
354 
355 #endif  // CHRE_CORE_GNSS_MANAGER_H_
356