/* * 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_scanner" #include "le_scanning_manager.h" #include #include #include #include #include #include "btif/include/btif_common.h" #include "gd/hci/address.h" #include "gd/hci/le_scanning_manager.h" #include "gd/storage/device.h" #include "gd/storage/le_device.h" #include "gd/storage/storage_module.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" #include "main/shim/shim.h" #include "advertise_data_parser.h" #include "stack/btm/btm_int_types.h" using bluetooth::ToRawAddress; using bluetooth::ToGdAddress; extern void btm_ble_process_adv_pkt_cont_for_inquiry( uint16_t event_type, uint8_t address_type, const RawAddress& raw_address, uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, int8_t tx_power, int8_t rssi, uint16_t periodic_adv_int, std::vector advertising_data); extern void btif_dm_update_ble_remote_properties(const RawAddress& bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE dev_type); class BleScannerInterfaceImpl : public BleScannerInterface, public bluetooth::hci::ScanningCallback { public: ~BleScannerInterfaceImpl() override{}; void Init() { LOG_INFO("init BleScannerInterfaceImpl"); bluetooth::shim::GetScanning()->RegisterScanningCallback(this); } /** Registers a scanner with the stack */ void RegisterScanner(const bluetooth::Uuid& uuid, RegisterCallback) { LOG(INFO) << __func__ << " in shim layer"; auto app_uuid = bluetooth::hci::Uuid::From128BitBE(uuid.To128BitBE()); bluetooth::shim::GetScanning()->RegisterScanner(app_uuid); } /** Unregister a scanner from the stack */ void Unregister(int scanner_id) { LOG(INFO) << __func__ << " in shim layer, scanner_id:" << scanner_id; bluetooth::shim::GetScanning()->Unregister(scanner_id); } /** Start or stop LE device scanning */ void Scan(bool start) { LOG(INFO) << __func__ << " in shim layer"; bluetooth::shim::GetScanning()->Scan(start); init_address_cache(); } /** Setup scan filter params */ void ScanFilterParamSetup( uint8_t client_if, uint8_t action, uint8_t filter_index, std::unique_ptr filt_param, FilterParamSetupCallback cb) { LOG(INFO) << __func__ << " in shim layer"; auto apcf_action = static_cast(action); bluetooth::hci::AdvertisingFilterParameter advertising_filter_parameter; if (filt_param != nullptr) { if (filt_param && filt_param->dely_mode == 1) { bluetooth::shim::GetScanning()->TrackAdvertiser(client_if); } advertising_filter_parameter.feature_selection = filt_param->feat_seln; advertising_filter_parameter.list_logic_type = filt_param->list_logic_type; advertising_filter_parameter.filter_logic_type = filt_param->filt_logic_type; advertising_filter_parameter.rssi_high_thresh = filt_param->rssi_high_thres; advertising_filter_parameter.delivery_mode = static_cast(filt_param->dely_mode); if (filt_param && filt_param->dely_mode == 1) { advertising_filter_parameter.onfound_timeout = filt_param->found_timeout; advertising_filter_parameter.onfound_timeout_cnt = filt_param->found_timeout_cnt; advertising_filter_parameter.rssi_low_thres = filt_param->rssi_low_thres; advertising_filter_parameter.onlost_timeout = filt_param->lost_timeout; advertising_filter_parameter.num_of_tracking_entries = filt_param->num_of_tracking_entries; } } bluetooth::shim::GetScanning()->ScanFilterParameterSetup( apcf_action, filter_index, advertising_filter_parameter); // TODO refactor callback mechanism do_in_jni_thread(FROM_HERE, base::Bind(cb, 0, 0, btm_status_value(BTM_SUCCESS))); } /** Configure a scan filter condition */ void ScanFilterAdd(int filter_index, std::vector filters, FilterConfigCallback cb) { LOG(INFO) << __func__ << " in shim layer"; std::vector new_filters = {}; for (size_t i = 0; i < filters.size(); i++) { bluetooth::hci::AdvertisingPacketContentFilterCommand command{}; if (!parse_filter_command(command, filters[i])) { LOG_ERROR("invalid apcf command"); return; } new_filters.push_back(command); } bluetooth::shim::GetScanning()->ScanFilterAdd(filter_index, new_filters); do_in_jni_thread(FROM_HERE, base::Bind(cb, 0, 0, 0, btm_status_value(BTM_SUCCESS))); } /** Clear all scan filter conditions for specific filter index*/ void ScanFilterClear(int filter_index, FilterConfigCallback cb) { LOG(INFO) << __func__ << " in shim layer"; // This function doesn't used in java layer } /** Enable / disable scan filter feature*/ void ScanFilterEnable(bool enable, EnableCallback cb) { LOG(INFO) << __func__ << " in shim layer"; bluetooth::shim::GetScanning()->ScanFilterEnable(enable); uint8_t action = enable ? 1 : 0; do_in_jni_thread(FROM_HERE, base::Bind(cb, action, btm_status_value(BTM_SUCCESS))); } /** Sets the LE scan interval and window in units of N*0.625 msec */ void SetScanParameters(int scan_interval, int scan_window, Callback cb) { LOG(INFO) << __func__ << " in shim layer"; // use active scan auto scan_type = static_cast(0x01); bluetooth::shim::GetScanning()->SetScanParameters(scan_type, scan_interval, scan_window); do_in_jni_thread(FROM_HERE, base::Bind(cb, 0)); } /* Configure the batchscan storage */ void BatchscanConfigStorage(int client_if, int batch_scan_full_max, int batch_scan_trunc_max, int batch_scan_notify_threshold, Callback cb) { LOG(INFO) << __func__ << " in shim layer"; bluetooth::shim::GetScanning()->BatchScanConifgStorage( batch_scan_full_max, batch_scan_trunc_max, batch_scan_notify_threshold, client_if); do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS))); } /* Enable batchscan */ virtual void BatchscanEnable(int scan_mode, int scan_interval, int scan_window, int addr_type, int discard_rule, Callback cb) { LOG(INFO) << __func__ << " in shim layer"; auto batch_scan_mode = static_cast(scan_mode); auto batch_scan_discard_rule = static_cast(discard_rule); bluetooth::shim::GetScanning()->BatchScanEnable( batch_scan_mode, scan_window, scan_interval, batch_scan_discard_rule); do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS))); } /* Disable batchscan */ virtual void BatchscanDisable(Callback cb) { LOG(INFO) << __func__ << " in shim layer"; bluetooth::shim::GetScanning()->BatchScanDisable(); do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS))); } /* Read out batchscan reports */ void BatchscanReadReports(int client_if, int scan_mode) { LOG(INFO) << __func__ << " in shim layer"; auto batch_scan_mode = static_cast(scan_mode); auto scanner_id = static_cast(client_if); bluetooth::shim::GetScanning()->BatchScanReadReport(scanner_id, batch_scan_mode); } void StartSync(uint8_t sid, RawAddress address, uint16_t skip, uint16_t timeout, StartSyncCb start_cb, SyncReportCb report_cb, SyncLostCb lost_cb) { LOG(INFO) << __func__ << " in shim layer"; // This function doesn't implement in the old stack } void StopSync(uint16_t handle) { LOG(INFO) << __func__ << " in shim layer"; // This function doesn't implement in the old stack } void RegisterCallbacks(ScanningCallbacks* callbacks) { LOG(INFO) << __func__ << " in shim layer"; scanning_callbacks_ = callbacks; } void OnScannerRegistered(const bluetooth::hci::Uuid app_uuid, bluetooth::hci::ScannerId scanner_id, ScanningStatus status) { auto uuid = bluetooth::Uuid::From128BitBE(app_uuid.To128BitBE()); do_in_jni_thread(FROM_HERE, base::Bind(&ScanningCallbacks::OnScannerRegistered, base::Unretained(scanning_callbacks_), uuid, scanner_id, status)); } void OnScanResult(uint16_t event_type, uint8_t address_type, bluetooth::hci::Address address, uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, int8_t tx_power, int8_t rssi, uint16_t periodic_advertising_interval, std::vector advertising_data) { RawAddress raw_address = ToRawAddress(address); do_in_jni_thread( FROM_HERE, base::BindOnce(&BleScannerInterfaceImpl::handle_remote_properties, base::Unretained(this), raw_address, address_type, advertising_data)); do_in_jni_thread( FROM_HERE, base::BindOnce(&ScanningCallbacks::OnScanResult, base::Unretained(scanning_callbacks_), event_type, address_type, raw_address, primary_phy, secondary_phy, advertising_sid, tx_power, rssi, periodic_advertising_interval, advertising_data)); // TODO: Remove when StartInquiry in GD part implemented btm_ble_process_adv_pkt_cont_for_inquiry( event_type, address_type, raw_address, primary_phy, secondary_phy, advertising_sid, tx_power, rssi, periodic_advertising_interval, advertising_data); } void OnTrackAdvFoundLost(bluetooth::hci::AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info) { AdvertisingTrackInfo track_info = {}; RawAddress raw_address = ToRawAddress(on_found_on_lost_info.advertiser_address); track_info.advertiser_address = raw_address; track_info.advertiser_address_type = on_found_on_lost_info.advertiser_address_type; track_info.scanner_id = on_found_on_lost_info.scanner_id; track_info.filter_index = on_found_on_lost_info.filter_index; track_info.advertiser_state = on_found_on_lost_info.advertiser_state; track_info.advertiser_info_present = static_cast(on_found_on_lost_info.advertiser_info_present); if (on_found_on_lost_info.advertiser_info_present == bluetooth::hci::AdvtInfoPresent::ADVT_INFO_PRESENT) { track_info.tx_power = on_found_on_lost_info.tx_power; track_info.rssi = on_found_on_lost_info.rssi; track_info.time_stamp = on_found_on_lost_info.time_stamp; auto adv_data = on_found_on_lost_info.adv_packet; track_info.adv_packet_len = (uint8_t)adv_data.size(); track_info.adv_packet.reserve(adv_data.size()); track_info.adv_packet.insert(track_info.adv_packet.end(), adv_data.begin(), adv_data.end()); auto scan_rsp_data = on_found_on_lost_info.scan_response; track_info.scan_response_len = (uint8_t)scan_rsp_data.size(); track_info.scan_response.reserve(adv_data.size()); track_info.scan_response.insert(track_info.scan_response.end(), scan_rsp_data.begin(), scan_rsp_data.end()); } do_in_jni_thread( FROM_HERE, base::BindOnce(&ScanningCallbacks::OnTrackAdvFoundLost, base::Unretained(scanning_callbacks_), track_info)); } void OnBatchScanReports(int client_if, int status, int report_format, int num_records, std::vector data) { do_in_jni_thread( FROM_HERE, base::BindOnce(&ScanningCallbacks::OnBatchScanReports, base::Unretained(scanning_callbacks_), client_if, status, report_format, num_records, data)); } void OnBatchScanThresholdCrossed(int client_if) { do_in_jni_thread( FROM_HERE, base::BindOnce(&ScanningCallbacks::OnBatchScanThresholdCrossed, base::Unretained(scanning_callbacks_), client_if)); } void OnTimeout() {} void OnFilterEnable(bluetooth::hci::Enable enable, uint8_t status){}; void OnFilterParamSetup(uint8_t available_spaces, bluetooth::hci::ApcfAction action, uint8_t status){}; void OnFilterConfigCallback(bluetooth::hci::ApcfFilterType filter_type, uint8_t available_spaces, bluetooth::hci::ApcfAction action, uint8_t status){}; ScanningCallbacks* scanning_callbacks_; private: bool parse_filter_command( bluetooth::hci::AdvertisingPacketContentFilterCommand& advertising_packet_content_filter_command, ApcfCommand apcf_command) { advertising_packet_content_filter_command.filter_type = static_cast(apcf_command.type); bluetooth::hci::Address address = ToGdAddress(apcf_command.address); advertising_packet_content_filter_command.address = address; advertising_packet_content_filter_command.application_address_type = static_cast( apcf_command.addr_type); if (!apcf_command.uuid.IsEmpty()) { uint8_t uuid_len = apcf_command.uuid.GetShortestRepresentationSize(); switch (uuid_len) { case bluetooth::Uuid::kNumBytes16: { advertising_packet_content_filter_command.uuid = bluetooth::hci::Uuid::From16Bit(apcf_command.uuid.As16Bit()); } break; case bluetooth::Uuid::kNumBytes32: { advertising_packet_content_filter_command.uuid = bluetooth::hci::Uuid::From32Bit(apcf_command.uuid.As32Bit()); } break; case bluetooth::Uuid::kNumBytes128: { advertising_packet_content_filter_command.uuid = bluetooth::hci::Uuid::From128BitBE( apcf_command.uuid.To128BitBE()); } break; default: LOG_WARN("illegal UUID length %d", (uint16_t)uuid_len); return false; } } if (!apcf_command.uuid_mask.IsEmpty()) { uint8_t uuid_len = apcf_command.uuid.GetShortestRepresentationSize(); switch (uuid_len) { case bluetooth::Uuid::kNumBytes16: { advertising_packet_content_filter_command.uuid_mask = bluetooth::hci::Uuid::From16Bit(apcf_command.uuid_mask.As16Bit()); } break; case bluetooth::Uuid::kNumBytes32: { advertising_packet_content_filter_command.uuid_mask = bluetooth::hci::Uuid::From32Bit(apcf_command.uuid_mask.As32Bit()); } break; case bluetooth::Uuid::kNumBytes128: { advertising_packet_content_filter_command.uuid_mask = bluetooth::hci::Uuid::From128BitBE( apcf_command.uuid_mask.To128BitBE()); } break; default: LOG_WARN("illegal UUID length %d", (uint16_t)uuid_len); return false; } } advertising_packet_content_filter_command.name.assign( apcf_command.name.begin(), apcf_command.name.end()); advertising_packet_content_filter_command.company = apcf_command.company; advertising_packet_content_filter_command.company_mask = apcf_command.company_mask; advertising_packet_content_filter_command.data.assign( apcf_command.data.begin(), apcf_command.data.end()); advertising_packet_content_filter_command.data_mask.assign( apcf_command.data_mask.begin(), apcf_command.data_mask.end()); return true; } void handle_remote_properties(RawAddress bd_addr, tBLE_ADDR_TYPE addr_type, std::vector advertising_data) { // skip anonymous advertisment if (addr_type == BLE_ADDR_ANONYMOUS) { return; } auto device_type = bluetooth::hci::DeviceType::LE; uint8_t flag_len; const uint8_t* p_flag = AdvertiseDataParser::GetFieldByType( advertising_data, BTM_BLE_AD_TYPE_FLAG, &flag_len); if (p_flag != NULL && flag_len != 0) { if ((BTM_BLE_BREDR_NOT_SPT & *p_flag) == 0) { device_type = bluetooth::hci::DeviceType::DUAL; } } uint8_t remote_name_len; const uint8_t* p_eir_remote_name = AdvertiseDataParser::GetFieldByType( advertising_data, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len); if (p_eir_remote_name == NULL) { p_eir_remote_name = AdvertiseDataParser::GetFieldByType( advertising_data, BT_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len); } // update device name if ((addr_type != BLE_ADDR_RANDOM) || (p_eir_remote_name)) { if (!find_address_cache(bd_addr)) { add_address_cache(bd_addr); if (p_eir_remote_name) { if (remote_name_len > BD_NAME_LEN + 1 || (remote_name_len == BD_NAME_LEN + 1 && p_eir_remote_name[BD_NAME_LEN] != '\0')) { LOG_INFO("%s dropping invalid packet - device name too long: %d", __func__, remote_name_len); return; } bt_bdname_t bdname; memcpy(bdname.name, p_eir_remote_name, remote_name_len); if (remote_name_len < BD_NAME_LEN + 1) bdname.name[remote_name_len] = '\0'; btif_dm_update_ble_remote_properties(bd_addr, bdname.name, device_type); } } } if (!bluetooth::shim::is_gd_stack_started_up()) { LOG_WARN("Gd stack is stopped, return"); return; } auto* storage_module = bluetooth::shim::GetStorage(); bluetooth::hci::Address address = ToGdAddress(bd_addr); // update device type auto mutation = storage_module->Modify(); bluetooth::storage::Device device = storage_module->GetDeviceByLegacyKey(address); mutation.Add(device.SetDeviceType(device_type)); mutation.Commit(); // update address type auto mutation2 = storage_module->Modify(); bluetooth::storage::LeDevice le_device = device.Le(); mutation2.Add( le_device.SetAddressType((bluetooth::hci::AddressType)addr_type)); mutation2.Commit(); } void add_address_cache(const RawAddress& p_bda) { // Remove the oldest entries while (remote_bdaddr_cache_.size() >= remote_bdaddr_cache_max_size_) { const RawAddress& raw_address = remote_bdaddr_cache_ordered_.front(); remote_bdaddr_cache_.erase(raw_address); remote_bdaddr_cache_ordered_.pop(); } remote_bdaddr_cache_.insert(p_bda); remote_bdaddr_cache_ordered_.push(p_bda); } bool find_address_cache(const RawAddress& p_bda) { return (remote_bdaddr_cache_.find(p_bda) != remote_bdaddr_cache_.end()); } void init_address_cache(void) { remote_bdaddr_cache_.clear(); remote_bdaddr_cache_ordered_ = {}; } // all access to this variable should be done on the jni thread std::set remote_bdaddr_cache_; std::queue remote_bdaddr_cache_ordered_; const size_t remote_bdaddr_cache_max_size_ = 1024; }; BleScannerInterfaceImpl* bt_le_scanner_instance = nullptr; BleScannerInterface* bluetooth::shim::get_ble_scanner_instance() { if (bt_le_scanner_instance == nullptr) { bt_le_scanner_instance = new BleScannerInterfaceImpl(); } return bt_le_scanner_instance; } void bluetooth::shim::init_scanning_manager() { bt_le_scanner_instance->Init(); }