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