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