1 /*
2  * Copyright (C) 2016 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_WIFI_REQUEST_MANAGER_H_
18 #define CHRE_CORE_WIFI_REQUEST_MANAGER_H_
19 
20 #include "chre/core/nanoapp.h"
21 #include "chre/platform/platform_wifi.h"
22 #include "chre/util/buffer.h"
23 #include "chre/util/non_copyable.h"
24 #include "chre/util/optional.h"
25 #include "chre/util/time.h"
26 #include "chre_api/chre/wifi.h"
27 
28 namespace chre {
29 
30 /**
31  * The WifiRequestManager handles requests from nanoapps for Wifi information.
32  * This includes multiplexing multiple requests into one for the platform to
33  * handle.
34  *
35  * This class is effectively a singleton as there can only be one instance of
36  * the PlatformWifi instance.
37  */
38 class WifiRequestManager : public NonCopyable {
39  public:
40    /**
41     * Initializes the WifiRequestManager with a default state and memory for any
42     * requests.
43     */
44   WifiRequestManager();
45 
46   /**
47    * Initializes the underlying platform-specific WiFi module. Must be called
48    * prior to invoking any other methods in this class.
49    */
50   void init();
51 
52   /**
53    * @return the WiFi capabilities exposed by this platform.
54    */
55   uint32_t getCapabilities();
56 
57   /**
58    * Handles a request from a nanoapp to configure the scan monitor. This
59    * includes merging multiple requests for scan monitoring to the PAL (ie: if
60    * multiple apps enable the scan monitor the PAL is only enabled once).
61    *
62    * @param nanoapp The nanoapp that has requested that the scan monitor be
63    *        configured.
64    * @param enable true to enable scan monitoring, false to disable scan
65    *        monitoring.
66    * @param cookie A cookie that is round-tripped back to the nanoapp to
67    *        provide a context when making the request.
68    *
69    * @return true if the request was accepted. The result is delivered
70    *         asynchronously through a CHRE event.
71    */
72   bool configureScanMonitor(Nanoapp *nanoapp, bool enable, const void *cookie);
73 
74   /**
75    * Handles a nanoapp's request for RTT ranging against a set of devices.
76    *
77    * @param nanoapp Nanoapp issuing the request.
78    * @param params Non-null pointer to parameters, supplied by the nanoapp via
79    *        chreWifiRequestRangingAsync()
80    * @param cookie Opaque pointer supplied by the nanoapp and passed back in the
81    *        async result.
82    *
83    * @return true if the request was accepted. The result is delivered
84    *         asynchronously through a CHRE event.
85    */
86   bool requestRanging(Nanoapp *nanoapp, const chreWifiRangingParams *params,
87                       const void *cookie);
88 
89   /**
90    * Performs an active wifi scan.
91    *
92    * This is currently a 1:1 mapping into the PAL. If more than one nanoapp
93    * requests an active wifi scan, this will be an assertion failure for debug
94    * builds and a no-op in production (ie: subsequent requests are ignored).
95    *
96    * @param nanoapp The nanoapp that has requested an active wifi scan.
97    * @param params Non-null pointer to the scan parameters structure supplied by
98    *        the nanoapp.
99    * @param cookie A cookie that is round-tripped back to the nanoapp to provide
100    *        a context when making the request.
101    *
102    * @return true if the request was accepted. The result is delivered
103    *         asynchronously through a CHRE event.
104    */
105   bool requestScan(Nanoapp *nanoapp, const chreWifiScanParams *params,
106                    const void *cookie);
107 
108   /**
109    * Passes the result of an RTT ranging request on to the requesting nanoapp.
110    *
111    * @param errorCode Value from enum chreError
112    * @param event Event containing ranging results, or null if errorCode is not
113    *        chreError
114    */
115   void handleRangingEvent(uint8_t errorCode,
116                           struct chreWifiRangingEvent *event);
117 
118   /**
119    * Handles the result of a request to PlatformWifi to change the state of the
120    * scan monitor.
121    *
122    * @param enabled true if the result of the operation was an enabled scan
123    *        monitor.
124    * @param errorCode an error code that is provided to indicate success or what
125    *        type of error has occurred. See the chreError enum in the CHRE API
126    *        for additional details.
127    */
128   void handleScanMonitorStateChange(bool enabled, uint8_t errorCode);
129 
130   /**
131    * Handles the result of a request to the PlatformWifi to request an active
132    * Wifi scan.
133    *
134    * @param pending The result of the request was successful and the results
135    *        be sent via the handleScanEvent method.
136    * @param errorCode an error code that is used to indicate success or what
137    *        type of error has occurred. See the chreError enum in the CHRE API
138    *        for additional details.
139    */
140   void handleScanResponse(bool pending, uint8_t errorCode);
141 
142   /**
143    * Handles a CHRE wifi scan event.
144    *
145    * @param event The wifi scan event provided to the wifi request manager. This
146    *        memory is guaranteed not to be modified until it has been explicitly
147    *        released through the PlatformWifi instance.
148    */
149   void handleScanEvent(chreWifiScanEvent *event);
150 
151   /**
152    * Prints state in a string buffer. Must only be called from the context of
153    * the main CHRE thread.
154    *
155    * @param buffer Pointer to the start of the buffer.
156    * @param bufferPos Pointer to buffer position to start the print (in-out).
157    * @param size Size of the buffer in bytes.
158    */
159   void logStateToBuffer(char *buffer, size_t *bufferPos,
160                         size_t bufferSize) const;
161 
162  private:
163   struct PendingRequestBase {
164     uint32_t nanoappInstanceId;  //!< ID of the Nanoapp issuing this request
165     const void *cookie;          //!< User data supplied by the nanoapp
166   };
167 
168   struct PendingRangingRequest : public PendingRequestBase {
169     //! If the request was queued, a variable-length list of devices to
170     //! perform ranging against (used to reconstruct chreWifiRangingParams)
171     Buffer<struct chreWifiRangingTarget> targetList;
172   };
173 
174   struct PendingScanMonitorRequest : public PendingRequestBase {
175     bool enable;  //!< Requested scan monitor state
176   };
177 
178   static constexpr size_t kMaxScanMonitorStateTransitions = 8;
179   static constexpr size_t kMaxPendingRangingRequests = 4;
180 
181   PlatformWifi mPlatformWifi;
182 
183   //! The queue of state transition requests for the scan monitor. Only one
184   //! asynchronous scan monitor state transition can be in flight at one time.
185   //! Any further requests are queued here.
186   ArrayQueue<PendingScanMonitorRequest, kMaxScanMonitorStateTransitions>
187       mPendingScanMonitorRequests;
188 
189   //! The list of nanoapps who have enabled scan monitoring. This list is
190   //! maintained to ensure that nanoapps are always subscribed to wifi scan
191   //! results as requested. Note that a request for wifi scan monitoring can
192   //! exceed the duration of a single active wifi scan request. This makes it
193   //! insuitable only subscribe to wifi scan events when an active request is
194   //! made and the scan monitor must remain enabled when an active request has
195   //! completed.
196   DynamicVector<uint32_t> mScanMonitorNanoapps;
197 
198   // TODO: Support multiple requests for active wifi scans.
199   //! The instance ID of the nanoapp that has a pending active scan request. At
200   //! this time, only one nanoapp can have a pending request for an active WiFi
201   //! scan.
202   Optional<uint32_t> mScanRequestingNanoappInstanceId;
203 
204   //! The cookie passed in by a nanoapp making an active request for wifi scans.
205   //! Note that this will only be valid if the mScanRequestingNanoappInstanceId
206   //! is set.
207   const void *mScanRequestingNanoappCookie;
208 
209   //! This is set to true if the results of an active scan request are pending.
210   bool mScanRequestResultsArePending = false;
211 
212   //! Accumulates the number of scan event results to determine when the last
213   //! in a scan event stream has been received.
214   uint8_t mScanEventResultCountAccumulator = 0;
215 
216   //! System time when last scan request was made.
217   Nanoseconds mLastScanRequestTime;
218 
219   //! Tracks the in-flight ranging request and any others queued up behind it
220   ArrayQueue<PendingRangingRequest, kMaxPendingRangingRequests>
221       mPendingRangingRequests;
222 
223   //! Helps ensure we don't get stuck if platform isn't behaving as expected
224   Nanoseconds mRangingResponseTimeout;
225 
226   /**
227    * @return true if the scan monitor is enabled by any nanoapps.
228    */
229   bool scanMonitorIsEnabled() const;
230 
231   /**
232    * @param instanceId the instance ID of the nanoapp.
233    * @param index an optional pointer to a size_t to populate with the index of
234    *        the nanoapp in the list of nanoapps.
235    *
236    * @return true if the nanoapp has an active request for scan monitoring.
237    */
238   bool nanoappHasScanMonitorRequest(uint32_t instanceId,
239                                     size_t *index = nullptr) const;
240 
241   /**
242    * @param requestedState The requested state to compare against.
243    * @param nanoappHasRequest The requesting nanoapp has an existing request.
244    *
245    * @return true if the scan monitor is in the requested state.
246    */
247   bool scanMonitorIsInRequestedState(bool requestedState,
248                                      bool nanoappHasRequest) const;
249 
250   /**
251    * @param requestedState The requested state to compare against.
252    * @param nanoappHasRequest The requesting nanoapp has an existing request.
253    *
254    * @return true if a state transition is required to reach the requested
255    * state.
256    */
257   bool scanMonitorStateTransitionIsRequired(bool requestedState,
258                                             bool nanoappHasRequest) const;
259 
260   /**
261    * Builds a scan monitor state transition and adds it to the queue of incoming
262    * requests.
263    * @param nanoapp A non-null pointer to a nanoapp that is requesting the
264    *        change.
265    * @param enable The target requested scan monitoring state.
266    * @param cookie The pointer cookie passed in by the calling nanoapp to return
267    *        to the nanoapp when the request completes.
268    *
269    * @return true if the request is enqueued or false if the queue is full.
270    */
271   bool addScanMonitorRequestToQueue(Nanoapp *nanoapp, bool enable,
272                                     const void *cookie);
273 
274   /**
275    * Adds a nanoapp to the list of nanoapps that are monitoring for wifi scans.
276    * @param enable true if enabling scan monitoring.
277    * @param instanceId The instance ID of the scan monitoring nanoapp.
278    *
279    * @return true if the nanoapp was added to the list.
280    */
281   bool updateNanoappScanMonitoringList(bool enable, uint32_t instanceId);
282 
283   /**
284    * Posts an event to a nanoapp indicating the result of a wifi scan monitoring
285    * configuration change.
286    *
287    * @param nanoappInstanceId The nanoapp instance ID to direct the event to.
288    * @param success If the request for a wifi resource was successful.
289    * @param enable The target state of the request. If enable is set to false
290    *        and the request was successful, the nanoapp is removed from the
291    *        list of nanoapps requesting scan monitoring.
292    * @param errorCode The error code when success is set to false.
293    * @param cookie The cookie to be provided to the nanoapp. This is
294    *        round-tripped from the nanoapp to provide context.
295    *
296    * @return true if the event was successfully posted to the event loop.
297    */
298   bool postScanMonitorAsyncResultEvent(
299       uint32_t nanoappInstanceId, bool success, bool enable, uint8_t errorCode,
300       const void *cookie);
301 
302   /**
303    * Calls through to postScanMonitorAsyncResultEvent but invokes the
304    * FATAL_ERROR macro if the event is not posted successfully. This is used in
305    * asynchronous contexts where a nanoapp could be stuck waiting for a response
306    * but CHRE failed to enqueue one. For parameter details,
307    * @see postScanMonitorAsyncResultEvent
308    */
309   void postScanMonitorAsyncResultEventFatal(
310       uint32_t nanoappInstanceId, bool success, bool enable, uint8_t errorCode,
311       const void *cookie);
312 
313   /**
314    * Posts an event to a nanoapp indicating the result of a request for an
315    * active wifi scan.
316    *
317    * @param nanoappInstanceId The nanoapp instance ID to direct the event to.
318    * @param success If the request for a wifi resource was successful.
319    * @param errorCode The error code when success is set to false.
320    * @param cookie The cookie to be provided to the nanoapp. This is
321    *        round-tripped from the nanoapp to provide context.
322    *
323    * @return true if the event was successfully posted to the event loop.
324    */
325   bool postScanRequestAsyncResultEvent(
326       uint32_t nanoappInstanceId, bool success, uint8_t errorCode,
327       const void *cookie);
328 
329   /**
330    * Calls through to postScanRequestAsyncResultEvent but invokes the
331    * FATAL_ERROR macro if the event is not posted successfully. This is used in
332    * asynchronous contexts where a nanoapp could be stuck waiting for a response
333    * but CHRE failed to enqueue one. For parameter details,
334    * @see postScanRequestAsyncResultEvent
335    */
336   void postScanRequestAsyncResultEventFatal(
337       uint32_t nanoappInstanceId, bool success, uint8_t errorCode,
338       const void *cookie);
339 
340   /**
341    * Posts a broadcast event containing the results of a wifi scan. Failure to
342    * post this event is a FATAL_ERROR. This is unrecoverable as the nanoapp will
343    * be stuck waiting for wifi scan results but there may be a gap.
344    *
345    * @param event the wifi scan event.
346    */
347   void postScanEventFatal(chreWifiScanEvent *event);
348 
349   /**
350    * Handles the result of a request to PlatformWifi to change the state of the
351    * scan monitor. See the handleScanMonitorStateChange method which may be
352    * called from any thread. This method is intended to be invoked on the CHRE
353    * event loop thread.
354    *
355    * @param enabled true if the result of the operation was an enabled scan
356    *        monitor.
357    * @param errorCode an error code that is provided to indicate success or what
358    *        type of error has occurred. See the chreError enum in the CHRE API
359    *        for additional details.
360    */
361   void handleScanMonitorStateChangeSync(bool enabled, uint8_t errorCode);
362 
363   /**
364    * Handles the result of a request to PlatformWifi to perform an active WiFi
365    * scan. See the handleScanResponse method which may be called from any
366    * thread. This method is intended to be invoked on the CHRE event loop
367    * thread.
368    *
369    * @param enabled true if the result of the operation was an enabled scan
370    *        monitor.
371    * @param errorCode an error code that is provided to indicate success or what
372    *        type of error has occurred. See the chreError enum in the CHRE API
373    *        for additional details.
374    */
375   void handleScanResponseSync(bool pending, uint8_t errorCode);
376 
377   /**
378    * Sends CHRE_EVENT_WIFI_ASYNC_RESULT for the ranging request at the head of
379    * the pending queue.
380    *
381    * @param errorCode Indicates the overall result of the ranging operation
382    *
383    * @return true on success
384    */
385   bool postRangingAsyncResult(uint8_t errorCode);
386 
387   /**
388    * Issues the next pending ranging request to the platform.
389    *
390    * @return Result of PlatformWifi::requestRanging()
391    */
392   bool dispatchQueuedRangingRequest();
393 
394   /**
395    * Processes the result of a ranging request within the context of the CHRE
396    * thread.
397    *
398    * @param errorCode Result of the ranging operation
399    * @param event On success, pointer to event data provided by platform
400    */
401   void handleRangingEventSync(uint8_t errorCode,
402                               struct chreWifiRangingEvent *event);
403 
404   /**
405    * Handles the releasing of a WiFi scan event and unsubscribes a nanoapp who
406    * has made an active request for a wifi scan from WiFi scan events in the
407    * future (if it has not subscribed to passive events).
408    *
409    * @param scanEvent The scan event to release.
410    */
411   void handleFreeWifiScanEvent(chreWifiScanEvent *scanEvent);
412 
413   /**
414    * Releases a wifi scan event after nanoapps have consumed it.
415    *
416    * @param eventType the type of event being freed.
417    * @param eventData a pointer to the scan event to release.
418    */
419   static void freeWifiScanEventCallback(uint16_t eventType, void *eventData);
420   static void freeWifiRangingEventCallback(uint16_t eventType, void *eventData);
421 };
422 
423 }  // namespace chre
424 
425 #endif  // CHRE_CORE_WIFI_REQUEST_MANAGER_H_
426