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