• 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/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