xref: /aosp_15_r20/system/chre/core/include/chre/core/ble_request_manager.h (revision 84e339476a462649f82315436d70fd732297a399)
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