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