blob: 9a6d6947b6ab4541a5d9d1222aa2e4f48b244fa1 [file] [log] [blame]
/*
* Copyright 2023 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_bta_dm"
#include "bta/dm/bta_dm_disc.h"
#include <android_bluetooth_flags.h>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <stddef.h>
#include <cstdint>
#include <vector>
#include "android_bluetooth_flags.h"
#include "bta/dm/bta_dm_disc_int.h"
#include "bta/include/bta_gatt_api.h"
#include "bta/include/bta_sdp_api.h"
#include "btif/include/btif_config.h"
#include "common/circular_buffer.h"
#include "common/init_flags.h"
#include "common/strings.h"
#include "device/include/interop.h"
#include "include/bind_helpers.h"
#include "include/check.h"
#include "internal_include/bt_target.h"
#include "main/shim/dumpsys.h"
#include "os/log.h"
#include "osi/include/allocator.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/osi.h" // UNUSED_ATTR
#include "stack/btm/btm_int_types.h" // TimestampedStringCircularBuffer
#include "stack/btm/neighbor_inquiry.h"
#include "stack/include/avrc_api.h"
#include "stack/include/bt_dev_class.h"
#include "stack/include/bt_hdr.h"
#include "stack/include/bt_name.h"
#include "stack/include/bt_uuid16.h"
#include "stack/include/btm_client_interface.h"
#include "stack/include/btm_log_history.h"
#include "stack/include/btm_sec_api.h" // BTM_IsRemoteNameKnown
#include "stack/include/gap_api.h" // GAP_BleReadPeerPrefConnParams
#include "stack/include/hidh_api.h"
#include "stack/include/sdp_status.h"
#include "stack/sdp/sdpint.h" // is_sdp_pbap_pce_disabled
#include "storage/config_keys.h"
#include "types/raw_address.h"
#ifdef TARGET_FLOSS
#include "stack/include/srvc_api.h"
#endif
using bluetooth::Uuid;
using namespace bluetooth::legacy::stack::sdp;
using namespace bluetooth;
tBTM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void);
namespace {
constexpr char kBtmLogTag[] = "SDP";
tBTA_DM_SEARCH_CB bta_dm_search_cb;
} // namespace
static void bta_dm_gatt_disc_complete(uint16_t conn_id, tGATT_STATUS status);
static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir,
uint16_t eir_len);
static void bta_dm_inq_cmpl(uint8_t num);
static void bta_dm_inq_cmpl_cb(void* p_result);
static void bta_dm_service_search_remname_cback(const RawAddress& bd_addr,
DEV_CLASS dc,
tBTM_BD_NAME bd_name);
static void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p);
static void bta_dm_find_services(const RawAddress& bd_addr);
static void bta_dm_discover_next_device(void);
static void bta_dm_sdp_callback(const RawAddress& bd_addr,
tSDP_STATUS sdp_status);
static void bta_dm_search_timer_cback(void* data);
static bool bta_dm_read_remote_device_name(const RawAddress& bd_addr,
tBT_TRANSPORT transport);
static void bta_dm_discover_device(const RawAddress& remote_bd_addr);
static void bta_dm_disable_search_and_disc(void);
static void bta_dm_gattc_register(void);
static void btm_dm_start_gatt_discovery(const RawAddress& bd_addr);
static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
static void bta_dm_search_cmpl();
static void bta_dm_free_sdp_db();
static void bta_dm_execute_queued_request();
static void bta_dm_search_cancel_notify();
static void bta_dm_close_gatt_conn(UNUSED_ATTR tBTA_DM_MSG* p_data);
TimestampedStringCircularBuffer disc_gatt_history_{50};
namespace {
struct gatt_interface_t {
void (*BTA_GATTC_CancelOpen)(tGATT_IF client_if, const RawAddress& remote_bda,
bool is_direct);
void (*BTA_GATTC_Refresh)(const RawAddress& remote_bda);
void (*BTA_GATTC_GetGattDb)(uint16_t conn_id, uint16_t start_handle,
uint16_t end_handle, btgatt_db_element_t** db,
int* count);
void (*BTA_GATTC_AppRegister)(tBTA_GATTC_CBACK* p_client_cb,
BtaAppRegisterCallback cb, bool eatt_support);
void (*BTA_GATTC_Close)(uint16_t conn_id);
void (*BTA_GATTC_ServiceSearchRequest)(uint16_t conn_id,
const bluetooth::Uuid* p_srvc_uuid);
void (*BTA_GATTC_Open)(tGATT_IF client_if, const RawAddress& remote_bda,
tBTM_BLE_CONN_TYPE connection_type,
bool opportunistic);
} default_gatt_interface = {
.BTA_GATTC_CancelOpen =
[](tGATT_IF client_if, const RawAddress& remote_bda, bool is_direct) {
disc_gatt_history_.Push(base::StringPrintf(
"%-32s bd_addr:%s client_if:%hu is_direct:%c", "GATTC_CancelOpen",
ADDRESS_TO_LOGGABLE_CSTR(remote_bda), client_if,
(is_direct) ? 'T' : 'F'));
BTA_GATTC_CancelOpen(client_if, remote_bda, is_direct);
},
.BTA_GATTC_Refresh =
[](const RawAddress& remote_bda) {
disc_gatt_history_.Push(
base::StringPrintf("%-32s bd_addr:%s", "GATTC_Refresh",
ADDRESS_TO_LOGGABLE_CSTR(remote_bda)));
BTA_GATTC_Refresh(remote_bda);
},
.BTA_GATTC_GetGattDb =
[](uint16_t conn_id, uint16_t start_handle, uint16_t end_handle,
btgatt_db_element_t** db, int* count) {
disc_gatt_history_.Push(base::StringPrintf(
"%-32s conn_id:%hu start_handle:%hu end:handle:%hu",
"GATTC_GetGattDb", conn_id, start_handle, end_handle));
BTA_GATTC_GetGattDb(conn_id, start_handle, end_handle, db, count);
},
.BTA_GATTC_AppRegister =
[](tBTA_GATTC_CBACK* p_client_cb, BtaAppRegisterCallback cb,
bool eatt_support) {
disc_gatt_history_.Push(
base::StringPrintf("%-32s eatt_support:%c", "GATTC_AppRegister",
(eatt_support) ? 'T' : 'F'));
BTA_GATTC_AppRegister(p_client_cb, cb, eatt_support);
},
.BTA_GATTC_Close =
[](uint16_t conn_id) {
disc_gatt_history_.Push(
base::StringPrintf("%-32s conn_id:%hu", "GATTC_Close", conn_id));
BTA_GATTC_Close(conn_id);
},
.BTA_GATTC_ServiceSearchRequest =
[](uint16_t conn_id, const bluetooth::Uuid* p_srvc_uuid) {
disc_gatt_history_.Push(base::StringPrintf(
"%-32s conn_id:%hu", "GATTC_ServiceSearchRequest", conn_id));
BTA_GATTC_ServiceSearchRequest(conn_id, p_srvc_uuid);
},
.BTA_GATTC_Open =
[](tGATT_IF client_if, const RawAddress& remote_bda,
tBTM_BLE_CONN_TYPE connection_type, bool opportunistic) {
disc_gatt_history_.Push(base::StringPrintf(
"%-32s bd_addr:%s client_if:%hu type:0x%x opportunistic:%c",
"GATTC_Open", ADDRESS_TO_LOGGABLE_CSTR(remote_bda), client_if,
connection_type, (opportunistic) ? 'T' : 'F'));
BTA_GATTC_Open(client_if, remote_bda, connection_type, opportunistic);
},
};
gatt_interface_t* gatt_interface = &default_gatt_interface;
gatt_interface_t& get_gatt_interface() { return *gatt_interface; }
} // namespace
void bta_dm_disc_disable_search_and_disc() { bta_dm_disable_search_and_disc(); }
void bta_dm_disc_gatt_cancel_open(const RawAddress& bd_addr) {
get_gatt_interface().BTA_GATTC_CancelOpen(0, bd_addr, false);
}
void bta_dm_disc_gatt_refresh(const RawAddress& bd_addr) {
get_gatt_interface().BTA_GATTC_Refresh(bd_addr);
}
void bta_dm_disc_remove_device(const RawAddress& bd_addr) {
if (bta_dm_search_cb.state == BTA_DM_DISCOVER_ACTIVE &&
bta_dm_search_cb.peer_bdaddr == bd_addr) {
log::info(
"Device removed while service discovery was pending, conclude the "
"service disvovery");
bta_dm_gatt_disc_complete((uint16_t)GATT_INVALID_CONN_ID,
(tGATT_STATUS)GATT_ERROR);
}
}
void bta_dm_disc_discover_next_device() { bta_dm_discover_next_device(); }
void bta_dm_disc_gattc_register() { bta_dm_gattc_register(); }
static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq,
const uint8_t* p_eir, uint16_t eir_len);
static void bta_dm_observe_cmpl_cb(void* p_result);
const uint16_t bta_service_id_to_uuid_lkup_tbl[BTA_MAX_SERVICE_ID] = {
UUID_SERVCLASS_PNP_INFORMATION, /* Reserved */
UUID_SERVCLASS_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */
UUID_SERVCLASS_DIALUP_NETWORKING, /* BTA_DUN_SERVICE_ID */
UUID_SERVCLASS_AUDIO_SOURCE, /* BTA_A2DP_SOURCE_SERVICE_ID */
UUID_SERVCLASS_LAN_ACCESS_USING_PPP, /* BTA_LAP_SERVICE_ID */
UUID_SERVCLASS_HEADSET, /* BTA_HSP_HS_SERVICE_ID */
UUID_SERVCLASS_HF_HANDSFREE, /* BTA_HFP_HS_SERVICE_ID */
UUID_SERVCLASS_OBEX_OBJECT_PUSH, /* BTA_OPP_SERVICE_ID */
UUID_SERVCLASS_OBEX_FILE_TRANSFER, /* BTA_FTP_SERVICE_ID */
UUID_SERVCLASS_CORDLESS_TELEPHONY, /* BTA_CTP_SERVICE_ID */
UUID_SERVCLASS_INTERCOM, /* BTA_ICP_SERVICE_ID */
UUID_SERVCLASS_IRMC_SYNC, /* BTA_SYNC_SERVICE_ID */
UUID_SERVCLASS_DIRECT_PRINTING, /* BTA_BPP_SERVICE_ID */
UUID_SERVCLASS_IMAGING_RESPONDER, /* BTA_BIP_SERVICE_ID */
UUID_SERVCLASS_PANU, /* BTA_PANU_SERVICE_ID */
UUID_SERVCLASS_NAP, /* BTA_NAP_SERVICE_ID */
UUID_SERVCLASS_GN, /* BTA_GN_SERVICE_ID */
UUID_SERVCLASS_SAP, /* BTA_SAP_SERVICE_ID */
UUID_SERVCLASS_AUDIO_SINK, /* BTA_A2DP_SERVICE_ID */
UUID_SERVCLASS_AV_REMOTE_CONTROL, /* BTA_AVRCP_SERVICE_ID */
UUID_SERVCLASS_HUMAN_INTERFACE, /* BTA_HID_SERVICE_ID */
UUID_SERVCLASS_VIDEO_SINK, /* BTA_VDP_SERVICE_ID */
UUID_SERVCLASS_PBAP_PSE, /* BTA_PBAP_SERVICE_ID */
UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, /* BTA_HSP_SERVICE_ID */
UUID_SERVCLASS_AG_HANDSFREE, /* BTA_HFP_SERVICE_ID */
UUID_SERVCLASS_MESSAGE_ACCESS, /* BTA_MAP_SERVICE_ID */
UUID_SERVCLASS_MESSAGE_NOTIFICATION, /* BTA_MN_SERVICE_ID */
UUID_SERVCLASS_HDP_PROFILE, /* BTA_HDP_SERVICE_ID */
UUID_SERVCLASS_PBAP_PCE, /* BTA_PCE_SERVICE_ID */
UUID_PROTOCOL_ATT /* BTA_GATT_SERVICE_ID */
};
#define MAX_DISC_RAW_DATA_BUF (4096)
static uint8_t g_disc_raw_data_buf[MAX_DISC_RAW_DATA_BUF];
static void bta_dm_search_set_state(tBTA_DM_STATE state) {
bta_dm_search_cb.state = state;
}
static tBTA_DM_STATE bta_dm_search_get_state() {
return bta_dm_search_cb.state;
}
/*******************************************************************************
*
* Function bta_dm_search_start
*
* Description Starts an inquiry
*
*
* Returns void
*
******************************************************************************/
static void bta_dm_search_start(tBTA_DM_MSG* p_data) {
bta_dm_gattc_register();
get_btm_client_interface().db.BTM_ClearInqDb(nullptr);
/* save search params */
bta_dm_search_cb.p_search_cback = p_data->search.p_cback;
bta_dm_search_cb.services = p_data->search.services;
const tBTM_STATUS btm_status =
BTM_StartInquiry(bta_dm_inq_results_cb, bta_dm_inq_cmpl_cb);
switch (btm_status) {
case BTM_CMD_STARTED:
// Completion callback will be executed when controller inquiry
// timer pops or is cancelled by the user
break;
default:
log::warn("Unable to start device discovery search btm_status:{}",
btm_status_text(btm_status));
// Not started so completion callback is executed now
bta_dm_inq_cmpl(0);
break;
}
}
/*******************************************************************************
*
* Function bta_dm_search_cancel
*
* Description Cancels an ongoing search for devices
*
*
* Returns void
*
******************************************************************************/
static void bta_dm_search_cancel() {
if (BTM_IsInquiryActive()) {
BTM_CancelInquiry();
bta_dm_search_cancel_notify();
bta_dm_search_cmpl();
}
/* If no Service Search going on then issue cancel remote name in case it is
active */
else if (!bta_dm_search_cb.name_discover_done) {
get_btm_client_interface().peer.BTM_CancelRemoteDeviceName();
#ifndef TARGET_FLOSS
/* bta_dm_search_cmpl is called when receiving the remote name cancel evt */
if (!IS_FLAG_ENABLED(
bta_dm_defer_device_discovery_state_change_until_rnr_complete)) {
bta_dm_search_cmpl();
}
#endif
} else {
bta_dm_inq_cmpl(0);
}
}
/*******************************************************************************
*
* Function bta_dm_discover
*
* Description Discovers services on a remote device
*
*
* Returns void
*
******************************************************************************/
static void bta_dm_discover(tBTA_DM_MSG* p_data) {
/* save the search condition */
bta_dm_search_cb.services = BTA_ALL_SERVICE_MASK;
bta_dm_gattc_register();
bta_dm_search_cb.p_search_cback = p_data->discover.p_cback;
bta_dm_search_cb.services_to_search = bta_dm_search_cb.services;
bta_dm_search_cb.service_index = 0;
bta_dm_search_cb.services_found = 0;
bta_dm_search_cb.peer_name[0] = 0;
bta_dm_search_cb.p_btm_inq_info =
get_btm_client_interface().db.BTM_InqDbRead(p_data->discover.bd_addr);
bta_dm_search_cb.transport = p_data->discover.transport;
bta_dm_search_cb.name_discover_done = false;
log::info(
"bta_dm_discovery: starting service discovery to {} , transport: {}",
ADDRESS_TO_LOGGABLE_CSTR(p_data->discover.bd_addr),
bt_transport_text(p_data->discover.transport));
bta_dm_discover_device(p_data->discover.bd_addr);
}
/*******************************************************************************
*
* Function bta_dm_disable_search_and_disc
*
* Description Cancels an ongoing search or discovery for devices in case
* of a Bluetooth disable
*
* Returns void
*
******************************************************************************/
static void bta_dm_disable_search_and_disc(void) {
switch (bta_dm_search_get_state()) {
case BTA_DM_SEARCH_IDLE:
break;
case BTA_DM_SEARCH_ACTIVE:
case BTA_DM_SEARCH_CANCELLING:
case BTA_DM_DISCOVER_ACTIVE:
default:
log::debug(
"Search state machine is not idle so issuing search cancel current "
"state:{}",
bta_dm_state_text(bta_dm_search_get_state()));
bta_dm_search_cancel();
}
}
/*******************************************************************************
*
* Function bta_dm_read_remote_device_name
*
* Description Initiate to get remote device name
*
* Returns true if started to get remote name
*
******************************************************************************/
static bool bta_dm_read_remote_device_name(const RawAddress& bd_addr,
tBT_TRANSPORT transport) {
tBTM_STATUS btm_status;
log::verbose("");
bta_dm_search_cb.peer_bdaddr = bd_addr;
bta_dm_search_cb.peer_name[0] = 0;
btm_status = get_btm_client_interface().peer.BTM_ReadRemoteDeviceName(
bta_dm_search_cb.peer_bdaddr, bta_dm_remname_cback, transport);
if (btm_status == BTM_CMD_STARTED) {
log::verbose("BTM_ReadRemoteDeviceName is started");
return (true);
} else if (btm_status == BTM_BUSY) {
log::verbose("BTM_ReadRemoteDeviceName is busy");
/* Remote name discovery is on going now so BTM cannot notify through
* "bta_dm_remname_cback" */
/* adding callback to get notified that current reading remote name done */
get_btm_client_interface().security.BTM_SecAddRmtNameNotifyCallback(
&bta_dm_service_search_remname_cback);
return (true);
} else {
log::warn("BTM_ReadRemoteDeviceName returns 0x{:02X}", btm_status);
return (false);
}
}
/*******************************************************************************
*
* Function bta_dm_inq_cmpl
*
* Description Process the inquiry complete event from BTM
*
* Returns void
*
******************************************************************************/
static void bta_dm_inq_cmpl(uint8_t num) {
if (bta_dm_search_get_state() == BTA_DM_SEARCH_CANCELLING) {
bta_dm_search_set_state(BTA_DM_SEARCH_IDLE);
bta_dm_execute_queued_request();
return;
}
if (bta_dm_search_get_state() != BTA_DM_SEARCH_ACTIVE) {
return;
}
tBTA_DM_SEARCH data;
log::verbose("bta_dm_inq_cmpl");
data.inq_cmpl.num_resps = num;
bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data);
bta_dm_search_cb.p_btm_inq_info =
get_btm_client_interface().db.BTM_InqDbFirst();
if (bta_dm_search_cb.p_btm_inq_info != NULL) {
/* start name and service discovery from the first device on inquiry result
*/
bta_dm_search_cb.name_discover_done = false;
bta_dm_search_cb.peer_name[0] = 0;
bta_dm_discover_device(
bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
} else {
bta_dm_search_cb.services = 0;
bta_dm_search_cmpl();
}
}
static void bta_dm_remote_name_cmpl(const tBTA_DM_MSG* p_data) {
CHECK(p_data != nullptr);
const tBTA_DM_REMOTE_NAME& remote_name_msg = p_data->remote_name_msg;
BTM_LogHistory(kBtmLogTag, remote_name_msg.bd_addr, "Remote name completed",
base::StringPrintf(
"status:%s state:%s name:\"%s\"",
hci_status_code_text(remote_name_msg.hci_status).c_str(),
bta_dm_state_text(bta_dm_search_get_state()).c_str(),
PRIVATE_NAME(remote_name_msg.bd_name)));
tBTM_INQ_INFO* p_btm_inq_info =
get_btm_client_interface().db.BTM_InqDbRead(remote_name_msg.bd_addr);
if (!bd_name_is_empty(remote_name_msg.bd_name) && p_btm_inq_info) {
p_btm_inq_info->appl_knows_rem_name = true;
}
// Callback with this property
if (bta_dm_search_cb.p_search_cback != nullptr) {
tBTA_DM_SEARCH search_data = {
.disc_res = // tBTA_DM_DISC_RES
{
.bd_addr = remote_name_msg.bd_addr,
.bd_name = {},
.services = {},
.device_type = {},
.num_uuids = 0UL,
.p_uuid_list = nullptr,
.result = (remote_name_msg.hci_status == HCI_SUCCESS) ? BTA_SUCCESS
: BTA_FAILURE,
.hci_status = remote_name_msg.hci_status,
},
};
if (remote_name_msg.hci_status == HCI_SUCCESS) {
bd_name_copy(search_data.disc_res.bd_name, remote_name_msg.bd_name);
}
bta_dm_search_cb.p_search_cback(BTA_DM_NAME_READ_EVT, &search_data);
} else {
log::warn("Received remote name complete without callback");
}
switch (bta_dm_search_get_state()) {
case BTA_DM_SEARCH_ACTIVE:
bta_dm_discover_device(bta_dm_search_cb.peer_bdaddr);
break;
case BTA_DM_DISCOVER_ACTIVE:
bta_dm_discover_device(remote_name_msg.bd_addr);
break;
case BTA_DM_SEARCH_IDLE:
case BTA_DM_SEARCH_CANCELLING:
log::warn("Received remote name request in state:{}",
bta_dm_state_text(bta_dm_search_get_state()));
break;
}
}
static void store_avrcp_profile_feature(tSDP_DISC_REC* sdp_rec) {
tSDP_DISC_ATTR* p_attr =
get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
sdp_rec, ATTR_ID_SUPPORTED_FEATURES);
if (p_attr == NULL) {
return;
}
uint16_t avrcp_features = p_attr->attr_value.v.u16;
if (avrcp_features == 0) {
return;
}
if (btif_config_set_bin(sdp_rec->remote_bd_addr.ToString().c_str(),
BTIF_STORAGE_KEY_AV_REM_CTRL_FEATURES,
(const uint8_t*)&avrcp_features,
sizeof(avrcp_features))) {
log::info("Saving avrcp_features: 0x{:x}", avrcp_features);
} else {
log::info("Failed to store avrcp_features 0x{:x} for {}", avrcp_features,
ADDRESS_TO_LOGGABLE_CSTR(sdp_rec->remote_bd_addr));
}
}
static void bta_dm_store_audio_profiles_version() {
struct AudioProfile {
const uint16_t servclass_uuid;
const uint16_t btprofile_uuid;
const char* profile_key;
void (*store_audio_profile_feature)(tSDP_DISC_REC*);
};
std::array<AudioProfile, 1> audio_profiles = {{
{
.servclass_uuid = UUID_SERVCLASS_AV_REMOTE_CONTROL,
.btprofile_uuid = UUID_SERVCLASS_AV_REMOTE_CONTROL,
.profile_key = BTIF_STORAGE_KEY_AVRCP_CONTROLLER_VERSION,
.store_audio_profile_feature = store_avrcp_profile_feature,
},
}};
for (const auto& audio_profile : audio_profiles) {
tSDP_DISC_REC* sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb(
bta_dm_search_cb.p_sdp_db, audio_profile.servclass_uuid, NULL);
if (sdp_rec == NULL) continue;
if (get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
sdp_rec, ATTR_ID_BT_PROFILE_DESC_LIST) == NULL)
continue;
uint16_t profile_version = 0;
/* get profile version (if failure, version parameter is not updated) */
get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec(
sdp_rec, audio_profile.btprofile_uuid, &profile_version);
if (profile_version != 0) {
if (btif_config_set_bin(sdp_rec->remote_bd_addr.ToString().c_str(),
audio_profile.profile_key,
(const uint8_t*)&profile_version,
sizeof(profile_version))) {
} else {
log::info("Failed to store peer profile version for {}",
ADDRESS_TO_LOGGABLE_CSTR(sdp_rec->remote_bd_addr));
}
}
audio_profile.store_audio_profile_feature(sdp_rec);
}
}
/*******************************************************************************
*
* Function bta_dm_sdp_result
*
* Description Process the discovery result from sdp
*
* Returns void
*
******************************************************************************/
static void bta_dm_sdp_result(tBTA_DM_MSG* p_data) {
tSDP_DISC_REC* p_sdp_rec = NULL;
tBTA_DM_MSG* p_msg;
bool scn_found = false;
uint16_t service = 0xFFFF;
tSDP_PROTOCOL_ELEM pe;
std::vector<Uuid> uuid_list;
const tSDP_RESULT sdp_result = p_data->sdp_event.sdp_result;
if ((p_data->sdp_event.sdp_result == SDP_SUCCESS) ||
(p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH) ||
(p_data->sdp_event.sdp_result == SDP_DB_FULL)) {
log::verbose("sdp_result::0x{:x}", p_data->sdp_event.sdp_result);
do {
p_sdp_rec = NULL;
if (bta_dm_search_cb.service_index == (BTA_USER_SERVICE_ID + 1)) {
if (p_sdp_rec &&
get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec(
p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
bta_dm_search_cb.peer_scn = (uint8_t)pe.params[0];
scn_found = true;
}
} else {
service =
bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index - 1];
p_sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb(
bta_dm_search_cb.p_sdp_db, service, p_sdp_rec);
}
/* finished with BR/EDR services, now we check the result for GATT based
* service UUID */
if (bta_dm_search_cb.service_index == BTA_MAX_SERVICE_ID) {
/* all GATT based services */
std::vector<Uuid> gatt_uuids;
do {
/* find a service record, report it */
p_sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb(
bta_dm_search_cb.p_sdp_db, 0, p_sdp_rec);
if (p_sdp_rec) {
Uuid service_uuid;
if (get_legacy_stack_sdp_api()->record.SDP_FindServiceUUIDInRec(
p_sdp_rec, &service_uuid)) {
gatt_uuids.push_back(service_uuid);
}
}
} while (p_sdp_rec);
if (!gatt_uuids.empty()) {
log::info("GATT services discovered using SDP");
// send all result back to app
tBTA_DM_SEARCH result;
result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
BD_NAME_LEN + 1);
result.disc_ble_res.services = &gatt_uuids;
bta_dm_search_cb.p_search_cback(BTA_DM_GATT_OVER_SDP_RES_EVT,
&result);
}
} else {
/* SDP_DB_FULL means some records with the
required attributes were received */
if (((p_data->sdp_event.sdp_result == SDP_DB_FULL) &&
bta_dm_search_cb.services != BTA_ALL_SERVICE_MASK) ||
(p_sdp_rec != NULL)) {
if (service != UUID_SERVCLASS_PNP_INFORMATION) {
bta_dm_search_cb.services_found |=
(tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(
bta_dm_search_cb.service_index - 1));
uint16_t tmp_svc =
bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index -
1];
/* Add to the list of UUIDs */
uuid_list.push_back(Uuid::From16Bit(tmp_svc));
}
}
}
if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK &&
bta_dm_search_cb.services_to_search == 0) {
bta_dm_search_cb.service_index++;
} else /* regular one service per search or PNP search */
break;
} while (bta_dm_search_cb.service_index <= BTA_MAX_SERVICE_ID);
log::verbose("services_found = {:04x}", bta_dm_search_cb.services_found);
/* Collect the 128-bit services here and put them into the list */
if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) {
p_sdp_rec = NULL;
do {
/* find a service record, report it */
p_sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb_128bit(
bta_dm_search_cb.p_sdp_db, p_sdp_rec);
if (p_sdp_rec) {
// SDP_FindServiceUUIDInRec_128bit is used only once, refactor?
Uuid temp_uuid;
if (get_legacy_stack_sdp_api()
->record.SDP_FindServiceUUIDInRec_128bit(p_sdp_rec,
&temp_uuid)) {
uuid_list.push_back(temp_uuid);
}
}
} while (p_sdp_rec);
}
if (bluetooth::common::init_flags::
dynamic_avrcp_version_enhancement_is_enabled() &&
bta_dm_search_cb.services_to_search == 0) {
bta_dm_store_audio_profiles_version();
}
#if TARGET_FLOSS
tSDP_DI_GET_RECORD di_record;
if (get_legacy_stack_sdp_api()->device_id.SDP_GetDiRecord(
1, &di_record, bta_dm_search_cb.p_sdp_db) == SDP_SUCCESS) {
tBTA_DM_SEARCH result;
result.did_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
result.did_res.vendor_id_src = di_record.rec.vendor_id_source;
result.did_res.vendor_id = di_record.rec.vendor;
result.did_res.product_id = di_record.rec.product;
result.did_res.version = di_record.rec.version;
bta_dm_search_cb.p_search_cback(BTA_DM_DID_RES_EVT, &result);
}
#endif
/* if there are more services to search for */
if (bta_dm_search_cb.services_to_search) {
/* Free up the p_sdp_db before checking the next one */
bta_dm_free_sdp_db();
bta_dm_find_services(bta_dm_search_cb.peer_bdaddr);
} else {
/* callbacks */
/* start next bd_addr if necessary */
get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback(
&bta_dm_service_search_remname_cback);
BTM_LogHistory(
kBtmLogTag, bta_dm_search_cb.peer_bdaddr, "Discovery completed",
base::StringPrintf("Result:%s services_found:0x%x service_index:0x%d",
sdp_result_text(sdp_result).c_str(),
bta_dm_search_cb.services_found,
bta_dm_search_cb.service_index));
p_msg = (tBTA_DM_MSG*)osi_calloc(sizeof(tBTA_DM_MSG));
p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
p_msg->disc_result.result.disc_res.num_uuids = uuid_list.size();
p_msg->disc_result.result.disc_res.p_uuid_list = NULL;
if (uuid_list.size() > 0) {
// TODO(jpawlowski): make p_uuid_list into vector, and just copy
// vectors, but first get rid of bta_sys_sendmsg below.
p_msg->disc_result.result.disc_res.p_uuid_list =
(Uuid*)osi_calloc(uuid_list.size() * sizeof(Uuid));
memcpy(p_msg->disc_result.result.disc_res.p_uuid_list, uuid_list.data(),
uuid_list.size() * sizeof(Uuid));
}
// Copy the raw_data to the discovery result structure
if (bta_dm_search_cb.p_sdp_db != NULL &&
bta_dm_search_cb.p_sdp_db->raw_used != 0 &&
bta_dm_search_cb.p_sdp_db->raw_data != NULL) {
log::verbose("raw_data used = 0x{:x} raw_data_ptr = 0x{}",
bta_dm_search_cb.p_sdp_db->raw_used,
fmt::ptr(bta_dm_search_cb.p_sdp_db->raw_data));
bta_dm_search_cb.p_sdp_db->raw_data =
NULL; // no need to free this - it is a global assigned.
bta_dm_search_cb.p_sdp_db->raw_used = 0;
bta_dm_search_cb.p_sdp_db->raw_size = 0;
} else {
log::verbose("raw data size is 0 or raw_data is null!!");
}
/* Done with p_sdp_db. Free it */
bta_dm_free_sdp_db();
p_msg->disc_result.result.disc_res.services =
bta_dm_search_cb.services_found;
// Piggy back the SCN over result field
if (scn_found) {
p_msg->disc_result.result.disc_res.result =
static_cast<tBTA_STATUS>((3 + bta_dm_search_cb.peer_scn));
p_msg->disc_result.result.disc_res.services |= BTA_USER_SERVICE_MASK;
log::verbose("Piggy back the SCN over result field SCN={}",
bta_dm_search_cb.peer_scn);
}
p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
bta_dm_get_remname(), BD_NAME_LEN + 1);
bta_sys_sendmsg(p_msg);
}
} else {
BTM_LogHistory(
kBtmLogTag, bta_dm_search_cb.peer_bdaddr, "Discovery failed",
base::StringPrintf("Result:%s", sdp_result_text(sdp_result).c_str()));
log::error("SDP connection failed {}", sdp_status_text(sdp_result));
if (p_data->sdp_event.sdp_result == SDP_CONN_FAILED)
bta_dm_search_cb.wait_disc = false;
/* not able to connect go to next device */
if (bta_dm_search_cb.p_sdp_db)
osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback(
&bta_dm_service_search_remname_cback);
p_msg = (tBTA_DM_MSG*)osi_calloc(sizeof(tBTA_DM_MSG));
p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
p_msg->disc_result.result.disc_res.result = BTA_FAILURE;
p_msg->disc_result.result.disc_res.services =
bta_dm_search_cb.services_found;
p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
bta_dm_get_remname(), BD_NAME_LEN + 1);
bta_sys_sendmsg(p_msg);
}
}
/** Callback of peer's DIS reply. This is only called for floss */
#if TARGET_FLOSS
static void bta_dm_read_dis_cmpl(const RawAddress& addr,
tDIS_VALUE* p_dis_value) {
if (!p_dis_value) {
log::warn("read DIS failed");
} else {
tBTA_DM_SEARCH result;
result.did_res.bd_addr = addr;
result.did_res.vendor_id_src = p_dis_value->pnp_id.vendor_id_src;
result.did_res.vendor_id = p_dis_value->pnp_id.vendor_id;
result.did_res.product_id = p_dis_value->pnp_id.product_id;
result.did_res.version = p_dis_value->pnp_id.product_version;
bta_dm_search_cb.p_search_cback(BTA_DM_DID_RES_EVT, &result);
}
bta_dm_execute_queued_request();
}
#endif
/*******************************************************************************
*
* Function bta_dm_search_cmpl
*
* Description Sends event to application
*
* Returns void
*
******************************************************************************/
static void bta_dm_search_cmpl() {
bta_dm_search_set_state(BTA_DM_SEARCH_IDLE);
uint16_t conn_id = bta_dm_search_cb.conn_id;
tBTA_DM_SEARCH result;
std::vector<Uuid> gatt_services;
result.disc_ble_res.services = &gatt_services;
result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
BD_NAME_LEN + 1);
bool send_gatt_results =
bluetooth::common::init_flags::
always_send_services_if_gatt_disc_done_is_enabled()
? bta_dm_search_cb.gatt_disc_active
: false;
/* no BLE connection, i.e. Classic service discovery end */
if (conn_id == GATT_INVALID_CONN_ID) {
if (bta_dm_search_cb.gatt_disc_active) {
log::warn(
"GATT active but no BLE connection, likely disconnected midway "
"through");
} else {
log::info("No BLE connection, processing classic results");
}
} else {
btgatt_db_element_t* db = NULL;
int count = 0;
get_gatt_interface().BTA_GATTC_GetGattDb(conn_id, 0x0000, 0xFFFF, &db,
&count);
if (count != 0) {
for (int i = 0; i < count; i++) {
// we process service entries only
if (db[i].type == BTGATT_DB_PRIMARY_SERVICE) {
gatt_services.push_back(db[i].uuid);
}
}
osi_free(db);
log::info(
"GATT services discovered using LE Transport, will always send to "
"upper layer");
send_gatt_results = true;
} else {
log::warn("Empty GATT database - no BLE services discovered");
}
}
// send all result back to app
if (send_gatt_results) {
log::info("Sending GATT results to upper layer");
bta_dm_search_cb.p_search_cback(BTA_DM_GATT_OVER_LE_RES_EVT, &result);
}
bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, nullptr);
bta_dm_search_cb.gatt_disc_active = false;
#if TARGET_FLOSS
if (conn_id != GATT_INVALID_CONN_ID &&
DIS_ReadDISInfo(bta_dm_search_cb.peer_bdaddr, bta_dm_read_dis_cmpl,
DIS_ATTR_PNP_ID_BIT)) {
return;
}
#endif
bta_dm_execute_queued_request();
}
/*******************************************************************************
*
* Function bta_dm_disc_result
*
* Description Service discovery result when discovering services on a
* device
*
* Returns void
*
******************************************************************************/
static void bta_dm_disc_result(tBTA_DM_MSG* p_data) {
log::verbose("");
/* disc_res.device_type is set only when GATT discovery is finished in
* bta_dm_gatt_disc_complete */
bool is_gatt_over_ble = ((p_data->disc_result.result.disc_res.device_type &
BT_DEVICE_TYPE_BLE) != 0);
/* if any BR/EDR service discovery has been done, report the event */
if (!is_gatt_over_ble && (bta_dm_search_cb.services &
((BTA_ALL_SERVICE_MASK | BTA_USER_SERVICE_MASK) &
~BTA_BLE_SERVICE_MASK)))
bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT,
&p_data->disc_result.result);
get_gatt_interface().BTA_GATTC_CancelOpen(0, bta_dm_search_cb.peer_bdaddr,
true);
bta_dm_search_cmpl();
}
/*******************************************************************************
*
* Function bta_dm_search_result
*
* Description Service discovery result while searching for devices
*
* Returns void
*
******************************************************************************/
static void bta_dm_search_result(tBTA_DM_MSG* p_data) {
log::verbose("searching:0x{:04x}, result:0x{:04x}", bta_dm_search_cb.services,
p_data->disc_result.result.disc_res.services);
/* call back if application wants name discovery or found services that
* application is searching */
if ((!bta_dm_search_cb.services) ||
((bta_dm_search_cb.services) &&
(p_data->disc_result.result.disc_res.services))) {
if (bta_dm_search_cb.p_search_cback) {
bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT,
&p_data->disc_result.result);
} else {
log::warn("Received search result without valid callback");
}
}
/* if searching did not initiate to create link */
if (!bta_dm_search_cb.wait_disc) {
/* if service searching is done with EIR, don't search next device */
if (bta_dm_search_cb.p_btm_inq_info) bta_dm_discover_next_device();
} else {
/* wait until link is disconnected or timeout */
bta_dm_search_cb.sdp_results = true;
alarm_set_on_mloop(bta_dm_search_cb.search_timer,
1000 * (L2CAP_LINK_INACTIVITY_TOUT + 1),
bta_dm_search_timer_cback, NULL);
}
}
/*******************************************************************************
*
* Function bta_dm_search_timer_cback
*
* Description Called when ACL disconnect time is over
*
*
* Returns void
*
******************************************************************************/
static void bta_dm_search_timer_cback(UNUSED_ATTR void* data) {
log::verbose("");
bta_dm_search_cb.wait_disc = false;
/* proceed with next device */
bta_dm_discover_next_device();
}
/*******************************************************************************
*
* Function bta_dm_free_sdp_db
*
* Description Frees SDP data base
*
* Returns void
*
******************************************************************************/
static void bta_dm_free_sdp_db() {
osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
}
/*******************************************************************************
*
* Function bta_dm_queue_search
*
* Description Queues search command
*
* Returns void
*
******************************************************************************/
static void bta_dm_queue_search(tBTA_DM_MSG* p_data) {
if (bta_dm_search_cb.p_pending_search) {
log::warn("Overwrote previous device discovery inquiry scan request");
}
osi_free_and_reset((void**)&bta_dm_search_cb.p_pending_search);
bta_dm_search_cb.p_pending_search =
(tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_API_SEARCH));
memcpy(bta_dm_search_cb.p_pending_search, p_data, sizeof(tBTA_DM_API_SEARCH));
log::info("Queued device discovery inquiry scan request");
}
/*******************************************************************************
*
* Function bta_dm_queue_disc
*
* Description Queues discovery command
*
* Returns void
*
******************************************************************************/
static void bta_dm_queue_disc(tBTA_DM_MSG* p_data) {
tBTA_DM_MSG* p_pending_discovery =
(tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_API_DISCOVER));
memcpy(p_pending_discovery, p_data, sizeof(tBTA_DM_API_DISCOVER));
log::info("bta_dm_discovery: queuing service discovery to {}",
ADDRESS_TO_LOGGABLE_CSTR(p_pending_discovery->discover.bd_addr));
fixed_queue_enqueue(bta_dm_search_cb.pending_discovery_queue,
p_pending_discovery);
}
/*******************************************************************************
*
* Function bta_dm_execute_queued_request
*
* Description Executes queued request if one exists
*
* Returns void
*
******************************************************************************/
static void bta_dm_execute_queued_request() {
tBTA_DM_MSG* p_pending_discovery = (tBTA_DM_MSG*)fixed_queue_try_dequeue(
bta_dm_search_cb.pending_discovery_queue);
if (p_pending_discovery) {
log::info("Start pending discovery");
bta_sys_sendmsg(p_pending_discovery);
} else if (bta_dm_search_cb.p_pending_search) {
log::info("Start pending search");
bta_sys_sendmsg(bta_dm_search_cb.p_pending_search);
bta_dm_search_cb.p_pending_search = NULL;
}
}
/*******************************************************************************
*
* Function bta_dm_is_search_request_queued
*
* Description Checks if there is a queued search request
*
* Returns bool
*
******************************************************************************/
bool bta_dm_is_search_request_queued() {
return bta_dm_search_cb.p_pending_search != NULL;
}
/*******************************************************************************
*
* Function bta_dm_search_clear_queue
*
* Description Clears the queue if API search cancel is called
*
* Returns void
*
******************************************************************************/
static void bta_dm_search_clear_queue() {
osi_free_and_reset((void**)&bta_dm_search_cb.p_pending_search);
if (bluetooth::common::InitFlags::
IsBtmDmFlushDiscoveryQueueOnSearchCancel()) {
fixed_queue_flush(bta_dm_search_cb.pending_discovery_queue, osi_free);
}
}
/*******************************************************************************
*
* Function bta_dm_search_cancel_notify
*
* Description Notify application that search has been cancelled
*
* Returns void
*
******************************************************************************/
static void bta_dm_search_cancel_notify() {
if (bta_dm_search_cb.p_search_cback) {
bta_dm_search_cb.p_search_cback(BTA_DM_SEARCH_CANCEL_CMPL_EVT, NULL);
}
switch (bta_dm_search_get_state()) {
case BTA_DM_SEARCH_ACTIVE:
case BTA_DM_SEARCH_CANCELLING:
if (!bta_dm_search_cb.name_discover_done) {
get_btm_client_interface().peer.BTM_CancelRemoteDeviceName();
}
break;
case BTA_DM_SEARCH_IDLE:
case BTA_DM_DISCOVER_ACTIVE:
// Nothing to do
break;
}
}
/*******************************************************************************
*
* Function bta_dm_find_services
*
* Description Starts discovery on a device
*
* Returns void
*
******************************************************************************/
static void bta_dm_find_services(const RawAddress& bd_addr) {
while (bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) {
Uuid uuid = Uuid::kEmpty;
if (bta_dm_search_cb.services_to_search &
(tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(
bta_dm_search_cb.service_index))) {
bta_dm_search_cb.p_sdp_db =
(tSDP_DISCOVERY_DB*)osi_malloc(BTA_DM_SDP_DB_SIZE);
log::verbose("bta_dm_search_cb.services = {:04x}***********",
bta_dm_search_cb.services);
/* try to search all services by search based on L2CAP UUID */
if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) {
log::info("services_to_search={:08x}",
bta_dm_search_cb.services_to_search);
if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK) {
uuid = Uuid::From16Bit(bta_service_id_to_uuid_lkup_tbl[0]);
bta_dm_search_cb.services_to_search &= ~BTA_RES_SERVICE_MASK;
} else {
uuid = Uuid::From16Bit(UUID_PROTOCOL_L2CAP);
bta_dm_search_cb.services_to_search = 0;
}
} else {
/* for LE only profile */
if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID) {
uuid = Uuid::From16Bit(
bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]);
bta_dm_search_cb.services_to_search &= (tBTA_SERVICE_MASK)(~(
BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index)));
} else {
/* remove the service from services to be searched */
bta_dm_search_cb.services_to_search &= (tBTA_SERVICE_MASK)(~(
BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index)));
uuid = Uuid::From16Bit(
bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]);
}
}
log::info("search UUID = {}", uuid.ToString());
get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb(
bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1, &uuid, 0, NULL);
memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
bta_dm_search_cb.p_sdp_db->raw_data = g_disc_raw_data_buf;
bta_dm_search_cb.p_sdp_db->raw_size = MAX_DISC_RAW_DATA_BUF;
if (!get_legacy_stack_sdp_api()
->service.SDP_ServiceSearchAttributeRequest(
bd_addr, bta_dm_search_cb.p_sdp_db, &bta_dm_sdp_callback)) {
/*
* If discovery is not successful with this device, then
* proceed with the next one.
*/
osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
bta_dm_search_cb.service_index = BTA_MAX_SERVICE_ID;
} else {
if (uuid == Uuid::From16Bit(UUID_PROTOCOL_L2CAP)) {
if (!is_sdp_pbap_pce_disabled(bd_addr)) {
log::debug("SDP search for PBAP Client");
BTA_SdpSearch(bd_addr, Uuid::From16Bit(UUID_SERVCLASS_PBAP_PCE));
}
}
bta_dm_search_cb.service_index++;
return;
}
}
bta_dm_search_cb.service_index++;
}
/* no more services to be discovered */
if (bta_dm_search_cb.service_index >= BTA_MAX_SERVICE_ID) {
tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
/* initialize the data structure */
memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES));
p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
p_msg->disc_result.result.disc_res.services =
bta_dm_search_cb.services_found;
p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
bta_dm_get_remname(), BD_NAME_LEN + 1);
bta_sys_sendmsg(p_msg);
}
}
/*******************************************************************************
*
* Function bta_dm_discover_next_device
*
* Description Starts discovery on the next device in Inquiry data base
*
* Returns void
*
******************************************************************************/
static void bta_dm_discover_next_device(void) {
log::verbose("bta_dm_discover_next_device");
/* searching next device on inquiry result */
bta_dm_search_cb.p_btm_inq_info = get_btm_client_interface().db.BTM_InqDbNext(
bta_dm_search_cb.p_btm_inq_info);
if (bta_dm_search_cb.p_btm_inq_info != NULL) {
bta_dm_search_cb.name_discover_done = false;
bta_dm_search_cb.peer_name[0] = 0;
bta_dm_discover_device(
bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
} else {
tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
/* no devices, search complete */
bta_dm_search_cb.services = 0;
p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
bta_sys_sendmsg(p_msg);
}
}
/*******************************************************************************
*
* Function bta_dm_discover_device
*
* Description Starts name and service discovery on the device
*
* Returns void
*
******************************************************************************/
static tBT_TRANSPORT bta_dm_determine_discovery_transport(
const RawAddress& remote_bd_addr) {
tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
if (bta_dm_search_cb.transport == BT_TRANSPORT_AUTO) {
tBT_DEVICE_TYPE dev_type;
tBLE_ADDR_TYPE addr_type;
get_btm_client_interface().peer.BTM_ReadDevInfo(remote_bd_addr, &dev_type,
&addr_type);
if (dev_type == BT_DEVICE_TYPE_BLE || addr_type == BLE_ADDR_RANDOM) {
transport = BT_TRANSPORT_LE;
} else if (dev_type == BT_DEVICE_TYPE_DUMO) {
if (get_btm_client_interface().peer.BTM_IsAclConnectionUp(
remote_bd_addr, BT_TRANSPORT_BR_EDR)) {
transport = BT_TRANSPORT_BR_EDR;
} else if (get_btm_client_interface().peer.BTM_IsAclConnectionUp(
remote_bd_addr, BT_TRANSPORT_LE)) {
transport = BT_TRANSPORT_LE;
}
}
} else {
transport = bta_dm_search_cb.transport;
}
return transport;
}
static void bta_dm_discover_device(const RawAddress& remote_bd_addr) {
const tBT_TRANSPORT transport =
bta_dm_determine_discovery_transport(remote_bd_addr);
log::verbose("BDA: {}", ADDRESS_TO_LOGGABLE_STR(remote_bd_addr));
bta_dm_search_cb.peer_bdaddr = remote_bd_addr;
log::verbose(
"name_discover_done = {} p_btm_inq_info 0x{} state = {}, transport={}",
bta_dm_search_cb.name_discover_done,
fmt::ptr(bta_dm_search_cb.p_btm_inq_info), bta_dm_search_get_state(),
transport);
if (bta_dm_search_cb.p_btm_inq_info) {
log::verbose("appl_knows_rem_name {}",
bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name);
}
if (((bta_dm_search_cb.p_btm_inq_info) &&
(bta_dm_search_cb.p_btm_inq_info->results.device_type ==
BT_DEVICE_TYPE_BLE) &&
(bta_dm_search_get_state() == BTA_DM_SEARCH_ACTIVE)) ||
(transport == BT_TRANSPORT_LE &&
interop_match_addr(INTEROP_DISABLE_NAME_REQUEST,
&bta_dm_search_cb.peer_bdaddr))) {
/* Do not perform RNR for LE devices at inquiry complete*/
bta_dm_search_cb.name_discover_done = true;
}
// If we already have the name we can skip getting the name
if (BTM_IsRemoteNameKnown(remote_bd_addr, transport) &&
bluetooth::common::init_flags::sdp_skip_rnr_if_known_is_enabled()) {
log::debug(
"Security record already known skipping read remote name peer:{}",
ADDRESS_TO_LOGGABLE_CSTR(remote_bd_addr));
bta_dm_search_cb.name_discover_done = true;
}
/* if name discovery is not done and application needs remote name */
if ((!bta_dm_search_cb.name_discover_done) &&
((bta_dm_search_cb.p_btm_inq_info == NULL) ||
(bta_dm_search_cb.p_btm_inq_info &&
(!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name)))) {
if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr,
transport)) {
if (bta_dm_search_get_state() != BTA_DM_DISCOVER_ACTIVE) {
log::debug("Reset transport state for next discovery");
bta_dm_search_cb.transport = BT_TRANSPORT_AUTO;
}
BTM_LogHistory(kBtmLogTag, bta_dm_search_cb.peer_bdaddr,
"Read remote name",
base::StringPrintf("Transport:%s",
bt_transport_text(transport).c_str()));
return;
} else {
log::error("Unable to start read remote device name");
}
/* starting name discovery failed */
bta_dm_search_cb.name_discover_done = true;
}
/* Reset transport state for next discovery */
bta_dm_search_cb.transport = BT_TRANSPORT_AUTO;
bool sdp_disable = HID_HostSDPDisable(remote_bd_addr);
if (sdp_disable)
log::debug("peer:{} with HIDSDPDisable attribute.",
ADDRESS_TO_LOGGABLE_CSTR(remote_bd_addr));
/* if application wants to discover service and HIDSDPDisable attribute is
false.
Classic mouses with this attribute should not start SDP here, because the
SDP has been done during bonding. SDP request here will interleave with
connections to the Control or Interrupt channels */
if (bta_dm_search_cb.services && !sdp_disable) {
BTM_LogHistory(kBtmLogTag, remote_bd_addr, "Discovery started ",
base::StringPrintf("Transport:%s",
bt_transport_text(transport).c_str()));
/* initialize variables */
bta_dm_search_cb.service_index = 0;
bta_dm_search_cb.services_found = 0;
bta_dm_search_cb.services_to_search = bta_dm_search_cb.services;
/* if seaching with EIR is not completed */
if (bta_dm_search_cb.services_to_search) {
/* check whether connection already exists to the device
if connection exists, we don't have to wait for ACL
link to go down to start search on next device */
if (transport == BT_TRANSPORT_BR_EDR) {
if (get_btm_client_interface().peer.BTM_IsAclConnectionUp(
bta_dm_search_cb.peer_bdaddr, BT_TRANSPORT_BR_EDR))
bta_dm_search_cb.wait_disc = false;
else
bta_dm_search_cb.wait_disc = true;
}
if (bta_dm_search_cb.p_btm_inq_info) {
log::verbose(
"p_btm_inq_info 0x{} results.device_type 0x{:x} services_to_search "
"0x{:x}",
fmt::ptr(bta_dm_search_cb.p_btm_inq_info),
bta_dm_search_cb.p_btm_inq_info->results.device_type,
bta_dm_search_cb.services_to_search);
}
if (transport == BT_TRANSPORT_LE) {
if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK) {
log::info("bta_dm_discovery: starting GATT discovery on {}",
ADDRESS_TO_LOGGABLE_CSTR(bta_dm_search_cb.peer_bdaddr));
// set the raw data buffer here
memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
/* start GATT for service discovery */
btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
return;
}
} else {
log::info("bta_dm_discovery: starting SDP discovery on {}",
ADDRESS_TO_LOGGABLE_CSTR(bta_dm_search_cb.peer_bdaddr));
bta_dm_search_cb.sdp_results = false;
bta_dm_find_services(bta_dm_search_cb.peer_bdaddr);
return;
}
}
}
/* name discovery and service discovery are done for this device */
tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
/* initialize the data structure */
memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES));
p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
bta_dm_get_remname(), BD_NAME_LEN + 1);
bta_sys_sendmsg(p_msg);
}
/*******************************************************************************
*
* Function bta_dm_sdp_callback
*
* Description Callback from sdp with discovery status
*
* Returns void
*
******************************************************************************/
static void bta_dm_sdp_callback(UNUSED_ATTR const RawAddress& bd_addr,
tSDP_STATUS sdp_status) {
tBTA_DM_SDP_RESULT* p_msg =
(tBTA_DM_SDP_RESULT*)osi_malloc(sizeof(tBTA_DM_SDP_RESULT));
p_msg->hdr.event = BTA_DM_SDP_RESULT_EVT;
p_msg->sdp_result = sdp_status;
bta_sys_sendmsg(p_msg);
}
/*******************************************************************************
*
* Function bta_dm_inq_results_cb
*
* Description Inquiry results callback from BTM
*
* Returns void
*
******************************************************************************/
static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir,
uint16_t eir_len) {
tBTA_DM_SEARCH result;
tBTM_INQ_INFO* p_inq_info;
uint16_t service_class;
result.inq_res.bd_addr = p_inq->remote_bd_addr;
// Pass the original address to GattService#onScanResult
result.inq_res.original_bda = p_inq->original_bda;
result.inq_res.dev_class = p_inq->dev_class;
BTM_COD_SERVICE_CLASS(service_class, p_inq->dev_class);
result.inq_res.is_limited =
(service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? true : false;
result.inq_res.rssi = p_inq->rssi;
result.inq_res.ble_addr_type = p_inq->ble_addr_type;
result.inq_res.inq_result_type = p_inq->inq_result_type;
result.inq_res.device_type = p_inq->device_type;
result.inq_res.flag = p_inq->flag;
result.inq_res.include_rsi = p_inq->include_rsi;
result.inq_res.clock_offset = p_inq->clock_offset;
/* application will parse EIR to find out remote device name */
result.inq_res.p_eir = const_cast<uint8_t*>(p_eir);
result.inq_res.eir_len = eir_len;
result.inq_res.ble_evt_type = p_inq->ble_evt_type;
p_inq_info =
get_btm_client_interface().db.BTM_InqDbRead(p_inq->remote_bd_addr);
if (p_inq_info != NULL) {
/* initialize remt_name_not_required to false so that we get the name by
* default */
result.inq_res.remt_name_not_required = false;
}
if (bta_dm_search_cb.p_search_cback)
bta_dm_search_cb.p_search_cback(BTA_DM_INQ_RES_EVT, &result);
if (p_inq_info) {
/* application indicates if it knows the remote name, inside the callback
copy that to the inquiry data base*/
if (result.inq_res.remt_name_not_required)
p_inq_info->appl_knows_rem_name = true;
}
}
/*******************************************************************************
*
* Function bta_dm_inq_cmpl_cb
*
* Description Inquiry complete callback from BTM
*
* Returns void
*
******************************************************************************/
static void bta_dm_inq_cmpl_cb(void* p_result) {
log::verbose("");
bta_dm_inq_cmpl(((tBTM_INQUIRY_CMPL*)p_result)->num_resp);
}
/*******************************************************************************
*
* Function bta_dm_service_search_remname_cback
*
* Description Remote name call back from BTM during service discovery
*
* Returns void
*
******************************************************************************/
static void bta_dm_service_search_remname_cback(const RawAddress& bd_addr,
UNUSED_ATTR DEV_CLASS dc,
tBTM_BD_NAME bd_name) {
tBTM_REMOTE_DEV_NAME rem_name = {};
tBTM_STATUS btm_status;
log::verbose("name=<{}>", reinterpret_cast<char const*>(bd_name));
/* if this is what we are looking for */
if (bta_dm_search_cb.peer_bdaddr == bd_addr) {
rem_name.bd_addr = bd_addr;
rem_name.length = strlcpy((char*)rem_name.remote_bd_name, (char*)bd_name,
BD_NAME_LEN + 1);
if (rem_name.length > BD_NAME_LEN) {
rem_name.length = BD_NAME_LEN;
}
rem_name.status = BTM_SUCCESS;
rem_name.hci_status = HCI_SUCCESS;
bta_dm_remname_cback(&rem_name);
} else {
/* get name of device */
btm_status = get_btm_client_interface().peer.BTM_ReadRemoteDeviceName(
bta_dm_search_cb.peer_bdaddr, bta_dm_remname_cback,
BT_TRANSPORT_BR_EDR);
if (btm_status == BTM_BUSY) {
/* wait for next chance(notification of remote name discovery done) */
log::verbose("BTM_ReadRemoteDeviceName is busy");
} else if (btm_status != BTM_CMD_STARTED) {
/* if failed to start getting remote name then continue */
log::warn("BTM_ReadRemoteDeviceName returns 0x{:02X}", btm_status);
// needed so our response is not ignored, since this corresponds to the
// actual peer_bdaddr
rem_name.bd_addr = bta_dm_search_cb.peer_bdaddr;
rem_name.length = 0;
rem_name.remote_bd_name[0] = 0;
rem_name.status = btm_status;
rem_name.hci_status = HCI_SUCCESS;
bta_dm_remname_cback(&rem_name);
}
}
}
/*******************************************************************************
*
* Function bta_dm_remname_cback
*
* Description Remote name complete call back from BTM
*
* Returns void
*
******************************************************************************/
static void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p_remote_name) {
CHECK(p_remote_name != nullptr);
log::info(
"Remote name request complete peer:{} btm_status:{} hci_status:{} "
"name[0]:{:c} length:{}",
ADDRESS_TO_LOGGABLE_CSTR(p_remote_name->bd_addr),
btm_status_text(p_remote_name->status),
hci_error_code_text(p_remote_name->hci_status),
p_remote_name->remote_bd_name[0], p_remote_name->length);
if (bta_dm_search_cb.peer_bdaddr == p_remote_name->bd_addr) {
get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback(
&bta_dm_service_search_remname_cback);
} else {
// if we got a different response, maybe ignore it
// we will have made a request directly from BTM_ReadRemoteDeviceName so we
// expect a dedicated response for us
if (p_remote_name->hci_status == HCI_ERR_CONNECTION_EXISTS) {
get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback(
&bta_dm_service_search_remname_cback);
log::info(
"Assume command failed due to disconnection hci_status:{} peer:{}",
hci_error_code_text(p_remote_name->hci_status),
ADDRESS_TO_LOGGABLE_CSTR(p_remote_name->bd_addr));
} else {
log::info(
"Ignored remote name response for the wrong address exp:{} act:{}",
ADDRESS_TO_LOGGABLE_CSTR(bta_dm_search_cb.peer_bdaddr),
ADDRESS_TO_LOGGABLE_CSTR(p_remote_name->bd_addr));
return;
}
}
/* remote name discovery is done but it could be failed */
bta_dm_search_cb.name_discover_done = true;
strlcpy((char*)bta_dm_search_cb.peer_name,
(char*)p_remote_name->remote_bd_name, BD_NAME_LEN + 1);
if (bta_dm_search_cb.transport == BT_TRANSPORT_LE) {
GAP_BleReadPeerPrefConnParams(bta_dm_search_cb.peer_bdaddr);
}
tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
*p_msg = {
.remote_name_msg =
{
// tBTA_DM_REMOTE_NAME
.hdr =
{
.event = BTA_DM_REMT_NAME_EVT,
.len = 0,
.offset = 0,
.layer_specific = 0,
},
.bd_addr = bta_dm_search_cb.peer_bdaddr,
.bd_name = {},
.hci_status = p_remote_name->hci_status,
},
};
bd_name_copy(p_msg->remote_name_msg.bd_name, p_remote_name->remote_bd_name);
bta_sys_sendmsg(p_msg);
}
/*******************************************************************************
*
* Function bta_dm_get_remname
*
* Description Returns a pointer to the remote name stored in the DM
* control block if it exists, or from the BTM memory.
*
* Returns char * - Pointer to the remote device name
******************************************************************************/
const char* bta_dm_get_remname(void) {
const char* p_name = (const char*)bta_dm_search_cb.peer_name;
/* If the name isn't already stored, try retrieving from BTM */
if (*p_name == '\0') {
const char* p_temp = get_btm_client_interface().security.BTM_SecReadDevName(
bta_dm_search_cb.peer_bdaddr);
if (p_temp != NULL) p_name = (const char*)p_temp;
}
return p_name;
}
/*******************************************************************************
*
* Function bta_dm_observe_results_cb
*
* Description Callback for BLE Observe result
*
*
* Returns void
*
******************************************************************************/
static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq,
const uint8_t* p_eir, uint16_t eir_len) {
tBTA_DM_SEARCH result;
tBTM_INQ_INFO* p_inq_info;
log::verbose("bta_dm_observe_results_cb");
result.inq_res.bd_addr = p_inq->remote_bd_addr;
result.inq_res.original_bda = p_inq->original_bda;
result.inq_res.rssi = p_inq->rssi;
result.inq_res.ble_addr_type = p_inq->ble_addr_type;
result.inq_res.inq_result_type = p_inq->inq_result_type;
result.inq_res.device_type = p_inq->device_type;
result.inq_res.flag = p_inq->flag;
result.inq_res.ble_evt_type = p_inq->ble_evt_type;
result.inq_res.ble_primary_phy = p_inq->ble_primary_phy;
result.inq_res.ble_secondary_phy = p_inq->ble_secondary_phy;
result.inq_res.ble_advertising_sid = p_inq->ble_advertising_sid;
result.inq_res.ble_tx_power = p_inq->ble_tx_power;
result.inq_res.ble_periodic_adv_int = p_inq->ble_periodic_adv_int;
/* application will parse EIR to find out remote device name */
result.inq_res.p_eir = const_cast<uint8_t*>(p_eir);
result.inq_res.eir_len = eir_len;
p_inq_info =
get_btm_client_interface().db.BTM_InqDbRead(p_inq->remote_bd_addr);
if (p_inq_info != NULL) {
/* initialize remt_name_not_required to false so that we get the name by
* default */
result.inq_res.remt_name_not_required = false;
}
if (bta_dm_search_cb.p_scan_cback)
bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_RES_EVT, &result);
if (p_inq_info) {
/* application indicates if it knows the remote name, inside the callback
copy that to the inquiry data base*/
if (result.inq_res.remt_name_not_required)
p_inq_info->appl_knows_rem_name = true;
}
}
/*******************************************************************************
*
* Function bta_dm_opportunistic_observe_results_cb
*
* Description Callback for BLE Observe result
*
*
* Returns void
*
******************************************************************************/
static void bta_dm_opportunistic_observe_results_cb(tBTM_INQ_RESULTS* p_inq,
const uint8_t* p_eir,
uint16_t eir_len) {
tBTA_DM_SEARCH result;
tBTM_INQ_INFO* p_inq_info;
result.inq_res.bd_addr = p_inq->remote_bd_addr;
result.inq_res.rssi = p_inq->rssi;
result.inq_res.ble_addr_type = p_inq->ble_addr_type;
result.inq_res.inq_result_type = p_inq->inq_result_type;
result.inq_res.device_type = p_inq->device_type;
result.inq_res.flag = p_inq->flag;
result.inq_res.ble_evt_type = p_inq->ble_evt_type;
result.inq_res.ble_primary_phy = p_inq->ble_primary_phy;
result.inq_res.ble_secondary_phy = p_inq->ble_secondary_phy;
result.inq_res.ble_advertising_sid = p_inq->ble_advertising_sid;
result.inq_res.ble_tx_power = p_inq->ble_tx_power;
result.inq_res.ble_periodic_adv_int = p_inq->ble_periodic_adv_int;
/* application will parse EIR to find out remote device name */
result.inq_res.p_eir = const_cast<uint8_t*>(p_eir);
result.inq_res.eir_len = eir_len;
p_inq_info =
get_btm_client_interface().db.BTM_InqDbRead(p_inq->remote_bd_addr);
if (p_inq_info != NULL) {
/* initialize remt_name_not_required to false so that we get the name by
* default */
result.inq_res.remt_name_not_required = false;
}
if (bta_dm_search_cb.p_csis_scan_cback)
bta_dm_search_cb.p_csis_scan_cback(BTA_DM_INQ_RES_EVT, &result);
if (p_inq_info) {
/* application indicates if it knows the remote name, inside the callback
copy that to the inquiry data base*/
if (result.inq_res.remt_name_not_required)
p_inq_info->appl_knows_rem_name = true;
}
}
/*******************************************************************************
*
* Function bta_dm_observe_cmpl_cb
*
* Description Callback for BLE Observe complete
*
*
* Returns void
*
******************************************************************************/
static void bta_dm_observe_cmpl_cb(void* p_result) {
tBTA_DM_SEARCH data;
log::verbose("bta_dm_observe_cmpl_cb");
data.inq_cmpl.num_resps = ((tBTM_INQUIRY_CMPL*)p_result)->num_resp;
if (bta_dm_search_cb.p_scan_cback) {
bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data);
}
if (bta_dm_search_cb.p_csis_scan_cback) {
bta_dm_search_cb.p_csis_scan_cback(BTA_DM_INQ_CMPL_EVT, &data);
}
}
static void bta_dm_start_scan(uint8_t duration_sec,
bool low_latency_scan = false) {
tBTM_STATUS status = get_btm_client_interface().ble.BTM_BleObserve(
true, duration_sec, bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb,
low_latency_scan);
if (status != BTM_CMD_STARTED) {
tBTA_DM_SEARCH data = {
.inq_cmpl =
{
.num_resps = 0,
},
};
log::warn("BTM_BleObserve failed. status {}", status);
if (bta_dm_search_cb.p_scan_cback) {
bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data);
}
if (bta_dm_search_cb.p_csis_scan_cback) {
bta_dm_search_cb.p_csis_scan_cback(BTA_DM_INQ_CMPL_EVT, &data);
}
}
}
void bta_dm_ble_observe(bool start, uint8_t duration,
tBTA_DM_SEARCH_CBACK* p_cback) {
if (!start) {
bta_dm_search_cb.p_scan_cback = NULL;
get_btm_client_interface().ble.BTM_BleObserve(false, 0, NULL, NULL, false);
return;
}
/*Save the callback to be called when a scan results are available */
bta_dm_search_cb.p_scan_cback = p_cback;
bta_dm_start_scan(duration);
}
void bta_dm_ble_scan(bool start, uint8_t duration_sec,
bool low_latency_scan = false) {
/* Start or stop only if there is no active main scanner */
if (bta_dm_search_cb.p_scan_cback != NULL) return;
if (!start) {
get_btm_client_interface().ble.BTM_BleObserve(false, 0, NULL, NULL, false);
return;
}
bta_dm_start_scan(duration_sec, low_latency_scan);
}
void bta_dm_ble_csis_observe(bool observe, tBTA_DM_SEARCH_CBACK* p_cback) {
if (!observe) {
bta_dm_search_cb.p_csis_scan_cback = NULL;
BTM_BleOpportunisticObserve(false, NULL);
return;
}
/* Save the callback to be called when a scan results are available */
bta_dm_search_cb.p_csis_scan_cback = p_cback;
BTM_BleOpportunisticObserve(true, bta_dm_opportunistic_observe_results_cb);
}
#ifndef BTA_DM_GATT_CLOSE_DELAY_TOUT
#define BTA_DM_GATT_CLOSE_DELAY_TOUT 1000
#endif
/*******************************************************************************
*
* Function bta_dm_gattc_register
*
* Description Register with GATTC in DM if BLE is needed.
*
*
* Returns void
*
******************************************************************************/
static void bta_dm_gattc_register(void) {
if (bta_dm_search_cb.client_if != BTA_GATTS_INVALID_IF) {
// Already registered
return;
}
get_gatt_interface().BTA_GATTC_AppRegister(
bta_dm_gattc_callback, base::Bind([](uint8_t client_id, uint8_t status) {
tGATT_STATUS gatt_status = static_cast<tGATT_STATUS>(status);
disc_gatt_history_.Push(base::StringPrintf(
"%-32s client_id:%hu status:%s", "GATTC_RegisteredCallback",
client_id, gatt_status_text(gatt_status).c_str()));
if (static_cast<tGATT_STATUS>(status) == GATT_SUCCESS) {
log::info(
"Registered device discovery search gatt client tGATT_IF:{}",
client_id);
bta_dm_search_cb.client_if = client_id;
} else {
log::warn(
"Failed to register device discovery search gatt client "
"gatt_status:{} previous tGATT_IF:{}",
bta_dm_search_cb.client_if, status);
bta_dm_search_cb.client_if = BTA_GATTS_INVALID_IF;
}
}),
false);
}
/*******************************************************************************
*
* Function bta_dm_gatt_disc_complete
*
* Description This function process the GATT service search complete.
*
* Parameters:
*
******************************************************************************/
static void bta_dm_gatt_disc_complete(uint16_t conn_id, tGATT_STATUS status) {
log::verbose("conn_id = {}", conn_id);
tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
/* no more services to be discovered */
p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
p_msg->disc_result.result.disc_res.result =
(status == GATT_SUCCESS) ? BTA_SUCCESS : BTA_FAILURE;
log::verbose("service found: 0x{:08x}", bta_dm_search_cb.services_found);
p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
p_msg->disc_result.result.disc_res.num_uuids = 0;
p_msg->disc_result.result.disc_res.p_uuid_list = NULL;
p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
bta_dm_get_remname(), BD_NAME_LEN + 1);
p_msg->disc_result.result.disc_res.device_type |= BT_DEVICE_TYPE_BLE;
bta_sys_sendmsg(p_msg);
if (conn_id != GATT_INVALID_CONN_ID) {
bta_dm_search_cb.pending_close_bda = bta_dm_search_cb.peer_bdaddr;
// Gatt will be close immediately if bluetooth.gatt.delay_close.enabled is
// set to false. If property is true / unset there will be a delay
if (bta_dm_search_cb.gatt_close_timer != nullptr) {
/* start a GATT channel close delay timer */
bta_sys_start_timer(bta_dm_search_cb.gatt_close_timer,
BTA_DM_GATT_CLOSE_DELAY_TOUT,
BTA_DM_DISC_CLOSE_TOUT_EVT, 0);
} else {
p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
p_msg->hdr.event = BTA_DM_DISC_CLOSE_TOUT_EVT;
p_msg->hdr.layer_specific = 0;
bta_sys_sendmsg(p_msg);
}
} else {
if (bluetooth::common::init_flags::
bta_dm_clear_conn_id_on_client_close_is_enabled()) {
bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID;
}
if (IS_FLAG_ENABLED(bta_dm_disc_stuck_in_cancelling_fix)) {
log::info(
"Discovery complete for invalid conn ID. Will pick up next job");
bta_dm_search_set_state(BTA_DM_SEARCH_IDLE);
bta_dm_free_sdp_db();
bta_dm_execute_queued_request();
}
}
}
/*******************************************************************************
*
* Function bta_dm_close_gatt_conn
*
* Description This function close the GATT connection after delay
*timeout.
*
* Parameters:
*
******************************************************************************/
static void bta_dm_close_gatt_conn(UNUSED_ATTR tBTA_DM_MSG* p_data) {
if (bta_dm_search_cb.conn_id != GATT_INVALID_CONN_ID)
BTA_GATTC_Close(bta_dm_search_cb.conn_id);
bta_dm_search_cb.pending_close_bda = RawAddress::kEmpty;
bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID;
}
/*******************************************************************************
*
* Function btm_dm_start_gatt_discovery
*
* Description This is GATT initiate the service search by open a GATT
* connection first.
*
* Parameters:
*
******************************************************************************/
static void btm_dm_start_gatt_discovery(const RawAddress& bd_addr) {
constexpr bool kUseOpportunistic = true;
bta_dm_search_cb.gatt_disc_active = true;
/* connection is already open */
if (bta_dm_search_cb.pending_close_bda == bd_addr &&
bta_dm_search_cb.conn_id != GATT_INVALID_CONN_ID) {
bta_dm_search_cb.pending_close_bda = RawAddress::kEmpty;
alarm_cancel(bta_dm_search_cb.gatt_close_timer);
get_gatt_interface().BTA_GATTC_ServiceSearchRequest(
bta_dm_search_cb.conn_id, nullptr);
} else {
if (get_btm_client_interface().peer.BTM_IsAclConnectionUp(
bd_addr, BT_TRANSPORT_LE)) {
log::debug(
"Use existing gatt client connection for discovery peer:{} "
"transport:{} opportunistic:{:c}",
ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(BT_TRANSPORT_LE),
(kUseOpportunistic) ? 'T' : 'F');
get_gatt_interface().BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr,
BTM_BLE_DIRECT_CONNECTION,
kUseOpportunistic);
} else {
log::debug(
"Opening new gatt client connection for discovery peer:{} "
"transport:{} opportunistic:{:c}",
ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(BT_TRANSPORT_LE),
(!kUseOpportunistic) ? 'T' : 'F');
get_gatt_interface().BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr,
BTM_BLE_DIRECT_CONNECTION,
!kUseOpportunistic);
}
}
}
/*******************************************************************************
*
* Function bta_dm_proc_open_evt
*
* Description process BTA_GATTC_OPEN_EVT in DM.
*
* Parameters:
*
******************************************************************************/
static void bta_dm_proc_open_evt(tBTA_GATTC_OPEN* p_data) {
log::verbose("DM Search state= {} search_cb.peer_dbaddr:{} connected_bda={}",
bta_dm_search_get_state(),
ADDRESS_TO_LOGGABLE_STR(bta_dm_search_cb.peer_bdaddr),
ADDRESS_TO_LOGGABLE_STR(p_data->remote_bda));
log::debug("BTA_GATTC_OPEN_EVT conn_id = {} client_if={} status = {}",
p_data->conn_id, p_data->client_if, p_data->status);
disc_gatt_history_.Push(base::StringPrintf(
"%-32s bd_addr:%s conn_id:%hu client_if:%hu event:%s",
"GATTC_EventCallback", ADDRESS_TO_LOGGABLE_CSTR(p_data->remote_bda),
p_data->conn_id, p_data->client_if,
gatt_client_event_text(BTA_GATTC_OPEN_EVT).c_str()));
bta_dm_search_cb.conn_id = p_data->conn_id;
if (p_data->status == GATT_SUCCESS) {
get_gatt_interface().BTA_GATTC_ServiceSearchRequest(p_data->conn_id,
nullptr);
} else {
bta_dm_gatt_disc_complete(GATT_INVALID_CONN_ID, p_data->status);
}
}
/*******************************************************************************
*
* Function bta_dm_gattc_callback
*
* Description This is GATT client callback function used in DM.
*
* Parameters:
*
******************************************************************************/
static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
log::verbose("bta_dm_gattc_callback event = {}", event);
switch (event) {
case BTA_GATTC_OPEN_EVT:
bta_dm_proc_open_evt(&p_data->open);
break;
case BTA_GATTC_SEARCH_CMPL_EVT:
switch (bta_dm_search_get_state()) {
case BTA_DM_SEARCH_IDLE:
break;
case BTA_DM_SEARCH_ACTIVE:
case BTA_DM_SEARCH_CANCELLING:
case BTA_DM_DISCOVER_ACTIVE:
bta_dm_gatt_disc_complete(p_data->search_cmpl.conn_id,
p_data->search_cmpl.status);
break;
}
disc_gatt_history_.Push(base::StringPrintf(
"%-32s conn_id:%hu status:%s", "GATTC_EventCallback",
p_data->search_cmpl.conn_id,
gatt_status_text(p_data->search_cmpl.status).c_str()));
break;
case BTA_GATTC_CLOSE_EVT:
log::info("BTA_GATTC_CLOSE_EVT reason = {}", p_data->close.reason);
if (p_data->close.remote_bda == bta_dm_search_cb.peer_bdaddr) {
if (bluetooth::common::init_flags::
bta_dm_clear_conn_id_on_client_close_is_enabled()) {
bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID;
}
}
switch (bta_dm_search_get_state()) {
case BTA_DM_SEARCH_IDLE:
case BTA_DM_SEARCH_ACTIVE:
break;
case BTA_DM_SEARCH_CANCELLING:
case BTA_DM_DISCOVER_ACTIVE:
/* in case of disconnect before search is completed */
if (p_data->close.remote_bda == bta_dm_search_cb.peer_bdaddr) {
bta_dm_gatt_disc_complete((uint16_t)GATT_INVALID_CONN_ID,
(tGATT_STATUS)GATT_ERROR);
}
}
break;
case BTA_GATTC_ACL_EVT:
case BTA_GATTC_CANCEL_OPEN_EVT:
case BTA_GATTC_CFG_MTU_EVT:
case BTA_GATTC_CONGEST_EVT:
case BTA_GATTC_CONN_UPDATE_EVT:
case BTA_GATTC_DEREG_EVT:
case BTA_GATTC_ENC_CMPL_CB_EVT:
case BTA_GATTC_EXEC_EVT:
case BTA_GATTC_NOTIF_EVT:
case BTA_GATTC_PHY_UPDATE_EVT:
case BTA_GATTC_SEARCH_RES_EVT:
case BTA_GATTC_SRVC_CHG_EVT:
case BTA_GATTC_SRVC_DISC_DONE_EVT:
case BTA_GATTC_SUBRATE_CHG_EVT:
disc_gatt_history_.Push(
base::StringPrintf("%-32s event:%s", "GATTC_EventCallback",
gatt_client_event_text(event).c_str()));
break;
}
}
namespace bluetooth {
namespace legacy {
namespace testing {
void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p) {
::bta_dm_remname_cback(p);
}
tBT_TRANSPORT bta_dm_determine_discovery_transport(const RawAddress& bd_addr) {
return ::bta_dm_determine_discovery_transport(bd_addr);
}
void bta_dm_remote_name_cmpl(const tBTA_DM_MSG* p_data) {
::bta_dm_remote_name_cmpl(p_data);
}
void bta_dm_sdp_result(tBTA_DM_MSG* p_data) { ::bta_dm_sdp_result(p_data); }
} // namespace testing
} // namespace legacy
} // namespace bluetooth
namespace {
constexpr size_t kSearchStateHistorySize = 50;
constexpr char kTimeFormatString[] = "%Y-%m-%d %H:%M:%S";
constexpr unsigned MillisPerSecond = 1000;
std::string EpochMillisToString(long long time_ms) {
time_t time_sec = time_ms / MillisPerSecond;
struct tm tm;
localtime_r(&time_sec, &tm);
std::string s = bluetooth::common::StringFormatTime(kTimeFormatString, tm);
return base::StringPrintf(
"%s.%03u", s.c_str(),
static_cast<unsigned int>(time_ms % MillisPerSecond));
}
} // namespace
struct tSEARCH_STATE_HISTORY {
const tBTA_DM_STATE state;
const tBTA_DM_EVT event;
std::string ToString() const {
return base::StringPrintf("state:%25s event:%s",
bta_dm_state_text(state).c_str(),
bta_dm_event_text(event).c_str());
}
};
bluetooth::common::TimestampedCircularBuffer<tSEARCH_STATE_HISTORY>
search_state_history_(kSearchStateHistorySize);
/*******************************************************************************
*
* Function bta_dm_sm_search_disable
*
* Description unregister BTA SEARCH DM
*
*
* Returns void
*
******************************************************************************/
void bta_dm_search_sm_disable() { bta_sys_deregister(BTA_ID_DM_SEARCH); }
/*******************************************************************************
*
* Function bta_dm_search_sm_execute
*
* Description State machine event handling function for DM
*
*
* Returns void
*
******************************************************************************/
bool bta_dm_search_sm_execute(const BT_HDR_RIGID* p_msg) {
const tBTA_DM_EVT event = static_cast<tBTA_DM_EVT>(p_msg->event);
log::info("state:{}, event:{}[0x{:x}]",
bta_dm_state_text(bta_dm_search_get_state()),
bta_dm_event_text(event), event);
search_state_history_.Push({
.state = bta_dm_search_get_state(),
.event = event,
});
tBTA_DM_MSG* message = (tBTA_DM_MSG*)p_msg;
switch (bta_dm_search_get_state()) {
case BTA_DM_SEARCH_IDLE:
switch (p_msg->event) {
case BTA_DM_API_SEARCH_EVT:
bta_dm_search_set_state(BTA_DM_SEARCH_ACTIVE);
bta_dm_search_start(message);
break;
case BTA_DM_API_DISCOVER_EVT:
bta_dm_search_set_state(BTA_DM_DISCOVER_ACTIVE);
bta_dm_discover(message);
break;
case BTA_DM_API_SEARCH_CANCEL_EVT:
bta_dm_search_clear_queue();
bta_dm_search_cancel_notify();
break;
case BTA_DM_SDP_RESULT_EVT:
bta_dm_free_sdp_db();
break;
case BTA_DM_DISC_CLOSE_TOUT_EVT:
bta_dm_close_gatt_conn(message);
break;
default:
log::info("Received unexpected event {}[0x{:x}] in state {}",
bta_dm_event_text(event), event,
bta_dm_state_text(bta_dm_search_get_state()));
}
break;
case BTA_DM_SEARCH_ACTIVE:
switch (p_msg->event) {
case BTA_DM_REMT_NAME_EVT:
bta_dm_remote_name_cmpl(message);
break;
case BTA_DM_SEARCH_CMPL_EVT:
bta_dm_search_cmpl();
break;
case BTA_DM_DISCOVERY_RESULT_EVT:
bta_dm_search_result(message);
break;
case BTA_DM_DISC_CLOSE_TOUT_EVT:
bta_dm_close_gatt_conn(message);
break;
case BTA_DM_API_DISCOVER_EVT:
bta_dm_queue_disc(message);
break;
case BTA_DM_API_SEARCH_CANCEL_EVT:
bta_dm_search_clear_queue();
bta_dm_search_set_state(BTA_DM_SEARCH_CANCELLING);
bta_dm_search_cancel();
break;
default:
log::info("Received unexpected event {}[0x{:x}] in state {}",
bta_dm_event_text(event), event,
bta_dm_state_text(bta_dm_search_get_state()));
}
break;
case BTA_DM_SEARCH_CANCELLING:
switch (p_msg->event) {
case BTA_DM_API_SEARCH_EVT:
bta_dm_queue_search(message);
break;
case BTA_DM_API_DISCOVER_EVT:
bta_dm_queue_disc(message);
break;
case BTA_DM_API_SEARCH_CANCEL_EVT:
bta_dm_search_clear_queue();
bta_dm_search_cancel_notify();
break;
case BTA_DM_SDP_RESULT_EVT:
case BTA_DM_REMT_NAME_EVT:
case BTA_DM_SEARCH_CMPL_EVT:
case BTA_DM_DISCOVERY_RESULT_EVT:
bta_dm_search_set_state(BTA_DM_SEARCH_IDLE);
bta_dm_free_sdp_db();
bta_dm_search_cancel_notify();
bta_dm_execute_queued_request();
break;
case BTA_DM_DISC_CLOSE_TOUT_EVT:
if (bluetooth::common::init_flags::
bta_dm_clear_conn_id_on_client_close_is_enabled()) {
bta_dm_close_gatt_conn(message);
break;
}
[[fallthrough]];
default:
log::info("Received unexpected event {}[0x{:x}] in state {}",
bta_dm_event_text(event), event,
bta_dm_state_text(bta_dm_search_get_state()));
}
break;
case BTA_DM_DISCOVER_ACTIVE:
switch (p_msg->event) {
case BTA_DM_REMT_NAME_EVT:
bta_dm_remote_name_cmpl(message);
break;
case BTA_DM_SDP_RESULT_EVT:
bta_dm_sdp_result(message);
break;
case BTA_DM_SEARCH_CMPL_EVT:
bta_dm_search_cmpl();
break;
case BTA_DM_DISCOVERY_RESULT_EVT:
bta_dm_disc_result(message);
break;
case BTA_DM_API_SEARCH_EVT:
bta_dm_queue_search(message);
break;
case BTA_DM_API_DISCOVER_EVT:
bta_dm_queue_disc(message);
break;
case BTA_DM_API_SEARCH_CANCEL_EVT:
bta_dm_search_clear_queue();
bta_dm_search_set_state(BTA_DM_SEARCH_CANCELLING);
bta_dm_search_cancel_notify();
break;
case BTA_DM_DISC_CLOSE_TOUT_EVT:
if (bluetooth::common::init_flags::
bta_dm_clear_conn_id_on_client_close_is_enabled()) {
bta_dm_close_gatt_conn(message);
break;
}
[[fallthrough]];
default:
log::info("Received unexpected event {}[0x{:x}] in state {}",
bta_dm_event_text(event), event,
bta_dm_state_text(bta_dm_search_get_state()));
}
break;
}
return true;
}
static void bta_dm_disc_init_search_cb(tBTA_DM_SEARCH_CB& bta_dm_search_cb) {
bta_dm_search_cb = {};
bta_dm_search_cb.state = BTA_DM_SEARCH_IDLE;
bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID;
bta_dm_search_cb.transport = BT_TRANSPORT_AUTO;
}
static void bta_dm_disc_reset() {
alarm_free(bta_dm_search_cb.search_timer);
alarm_free(bta_dm_search_cb.gatt_close_timer);
osi_free_and_reset((void**)&bta_dm_search_cb.p_pending_search);
fixed_queue_free(bta_dm_search_cb.pending_discovery_queue, osi_free);
bta_dm_disc_init_search_cb(::bta_dm_search_cb);
}
void bta_dm_disc_start(bool delay_close_gatt) {
bta_dm_disc_reset();
bta_dm_search_cb.search_timer = alarm_new("bta_dm_search.search_timer");
bta_dm_search_cb.gatt_close_timer =
delay_close_gatt ? alarm_new("bta_dm_search.gatt_close_timer") : nullptr;
bta_dm_search_cb.pending_discovery_queue = fixed_queue_new(SIZE_MAX);
}
void bta_dm_disc_acl_down(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
switch (transport) {
case BT_TRANSPORT_BR_EDR:
if (bta_dm_search_cb.wait_disc &&
bta_dm_search_cb.peer_bdaddr == bd_addr) {
bta_dm_search_cb.wait_disc = false;
if (bta_dm_search_cb.sdp_results) {
log::verbose("timer stopped");
alarm_cancel(bta_dm_search_cb.search_timer);
bta_dm_disc_discover_next_device();
}
}
break;
case BT_TRANSPORT_LE:
default:
break;
}
}
void bta_dm_disc_stop() { bta_dm_disc_reset(); }
void bta_dm_disc_start_device_discovery(tBTA_DM_SEARCH_CBACK* p_cback) {
tBTA_DM_API_SEARCH* p_msg =
(tBTA_DM_API_SEARCH*)osi_calloc(sizeof(tBTA_DM_API_SEARCH));
p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
p_msg->p_cback = p_cback;
bta_sys_sendmsg(p_msg);
}
void bta_dm_disc_stop_device_discovery() {
tBTA_DM_API_DISCOVERY_CANCEL* p_msg =
(tBTA_DM_API_DISCOVERY_CANCEL*)osi_calloc(
sizeof(tBTA_DM_API_DISCOVERY_CANCEL));
p_msg->hdr.event = BTA_DM_API_SEARCH_CANCEL_EVT;
bta_sys_sendmsg(p_msg);
}
void bta_dm_disc_start_service_discovery(tBTA_DM_SEARCH_CBACK* p_cback,
const RawAddress& bd_addr,
tBT_TRANSPORT transport) {
tBTA_DM_API_DISCOVER* p_msg =
(tBTA_DM_API_DISCOVER*)osi_calloc(sizeof(tBTA_DM_API_DISCOVER));
p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
p_msg->bd_addr = bd_addr;
p_msg->transport = transport;
p_msg->p_cback = p_cback;
bta_sys_sendmsg(p_msg);
}
void bta_dm_disc_stop_service_discovery(const RawAddress& bd_addr,
tBT_TRANSPORT transport) {
log::warn("Stop service discovery not yet implemented for legacy module");
}
#define DUMPSYS_TAG "shim::legacy::bta::dm"
void DumpsysBtaDmDisc(int fd) {
auto copy = search_state_history_.Pull();
LOG_DUMPSYS(fd, " last %zu search state transitions", copy.size());
for (const auto& it : copy) {
LOG_DUMPSYS(fd, " %s %s", EpochMillisToString(it.timestamp).c_str(),
it.entry.ToString().c_str());
}
LOG_DUMPSYS(fd, " current bta_dm_search_state:%s",
bta_dm_state_text(bta_dm_search_get_state()).c_str());
}
#undef DUMPSYS_TAG
namespace bluetooth {
namespace legacy {
namespace testing {
void bta_dm_disc_init_search_cb(tBTA_DM_SEARCH_CB& bta_dm_search_cb) {
::bta_dm_disc_init_search_cb(bta_dm_search_cb);
}
tBTA_DM_SEARCH_CB bta_dm_disc_get_search_cb() {
tBTA_DM_SEARCH_CB search_cb = {};
::bta_dm_disc_init_search_cb(search_cb);
return search_cb;
}
void bta_dm_disc_search_cb(const tBTA_DM_SEARCH_CB& search_cb) {
::bta_dm_search_cb = search_cb;
}
const tBTA_DM_SEARCH_CB& bta_dm_disc_search_cb() { return ::bta_dm_search_cb; }
bool bta_dm_read_remote_device_name(const RawAddress& bd_addr,
tBT_TRANSPORT transport) {
return ::bta_dm_read_remote_device_name(bd_addr, transport);
}
void bta_dm_discover_next_device() { ::bta_dm_discover_next_device(); }
void bta_dm_execute_queued_request() { ::bta_dm_execute_queued_request(); }
void bta_dm_find_services(const RawAddress& bd_addr) {
::bta_dm_find_services(bd_addr);
}
void bta_dm_inq_cmpl(uint8_t num) { ::bta_dm_inq_cmpl(num); }
void bta_dm_inq_cmpl_cb(void* p_result) { ::bta_dm_inq_cmpl_cb(p_result); }
void bta_dm_observe_cmpl_cb(void* p_result) {
::bta_dm_observe_cmpl_cb(p_result);
}
void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir,
uint16_t eir_len) {
::bta_dm_observe_results_cb(p_inq, p_eir, eir_len);
}
void bta_dm_opportunistic_observe_results_cb(tBTM_INQ_RESULTS* p_inq,
const uint8_t* p_eir,
uint16_t eir_len) {
::bta_dm_opportunistic_observe_results_cb(p_inq, p_eir, eir_len);
}
void bta_dm_queue_search(tBTA_DM_MSG* p_data) { ::bta_dm_queue_search(p_data); }
void bta_dm_search_result(tBTA_DM_MSG* p_data) {
::bta_dm_search_result(p_data);
}
void bta_dm_search_timer_cback(void* data) {
::bta_dm_search_timer_cback(data);
}
void bta_dm_service_search_remname_cback(const RawAddress& bd_addr,
DEV_CLASS dc, tBTM_BD_NAME bd_name) {
::bta_dm_service_search_remname_cback(bd_addr, dc, bd_name);
}
void bta_dm_start_scan(uint8_t duration_sec, bool low_latency_scan = false) {
::bta_dm_start_scan(duration_sec, low_latency_scan);
}
void store_avrcp_profile_feature(tSDP_DISC_REC* sdp_rec) {
::store_avrcp_profile_feature(sdp_rec);
}
} // namespace testing
} // namespace legacy
} // namespace bluetooth