• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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