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/pal/ble.h"
18
19 #include "chre.h"
20 #include "chre/platform/linux/pal_ble.h"
21 #include "chre/platform/linux/task_util/task_manager.h"
22 #include "chre/util/memory.h"
23 #include "chre/util/unique_ptr.h"
24
25 #include <chrono>
26 #include <optional>
27 #include <vector>
28
29 /**
30 * A simulated implementation of the BLE PAL for the linux platform.
31 */
32 namespace {
33
34 using ::chre::TaskManagerSingleton;
35
36 const struct chrePalSystemApi *gSystemApi = nullptr;
37 const struct chrePalBleCallbacks *gCallbacks = nullptr;
38
39 bool gBleEnabled = false;
40 bool gDelayScanStart = false;
41
42 std::mutex gBatchMutex;
43 std::vector<struct chreBleAdvertisementEvent *> gBatchedAdEvents;
44 std::chrono::time_point<std::chrono::steady_clock> gLastAdDataTimestamp;
45 std::optional<uint32_t> gReportDelayMs;
46 std::chrono::nanoseconds gScanInterval = std::chrono::milliseconds(1400);
47
48 // Tasks for startScan, sendAdReportEvents, and stopScan.
49 std::optional<uint32_t> gBleAdReportEventTaskId;
50 std::optional<uint32_t> gBleFlushTaskId;
51
updateScanInterval(chreBleScanMode mode)52 void updateScanInterval(chreBleScanMode mode) {
53 gScanInterval = std::chrono::milliseconds(1400);
54 switch (mode) {
55 case CHRE_BLE_SCAN_MODE_BACKGROUND:
56 gScanInterval = std::chrono::milliseconds(1400);
57 break;
58 case CHRE_BLE_SCAN_MODE_FOREGROUND:
59 gScanInterval = std::chrono::milliseconds(700);
60 break;
61 case CHRE_BLE_SCAN_MODE_AGGRESSIVE:
62 gScanInterval = std::chrono::milliseconds(100);
63 break;
64 }
65 }
66
flush()67 void flush() {
68 std::lock_guard<std::mutex> lock(gBatchMutex);
69 for (struct chreBleAdvertisementEvent *batchedEvent : gBatchedAdEvents) {
70 gCallbacks->advertisingEventCallback(batchedEvent);
71 }
72 gBatchedAdEvents.clear();
73 gLastAdDataTimestamp = std::chrono::steady_clock::now();
74 }
75
sendAdReportEvents()76 void sendAdReportEvents() {
77 auto event = chre::MakeUniqueZeroFill<struct chreBleAdvertisementEvent>();
78 auto report = chre::MakeUniqueZeroFill<struct chreBleAdvertisingReport>();
79 uint8_t *data =
80 static_cast<uint8_t *>(chre::memoryAlloc(sizeof(uint8_t) * 2));
81 data[0] = 0x01;
82 data[1] = 0x16;
83 report->timestamp = chreGetTime();
84 report->data = data;
85 report->dataLength = 2;
86 event->reports = report.release();
87 event->numReports = 1;
88
89 std::lock_guard<std::mutex> lock(gBatchMutex);
90 if (!gReportDelayMs.has_value() || gReportDelayMs.value() == 0) {
91 gCallbacks->advertisingEventCallback(event.release());
92 } else {
93 gBatchedAdEvents.push_back(event.release());
94 }
95 }
96
stopAllTasks()97 void stopAllTasks() {
98 if (gBleAdReportEventTaskId.has_value()) {
99 TaskManagerSingleton::get()->cancelTask(gBleAdReportEventTaskId.value());
100 gBleAdReportEventTaskId.reset();
101 }
102
103 if (gBleFlushTaskId.has_value()) {
104 TaskManagerSingleton::get()->cancelTask(gBleFlushTaskId.value());
105 gBleFlushTaskId.reset();
106 }
107 }
108
startScan()109 bool startScan() {
110 stopAllTasks();
111
112 std::lock_guard<std::mutex> lock(gBatchMutex);
113 gLastAdDataTimestamp = std::chrono::steady_clock::now();
114
115 gBleAdReportEventTaskId =
116 TaskManagerSingleton::get()->addTask(sendAdReportEvents, gScanInterval);
117 if (!gBleAdReportEventTaskId.has_value()) {
118 return false;
119 }
120
121 if (gReportDelayMs.has_value()) {
122 gBleFlushTaskId = TaskManagerSingleton::get()->addTask(
123 flush, std::chrono::duration_cast<std::chrono::nanoseconds>(
124 std::chrono::milliseconds(gReportDelayMs.value())));
125 if (!gBleFlushTaskId.has_value()) {
126 stopAllTasks();
127 return false;
128 }
129 }
130
131 std::optional<uint32_t> callbackTaskId = TaskManagerSingleton::get()->addTask(
132 []() { gCallbacks->scanStatusChangeCallback(true, CHRE_ERROR_NONE); });
133 if (!callbackTaskId.has_value()) {
134 stopAllTasks();
135 return false;
136 }
137
138 gBleEnabled = true;
139 return true;
140 }
141
chrePalBleGetCapabilities()142 uint32_t chrePalBleGetCapabilities() {
143 return CHRE_BLE_CAPABILITIES_SCAN |
144 CHRE_BLE_CAPABILITIES_SCAN_RESULT_BATCHING |
145 CHRE_BLE_CAPABILITIES_SCAN_FILTER_BEST_EFFORT;
146 }
147
chrePalBleGetFilterCapabilities()148 uint32_t chrePalBleGetFilterCapabilities() {
149 return CHRE_BLE_FILTER_CAPABILITIES_RSSI |
150 CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA;
151 }
152
chrePalBleStartScan(chreBleScanMode mode,uint32_t reportDelayMs,const struct chreBleScanFilterV1_9 *)153 bool chrePalBleStartScan(chreBleScanMode mode, uint32_t reportDelayMs,
154 const struct chreBleScanFilterV1_9 * /* filter */) {
155 {
156 std::lock_guard<std::mutex> lock(gBatchMutex);
157
158 if (gReportDelayMs.has_value()) {
159 gReportDelayMs = std::min(gReportDelayMs.value(), reportDelayMs);
160 } else {
161 gReportDelayMs = reportDelayMs;
162 }
163 }
164
165 updateScanInterval(mode);
166 flush();
167 return gDelayScanStart || startScan();
168 }
169
chrePalBleStopScan()170 bool chrePalBleStopScan() {
171 stopAllTasks();
172 flush();
173
174 std::optional<uint32_t> callbackTaskId = TaskManagerSingleton::get()->addTask(
175 []() { gCallbacks->scanStatusChangeCallback(false, CHRE_ERROR_NONE); });
176
177 // If the callback is successfully scheduled, then BLE is disabled.
178 gBleEnabled = !callbackTaskId.has_value();
179 return callbackTaskId.has_value();
180 }
181
chrePalBleReleaseAdvertisingEvent(struct chreBleAdvertisementEvent * event)182 void chrePalBleReleaseAdvertisingEvent(
183 struct chreBleAdvertisementEvent *event) {
184 for (size_t i = 0; i < event->numReports; i++) {
185 auto report = const_cast<chreBleAdvertisingReport *>(&(event->reports[i]));
186 chre::memoryFree(const_cast<uint8_t *>(report->data));
187 }
188 chre::memoryFree(const_cast<chreBleAdvertisingReport *>(event->reports));
189 chre::memoryFree(event);
190 }
191
chrePalBleReadRssi(uint16_t connectionHandle)192 bool chrePalBleReadRssi(uint16_t connectionHandle) {
193 std::optional<uint32_t> readRssiTaskId =
194 TaskManagerSingleton::get()->addTask([connectionHandle]() {
195 gCallbacks->readRssiCallback(CHRE_ERROR_NONE, connectionHandle, -65);
196 });
197
198 return readRssiTaskId.has_value();
199 }
200
chrePalBleFlush()201 bool chrePalBleFlush() {
202 std::optional<uint32_t> flushTaskId =
203 TaskManagerSingleton::get()->addTask([]() {
204 flush();
205 gCallbacks->flushCallback(CHRE_ERROR_NONE);
206 });
207
208 return flushTaskId.has_value();
209 }
210
chrePalBleApiClose()211 void chrePalBleApiClose() {
212 stopAllTasks();
213
214 {
215 std::lock_guard<std::mutex> lock(gBatchMutex);
216
217 for (struct chreBleAdvertisementEvent *batchedEvent : gBatchedAdEvents) {
218 chrePalBleReleaseAdvertisingEvent(batchedEvent);
219 }
220 }
221 }
222
chrePalBleApiOpen(const struct chrePalSystemApi * systemApi,const struct chrePalBleCallbacks * callbacks)223 bool chrePalBleApiOpen(const struct chrePalSystemApi *systemApi,
224 const struct chrePalBleCallbacks *callbacks) {
225 chrePalBleApiClose();
226
227 bool success = false;
228 if (systemApi != nullptr && callbacks != nullptr) {
229 gSystemApi = systemApi;
230 gCallbacks = callbacks;
231 success = true;
232 }
233
234 return success;
235 }
236
237 } // anonymous namespace
238
chrePalIsBleEnabled()239 bool chrePalIsBleEnabled() {
240 return gBleEnabled;
241 }
242
delayBleScanStart(bool delay)243 void delayBleScanStart(bool delay) {
244 gDelayScanStart = delay;
245 }
246
startBleScan()247 bool startBleScan() {
248 return startScan();
249 }
250
chrePalBleGetApi(uint32_t requestedApiVersion)251 const struct chrePalBleApi *chrePalBleGetApi(uint32_t requestedApiVersion) {
252 static const struct chrePalBleApi kApi = {
253 .moduleVersion = CHRE_PAL_BLE_API_CURRENT_VERSION,
254 .open = chrePalBleApiOpen,
255 .close = chrePalBleApiClose,
256 .getCapabilities = chrePalBleGetCapabilities,
257 .getFilterCapabilities = chrePalBleGetFilterCapabilities,
258 .startScan = chrePalBleStartScan,
259 .stopScan = chrePalBleStopScan,
260 .releaseAdvertisingEvent = chrePalBleReleaseAdvertisingEvent,
261 .readRssi = chrePalBleReadRssi,
262 .flush = chrePalBleFlush,
263 };
264
265 if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(kApi.moduleVersion,
266 requestedApiVersion)) {
267 return nullptr;
268 } else {
269 return &kApi;
270 }
271 }
272