1 /* 2 * Copyright (C) 2021 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_BLE_REQUEST_MANAGER_H_ 18 #define CHRE_CORE_BLE_REQUEST_MANAGER_H_ 19 20 #include "chre/core/ble_request.h" 21 #include "chre/core/ble_request_multiplexer.h" 22 #include "chre/core/nanoapp.h" 23 #include "chre/core/settings.h" 24 #include "chre/core/timer_pool.h" 25 #include "chre/platform/platform_ble.h" 26 #include "chre/platform/system_time.h" 27 #include "chre/util/array_queue.h" 28 #include "chre/util/non_copyable.h" 29 #include "chre/util/system/debug_dump.h" 30 #include "chre/util/time.h" 31 32 namespace chre { 33 34 /** 35 * Manages requests for ble resources from nanoapps and multiplexes these 36 * requests into the platform-specific implementation of the ble subsystem. 37 */ 38 class BleRequestManager : public NonCopyable { 39 public: 40 /** 41 * Initializes the underlying platform-specific BLE module. Must be called 42 * prior to invoking any other methods in this class. 43 */ 44 void init(); 45 46 /** 47 * @return the BLE capabilities exposed by this platform. 48 */ 49 uint32_t getCapabilities(); 50 51 /** 52 * @return the BLE filter capabilities exposed by this platform. 53 */ 54 uint32_t getFilterCapabilities(); 55 56 /** 57 * Begins a BLE scan asynchronously. The result is delivered through a 58 * CHRE_EVENT_BLE_ASYNC_RESULT event. 59 * 60 * @param nanoapp The nanoapp starting the request. 61 * @param mode Scanning mode selected among enum chreBleScanMode 62 * @param reportDelayMs Maximum requested batching delay in ms. 0 indicates no 63 * batching. Note that the system may deliver results 64 * before the maximum specified delay is reached. 65 * @param filter Pointer to the requested best-effort filter configuration as 66 * defined by struct chreBleScanFilterV1_9. The ownership of 67 * filter and its nested elements remains with the caller, and 68 * the caller may release it as soon as 69 * chreBleStartScanAsyncV1_9() returns. 70 * @param cookie The cookie to be provided to the nanoapp. This is 71 * round-tripped from the nanoapp to provide context. 72 * @return true if scan was successfully enabled. 73 */ 74 bool startScanAsync(Nanoapp *nanoapp, chreBleScanMode mode, 75 uint32_t reportDelayMs, 76 const struct chreBleScanFilterV1_9 *filter, 77 const void *cookie); 78 79 /** 80 * End a BLE scan asynchronously. The result is delivered through a 81 * CHRE_EVENT_BLE_ASYNC_RESULT event. 82 * 83 * @param nanoapp The nanoapp stopping the request. 84 * @param cookie A cookie that is round-tripped back to the nanoapp to 85 * provide a context when making the request. 86 * @return whether the scan was successfully ended. 87 */ 88 bool stopScanAsync(Nanoapp *nanoapp, const void *cookie); 89 90 #ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED 91 /** 92 * Requests to read the RSSI of a peer device on the given LE connection 93 * handle. 94 * 95 * If the request is accepted, the response will be delivered in a 96 * CHRE_EVENT_BLE_RSSI_READ event with the same cookie. 97 * 98 * The request may be rejected if resources are not available to service the 99 * request (such as if too many outstanding requests already exist). If so, 100 * the client may retry later. 101 * 102 * Note that the connectionHandle is valid only while the connection remains 103 * active. If a peer device disconnects then reconnects, the handle may 104 * change. BluetoothGatt#getAclHandle() can be used from the Android framework 105 * to get the latest handle upon reconnection. 106 * 107 * @param connectionHandle 108 * @param cookie An opaque value that will be included in the chreAsyncResult 109 * embedded in the response to this request. 110 * @return True if the request has been accepted and dispatched to the 111 * controller. False otherwise. 112 * 113 * @since v1.8 114 * 115 */ 116 bool readRssiAsync(Nanoapp *nanoapp, uint16_t connectionHandle, 117 const void *cookie); 118 #endif 119 120 /** 121 * Initiates a flush operation where all batched advertisement events will be 122 * immediately processed and delivered. The nanoapp must have an existing 123 * active BLE scan. 124 * 125 * @param nanoapp the nanoapp requesting the flush operation. 126 * @param cookie the cookie value stored with the request. 127 * @return true if the request has been accepted and dispatched to the 128 * controller. false otherwise. 129 */ 130 bool flushAsync(Nanoapp *nanoapp, const void *cookie); 131 132 /** 133 * Disables active scan for a nanoapp (no-op if no active scan). 134 * 135 * @param nanoapp A non-null pointer to the nanoapp. 136 * @return the number of scans cancelled (1 or 0). 137 */ 138 uint32_t disableActiveScan(const Nanoapp *nanoapp); 139 140 /** 141 * Frees an advertising event that was previously provided to the BLE 142 * manager. 143 * 144 * @param event the event to release. 145 */ 146 void handleFreeAdvertisingEvent(struct chreBleAdvertisementEvent *event); 147 148 /** 149 * Releases BLE Advertising Event after nanoapps have processed it. 150 * 151 * @param eventType the type of event being freed. 152 * @param eventData a pointer to the scan event to release. 153 */ 154 static void freeAdvertisingEventCallback(uint16_t eventType, void *eventData); 155 156 /** 157 * Handles a CHRE BLE advertisement event. 158 * 159 * @param event The BLE advertisement event containing BLE advertising 160 * reports. This memory is guaranteed not to be modified until it 161 * has been explicitly released through the PlatformBle instance. 162 */ 163 void handleAdvertisementEvent(struct chreBleAdvertisementEvent *event); 164 165 /** 166 * Handles the result of a request to the PlatformBle to enable or end a scan. 167 * 168 * @param enable true if the scan is being enabled, false if not. 169 * @param errorCode an error code that is used to indicate success or what 170 * type of error has occurred. See chreError enum in the CHRE 171 * API for additional details. 172 */ 173 void handlePlatformChange(bool enable, uint8_t errorCode); 174 175 /** 176 * Invoked as a result of a requestStateResync() callback from the BLE PAL. 177 * Runs asynchronously in the context of the callback immediately. 178 */ 179 void handleRequestStateResyncCallback(); 180 181 #ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED 182 /** 183 * Handles a readRssi response from the BLE PAL. 184 * 185 * @param errorCode error code from enum chreError, with CHRE_ERROR_NONE 186 * indicating a successful response. 187 * @param connectionHandle the handle upon which the RSSI was read 188 * @param rssi the RSSI read, if successful 189 */ 190 void handleReadRssi(uint8_t errorCode, uint16_t connectionHandle, 191 int8_t rssi); 192 #endif 193 194 /** 195 * Handler for the flush complete operation. Called when a flush operation is 196 * complete. Processes in an asynchronous manner. 197 * 198 * @param errorCode the error code from the flush operation. 199 */ 200 void handleFlushComplete(uint8_t errorCode); 201 202 //! Timeout handler for the flush operation. Called on a timeout. 203 void handleFlushCompleteTimeout(); 204 205 /** 206 * Retrieves the current scan status. 207 * 208 * @param status A non-null pointer to where the scan status will be 209 * populated. 210 * 211 * @return True if the status was obtained successfully. 212 */ 213 bool getScanStatus(struct chreBleScanStatus *status); 214 215 /** 216 * Invoked when the host notifies CHRE that ble access has been 217 * disabled via the user settings. 218 * 219 * @param setting The setting that changed. 220 * @param enabled Whether setting is enabled or not. 221 */ 222 void onSettingChanged(Setting setting, bool enabled); 223 224 /** 225 * Prints state in a string buffer. Must only be called from the context of 226 * the main CHRE thread. 227 * 228 * @param debugDump The debug dump wrapper where a string can be printed 229 * into one of the buffers. 230 */ 231 void logStateToBuffer(DebugDumpWrapper &debugDump) const; 232 233 private: 234 friend class BleRequestManagerTest; 235 236 //! An internal structure to store incoming sensor flush requests 237 struct FlushRequest { FlushRequestFlushRequest238 FlushRequest(uint16_t id, const void *cookiePtr) 239 : nanoappInstanceId(id), cookie(cookiePtr) {} 240 241 //! The timestamp at which this request should complete. 242 Nanoseconds deadlineTimestamp = 243 SystemTime::getMonotonicTime() + 244 Nanoseconds(CHRE_BLE_FLUSH_COMPLETE_TIMEOUT_NS); 245 //! The ID of the nanoapp that requested the flush. 246 uint16_t nanoappInstanceId; 247 //! The opaque pointer provided in flushAsync(). 248 const void *cookie; 249 //! True if this flush request is active and is pending completion. 250 bool isActive = false; 251 }; 252 253 // Multiplexer used to keep track of BLE requests from nanoapps. 254 BleRequestMultiplexer mRequests; 255 256 // The platform BLE interface. 257 PlatformBle mPlatformBle; 258 259 // Expected platform state after completion of async platform request. 260 BleRequest mPendingPlatformRequest; 261 262 // Current state of the platform. 263 BleRequest mActivePlatformRequest; 264 265 // True if a platform request is in progress. 266 bool mPlatformRequestInProgress; 267 268 // True if a state resync request is pending to be processed. 269 bool mResyncPending; 270 271 // True if a setting change request is pending to be processed. 272 bool mSettingChangePending; 273 274 //! A queue of flush requests made by nanoapps. 275 static constexpr size_t kMaxFlushRequests = 16; 276 ArrayQueue<FlushRequest, kMaxFlushRequests> mFlushRequestQueue; 277 278 //! The timer handle for the flush operation. Used to track a flush timeout. 279 TimerHandle mFlushRequestTimerHandle = CHRE_TIMER_INVALID; 280 281 #ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED 282 // A pending request from a nanoapp 283 struct BleReadRssiRequest { 284 uint16_t instanceId; 285 uint16_t connectionHandle; 286 const void *cookie; 287 }; 288 289 // RSSI requests that have been accepted by the framework. The first entry (if 290 // present) has been dispatched to the PAL, and subsequent entries are queued. 291 static constexpr size_t kMaxPendingRssiRequests = 2; 292 ArrayQueue<BleReadRssiRequest, kMaxPendingRssiRequests> mPendingRssiRequests; 293 #endif 294 295 // Struct to hold ble request data for logging 296 struct BleRequestLog { BleRequestLogBleRequestLog297 BleRequestLog(Nanoseconds timestamp_, uint32_t instanceId_, bool enable_, 298 bool compliesWithBleSetting_) 299 : timestamp(timestamp_), 300 instanceId(instanceId_), 301 enable(enable_), 302 compliesWithBleSetting(compliesWithBleSetting_) {} populateRequestDataBleRequestLog303 void populateRequestData(const BleRequest &req) { 304 mode = req.getMode(); 305 reportDelayMs = req.getReportDelayMs(); 306 rssiThreshold = req.getRssiThreshold(); 307 scanFilterCount = static_cast<uint8_t>(req.getGenericFilters().size()); 308 broadcasterFilterCount = 309 static_cast<uint8_t>(req.getBroadcasterFilters().size()); 310 } 311 Nanoseconds timestamp; 312 uint32_t instanceId; 313 bool enable; 314 bool compliesWithBleSetting; 315 chreBleScanMode mode; 316 uint32_t reportDelayMs; 317 int8_t rssiThreshold; 318 uint8_t scanFilterCount; 319 uint8_t broadcasterFilterCount; 320 }; 321 322 // List of most recent ble request logs 323 static constexpr size_t kNumBleRequestLogs = 10; 324 ArrayQueue<BleRequestLog, kNumBleRequestLogs> mBleRequestLogs; 325 326 /** 327 * Configures BLE platform based on the current maximal BleRequest. 328 */ 329 bool controlPlatform(); 330 331 /** 332 * Processes nanoapp requests to start and stop a scan and updates BLE 333 * platform if necessary. 334 * 335 * @param request BLE request to start or stop scan. 336 * @return true if request was successfully processed. 337 */ 338 bool configure(BleRequest &&request); 339 340 /** 341 * Handle sending an async response if a nanoapp attempts to override an 342 * existing request. 343 * 344 * @param instanceId Instance id of nanoapp that made the request. 345 * @param hasExistingRequest Indicates whether a request exists corresponding 346 * to the nanoapp instance id of the new request. 347 * @param requestIndex If hasExistingRequest is true, requestIndex 348 * corresponds to the index of that request. 349 */ 350 void handleExistingRequest(uint16_t instanceId, bool *hasExistingRequest, 351 size_t *requestIndex); 352 353 /** 354 * Check whether a request is attempting to enable the BLE platform while the 355 * BLE setting is disabled. 356 * 357 * @param instanceId Instance id of nanoapp that made the request. 358 * @param enabled Whether the request should start or stop a scan. 359 * @param hasExistingRequest Indicates whether a request exists corresponding 360 * to the nanoapp instance id of the new request. 361 * @param requestIndex If hasExistingRequest is true, requestIndex 362 * corresponds to the index of that request. 363 * @param cookie The cookie to be provided to the nanoapp. 364 * @return true if the request does not attempt to enable the platform while 365 * the BLE setting is disabled. 366 */ 367 bool compliesWithBleSetting(uint16_t instanceId, bool enabled, 368 bool hasExistingRequest, size_t requestIndex, 369 const void *cookie); 370 371 /** 372 * Add a log to list of BLE request logs possibly pushing out the oldest log. 373 * 374 * @param instanceId Instance id of nanoapp that made the request. 375 * @param enabled Whether the request should start or stop a scan. 376 * @param requestIndex Index of request in multiplexer. Must check whether it 377 * is valid range before using. 378 * @param compliesWithBleSetting true if the request does not attempt to 379 * enable the platform while the BLE setting is disabled. 380 */ 381 void addBleRequestLog(uint32_t instanceId, bool enabled, size_t requestIndex, 382 bool compliesWithBleSetting); 383 384 /** 385 * Update active BLE scan requests upon successful starting or ending a scan 386 * and register or unregister nanoapp for BLE broadcast events. 387 * 388 * @param request Scan requested by nanoapp, only valid if nanoappEnabled is 389 * true. 390 * @param requestChanged Indicates when the new request resulted in a change 391 * to the underlying maximal request 392 * @param hasExistingRequest Indicates whether a request exists for the 393 * corresponding nanoapp instance Id of the new request. 394 * @param requestIndex If equal to mRequests.size(), indicates the request 395 * wasn't added (perhaps due to removing a non-existent 396 * request). Otherwise, indicates the correct index for 397 * the request. 398 * @return true if requests were successfully updated. 399 */ 400 bool updateRequests(BleRequest &&request, bool hasExistingRequest, 401 bool *requestChanged, size_t *requestIndex); 402 403 /** 404 * Handles the result of a request to the PlatformBle to enable or end a scan. 405 * This method is intended to be invoked on the CHRE event loop thread. The 406 * handlePlatformChange method which may be called from any thread. For 407 * parameter details, 408 * @see handleAdvertisementEvent 409 */ 410 void handlePlatformChangeSync(bool enable, uint8_t errorCode); 411 412 /** 413 * Dispatches pending BLE requests from nanoapps. 414 */ 415 void dispatchPendingRequests(); 416 417 /** 418 * Handles registering/unregistering a nanoapp to the appropriate broadcast 419 * event. 420 * 421 * @param instanceId Nanoapp instance to send result to. 422 * @param enabled Whether nanoapp was enabled or disabled for BLE events. 423 * @param success Whether the request was processed by the PAL successfully. 424 * @param forceUnregister Whether the nanoapp should be force unregistered 425 * from BLE broadcast events. 426 */ 427 void handleNanoappEventRegistration(uint16_t instanceId, bool enabled, 428 bool success, bool forceUnregister); 429 430 /** 431 * Handles an async result, sending the result to the requesting nanoapp and 432 * registering/unregistering it from the appropriate broadcast 433 * 434 * @param instanceId Nanoapp instance to send result to. 435 * @param enabled Whether nanoapp was enabled or disabled for BLE events. 436 * @param success Whether the request was processed by the PAL successfully 437 * @param errorCode Error code resulting from the request 438 * @param forceUnregister Whether the nanoapp should be force unregistered 439 * @param cookie The cookie to be provided to the nanoapp. This is 440 * round-tripped from the nanoapp to provide context. 441 * from BLE broadcast events. 442 */ 443 void handleAsyncResult(uint16_t instanceId, bool enabled, bool success, 444 uint8_t errorCode, const void *cookie, 445 bool forceUnregister = false); 446 447 /** 448 * Invoked as a result of a requestStateResync() callback from the BLE PAL. 449 * Runs in the context of the CHRE thread. 450 */ 451 void handleRequestStateResyncCallbackSync(); 452 453 /** 454 * Updates the platform BLE request according to the current state. It should 455 * be used to synchronize the BLE to the desired state, e.g. for setting 456 * changes or handling a state resync request. 457 * 458 * @param forceUpdate if true force the platform BLE request to be made. 459 */ 460 void updatePlatformRequest(bool forceUpdate = false); 461 462 /** 463 * Helper function for flush complete handling in all cases - normal and 464 * timeout. This function defers a call to handleFlushCompleteSync. 465 * 466 * @param errorCode the error code for the flush operation. 467 */ 468 void handleFlushCompleteInternal(uint8_t errorCode); 469 470 /** 471 * Synchronously processed a flush complete operation. Starts a new flush 472 * operation if there is one in the queue. Properly sends the flush complete 473 * event. 474 * 475 * @param errorCode the error code for the flush operation. 476 */ 477 void handleFlushCompleteSync(uint8_t errorCode); 478 479 /** 480 * Sends the flush request to the controller if there is a non-active flush 481 * request in the flush request queue. Sets the timer callback to handle 482 * timeouts. 483 * 484 * @return the error code, chreError enum (CHRE_ERROR_NONE for success). 485 */ 486 uint8_t doFlushRequest(); 487 488 /** 489 * Sends the flush complete event or aborts CHRE. 490 * 491 * @param flushRequest the current active flush request. 492 * @param errorCode the error code, chreError enum. 493 */ 494 void sendFlushCompleteEventOrDie(const FlushRequest &flushRequest, 495 uint8_t errorCode); 496 497 /** 498 * Processes flush requests in the flush request queue in order. Calls 499 * doFlushRequest on the request. If an error is detected, it sends the flush 500 * complete event with the error. This function continues to process requests 501 * until one flush request is successfully made. Once this happens, the 502 * request manager waits for a timeout or for a callback from the BLE 503 * platform. 504 * 505 * @return true if there was one flush request that was successfully 506 * initiated, false otherwise. 507 */ 508 bool processFlushRequests(); 509 510 /** 511 * Validates the parameters given to ensure that they can be issued to the 512 * PAL. 513 * 514 * @param request BleRequest sent by a nanoapp. 515 */ 516 static bool validateParams(const BleRequest &request); 517 518 /** 519 * Posts the result of a BLE start/stop scan request. 520 * 521 * @param instanceId The nanoapp instance ID that made the request. 522 * @param requestType The type of BLE request the nanoapp issued. 523 * @param success true if the operation was successful. 524 * @param errorCode the error code as a result of this operation. 525 * @param cookie The cookie to be provided to the nanoapp. 526 */ 527 static void postAsyncResultEventFatal(uint16_t instanceId, 528 uint8_t requestType, bool success, 529 uint8_t errorCode, const void *cookie); 530 531 /** 532 * @return True if the given advertisement type is valid 533 */ 534 static bool isValidAdType(uint8_t adType); 535 536 #ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED 537 /** 538 * Handles a readRssi response from the BLE PAL. 539 * Runs in the context of the CHRE thread. 540 * 541 * @param errorCode error code from enum chreError, with CHRE_ERROR_NONE 542 * indicating a successful response. 543 * @param connectionHandle the handle upon which the RSSI was read 544 * @param rssi the RSSI read, if successful 545 */ 546 void handleReadRssiSync(uint8_t errorCode, uint16_t connectionHandle, 547 int8_t rssi); 548 549 /** 550 * Posts a CHRE_EVENT_BLE_RSSI_READ event for the first request in 551 * mPendingRssiRequests with the specified errorCode and RSSI, and dequeues it 552 * from the queue. 553 * 554 * It is assumed that a pending request exists. Note that this does not 555 * dispatch the next request in the queue. 556 * 557 * @param errorCode the errorCode to include in the event 558 * @param rssi the RSSI to include in the event 559 */ 560 void resolvePendingRssiRequest(uint8_t errorCode, int8_t rssi); 561 562 /** 563 * Dispatches the next RSSI request in the queue, if one exists. Must only 564 * be called if no request is presently outstanding (i.e. right after the 565 * previous request completes, or when no previous request existed). 566 * 567 * If the request fails synchronously, it will be dequeued and the failure 568 * event CHRE_EVENT_BLE_RSSI_READ will be sent. It will then try to 569 * dispatch the next request in the queue until either a request succeeds, 570 * or the queue is depleted. 571 */ 572 void dispatchNextRssiRequestIfAny(); 573 574 /** 575 * Checks BLE settings and, if enabled, issues a request to the PAL to read 576 * RSSI. Returns CHRE_ERROR_FUNCTION_DISABLED if BLE is disabled and 577 * CHRE_ERROR if the PAL returns an error. 578 * 579 * @param connectionHandle 580 * @return uint8_t the error code, with CHRE_ERROR_NONE indicating success 581 */ 582 uint8_t readRssi(uint16_t connectionHandle); 583 #endif 584 585 /** 586 * @return true if BLE setting is enabled. 587 */ 588 bool bleSettingEnabled(); 589 }; 590 591 } // namespace chre 592 593 #endif // CHRE_CORE_BLE_REQUEST_MANAGER_H_ 594