| /* |
| * Copyright 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "bt_shim_advertiser" |
| |
| #include "le_advertising_manager.h" |
| |
| #include <hardware/bluetooth.h> |
| #include <hardware/bt_gatt.h> |
| |
| #include <vector> |
| |
| #include "btif/include/btif_common.h" |
| #include "gd/common/init_flags.h" |
| #include "gd/hci/acl_manager.h" |
| #include "gd/hci/controller.h" |
| #include "gd/hci/le_advertising_manager.h" |
| #include "gd/packet/packet_view.h" |
| #include "gd/storage/storage_module.h" |
| #include "main/shim/entry.h" |
| #include "main/shim/helpers.h" |
| #include "stack/include/ble_advertiser.h" |
| #include "stack/include/btm_api.h" |
| #include "types/raw_address.h" |
| |
| #include <base/logging.h> |
| |
| using bluetooth::hci::Address; |
| using bluetooth::hci::AddressType; |
| using bluetooth::hci::ErrorCode; |
| using bluetooth::hci::GapData; |
| using bluetooth::hci::OwnAddressType; |
| using std::vector; |
| |
| class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, |
| public bluetooth::hci::AdvertisingCallback { |
| public: |
| ~BleAdvertiserInterfaceImpl() override{}; |
| |
| void Init() { |
| // Register callback |
| bluetooth::shim::GetAdvertising()->RegisterAdvertisingCallback(this); |
| } |
| |
| // nobody use this function |
| void RegisterAdvertiser(IdStatusCallback cb) override { |
| LOG(INFO) << __func__ << " in shim layer"; |
| } |
| |
| void Unregister(uint8_t advertiser_id) override { |
| LOG(INFO) << __func__ << " in shim layer"; |
| bluetooth::shim::GetAdvertising()->RemoveAdvertiser(advertiser_id); |
| } |
| |
| void GetOwnAddress(uint8_t advertiser_id, GetAddressCallback cb) override { |
| LOG(INFO) << __func__ << " in shim layer"; |
| bluetooth::shim::GetAdvertising()->GetOwnAddress(advertiser_id); |
| } |
| |
| void SetParameters(uint8_t advertiser_id, AdvertiseParameters params, |
| ParametersCallback cb) override { |
| LOG(INFO) << __func__ << " in shim layer"; |
| bluetooth::hci::ExtendedAdvertisingConfig config{}; |
| parse_parameter(config, params); |
| bluetooth::shim::GetAdvertising()->SetParameters(advertiser_id, config); |
| } |
| |
| void SetData(int advertiser_id, bool set_scan_rsp, vector<uint8_t> data, |
| StatusCallback cb) override { |
| LOG(INFO) << __func__ << " in shim layer"; |
| |
| size_t offset = 0; |
| std::vector<GapData> advertising_data = {}; |
| |
| while (offset < data.size()) { |
| GapData gap_data; |
| uint8_t len = data[offset]; |
| auto begin = data.begin() + offset; |
| auto end = begin + len + 1; // 1 byte for len |
| auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end); |
| bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet( |
| data_copy); |
| GapData::Parse(&gap_data, packet.begin()); |
| advertising_data.push_back(gap_data); |
| offset += len + 1; // 1 byte for len |
| } |
| |
| bluetooth::shim::GetAdvertising()->SetData(advertiser_id, set_scan_rsp, |
| advertising_data); |
| } |
| |
| void Enable(uint8_t advertiser_id, bool enable, StatusCallback cb, |
| uint16_t duration, uint8_t maxExtAdvEvents, |
| StatusCallback timeout_cb) override { |
| LOG(INFO) << __func__ << " in shim layer"; |
| bluetooth::shim::GetAdvertising()->EnableAdvertiser( |
| advertiser_id, enable, duration, maxExtAdvEvents); |
| } |
| |
| // nobody use this function |
| void 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, |
| MultiAdvCb timeout_cb) override { |
| LOG(INFO) << __func__ << " in shim layer"; |
| } |
| |
| void StartAdvertisingSet(int reg_id, IdTxPowerStatusCallback register_cb, |
| 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 timeout_cb) { |
| LOG(INFO) << __func__ << " in shim layer"; |
| |
| bluetooth::hci::ExtendedAdvertisingConfig config{}; |
| parse_parameter(config, params); |
| bluetooth::hci::PeriodicAdvertisingParameters periodic_parameters; |
| periodic_parameters.max_interval = periodic_params.max_interval; |
| periodic_parameters.min_interval = periodic_params.min_interval; |
| periodic_parameters.properties = |
| periodic_params.periodic_advertising_properties; |
| config.periodic_advertising_parameters = periodic_parameters; |
| |
| size_t offset = 0; |
| while (offset < advertise_data.size()) { |
| GapData gap_data; |
| uint8_t len = advertise_data[offset]; |
| auto begin = advertise_data.begin() + offset; |
| auto end = begin + len + 1; // 1 byte for len |
| auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end); |
| bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet( |
| data_copy); |
| GapData::Parse(&gap_data, packet.begin()); |
| config.advertisement.push_back(gap_data); |
| offset += len + 1; // 1 byte for len |
| } |
| |
| offset = 0; |
| while (offset < scan_response_data.size()) { |
| GapData gap_data; |
| uint8_t len = scan_response_data[offset]; |
| auto begin = scan_response_data.begin() + offset; |
| auto end = begin + len + 1; // 1 byte for len |
| auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end); |
| bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet( |
| data_copy); |
| GapData::Parse(&gap_data, packet.begin()); |
| config.scan_response.push_back(gap_data); |
| offset += len + 1; // 1 byte for len |
| } |
| |
| offset = 0; |
| while (offset < periodic_data.size()) { |
| GapData gap_data; |
| uint8_t len = periodic_data[offset]; |
| auto begin = periodic_data.begin() + offset; |
| auto end = begin + len + 1; // 1 byte for len |
| auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end); |
| bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet( |
| data_copy); |
| GapData::Parse(&gap_data, packet.begin()); |
| config.periodic_data.push_back(gap_data); |
| offset += len + 1; // 1 byte for len |
| } |
| |
| bluetooth::hci::AdvertiserId id = |
| bluetooth::shim::GetAdvertising()->ExtendedCreateAdvertiser( |
| reg_id, config, scan_callback, set_terminated_callback, duration, |
| maxExtAdvEvents, bluetooth::shim::GetGdShimHandler()); |
| |
| LOG(INFO) << "create advertising set, reg_id:" << reg_id |
| << ", id:" << (uint16_t)id; |
| } |
| |
| void SetPeriodicAdvertisingParameters( |
| int advertiser_id, PeriodicAdvertisingParameters periodic_params, |
| StatusCallback cb) override { |
| LOG(INFO) << __func__ << " in shim layer"; |
| bluetooth::hci::PeriodicAdvertisingParameters parameters; |
| parameters.max_interval = periodic_params.max_interval; |
| parameters.min_interval = periodic_params.min_interval; |
| parameters.properties = periodic_params.periodic_advertising_properties; |
| bluetooth::shim::GetAdvertising()->SetPeriodicParameters(advertiser_id, |
| parameters); |
| } |
| |
| void SetPeriodicAdvertisingData(int advertiser_id, std::vector<uint8_t> data, |
| StatusCallback cb) override { |
| LOG(INFO) << __func__ << " in shim layer"; |
| |
| size_t offset = 0; |
| std::vector<GapData> advertising_data = {}; |
| |
| while (offset < data.size()) { |
| GapData gap_data; |
| uint8_t len = data[offset]; |
| auto begin = data.begin() + offset; |
| auto end = begin + len + 1; // 1 byte for len |
| auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end); |
| bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet( |
| data_copy); |
| GapData::Parse(&gap_data, packet.begin()); |
| advertising_data.push_back(gap_data); |
| offset += len + 1; // 1 byte for len |
| } |
| |
| bluetooth::shim::GetAdvertising()->SetPeriodicData(advertiser_id, |
| advertising_data); |
| } |
| |
| void SetPeriodicAdvertisingEnable(int advertiser_id, bool enable, |
| StatusCallback cb) override { |
| LOG(INFO) << __func__ << " in shim layer"; |
| bluetooth::shim::GetAdvertising()->EnablePeriodicAdvertising(advertiser_id, |
| enable); |
| } |
| |
| void RegisterCallbacks(AdvertisingCallbacks* callbacks) { |
| advertising_callbacks_ = callbacks; |
| } |
| |
| void on_scan(Address address, AddressType address_type) { |
| LOG(INFO) << __func__ << " in shim layer"; |
| } |
| |
| void on_set_terminated(ErrorCode error_code, uint8_t, uint8_t) { |
| LOG(INFO) << __func__ << " in shim layer"; |
| } |
| |
| const bluetooth::common::Callback<void(Address, AddressType)> scan_callback = |
| bluetooth::common::Bind(&BleAdvertiserInterfaceImpl::on_scan, |
| bluetooth::common::Unretained(this)); |
| |
| const bluetooth::common::Callback<void(ErrorCode, uint8_t, uint8_t)> |
| set_terminated_callback = bluetooth::common::Bind( |
| &BleAdvertiserInterfaceImpl::on_set_terminated, |
| bluetooth::common::Unretained(this)); |
| |
| // AdvertisingCallback |
| void OnAdvertisingSetStarted(int reg_id, uint8_t advertiser_id, |
| int8_t tx_power, |
| AdvertisingStatus status) override { |
| do_in_jni_thread( |
| FROM_HERE, base::Bind(&AdvertisingCallbacks::OnAdvertisingSetStarted, |
| base::Unretained(advertising_callbacks_), reg_id, |
| advertiser_id, tx_power, status)); |
| } |
| |
| void OnAdvertisingEnabled(uint8_t advertiser_id, bool enable, |
| uint8_t status) { |
| do_in_jni_thread(FROM_HERE, |
| base::Bind(&AdvertisingCallbacks::OnAdvertisingEnabled, |
| base::Unretained(advertising_callbacks_), |
| advertiser_id, enable, status)); |
| } |
| |
| void OnAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) { |
| do_in_jni_thread(FROM_HERE, |
| base::Bind(&AdvertisingCallbacks::OnAdvertisingDataSet, |
| base::Unretained(advertising_callbacks_), |
| advertiser_id, status)); |
| } |
| void OnScanResponseDataSet(uint8_t advertiser_id, uint8_t status) { |
| do_in_jni_thread(FROM_HERE, |
| base::Bind(&AdvertisingCallbacks::OnScanResponseDataSet, |
| base::Unretained(advertising_callbacks_), |
| advertiser_id, status)); |
| } |
| |
| void OnAdvertisingParametersUpdated(uint8_t advertiser_id, int8_t tx_power, |
| uint8_t status) { |
| do_in_jni_thread( |
| FROM_HERE, |
| base::Bind(&AdvertisingCallbacks::OnAdvertisingParametersUpdated, |
| base::Unretained(advertising_callbacks_), advertiser_id, |
| tx_power, status)); |
| } |
| |
| void OnPeriodicAdvertisingParametersUpdated(uint8_t advertiser_id, |
| uint8_t status) { |
| do_in_jni_thread( |
| FROM_HERE, |
| base::Bind( |
| &AdvertisingCallbacks::OnPeriodicAdvertisingParametersUpdated, |
| base::Unretained(advertising_callbacks_), advertiser_id, status)); |
| } |
| |
| void OnPeriodicAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) { |
| do_in_jni_thread( |
| FROM_HERE, |
| base::Bind(&AdvertisingCallbacks::OnPeriodicAdvertisingDataSet, |
| base::Unretained(advertising_callbacks_), advertiser_id, |
| status)); |
| } |
| |
| void OnPeriodicAdvertisingEnabled(uint8_t advertiser_id, bool enable, |
| uint8_t status) { |
| do_in_jni_thread( |
| FROM_HERE, |
| base::Bind(&AdvertisingCallbacks::OnPeriodicAdvertisingEnabled, |
| base::Unretained(advertising_callbacks_), advertiser_id, |
| enable, status)); |
| } |
| |
| void OnOwnAddressRead(uint8_t advertiser_id, uint8_t address_type, |
| bluetooth::hci::Address address) { |
| RawAddress raw_address = bluetooth::ToRawAddress(address); |
| do_in_jni_thread(FROM_HERE, |
| base::Bind(&AdvertisingCallbacks::OnOwnAddressRead, |
| base::Unretained(advertising_callbacks_), |
| advertiser_id, address_type, raw_address)); |
| } |
| |
| AdvertisingCallbacks* advertising_callbacks_; |
| |
| private: |
| void parse_parameter(bluetooth::hci::ExtendedAdvertisingConfig& config, |
| AdvertiseParameters params) { |
| config.connectable = params.advertising_event_properties & 0x01; |
| config.scannable = params.advertising_event_properties & 0x02; |
| config.legacy_pdus = params.advertising_event_properties & 0x10; |
| config.anonymous = params.advertising_event_properties & 0x20; |
| config.include_tx_power = params.advertising_event_properties & 0x40; |
| config.interval_min = params.min_interval; |
| config.interval_max = params.max_interval; |
| config.channel_map = params.channel_map; |
| config.tx_power = params.tx_power; |
| config.use_le_coded_phy = params.primary_advertising_phy == 0x03; |
| config.secondary_advertising_phy = |
| static_cast<bluetooth::hci::SecondaryPhyType>( |
| params.secondary_advertising_phy); |
| config.enable_scan_request_notifications = |
| static_cast<bluetooth::hci::Enable>( |
| params.scan_request_notification_enable); |
| |
| // TODO set own_address_type based on address policy |
| config.own_address_type = OwnAddressType::RANDOM_DEVICE_ADDRESS; |
| } |
| }; |
| |
| BleAdvertiserInterfaceImpl* bt_le_advertiser_instance = nullptr; |
| |
| BleAdvertiserInterface* bluetooth::shim::get_ble_advertiser_instance() { |
| if (bt_le_advertiser_instance == nullptr) { |
| bt_le_advertiser_instance = new BleAdvertiserInterfaceImpl(); |
| } |
| return bt_le_advertiser_instance; |
| }; |
| |
| void bluetooth::shim::init_advertising_manager() { |
| bt_le_advertiser_instance->Init(); |
| } |