1 /*
2 * Copyright 2020 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 #define LOG_TAG "bt_shim_advertiser"
18
19 #include "le_advertising_manager.h"
20
21 #include <bluetooth/log.h>
22 #include <hardware/bluetooth.h>
23 #include <hardware/bt_gatt.h>
24
25 #include <vector>
26
27 #include "btif/include/btif_common.h"
28 #include "common/init_flags.h"
29 #include "hci/le_advertising_manager.h"
30 #include "main/shim/entry.h"
31 #include "main/shim/helpers.h"
32 #include "stack/include/btm_log_history.h"
33 #include "stack/include/main_thread.h"
34 #include "types/raw_address.h"
35 #include "utils.h"
36
37 using bluetooth::hci::Address;
38 using bluetooth::hci::AddressType;
39 using bluetooth::hci::AdvertiserAddressType;
40 using bluetooth::hci::ErrorCode;
41 using bluetooth::hci::GapData;
42 using bluetooth::hci::OwnAddressType;
43 using bluetooth::shim::parse_gap_data;
44 using std::vector;
45 using namespace bluetooth;
46
47 namespace {
48 constexpr char kBtmLogTag[] = "ADV";
49 }
50
51 class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface,
52 public bluetooth::hci::AdvertisingCallback {
53 public:
~BleAdvertiserInterfaceImpl()54 ~BleAdvertiserInterfaceImpl() override{};
55
Init()56 void Init() {
57 // Register callback
58 bluetooth::shim::GetAdvertising()->RegisterAdvertisingCallback(this);
59 }
60
RegisterAdvertiser(IdStatusCallback cb)61 void RegisterAdvertiser(IdStatusCallback cb) override {
62 log::info("in shim layer");
63
64 bluetooth::shim::GetAdvertising()->RegisterAdvertiser(
65 bluetooth::shim::GetGdShimHandler()->BindOnce(
66 [](IdStatusCallback cb, uint8_t id, uint8_t status) {
67 do_in_main_thread(
68 FROM_HERE,
69 base::BindOnce([](IdStatusCallback cb, uint8_t id,
70 uint8_t status) { cb.Run(id, status); },
71 cb, id, status));
72 },
73 cb));
74 }
75
Unregister(uint8_t advertiser_id)76 void Unregister(uint8_t advertiser_id) override {
77 log::info("in shim layer");
78 bluetooth::shim::GetAdvertising()->RemoveAdvertiser(advertiser_id);
79 int reg_id =
80 bluetooth::shim::GetAdvertising()->GetAdvertiserRegId(advertiser_id);
81 uint8_t client_id = is_native_advertiser(reg_id);
82 // if registered by native client, remove the register id
83 if (client_id != kAdvertiserClientIdJni) {
84 native_reg_id_map[client_id].erase(reg_id);
85 }
86 BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le advert stopped",
87 base::StringPrintf("advert_id:%d", advertiser_id));
88 }
89
GetOwnAddress(uint8_t advertiser_id,GetAddressCallback cb)90 void GetOwnAddress(uint8_t advertiser_id, GetAddressCallback cb) override {
91 log::info("in shim layer");
92 address_callbacks_[advertiser_id] = jni_thread_wrapper(cb);
93 bluetooth::shim::GetAdvertising()->GetOwnAddress(advertiser_id);
94 }
95
SetParameters(uint8_t advertiser_id,AdvertiseParameters params,ParametersCallback)96 void SetParameters(uint8_t advertiser_id, AdvertiseParameters params,
97 ParametersCallback /* cb */) override {
98 log::info("in shim layer");
99 bluetooth::hci::AdvertisingConfig config{};
100 parse_parameter(config, params);
101 bluetooth::shim::GetAdvertising()->SetParameters(advertiser_id, config);
102 }
103
SetData(int advertiser_id,bool set_scan_rsp,vector<uint8_t> data,StatusCallback)104 void SetData(int advertiser_id, bool set_scan_rsp, vector<uint8_t> data,
105 StatusCallback /* cb */) override {
106 log::info("in shim layer");
107 std::vector<GapData> advertising_data = {};
108 parse_gap_data(data, advertising_data);
109 bluetooth::shim::GetAdvertising()->SetData(advertiser_id, set_scan_rsp,
110 advertising_data);
111 }
112
Enable(uint8_t advertiser_id,bool enable,StatusCallback,uint16_t duration,uint8_t maxExtAdvEvents,StatusCallback)113 void Enable(uint8_t advertiser_id, bool enable, StatusCallback /* cb */,
114 uint16_t duration, uint8_t maxExtAdvEvents,
115 StatusCallback /* timeout_cb */) override {
116 log::info("in shim layer");
117 bluetooth::shim::GetAdvertising()->EnableAdvertiser(
118 advertiser_id, enable, duration, maxExtAdvEvents);
119 }
120
121 // nobody use this function
StartAdvertising(uint8_t advertiser_id,StatusCallback cb,AdvertiseParameters params,std::vector<uint8_t> advertise_data,std::vector<uint8_t> scan_response_data,int timeout_s,StatusCallback timeout_cb)122 void StartAdvertising(uint8_t advertiser_id, StatusCallback cb,
123 AdvertiseParameters params,
124 std::vector<uint8_t> advertise_data,
125 std::vector<uint8_t> scan_response_data, int timeout_s,
126 StatusCallback timeout_cb) override {
127 log::info("in shim layer");
128
129 bluetooth::hci::AdvertisingConfig config{};
130 parse_parameter(config, params);
131
132 parse_gap_data(advertise_data, config.advertisement);
133 parse_gap_data(scan_response_data, config.scan_response);
134
135 bluetooth::shim::GetAdvertising()->StartAdvertising(
136 advertiser_id, config, timeout_s * 100, cb, timeout_cb, scan_callback,
137 set_terminated_callback, bluetooth::shim::GetGdShimHandler());
138 }
139
StartAdvertisingSet(uint8_t client_id,int reg_id,IdTxPowerStatusCallback,AdvertiseParameters params,std::vector<uint8_t> advertise_data,std::vector<uint8_t> scan_response_data,PeriodicAdvertisingParameters periodic_params,std::vector<uint8_t> periodic_data,uint16_t duration,uint8_t maxExtAdvEvents,IdStatusCallback)140 void StartAdvertisingSet(uint8_t client_id, int reg_id,
141 IdTxPowerStatusCallback /* register_cb */,
142 AdvertiseParameters params,
143 std::vector<uint8_t> advertise_data,
144 std::vector<uint8_t> scan_response_data,
145 PeriodicAdvertisingParameters periodic_params,
146 std::vector<uint8_t> periodic_data,
147 uint16_t duration, uint8_t maxExtAdvEvents,
148 IdStatusCallback /* timeout_cb */) {
149 log::info("in shim layer");
150
151 bluetooth::hci::AdvertisingConfig config{};
152 parse_parameter(config, params);
153 parse_periodic_advertising_parameter(config.periodic_advertising_parameters,
154 periodic_params);
155
156 parse_gap_data(advertise_data, config.advertisement);
157 parse_gap_data(scan_response_data, config.scan_response);
158 parse_gap_data(periodic_data, config.periodic_data);
159
160 // if registered by native client, add the register id
161 if (client_id != kAdvertiserClientIdJni) {
162 native_reg_id_map[client_id].insert(reg_id);
163 }
164
165 bluetooth::shim::GetAdvertising()->ExtendedCreateAdvertiser(
166 client_id, reg_id, config, scan_callback, set_terminated_callback,
167 duration, maxExtAdvEvents, bluetooth::shim::GetGdShimHandler());
168
169 log::info("create advertising set, client_id:{}, reg_id:{}", client_id,
170 reg_id);
171 BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le advert started",
172 base::StringPrintf("reg_id:%d", reg_id));
173
174 return;
175 }
176
SetPeriodicAdvertisingParameters(int advertiser_id,PeriodicAdvertisingParameters periodic_params,StatusCallback)177 void SetPeriodicAdvertisingParameters(
178 int advertiser_id, PeriodicAdvertisingParameters periodic_params,
179 StatusCallback /* cb */) override {
180 log::info("in shim layer");
181 bluetooth::hci::PeriodicAdvertisingParameters parameters;
182 parameters.max_interval = periodic_params.max_interval;
183 parameters.min_interval = periodic_params.min_interval;
184 parameters.properties = periodic_params.periodic_advertising_properties;
185 bluetooth::shim::GetAdvertising()->SetPeriodicParameters(advertiser_id,
186 parameters);
187 }
188
SetPeriodicAdvertisingData(int advertiser_id,std::vector<uint8_t> data,StatusCallback)189 void SetPeriodicAdvertisingData(int advertiser_id, std::vector<uint8_t> data,
190 StatusCallback /* cb */) override {
191 log::info("in shim layer");
192 std::vector<GapData> advertising_data = {};
193 parse_gap_data(data, advertising_data);
194 bluetooth::shim::GetAdvertising()->SetPeriodicData(advertiser_id,
195 advertising_data);
196 }
197
SetPeriodicAdvertisingEnable(int advertiser_id,bool enable,bool include_adi,StatusCallback)198 void SetPeriodicAdvertisingEnable(int advertiser_id, bool enable,
199 bool include_adi,
200 StatusCallback /* cb */) override {
201 log::info("in shim layer");
202 bluetooth::shim::GetAdvertising()->EnablePeriodicAdvertising(
203 advertiser_id, enable, include_adi);
204 }
205
RegisterCallbacks(AdvertisingCallbacks * callbacks)206 void RegisterCallbacks(AdvertisingCallbacks* callbacks) {
207 advertising_callbacks_ = callbacks;
208 }
209
RegisterCallbacksNative(AdvertisingCallbacks * callbacks,uint8_t client_id)210 void RegisterCallbacksNative(AdvertisingCallbacks* callbacks,
211 uint8_t client_id) {
212 native_adv_callbacks_map_[client_id] = callbacks;
213 }
214
on_scan(Address,AddressType)215 void on_scan(Address /* address */, AddressType /* address_type */) {
216 log::info("in shim layer");
217 }
218
on_set_terminated(ErrorCode,uint8_t,uint8_t)219 void on_set_terminated(ErrorCode /* error_code */, uint8_t, uint8_t) {
220 log::info("in shim layer");
221 }
222
223 const bluetooth::common::Callback<void(Address, AddressType)> scan_callback =
224 bluetooth::common::Bind(&BleAdvertiserInterfaceImpl::on_scan,
225 bluetooth::common::Unretained(this));
226
227 const bluetooth::common::Callback<void(ErrorCode, uint8_t, uint8_t)>
228 set_terminated_callback = bluetooth::common::Bind(
229 &BleAdvertiserInterfaceImpl::on_set_terminated,
230 bluetooth::common::Unretained(this));
231
232 // AdvertisingCallback
OnAdvertisingSetStarted(int reg_id,uint8_t advertiser_id,int8_t tx_power,AdvertisingStatus status)233 void OnAdvertisingSetStarted(int reg_id, uint8_t advertiser_id,
234 int8_t tx_power,
235 AdvertisingStatus status) override {
236 uint8_t client_id = is_native_advertiser(reg_id);
237 if (client_id != kAdvertiserClientIdJni) {
238 // Invoke callback for native client
239 do_in_main_thread(
240 FROM_HERE,
241 base::Bind(&AdvertisingCallbacks::OnAdvertisingSetStarted,
242 base::Unretained(native_adv_callbacks_map_[client_id]),
243 reg_id, advertiser_id, tx_power, status));
244 return;
245 }
246 do_in_jni_thread(
247 base::BindOnce(&AdvertisingCallbacks::OnAdvertisingSetStarted,
248 base::Unretained(advertising_callbacks_), reg_id,
249 advertiser_id, tx_power, status));
250 }
251
OnAdvertisingEnabled(uint8_t advertiser_id,bool enable,uint8_t status)252 void OnAdvertisingEnabled(uint8_t advertiser_id, bool enable,
253 uint8_t status) {
254 int reg_id =
255 bluetooth::shim::GetAdvertising()->GetAdvertiserRegId(advertiser_id);
256 uint8_t client_id = is_native_advertiser(reg_id);
257 if (client_id != kAdvertiserClientIdJni) {
258 // Invoke callback for native client
259 do_in_main_thread(
260 FROM_HERE,
261 base::Bind(&AdvertisingCallbacks::OnAdvertisingEnabled,
262 base::Unretained(native_adv_callbacks_map_[client_id]),
263 advertiser_id, enable, status));
264 return;
265 }
266 do_in_jni_thread(base::BindOnce(&AdvertisingCallbacks::OnAdvertisingEnabled,
267 base::Unretained(advertising_callbacks_),
268 advertiser_id, enable, status));
269 }
270
OnAdvertisingDataSet(uint8_t advertiser_id,uint8_t status)271 void OnAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) {
272 do_in_jni_thread(base::BindOnce(&AdvertisingCallbacks::OnAdvertisingDataSet,
273 base::Unretained(advertising_callbacks_),
274 advertiser_id, status));
275 }
OnScanResponseDataSet(uint8_t advertiser_id,uint8_t status)276 void OnScanResponseDataSet(uint8_t advertiser_id, uint8_t status) {
277 do_in_jni_thread(base::BindOnce(
278 &AdvertisingCallbacks::OnScanResponseDataSet,
279 base::Unretained(advertising_callbacks_), advertiser_id, status));
280 }
281
OnAdvertisingParametersUpdated(uint8_t advertiser_id,int8_t tx_power,uint8_t status)282 void OnAdvertisingParametersUpdated(uint8_t advertiser_id, int8_t tx_power,
283 uint8_t status) {
284 do_in_jni_thread(
285 base::BindOnce(&AdvertisingCallbacks::OnAdvertisingParametersUpdated,
286 base::Unretained(advertising_callbacks_), advertiser_id,
287 tx_power, status));
288 }
289
OnPeriodicAdvertisingParametersUpdated(uint8_t advertiser_id,uint8_t status)290 void OnPeriodicAdvertisingParametersUpdated(uint8_t advertiser_id,
291 uint8_t status) {
292 do_in_jni_thread(base::BindOnce(
293 &AdvertisingCallbacks::OnPeriodicAdvertisingParametersUpdated,
294 base::Unretained(advertising_callbacks_), advertiser_id, status));
295 }
296
OnPeriodicAdvertisingDataSet(uint8_t advertiser_id,uint8_t status)297 void OnPeriodicAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) {
298 do_in_jni_thread(base::BindOnce(
299 &AdvertisingCallbacks::OnPeriodicAdvertisingDataSet,
300 base::Unretained(advertising_callbacks_), advertiser_id, status));
301 }
302
OnPeriodicAdvertisingEnabled(uint8_t advertiser_id,bool enable,uint8_t status)303 void OnPeriodicAdvertisingEnabled(uint8_t advertiser_id, bool enable,
304 uint8_t status) {
305 do_in_jni_thread(
306 base::BindOnce(&AdvertisingCallbacks::OnPeriodicAdvertisingEnabled,
307 base::Unretained(advertising_callbacks_), advertiser_id,
308 enable, status));
309 }
310
OnOwnAddressRead(uint8_t advertiser_id,uint8_t address_type,bluetooth::hci::Address address)311 void OnOwnAddressRead(uint8_t advertiser_id, uint8_t address_type,
312 bluetooth::hci::Address address) {
313 RawAddress raw_address = bluetooth::ToRawAddress(address);
314 if (address_callbacks_.find(advertiser_id) != address_callbacks_.end()) {
315 address_callbacks_[advertiser_id].Run(address_type, raw_address);
316 address_callbacks_.erase(advertiser_id);
317 return;
318 }
319 do_in_jni_thread(base::BindOnce(&AdvertisingCallbacks::OnOwnAddressRead,
320 base::Unretained(advertising_callbacks_),
321 advertiser_id, address_type, raw_address));
322 }
323
324 AdvertisingCallbacks* advertising_callbacks_;
325 std::map<uint8_t, AdvertisingCallbacks*> native_adv_callbacks_map_;
326
327 private:
parse_parameter(bluetooth::hci::AdvertisingConfig & config,AdvertiseParameters params)328 void parse_parameter(bluetooth::hci::AdvertisingConfig& config,
329 AdvertiseParameters params) {
330 config.connectable = params.advertising_event_properties & 0x01;
331 config.scannable = params.advertising_event_properties & 0x02;
332 config.discoverable = params.advertising_event_properties & 0x04;
333 config.legacy_pdus = params.advertising_event_properties & 0x10;
334 config.anonymous = params.advertising_event_properties & 0x20;
335 config.include_tx_power = params.advertising_event_properties & 0x40;
336 config.interval_min = params.min_interval;
337 config.interval_max = params.max_interval;
338 config.channel_map = params.channel_map;
339 config.tx_power = params.tx_power;
340 config.use_le_coded_phy = params.primary_advertising_phy == 0x03;
341 config.secondary_advertising_phy =
342 static_cast<bluetooth::hci::SecondaryPhyType>(
343 params.secondary_advertising_phy);
344 config.enable_scan_request_notifications =
345 static_cast<bluetooth::hci::Enable>(
346 params.scan_request_notification_enable);
347 // Matching the ADDRESS_TYPE_* enums from Java
348 switch (params.own_address_type) {
349 case -1:
350 config.requested_advertiser_address_type =
351 AdvertiserAddressType::RESOLVABLE_RANDOM;
352 break;
353 case 0:
354 config.requested_advertiser_address_type =
355 AdvertiserAddressType::PUBLIC;
356 break;
357 case 1:
358 config.requested_advertiser_address_type =
359 AdvertiserAddressType::RESOLVABLE_RANDOM;
360 break;
361 case 2:
362 config.requested_advertiser_address_type =
363 AdvertiserAddressType::NONRESOLVABLE_RANDOM;
364 break;
365 default:
366 log::error("Received unexpected address type: {}",
367 params.own_address_type);
368 config.requested_advertiser_address_type =
369 AdvertiserAddressType::RESOLVABLE_RANDOM;
370 }
371 }
372
parse_periodic_advertising_parameter(bluetooth::hci::PeriodicAdvertisingParameters & config,PeriodicAdvertisingParameters periodic_params)373 void parse_periodic_advertising_parameter(
374 bluetooth::hci::PeriodicAdvertisingParameters& config,
375 PeriodicAdvertisingParameters periodic_params) {
376 config.max_interval = periodic_params.max_interval;
377 config.min_interval = periodic_params.min_interval;
378 config.properties = periodic_params.periodic_advertising_properties;
379 config.enable = periodic_params.enable;
380 config.include_adi = periodic_params.include_adi;
381 }
382
is_native_advertiser(int reg_id)383 uint8_t is_native_advertiser(int reg_id) {
384 // Return client id if it's native advertiser, otherwise return jni id as
385 // default
386 for (auto const& entry : native_adv_callbacks_map_) {
387 if (native_reg_id_map[entry.first].count(reg_id)) {
388 return entry.first;
389 }
390 }
391 return kAdvertiserClientIdJni;
392 }
393
394 std::map<uint8_t, GetAddressCallback> address_callbacks_;
395 std::map<uint8_t, std::set<int>> native_reg_id_map;
396 };
397
398 BleAdvertiserInterfaceImpl* bt_le_advertiser_instance = nullptr;
399
get_ble_advertiser_instance()400 BleAdvertiserInterface* bluetooth::shim::get_ble_advertiser_instance() {
401 if (bt_le_advertiser_instance == nullptr) {
402 bt_le_advertiser_instance = new BleAdvertiserInterfaceImpl();
403 }
404 return bt_le_advertiser_instance;
405 };
406
init_advertising_manager()407 void bluetooth::shim::init_advertising_manager() {
408 static_cast<BleAdvertiserInterfaceImpl*>(
409 bluetooth::shim::get_ble_advertiser_instance())
410 ->Init();
411 }
412