• 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 #include "chre/core/ble_request_manager.h"
18 
19 #include "chre/core/event_loop_manager.h"
20 #include "chre/platform/fatal_error.h"
21 #include "chre/platform/log.h"
22 #include "chre/util/nested_data_ptr.h"
23 
24 namespace chre {
25 
init()26 void BleRequestManager::init() {
27   mPlatformBle.init();
28 }
29 
getCapabilities()30 uint32_t BleRequestManager::getCapabilities() {
31   return mPlatformBle.getCapabilities();
32 }
33 
getFilterCapabilities()34 uint32_t BleRequestManager::getFilterCapabilities() {
35   return mPlatformBle.getFilterCapabilities();
36 }
37 
handleExistingRequest(uint16_t instanceId,bool * hasExistingRequest,size_t * requestIndex)38 void BleRequestManager::handleExistingRequest(uint16_t instanceId,
39                                               bool *hasExistingRequest,
40                                               size_t *requestIndex) {
41   const BleRequest *foundRequest =
42       mRequests.findRequest(instanceId, requestIndex);
43   *hasExistingRequest = (foundRequest != nullptr);
44   if (foundRequest != nullptr &&
45       foundRequest->getRequestStatus() != RequestStatus::APPLIED) {
46     handleAsyncResult(instanceId, foundRequest->isEnabled(),
47                       false /* success */, CHRE_ERROR_OBSOLETE_REQUEST,
48                       true /* forceUnregister */);
49   }
50 }
51 
compliesWithBleSetting(uint16_t instanceId,bool enabled,bool hasExistingRequest,size_t requestIndex)52 bool BleRequestManager::compliesWithBleSetting(uint16_t instanceId,
53                                                bool enabled,
54                                                bool hasExistingRequest,
55                                                size_t requestIndex) {
56   bool success = true;
57   if (enabled && !bleSettingEnabled()) {
58     success = false;
59     handleAsyncResult(instanceId, enabled, false /* success */,
60                       CHRE_ERROR_FUNCTION_DISABLED);
61     if (hasExistingRequest) {
62       bool requestChanged = false;
63       mRequests.removeRequest(requestIndex, &requestChanged);
64     }
65   }
66   return success;
67 }
68 
updateRequests(BleRequest && request,bool hasExistingRequest,bool * requestChanged,size_t * requestIndex)69 bool BleRequestManager::updateRequests(BleRequest &&request,
70                                        bool hasExistingRequest,
71                                        bool *requestChanged,
72                                        size_t *requestIndex) {
73   bool success = true;
74   if (hasExistingRequest) {
75     mRequests.updateRequest(*requestIndex, std::move(request), requestChanged);
76   } else if (request.isEnabled()) {
77     success =
78         mRequests.addRequest(std::move(request), requestIndex, requestChanged);
79   } else {
80     // Already disabled requests shouldn't result in work for the PAL.
81     *requestChanged = false;
82     *requestIndex = mRequests.getRequests().size();
83   }
84   return success;
85 }
86 
startScanAsync(Nanoapp * nanoapp,chreBleScanMode mode,uint32_t reportDelayMs,const struct chreBleScanFilter * filter)87 bool BleRequestManager::startScanAsync(Nanoapp *nanoapp, chreBleScanMode mode,
88                                        uint32_t reportDelayMs,
89                                        const struct chreBleScanFilter *filter) {
90   CHRE_ASSERT(nanoapp);
91   BleRequest request(nanoapp->getInstanceId(), true, mode, reportDelayMs,
92                      filter);
93   return configure(std::move(request));
94 }
95 
stopScanAsync(Nanoapp * nanoapp)96 bool BleRequestManager::stopScanAsync(Nanoapp *nanoapp) {
97   CHRE_ASSERT(nanoapp);
98   BleRequest request(nanoapp->getInstanceId(), false /* enable */);
99   return configure(std::move(request));
100 }
101 
disableActiveScan(const Nanoapp * nanoapp)102 uint32_t BleRequestManager::disableActiveScan(const Nanoapp *nanoapp) {
103   CHRE_ASSERT(nanoapp);
104 
105   size_t requestIndex;
106   const BleRequest *foundRequest =
107       mRequests.findRequest(nanoapp->getInstanceId(), &requestIndex);
108 
109   if (foundRequest == nullptr || !foundRequest->isEnabled()) {
110     // No active request found.
111     return 0;
112   }
113 
114   BleRequest request(nanoapp->getInstanceId(), false /* enable */);
115   configure(std::move(request));
116   return 1;
117 }
118 
addBleRequestLog(uint32_t instanceId,bool enabled,size_t requestIndex,bool compliesWithBleSetting)119 void BleRequestManager::addBleRequestLog(uint32_t instanceId, bool enabled,
120                                          size_t requestIndex,
121                                          bool compliesWithBleSetting) {
122   BleRequestLog log(SystemTime::getMonotonicTime(), instanceId, enabled,
123                     compliesWithBleSetting);
124   if (enabled) {
125     if (instanceId == CHRE_INSTANCE_ID) {
126       log.populateRequestData(mRequests.getCurrentMaximalRequest());
127     } else if (compliesWithBleSetting) {
128       log.populateRequestData(mRequests.getRequests()[requestIndex]);
129     }
130   }
131   mBleRequestLogs.kick_push(log);
132 }
133 
configure(BleRequest && request)134 bool BleRequestManager::configure(BleRequest &&request) {
135   bool success = validateParams(request);
136   if (success) {
137     bool requestChanged = false;
138     size_t requestIndex = 0;
139     bool hasExistingRequest = false;
140     uint16_t instanceId = request.getInstanceId();
141     uint8_t enabled = request.isEnabled();
142     handleExistingRequest(instanceId, &hasExistingRequest, &requestIndex);
143     bool compliant = compliesWithBleSetting(instanceId, enabled,
144                                             hasExistingRequest, requestIndex);
145     if (compliant) {
146       success = updateRequests(std::move(request), hasExistingRequest,
147                                &requestChanged, &requestIndex);
148       if (success) {
149         if (!asyncResponsePending()) {
150           if (!requestChanged) {
151             handleAsyncResult(instanceId, enabled, true /* success */,
152                               CHRE_ERROR_NONE);
153             if (requestIndex < mRequests.getRequests().size()) {
154               mRequests.getMutableRequests()[requestIndex].setRequestStatus(
155                   RequestStatus::APPLIED);
156             }
157           } else {
158             success = controlPlatform();
159             if (!success) {
160               handleNanoappEventRegistration(instanceId, enabled,
161                                              false /* success */,
162                                              true /* forceUnregister */);
163               mRequests.removeRequest(requestIndex, &requestChanged);
164             }
165           }
166         }
167       }
168     }
169     if (success) {
170       addBleRequestLog(instanceId, enabled, requestIndex, compliant);
171     }
172   }
173   return success;
174 }
175 
controlPlatform()176 bool BleRequestManager::controlPlatform() {
177   bool success = false;
178   const BleRequest &maxRequest = mRequests.getCurrentMaximalRequest();
179   bool enable = bleSettingEnabled() && maxRequest.isEnabled();
180   if (enable) {
181     chreBleScanFilter filter = maxRequest.getScanFilter();
182     success = mPlatformBle.startScanAsync(
183         maxRequest.getMode(), maxRequest.getReportDelayMs(), &filter);
184     mPendingPlatformRequest =
185         BleRequest(0, enable, maxRequest.getMode(),
186                    maxRequest.getReportDelayMs(), &filter);
187   } else {
188     success = mPlatformBle.stopScanAsync();
189     mPendingPlatformRequest = BleRequest(0, enable);
190   }
191   if (success) {
192     for (BleRequest &req : mRequests.getMutableRequests()) {
193       if (req.getRequestStatus() == RequestStatus::PENDING_REQ) {
194         req.setRequestStatus(RequestStatus::PENDING_RESP);
195       }
196     }
197   }
198 
199   return success;
200 }
201 
handleFreeAdvertisingEvent(struct chreBleAdvertisementEvent * event)202 void BleRequestManager::handleFreeAdvertisingEvent(
203     struct chreBleAdvertisementEvent *event) {
204   mPlatformBle.releaseAdvertisingEvent(event);
205 }
206 
freeAdvertisingEventCallback(uint16_t,void * eventData)207 void BleRequestManager::freeAdvertisingEventCallback(uint16_t /* eventType */,
208                                                      void *eventData) {
209   auto event = static_cast<chreBleAdvertisementEvent *>(eventData);
210   EventLoopManagerSingleton::get()
211       ->getBleRequestManager()
212       .handleFreeAdvertisingEvent(event);
213 }
214 
handleAdvertisementEvent(struct chreBleAdvertisementEvent * event)215 void BleRequestManager::handleAdvertisementEvent(
216     struct chreBleAdvertisementEvent *event) {
217   EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
218       CHRE_EVENT_BLE_ADVERTISEMENT, event, freeAdvertisingEventCallback);
219 }
220 
handlePlatformChange(bool enable,uint8_t errorCode)221 void BleRequestManager::handlePlatformChange(bool enable, uint8_t errorCode) {
222   auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
223     bool enable = NestedDataPtr<bool>(data);
224     uint8_t errorCode = NestedDataPtr<uint8_t>(extraData);
225     EventLoopManagerSingleton::get()
226         ->getBleRequestManager()
227         .handlePlatformChangeSync(enable, errorCode);
228   };
229 
230   EventLoopManagerSingleton::get()->deferCallback(
231       SystemCallbackType::BleScanResponse, NestedDataPtr<bool>(enable),
232       callback, NestedDataPtr<uint8_t>(errorCode));
233 }
234 
handlePlatformChangeSync(bool enable,uint8_t errorCode)235 void BleRequestManager::handlePlatformChangeSync(bool enable,
236                                                  uint8_t errorCode) {
237   bool success = (errorCode == CHRE_ERROR_NONE);
238   if (mPendingPlatformRequest.isEnabled() != enable) {
239     errorCode = CHRE_ERROR;
240     success = false;
241     CHRE_ASSERT_LOG(false, "BLE PAL did not transition to expected state");
242   }
243   if (mInternalRequestPending) {
244     mInternalRequestPending = false;
245     if (!success) {
246       FATAL_ERROR("Failed to resync BLE platform");
247     }
248   } else {
249     for (BleRequest &req : mRequests.getMutableRequests()) {
250       if (req.getRequestStatus() == RequestStatus::PENDING_RESP) {
251         handleAsyncResult(req.getInstanceId(), req.isEnabled(), success,
252                           errorCode);
253         if (success) {
254           req.setRequestStatus(RequestStatus::APPLIED);
255         }
256       }
257     }
258 
259     if (!success) {
260       mRequests.removeRequests(RequestStatus::PENDING_RESP);
261     }
262   }
263   if (success) {
264     // No need to waste memory for requests that have no effect on the overall
265     // maximal request.
266     mRequests.removeDisabledRequests();
267     mActivePlatformRequest = std::move(mPendingPlatformRequest);
268   }
269 
270   dispatchPendingRequests();
271 
272   // Only clear mResyncPending if the request succeeded or after all pending
273   // requests are dispatched and a resync request can be issued with only the
274   // requests that were previously applied.
275   if (mResyncPending) {
276     if (success) {
277       mResyncPending = false;
278     } else if (!success && !asyncResponsePending()) {
279       mResyncPending = false;
280       updatePlatformRequest(true /* forceUpdate */);
281     }
282   }
283   // Finish dispatching pending requests before processing the setting change
284   // request to ensure nanoapps receive CHRE_ERROR_FUNCTION_DISABLED responses.
285   // If both a resync and a setting change are pending, prioritize the resync.
286   // If the resync successfully completes, the PAL will be in the correct state
287   // and updatePlatformRequest will not begin a new request.
288   if (mSettingChangePending && !asyncResponsePending()) {
289     updatePlatformRequest();
290     mSettingChangePending = false;
291   }
292 }
293 
dispatchPendingRequests()294 void BleRequestManager::dispatchPendingRequests() {
295   if (mRequests.hasRequests(RequestStatus::PENDING_REQ)) {
296     uint8_t errorCode = CHRE_ERROR_NONE;
297     if (!bleSettingEnabled() && mRequests.isMaximalRequestEnabled()) {
298       errorCode = CHRE_ERROR_FUNCTION_DISABLED;
299     } else if (!controlPlatform()) {
300       errorCode = CHRE_ERROR;
301     }
302     if (errorCode != CHRE_ERROR_NONE) {
303       for (const BleRequest &req : mRequests.getRequests()) {
304         if (req.getRequestStatus() == RequestStatus::PENDING_REQ) {
305           handleAsyncResult(req.getInstanceId(), req.isEnabled(),
306                             false /* success */, errorCode);
307         }
308       }
309       mRequests.removeRequests(RequestStatus::PENDING_REQ);
310     }
311   }
312 }
313 
handleAsyncResult(uint16_t instanceId,bool enabled,bool success,uint8_t errorCode,bool forceUnregister)314 void BleRequestManager::handleAsyncResult(uint16_t instanceId, bool enabled,
315                                           bool success, uint8_t errorCode,
316                                           bool forceUnregister) {
317   uint8_t requestType = enabled ? CHRE_BLE_REQUEST_TYPE_START_SCAN
318                                 : CHRE_BLE_REQUEST_TYPE_STOP_SCAN;
319   postAsyncResultEventFatal(instanceId, requestType, success, errorCode);
320   handleNanoappEventRegistration(instanceId, enabled, success, forceUnregister);
321 }
322 
handleNanoappEventRegistration(uint16_t instanceId,bool enabled,bool success,bool forceUnregister)323 void BleRequestManager::handleNanoappEventRegistration(uint16_t instanceId,
324                                                        bool enabled,
325                                                        bool success,
326                                                        bool forceUnregister) {
327   Nanoapp *nanoapp =
328       EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
329           instanceId);
330   if (nanoapp != nullptr) {
331     if (success && enabled) {
332       nanoapp->registerForBroadcastEvent(CHRE_EVENT_BLE_ADVERTISEMENT);
333     } else if (!enabled || forceUnregister) {
334       nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_BLE_ADVERTISEMENT);
335     }
336   }
337 }
338 
handleRequestStateResyncCallback()339 void BleRequestManager::handleRequestStateResyncCallback() {
340   auto callback = [](uint16_t /* eventType */, void * /* eventData */,
341                      void * /* extraData */) {
342     EventLoopManagerSingleton::get()
343         ->getBleRequestManager()
344         .handleRequestStateResyncCallbackSync();
345   };
346   EventLoopManagerSingleton::get()->deferCallback(
347       SystemCallbackType::BleRequestResyncEvent, nullptr /* data */, callback);
348 }
349 
handleRequestStateResyncCallbackSync()350 void BleRequestManager::handleRequestStateResyncCallbackSync() {
351   if (asyncResponsePending()) {
352     mResyncPending = true;
353   } else {
354     updatePlatformRequest(true /* forceUpdate */);
355   }
356 }
357 
onSettingChanged(Setting setting,bool)358 void BleRequestManager::onSettingChanged(Setting setting, bool /* state */) {
359   if (setting == Setting::BLE_AVAILABLE) {
360     if (asyncResponsePending()) {
361       mSettingChangePending = true;
362     } else {
363       updatePlatformRequest();
364     }
365   }
366 }
367 
updatePlatformRequest(bool forceUpdate)368 void BleRequestManager::updatePlatformRequest(bool forceUpdate) {
369   bool desiredPlatformState =
370       bleSettingEnabled() && mRequests.isMaximalRequestEnabled();
371   bool updatePlatform = (forceUpdate || (desiredPlatformState !=
372                                          mActivePlatformRequest.isEnabled()));
373 
374   if (updatePlatform) {
375     if (controlPlatform()) {
376       mInternalRequestPending = true;
377       addBleRequestLog(CHRE_INSTANCE_ID, desiredPlatformState,
378                        mRequests.getRequests().size(),
379                        true /* compliesWithBleSetting */);
380     } else {
381       FATAL_ERROR("Failed to send update BLE platform request");
382     }
383   }
384 }
385 
asyncResponsePending() const386 bool BleRequestManager::asyncResponsePending() const {
387   return (mInternalRequestPending ||
388           mRequests.hasRequests(RequestStatus::PENDING_RESP));
389 }
390 
validateParams(const BleRequest & request)391 bool BleRequestManager::validateParams(const BleRequest &request) {
392   bool valid = true;
393   if (request.isEnabled()) {
394     for (const chreBleGenericFilter &filter : request.getGenericFilters()) {
395       if (!isValidAdType(filter.type)) {
396         valid = false;
397         break;
398       }
399       if (filter.len == 0 || filter.len > CHRE_BLE_DATA_LEN_MAX) {
400         valid = false;
401         break;
402       }
403     }
404   }
405   return valid;
406 }
407 
postAsyncResultEventFatal(uint16_t instanceId,uint8_t requestType,bool success,uint8_t errorCode)408 void BleRequestManager::postAsyncResultEventFatal(uint16_t instanceId,
409                                                   uint8_t requestType,
410                                                   bool success,
411                                                   uint8_t errorCode) {
412   chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
413   if (event == nullptr) {
414     FATAL_ERROR("Failed to alloc BLE async result");
415   } else {
416     event->requestType = requestType;
417     event->success = success;
418     event->errorCode = errorCode;
419     event->reserved = 0;
420 
421     EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
422         CHRE_EVENT_BLE_ASYNC_RESULT, event, freeEventDataCallback, instanceId);
423   }
424 }
425 
isValidAdType(uint8_t adType)426 bool BleRequestManager::isValidAdType(uint8_t adType) {
427   return adType == CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16;
428 }
429 
bleSettingEnabled()430 bool BleRequestManager::bleSettingEnabled() {
431   return EventLoopManagerSingleton::get()
432       ->getSettingManager()
433       .getSettingEnabled(Setting::BLE_AVAILABLE);
434 }
435 
logStateToBuffer(DebugDumpWrapper & debugDump) const436 void BleRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const {
437   debugDump.print("\nBLE:\n");
438   debugDump.print(" Active Platform Request:\n");
439   mActivePlatformRequest.logStateToBuffer(debugDump,
440                                           true /* isPlatformRequest */);
441   if (asyncResponsePending()) {
442     debugDump.print(" Pending Platform Request:\n");
443     mPendingPlatformRequest.logStateToBuffer(debugDump,
444                                              true /* isPlatformRequest */);
445   }
446   debugDump.print(" Request Multiplexer:\n");
447   for (const BleRequest &req : mRequests.getRequests()) {
448     req.logStateToBuffer(debugDump);
449   }
450   debugDump.print(" Last %zu valid BLE requests:\n", mBleRequestLogs.size());
451   static_assert(kNumBleRequestLogs <= INT8_MAX,
452                 "kNumBleRequestLogs must be less than INT8_MAX.");
453   for (int8_t i = static_cast<int8_t>(mBleRequestLogs.size()) - 1; i >= 0;
454        i--) {
455     const auto &log = mBleRequestLogs[static_cast<size_t>(i)];
456     debugDump.print("  ts=%" PRIu64 " instanceId=%" PRIu32 " %s",
457                     log.timestamp.toRawNanoseconds(), log.instanceId,
458                     log.enable ? "enable" : "disable\n");
459     if (log.enable && log.compliesWithBleSetting) {
460       debugDump.print(" mode=%" PRIu8 " reportDelayMs=%" PRIu32
461                       " rssiThreshold=%" PRId8 " scanCount=%" PRIu8 "\n",
462                       log.mode, log.reportDelayMs, log.rssiThreshold,
463                       log.scanFilterCount);
464     } else if (log.enable) {
465       debugDump.print(" request did not comply with BLE setting\n");
466     }
467   }
468 }
469 
470 }  // namespace chre
471