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