xref: /aosp_15_r20/system/chre/platform/linux/pal_ble.cc (revision 84e339476a462649f82315436d70fd732297a399)
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