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