1/*
2 * Copyright (C) 2017 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_REQUEST_MANAGER_H_
18#define CHRE_CORE_GNSS_REQUEST_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
27namespace chre {
28
29/**
30 * The GnssRequestManager handles requests from nanoapps for GNSS data. This
31 * includes multiplexing multiple requests into one for the platform to handle.
32 *
33 * This class is effectively a singleton as there can only be one instance of
34 * the PlatformGnss instance.
35 */
36class GnssRequestManager : public NonCopyable {
37 public:
38  /**
39   * Initializes a GnssRequestManager.
40   */
41  GnssRequestManager();
42
43  /**
44   * Initializes the underlying platform-specific GNSS module. Must be called
45   * prior to invoking any other methods in this class.
46   */
47  void init();
48
49  /**
50   * @return the GNSS capabilities exposed by this platform.
51   */
52  uint32_t getCapabilities();
53
54  /**
55   * Starts a location session asynchronously. The result is delivered through
56   * a CHRE_EVENT_GNSS_ASYNC_RESULT event.
57   *
58   * @param nanoapp The nanoapp requesting the location session.
59   * @param minInterval The minimum reporting interval for location results.
60   * @param timeToNextFix The amount of time that the locationing system is
61   *        allowed to delay generating a fix.
62   * @param cookie A cookie that is round-tripped to provide context to the
63   *               nanoapp making the request.
64   * @return true if the request was accepted for processing.
65   */
66  bool startLocationSession(Nanoapp *nanoapp, Milliseconds minInterval,
67                            Milliseconds minTimeToNextFix, const void *cookie);
68
69  /**
70   * Stops a location session asynchronously. The result is delivered through a
71   * CHRE_EVENT_GNSS_ASYNC_RESULT event.
72   *
73   * @param nanoapp The nanoapp requesting the location session to stop.
74   * @param cookie A cookie that is round-tripped to provide context to the
75   *        nanoapp making the request.
76   *  @return true if the request was accepted for processing.
77   */
78  bool stopLocationSession(Nanoapp *nanoapp, const void *cookie);
79
80  /**
81   * Handles the result of a request to the PlatformGnss to request a change to
82   * the location session.
83   *
84   * @param enabled true if the location session is currently active
85   * @param errorCode an error code that is used to indicate success or what
86   *        type of error has occured. See chreError enum in the CHRE API for
87   *        additional details.
88   */
89  void handleLocationSessionStatusChange(bool enabled, uint8_t errorCode);
90
91  /**
92   * Handles a CHRE GNSS location event.
93   *
94   * @param event The GNSS location event provided to the GNSS request manager.
95   *        This memory is guaranteed not to be modified until it has been
96   *        explicitly released through the PlatformGnss instance.
97   */
98  void handleLocationEvent(chreGnssLocationEvent *event);
99
100  /**
101   * Prints state in a string buffer. Must only be called from the context of
102   * the main CHRE thread.
103   *
104   * @param buffer Pointer to the start of the buffer.
105   * @param bufferPos Pointer to buffer position to start the print (in-out).
106   * @param size Size of the buffer in bytes.
107   *
108   * @return true if entire log printed, false if overflow or error.
109   */
110  bool logStateToBuffer(char *buffer, size_t *bufferPos,
111                        size_t bufferSize) const;
112
113 private:
114  /**
115   * Tracks a nanoapp that has subscribed to a location session and the
116   * reporting interval.
117   */
118  struct LocationSessionRequest {
119    //! The nanoapp instance ID that made this request.
120    uint32_t nanoappInstanceId;
121
122    //! The interval of location results requested.
123    Milliseconds minInterval;
124  };
125
126  /**
127   * Tracks the state of the locationing engine.
128   */
129  struct LocationSessionStateTransition {
130    //! The nanoapp instance ID that prompted the change.
131    uint32_t nanoappInstanceId;
132
133    //! The cookie provided to the CHRE API when the nanoapp requested a change
134    //! to the state of the location engine.
135    const void *cookie;
136
137    //! The target state of the location engine.
138    bool enable;
139
140    //! The target minimum reporting interval for the location engine. This is
141    //! only valid if enable is set to true.
142    Milliseconds minInterval;
143  };
144
145  //! The maximum number of state transitions allowed for location and GNSS
146  //! measurement resources.
147  static constexpr size_t kMaxGnssStateTransitions = 8;
148
149  //! The instance of the platform GNSS interface.
150  PlatformGnss mPlatformGnss;
151
152  //! The queue of state transitions for the location engine. Only one
153  //! asynchronous location engine state transition can be in flight at one
154  //! time. Any further requests are queued here.
155  ArrayQueue<LocationSessionStateTransition,
156             kMaxGnssStateTransitions> mLocationSessionStateTransitions;
157
158  //! The request multiplexer for GNSS location requests.
159  DynamicVector<LocationSessionRequest> mLocationSessionRequests;
160
161  //! The current interval being sent to the location session. This is only
162  //! valid if the mLocationSessionRequests is non-empty.
163  Milliseconds mCurrentLocationSessionInterval;
164
165  /**
166   * Configures the location engine to be enabled/disabled. If enable is set to
167   * true then the minInterval and minTimeToFirstFix values are valid.
168   *
169   * @param nanoapp The nanoapp requesting the state change for the location
170   *        engine.
171   * @param enable Whether to enable or disable the location engine.
172   * @param minInterval The minimum location reporting interval requested by the
173   *        nanoapp.
174   * @param minTimeToFirstFix The minimum time to the first fix.
175   * @param cookie The cookie provided by the nanoapp to round-trip for context.
176   * @return true if the request was accepted.
177   */
178  bool configureLocationSession(Nanoapp *nanoapp, bool enable,
179                                Milliseconds minInterval,
180                                Milliseconds minTimeToFirstFix,
181                                const void *cookie);
182
183  /**
184   * Checks if a nanoapp has an open location session request.
185   *
186   * @param instanceId The nanoapp instance ID to search for.
187   * @param requestIndex A pointer to an index to populate if the nanoapp has an
188   *        open location session.
189   * @return true if the provided instanceId was found.
190   */
191  bool nanoappHasLocationSessionRequest(uint32_t instanceId,
192                                        size_t *requestIndex = nullptr);
193
194  /**
195   * Adds a request for a location session to the queue of state transitions.
196   *
197   * @param instanceId The nanoapp instance ID requesting a location session.
198   * @param enable Whether the location session is being enabled or disabled for
199   *        this nanoapp.
200   * @param minInterval The minimum interval reqested by the nanoapp.
201   * @param cookie A cookie that is round-tripped to the nanoapp for context.
202   * @return true if the state transition was added to the queue.
203   */
204  bool addLocationSessionRequestToQueue(uint32_t instanceId, bool enable,
205                                        Milliseconds minInterval,
206                                        const void *cookie);
207
208  /**
209   * @return true if the location session is currently enabled.
210   */
211  bool locationSessionIsEnabled();
212
213  /**
214   * Determines if the location session is already in the requested state.
215   *
216   * @param requestedState The target state of the location session.
217   * @param minInterval The reporting interval if the requestedState is true.
218   * @param nanoappHasRequest true if the requesting nanoapp already has an
219   *        outstanding request.
220   * @return true if the location session is already in the requested state.
221   */
222  bool locationSessionIsInRequestedState(bool requestedState,
223                                         Milliseconds minInterval,
224                                         bool nanoappHasRequest);
225
226  /**
227   * Determines if a change to the location session state is required given a
228   * set of parameters.
229   *
230   * @param requestedState The target state requested by a nanoapp.
231   * @param minInterval The minimum location reporting interval.
232   * @param nanoappHasRequest If the nanoapp already has a request.
233   * @param requestIndex The index of the request in the list of open requests
234   *        if nanoappHasRequest is set to true.
235   * @return true if a state transition is required.
236   */
237  bool locationSessionStateTransitionIsRequired(bool requestedState,
238                                                Milliseconds minInterval,
239                                                bool nanoappHasRequest,
240                                                size_t requestIndex);
241
242  /**
243   * Updates the location session requests given a nanoapp and the interval
244   * requested.
245   *
246   * @param enable true if enabling the location session.
247   * @param minInterval the minimum reporting interval if enable is set to true.
248   * @param instanceId the nanoapp instance ID that owns the request.
249   * @return true if the location session request list was updated.
250   */
251  bool updateLocationSessionRequests(bool enable, Milliseconds minInterval,
252                                     uint32_t instanceId);
253
254  /**
255   * Posts the result of a GNSS location session start/stop request.
256   *
257   * @param instanceId The nanoapp instance ID that made the request.
258   * @param success true if the operation was successful.
259   * @param enable true if enabling the location session.
260   * @param minInterval the minimum location reporting interval.
261   * @param errorCode the error code as a result of this operation.
262   * @param cookie the cookie that the nanoapp is provided for context.
263   * @return true if the event was successfully posted.
264   */
265  bool postLocationSessionAsyncResultEvent(
266      uint32_t instanceId, bool success, bool enable, Milliseconds minInterval,
267      uint8_t errorCode, const void *cookie);
268
269  /**
270   * Calls through to postLocationSessionAsyncResultEvent but invokes
271   * FATAL_ERROR if the event is not posted successfully. This is used in
272   * asynchronous contexts where a nanoapp could be stuck waiting for a response
273   * but CHRE failed to enqueue one. For parameter details,
274   * @see postLocationSessionAsyncResultEvent
275   */
276  void postLocationSessionAsyncResultEventFatal(
277      uint32_t instanceId, bool success, bool enable, Milliseconds minInterval,
278      uint8_t errorCode, const void *cookie);
279
280  /**
281   * Handles the result of a request to PlatformGnss to change the state of the
282   * scan monitor. See the handleLocationSessionStatusChange method which may be
283   * called from any thread. This method is intended to be invoked on the CHRE
284   * event loop thread.
285   *
286   * @param enabled true if the location session was enabled
287   * @param errorCode an error code that is provided to indicate success.
288   */
289  void handleLocationSessionStatusChangeSync(bool enabled, uint8_t errorCode);
290
291  /**
292   * Handles the releasing of a GNSS location event.
293   *
294   * @param event The event to free.
295   */
296  void handleFreeLocationEvent(chreGnssLocationEvent *event);
297
298  /**
299   * Releases a GNSS location event after nanoapps have consumed it.
300   *
301   * @param eventType the type of event being freed.
302   * @param eventData a pointer to the scan event to release.
303   */
304  static void freeLocationEventCallback(uint16_t eventType, void *eventData);
305};
306
307}  // namespace chre
308
309#endif  // CHRE_CORE_GNSS_REQUEST_MANAGER_H_
310