| /****************************************************************************** |
| * |
| * Copyright (C) 2016 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_btif_scanner" |
| |
| #include <base/bind.h> |
| #include <base/threading/thread.h> |
| #include <errno.h> |
| #include <hardware/bluetooth.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unordered_set> |
| #include "device/include/controller.h" |
| |
| #include "btcore/include/bdaddr.h" |
| #include "btif_common.h" |
| #include "btif_util.h" |
| |
| #include <hardware/bt_gatt.h> |
| |
| #include "bta_api.h" |
| #include "bta_closure_api.h" |
| #include "bta_gatt_api.h" |
| #include "btif_config.h" |
| #include "btif_dm.h" |
| #include "btif_gatt.h" |
| #include "btif_gatt_util.h" |
| #include "btif_storage.h" |
| #include "osi/include/log.h" |
| #include "vendor_api.h" |
| |
| using base::Bind; |
| using base::Owned; |
| using std::vector; |
| using RegisterCallback = BleScannerInterface::RegisterCallback; |
| |
| extern const btgatt_callbacks_t* bt_gatt_callbacks; |
| |
| #define SCAN_CBACK_IN_JNI(P_CBACK, ...) \ |
| do { \ |
| if (bt_gatt_callbacks && bt_gatt_callbacks->scanner->P_CBACK) { \ |
| BTIF_TRACE_API("HAL bt_gatt_callbacks->client->%s", #P_CBACK); \ |
| do_in_jni_thread( \ |
| Bind(bt_gatt_callbacks->scanner->P_CBACK, __VA_ARGS__)); \ |
| } else { \ |
| ASSERTC(0, "Callback is NULL", 0); \ |
| } \ |
| } while (0) |
| |
| namespace std { |
| template <> |
| struct hash<bt_bdaddr_t> { |
| size_t operator()(const bt_bdaddr_t& f) const { |
| return f.address[0] + f.address[1] + f.address[2] + f.address[3] + |
| f.address[4] + f.address[5]; |
| } |
| }; |
| |
| template <> |
| struct equal_to<bt_bdaddr_t> { |
| size_t operator()(const bt_bdaddr_t& x, const bt_bdaddr_t& y) const { |
| return memcmp(x.address, y.address, BD_ADDR_LEN); |
| } |
| }; |
| } |
| |
| namespace { |
| |
| std::unordered_set<bt_bdaddr_t> p_dev_cb; |
| |
| void btif_gattc_add_remote_bdaddr(BD_ADDR p_bda, uint8_t addr_type) { |
| bt_bdaddr_t bd_addr; |
| memcpy(bd_addr.address, p_bda, BD_ADDR_LEN); |
| p_dev_cb.insert(bd_addr); |
| } |
| |
| bool btif_gattc_find_bdaddr(BD_ADDR p_bda) { |
| bt_bdaddr_t bd_addr; |
| memcpy(bd_addr.address, p_bda, BD_ADDR_LEN); |
| return (p_dev_cb.count(bd_addr) != 0); |
| } |
| |
| void btif_gattc_init_dev_cb(void) { p_dev_cb.clear(); } |
| |
| void btif_gatts_upstreams_evt(uint16_t event, char* p_param) { |
| LOG_VERBOSE(LOG_TAG, "%s: Event %d", __func__, event); |
| |
| tBTA_GATTC* p_data = (tBTA_GATTC*)p_param; |
| switch (event) { |
| case BTA_GATTC_DEREG_EVT: |
| break; |
| |
| case BTA_GATTC_SEARCH_CMPL_EVT: { |
| HAL_CBACK(bt_gatt_callbacks, client->search_complete_cb, |
| p_data->search_cmpl.conn_id, p_data->search_cmpl.status); |
| break; |
| } |
| |
| default: |
| LOG_DEBUG(LOG_TAG, "%s: Unhandled event (%d)", __func__, event); |
| break; |
| } |
| } |
| |
| void bta_gatts_cback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) { |
| bt_status_t status = |
| btif_transfer_context(btif_gatts_upstreams_evt, (uint16_t)event, |
| (char*)p_data, sizeof(tBTA_GATTC), NULL); |
| ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status); |
| } |
| |
| void bta_batch_scan_threshold_cb(tBTM_BLE_REF_VALUE ref_value) { |
| SCAN_CBACK_IN_JNI(batchscan_threshold_cb, ref_value); |
| } |
| |
| void bta_batch_scan_reports_cb(int client_id, tBTA_STATUS status, |
| uint8_t report_format, uint8_t num_records, |
| std::vector<uint8_t> data) { |
| SCAN_CBACK_IN_JNI(batchscan_reports_cb, client_id, status, report_format, |
| num_records, std::move(data)); |
| } |
| |
| void bta_scan_results_cb_impl(bt_bdaddr_t bd_addr, tBT_DEVICE_TYPE device_type, |
| int8_t rssi, uint8_t addr_type, |
| uint16_t ble_evt_type, uint8_t ble_primary_phy, |
| uint8_t ble_secondary_phy, |
| uint8_t ble_advertising_sid, int8_t ble_tx_power, |
| uint16_t ble_periodic_adv_int, |
| vector<uint8_t> value) { |
| uint8_t remote_name_len; |
| bt_device_type_t dev_type; |
| bt_property_t properties; |
| |
| const uint8_t* p_eir_remote_name = BTM_CheckAdvData( |
| value, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len); |
| |
| if (p_eir_remote_name == NULL) { |
| p_eir_remote_name = BTM_CheckAdvData( |
| value, BT_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len); |
| } |
| |
| if ((addr_type != BLE_ADDR_RANDOM) || (p_eir_remote_name)) { |
| if (!btif_gattc_find_bdaddr(bd_addr.address)) { |
| btif_gattc_add_remote_bdaddr(bd_addr.address, addr_type); |
| |
| if (p_eir_remote_name) { |
| bt_bdname_t bdname; |
| memcpy(bdname.name, p_eir_remote_name, remote_name_len); |
| bdname.name[remote_name_len] = '\0'; |
| |
| LOG_VERBOSE(LOG_TAG, "%s BLE device name=%s len=%d dev_type=%d", |
| __func__, bdname.name, remote_name_len, device_type); |
| btif_dm_update_ble_remote_properties(bd_addr.address, bdname.name, |
| device_type); |
| } |
| } |
| } |
| |
| dev_type = (bt_device_type_t)device_type; |
| BTIF_STORAGE_FILL_PROPERTY(&properties, BT_PROPERTY_TYPE_OF_DEVICE, |
| sizeof(dev_type), &dev_type); |
| btif_storage_set_remote_device_property(&(bd_addr), &properties); |
| |
| btif_storage_set_remote_addr_type(&bd_addr, addr_type); |
| HAL_CBACK(bt_gatt_callbacks, scanner->scan_result_cb, ble_evt_type, addr_type, |
| &bd_addr, ble_primary_phy, ble_secondary_phy, ble_advertising_sid, |
| ble_tx_power, rssi, ble_periodic_adv_int, std::move(value)); |
| } |
| |
| void bta_scan_results_cb(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) { |
| uint8_t len; |
| |
| if (event == BTA_DM_INQ_CMPL_EVT) { |
| BTIF_TRACE_DEBUG("%s BLE observe complete. Num Resp %d", __func__, |
| p_data->inq_cmpl.num_resps); |
| return; |
| } |
| |
| if (event != BTA_DM_INQ_RES_EVT) { |
| BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event); |
| return; |
| } |
| |
| vector<uint8_t> value; |
| if (p_data->inq_res.p_eir) { |
| value.insert(value.begin(), p_data->inq_res.p_eir, |
| p_data->inq_res.p_eir + p_data->inq_res.eir_len); |
| |
| if (BTM_CheckAdvData(value, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &len)) { |
| p_data->inq_res.remt_name_not_required = true; |
| } |
| } |
| |
| tBTA_DM_INQ_RES* r = &p_data->inq_res; |
| bt_bdaddr_t bdaddr; |
| bdcpy(bdaddr.address, r->bd_addr); |
| do_in_jni_thread(Bind(bta_scan_results_cb_impl, bdaddr, r->device_type, |
| r->rssi, r->ble_addr_type, r->ble_evt_type, |
| r->ble_primary_phy, r->ble_secondary_phy, |
| r->ble_advertising_sid, r->ble_tx_power, |
| r->ble_periodic_adv_int, std::move(value))); |
| } |
| |
| void bta_track_adv_event_cb(tBTM_BLE_TRACK_ADV_DATA* p_track_adv_data) { |
| btgatt_track_adv_info_t* btif_scan_track_cb = new btgatt_track_adv_info_t; |
| |
| BTIF_TRACE_DEBUG("%s", __func__); |
| btif_gatt_move_track_adv_data(btif_scan_track_cb, |
| (btgatt_track_adv_info_t*)p_track_adv_data); |
| |
| SCAN_CBACK_IN_JNI(track_adv_event_cb, Owned(btif_scan_track_cb)); |
| } |
| |
| class BleScannerInterfaceImpl : public BleScannerInterface { |
| ~BleScannerInterfaceImpl(){}; |
| |
| void RegisterScanner(RegisterCallback cb) override { |
| do_in_bta_thread(FROM_HERE, |
| Bind( |
| [](RegisterCallback cb) { |
| BTA_GATTC_AppRegister( |
| bta_gatts_cback, |
| jni_thread_wrapper(FROM_HERE, std::move(cb))); |
| }, |
| std::move(cb))); |
| } |
| |
| void Unregister(int scanner_id) override { |
| do_in_bta_thread(FROM_HERE, Bind(&BTA_GATTC_AppDeregister, scanner_id)); |
| } |
| |
| void Scan(bool start) override { |
| if (!start) { |
| do_in_bta_thread(FROM_HERE, Bind(&BTA_DmBleObserve, false, 0, nullptr)); |
| return; |
| } |
| |
| btif_gattc_init_dev_cb(); |
| do_in_bta_thread(FROM_HERE, |
| Bind(&BTA_DmBleObserve, true, 0, |
| (tBTA_DM_SEARCH_CBACK*)bta_scan_results_cb)); |
| } |
| |
| void ScanFilterParamSetup( |
| uint8_t client_if, uint8_t action, uint8_t filt_index, |
| std::unique_ptr<btgatt_filt_param_setup_t> filt_param, |
| FilterParamSetupCallback cb) override { |
| BTIF_TRACE_DEBUG("%s", __func__); |
| |
| if (filt_param && filt_param->dely_mode == 1) { |
| do_in_bta_thread( |
| FROM_HERE, base::Bind(BTM_BleTrackAdvertiser, bta_track_adv_event_cb, |
| client_if)); |
| } |
| |
| do_in_bta_thread(FROM_HERE, |
| base::Bind(&BTM_BleAdvFilterParamSetup, action, filt_index, |
| base::Passed(&filt_param), |
| jni_thread_wrapper(FROM_HERE, std::move(cb)))); |
| } |
| |
| void ScanFilterAddRemove(int action, int filt_type, int filt_index, |
| int company_id, int company_id_mask, |
| const bt_uuid_t* p_uuid, |
| const bt_uuid_t* p_uuid_mask, |
| const bt_bdaddr_t* bd_addr, char addr_type, |
| vector<uint8_t> data, vector<uint8_t> mask, |
| FilterConfigCallback cb) override { |
| BTIF_TRACE_DEBUG("%s, %d, %d", __func__, action, filt_type); |
| |
| /* If data is passed, both mask and data have to be the same length */ |
| if (data.size() != mask.size() && data.size() != 0 && mask.size() != 0) |
| return; |
| |
| switch (filt_type) { |
| case BTM_BLE_PF_ADDR_FILTER: { |
| tBLE_BD_ADDR target_addr; |
| bdcpy(target_addr.bda, bd_addr->address); |
| target_addr.type = addr_type; |
| |
| do_in_bta_thread( |
| FROM_HERE, |
| base::Bind(&BTM_LE_PF_addr_filter, action, filt_index, |
| std::move(target_addr), |
| jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type)))); |
| return; |
| } |
| |
| case BTM_BLE_PF_SRVC_DATA: |
| do_in_bta_thread(FROM_HERE, |
| base::Bind(&BTM_LE_PF_srvc_data, action, filt_index)); |
| return; |
| |
| case BTM_BLE_PF_SRVC_UUID: |
| case BTM_BLE_PF_SRVC_SOL_UUID: { |
| tBT_UUID bt_uuid; |
| btif_to_bta_uuid(&bt_uuid, p_uuid); |
| |
| if (p_uuid_mask == NULL) { |
| do_in_bta_thread( |
| FROM_HERE, |
| base::Bind(&BTM_LE_PF_uuid_filter, action, filt_index, filt_type, |
| bt_uuid, BTM_BLE_PF_LOGIC_AND, nullptr, |
| jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type)))); |
| return; |
| } |
| |
| tBTM_BLE_PF_COND_MASK* mask = new tBTM_BLE_PF_COND_MASK; |
| btif_to_bta_uuid_mask(mask, p_uuid_mask, p_uuid); |
| do_in_bta_thread( |
| FROM_HERE, |
| base::Bind(&BTM_LE_PF_uuid_filter, action, filt_index, filt_type, |
| bt_uuid, BTM_BLE_PF_LOGIC_AND, base::Owned(mask), |
| jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type)))); |
| return; |
| } |
| |
| case BTM_BLE_PF_LOCAL_NAME: { |
| do_in_bta_thread( |
| FROM_HERE, |
| base::Bind(&BTM_LE_PF_local_name, action, filt_index, |
| std::move(data), |
| jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type)))); |
| return; |
| } |
| |
| case BTM_BLE_PF_MANU_DATA: { |
| do_in_bta_thread( |
| FROM_HERE, |
| base::Bind(&BTM_LE_PF_manu_data, action, filt_index, company_id, |
| company_id_mask, std::move(data), std::move(mask), |
| jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type)))); |
| return; |
| } |
| |
| case BTM_BLE_PF_SRVC_DATA_PATTERN: { |
| do_in_bta_thread( |
| FROM_HERE, |
| base::Bind(&BTM_LE_PF_srvc_data_pattern, action, filt_index, |
| std::move(data), std::move(mask), |
| jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type)))); |
| return; |
| } |
| |
| default: |
| LOG_ERROR(LOG_TAG, "%s: Unknown filter type (%d)!", __func__, action); |
| return; |
| } |
| } |
| |
| void ScanFilterClear(int filter_index, FilterConfigCallback cb) override { |
| BTIF_TRACE_DEBUG("%s: filter_index: %d", __func__, filter_index); |
| do_in_bta_thread(FROM_HERE, |
| base::Bind(&BTM_LE_PF_clear, filter_index, |
| jni_thread_wrapper( |
| FROM_HERE, Bind(cb, BTM_BLE_PF_TYPE_ALL)))); |
| } |
| |
| void ScanFilterEnable(bool enable, EnableCallback cb) override { |
| BTIF_TRACE_DEBUG("%s: enable: %d", __func__, enable); |
| |
| uint8_t action = enable ? 1 : 0; |
| do_in_bta_thread(FROM_HERE, |
| base::Bind(&BTM_BleEnableDisableFilterFeature, action, |
| jni_thread_wrapper(FROM_HERE, std::move(cb)))); |
| } |
| |
| void SetScanParameters(int scan_interval, int scan_window, |
| Callback cb) override { |
| do_in_bta_thread( |
| FROM_HERE, base::Bind(&BTM_BleSetScanParams, scan_interval, scan_window, |
| BTM_BLE_SCAN_MODE_ACTI, |
| jni_thread_wrapper(FROM_HERE, std::move(cb)))); |
| } |
| |
| void BatchscanConfigStorage(int client_if, int batch_scan_full_max, |
| int batch_scan_trunc_max, |
| int batch_scan_notify_threshold, |
| Callback cb) override { |
| do_in_bta_thread( |
| FROM_HERE, |
| base::Bind(&BTM_BleSetStorageConfig, (uint8_t)batch_scan_full_max, |
| (uint8_t)batch_scan_trunc_max, |
| (uint8_t)batch_scan_notify_threshold, |
| jni_thread_wrapper(FROM_HERE, cb), |
| bta_batch_scan_threshold_cb, (tBTM_BLE_REF_VALUE)client_if)); |
| } |
| |
| void BatchscanEnable(int scan_mode, int scan_interval, int scan_window, |
| int addr_type, int discard_rule, Callback cb) override { |
| do_in_bta_thread( |
| FROM_HERE, base::Bind(&BTM_BleEnableBatchScan, scan_mode, scan_interval, |
| scan_window, discard_rule, addr_type, |
| jni_thread_wrapper(FROM_HERE, cb))); |
| } |
| |
| void BatchscanDisable(Callback cb) override { |
| do_in_bta_thread(FROM_HERE, base::Bind(&BTM_BleDisableBatchScan, |
| jni_thread_wrapper(FROM_HERE, cb))); |
| } |
| |
| void BatchscanReadReports(int client_if, int scan_mode) override { |
| do_in_bta_thread(FROM_HERE, |
| base::Bind(&BTM_BleReadScanReports, (uint8_t)scan_mode, |
| Bind(bta_batch_scan_reports_cb, client_if))); |
| } |
| |
| void StartSync(uint8_t sid, bt_bdaddr_t address, uint16_t skip, |
| uint16_t timeout, StartSyncCb start_cb, SyncReportCb report_cb, |
| SyncLostCb lost_cb) override {} |
| |
| void StopSync(uint16_t handle) override {} |
| }; |
| |
| BleScannerInterface* btLeScannerInstance = nullptr; |
| |
| } // namespace |
| |
| BleScannerInterface* get_ble_scanner_instance() { |
| if (btLeScannerInstance == nullptr) |
| btLeScannerInstance = new BleScannerInterfaceImpl(); |
| |
| return btLeScannerInstance; |
| } |