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