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