/*
* Copyright 2024 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_sd"
#include "bta/dm/bta_dm_device_search.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "bta/dm/bta_dm_device_search_int.h"
#include "bta/dm/bta_dm_disc_legacy.h"
#include "bta/include/bta_gatt_api.h"
#include "bta/include/bta_sdp_api.h"
#include "btif/include/btif_config.h"
#include "com_android_bluetooth_flags.h"
#include "common/circular_buffer.h"
#include "common/init_flags.h"
#include "common/strings.h"
#include "device/include/interop.h"
#include "internal_include/bt_target.h"
#include "main/shim/dumpsys.h"
#include "os/logging/log_adapter.h"
#include "osi/include/allocator.h"
#include "stack/btm/btm_int_types.h" // TimestampedStringCircularBuffer
#include "stack/btm/neighbor_inquiry.h"
#include "stack/include/bt_dev_class.h"
#include "stack/include/bt_name.h"
#include "stack/include/bt_uuid16.h"
#include "stack/include/btm_client_interface.h"
#include "stack/include/btm_inq.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/main_thread.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"
using namespace bluetooth;
namespace {
constexpr char kBtmLogTag[] = "DEV_SEARCH";
tBTA_DM_SEARCH_CB bta_dm_search_cb;
} // namespace
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();
static void bta_dm_inq_cmpl_cb(void* p_result);
static void bta_dm_search_cmpl();
static void bta_dm_discover_next_device(void);
static void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p);
static bool bta_dm_read_remote_device_name(const RawAddress& bd_addr,
tBT_TRANSPORT transport);
static void bta_dm_discover_name(const RawAddress& remote_bd_addr);
static void bta_dm_execute_queued_search_request();
static void bta_dm_search_cancel_notify();
static void bta_dm_disable_search();
static void bta_dm_search_sm_execute(tBTA_DM_DEV_SEARCH_EVT event,
std::unique_ptr msg);
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);
static void bta_dm_search_set_state(tBTA_DM_DEVICE_SEARCH_STATE state) {
bta_dm_search_cb.search_state = state;
}
static tBTA_DM_DEVICE_SEARCH_STATE bta_dm_search_get_state() {
return bta_dm_search_cb.search_state;
}
static void post_search_evt(tBTA_DM_DEV_SEARCH_EVT event,
std::unique_ptr msg) {
if (do_in_main_thread(FROM_HERE, base::BindOnce(&bta_dm_search_sm_execute,
event, std::move(msg))) !=
BT_STATUS_SUCCESS) {
log::error("post_search_evt failed");
}
}
void bta_dm_disc_disable_search() {
if (!com::android::bluetooth::flags::
separate_service_and_device_discovery()) {
log::info("no-op when flag is disabled");
return;
}
bta_dm_disable_search();
}
/*******************************************************************************
*
* Function bta_dm_search_start
*
* Description Starts an inquiry
*
*
* Returns void
*
******************************************************************************/
static void bta_dm_search_start(tBTA_DM_API_SEARCH& search) {
if (get_btm_client_interface().db.BTM_ClearInqDb(nullptr) != BTM_SUCCESS) {
log::warn("Unable to clear inquiry database for device discovery");
}
/* save search params */
bta_dm_search_cb.p_device_search_cback = search.p_cback;
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();
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) {
if (get_btm_client_interface().peer.BTM_CancelRemoteDeviceName() !=
BTM_CMD_STARTED) {
log::warn("Unable to cancel RNR");
}
/* bta_dm_search_cmpl is called when receiving the remote name cancel evt */
if (!com::android::bluetooth::flags::
bta_dm_defer_device_discovery_state_change_until_rnr_complete()) {
bta_dm_search_cmpl();
}
} else {
bta_dm_inq_cmpl();
}
}
/*******************************************************************************
*
* 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();
}
/*******************************************************************************
*
* 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(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_device_search_cback)
bta_dm_search_cb.p_device_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_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) {
log::assert_that(p_remote_name != nullptr,
"assert failed: p_remote_name != nullptr");
log::info(
"Remote name request complete peer:{} btm_status:{} hci_status:{} "
"name[0]:{:c} length:{}",
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],
strnlen((const char*)p_remote_name->remote_bd_name, BD_NAME_LEN));
if (bta_dm_search_cb.peer_bdaddr != p_remote_name->bd_addr) {
// 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) {
log::info(
"Assume command failed due to disconnection hci_status:{} peer:{}",
hci_error_code_text(p_remote_name->hci_status),
p_remote_name->bd_addr);
} else {
log::info(
"Ignored remote name response for the wrong address exp:{} act:{}",
bta_dm_search_cb.peer_bdaddr, p_remote_name->bd_addr);
return;
}
}
/* remote name discovery is done but it could be failed */
bta_dm_search_cb.name_discover_done = true;
bd_name_copy(bta_dm_search_cb.peer_name, p_remote_name->remote_bd_name);
auto msg = std::make_unique(tBTA_DM_REMOTE_NAME{});
auto& rmt_name_msg = std::get(*msg);
rmt_name_msg.bd_addr = bta_dm_search_cb.peer_bdaddr;
rmt_name_msg.hci_status = p_remote_name->hci_status;
bd_name_copy(rmt_name_msg.bd_name, p_remote_name->remote_bd_name);
post_search_evt(BTA_DM_REMT_NAME_EVT, std::move(msg));
}
/*******************************************************************************
*
* 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");
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() {
if (bta_dm_search_get_state() == BTA_DM_SEARCH_CANCELLING) {
bta_dm_search_set_state(BTA_DM_SEARCH_IDLE);
bta_dm_execute_queued_search_request();
return;
}
if (bta_dm_search_get_state() != BTA_DM_SEARCH_ACTIVE) {
return;
}
log::verbose("bta_dm_inq_cmpl");
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 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_name(
bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
} else {
bta_dm_search_cmpl();
}
}
static void bta_dm_remote_name_cmpl(
const tBTA_DM_REMOTE_NAME& 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_device_search_cback != nullptr) {
tBTA_DM_SEARCH search_data = {
.name_res = {.bd_addr = remote_name_msg.bd_addr, .bd_name = {}},
};
if (remote_name_msg.hci_status == HCI_SUCCESS) {
bd_name_copy(search_data.name_res.bd_name, remote_name_msg.bd_name);
}
bta_dm_search_cb.p_device_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_name(bta_dm_search_cb.peer_bdaddr);
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 bta_dm_search_cmpl() {
bta_dm_search_set_state(BTA_DM_SEARCH_IDLE);
if (bta_dm_search_cb.p_device_search_cback) {
bta_dm_search_cb.p_device_search_cback(BTA_DM_DISC_CMPL_EVT, nullptr);
}
bta_dm_execute_queued_search_request();
}
static void bta_dm_execute_queued_search_request() {
if (!bta_dm_search_cb.p_pending_search) return;
log::info("Start pending search");
post_search_evt(BTA_DM_API_SEARCH_EVT,
std::move(bta_dm_search_cb.p_pending_search));
bta_dm_search_cb.p_pending_search.reset();
}
/*******************************************************************************
*
* 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() {
bta_dm_search_cb.p_pending_search.reset();
}
/*******************************************************************************
*
* 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_device_search_cback) {
bta_dm_search_cb.p_device_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) {
if (get_btm_client_interface().peer.BTM_CancelRemoteDeviceName() !=
BTM_CMD_STARTED) {
log::warn("Unable to cancel RNR");
}
}
break;
case BTA_DM_SEARCH_IDLE:
// Nothing to do
break;
}
}
/*******************************************************************************
*
* 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_name(
bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
} else {
post_search_evt(BTA_DM_SEARCH_CMPL_EVT, nullptr);
}
}
/*TODO: this function is duplicated, make it common ?*/
static tBT_TRANSPORT bta_dm_determine_discovery_transport(
const RawAddress& remote_bd_addr) {
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) {
return 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)) {
return BT_TRANSPORT_BR_EDR;
} else if (get_btm_client_interface().peer.BTM_IsAclConnectionUp(
remote_bd_addr, BT_TRANSPORT_LE)) {
return BT_TRANSPORT_LE;
}
}
return BT_TRANSPORT_BR_EDR;
}
static void bta_dm_discover_name(const RawAddress& remote_bd_addr) {
const tBT_TRANSPORT transport =
bta_dm_determine_discovery_transport(remote_bd_addr);
log::verbose("BDA: {}", 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:{}",
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)) {
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;
}
/* name discovery is done for this device */
if (bta_dm_search_get_state() == BTA_DM_SEARCH_ACTIVE) {
// if p_btm_inq_info is nullptr, there is no more inquiry results to
// discover name for
if (bta_dm_search_cb.p_btm_inq_info) {
bta_dm_discover_next_device();
} else {
log::info("end of parsing inquiry result");
}
} else {
log::info("name discovery finished in bad state: {}",
bta_dm_state_text(bta_dm_search_get_state()));
}
}
/*******************************************************************************
*
* 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() {
if (!com::android::bluetooth::flags::
separate_service_and_device_discovery()) {
return bta_dm_disc_legacy::bta_dm_is_search_request_queued();
}
return bta_dm_search_cb.p_pending_search != NULL;
}
/*******************************************************************************
*
* Function bta_dm_queue_search
*
* Description Queues search command
*
* Returns void
*
******************************************************************************/
static void bta_dm_queue_search(tBTA_DM_API_SEARCH& search) {
if (bta_dm_search_cb.p_pending_search) {
log::warn("Overwrote previous device discovery inquiry scan request");
}
bta_dm_search_cb.p_pending_search.reset(new tBTA_DM_SEARCH_MSG(search));
log::info("Queued device discovery inquiry scan request");
}
/*******************************************************************************
*
* 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(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 (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(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) {
log::verbose("bta_dm_observe_cmpl_cb");
if (bta_dm_search_cb.p_csis_scan_cback) {
auto num_resps = ((tBTM_INQUIRY_CMPL*)p_result)->num_resp;
tBTA_DM_SEARCH data{.observe_cmpl{.num_resps = num_resps}};
bta_dm_search_cb.p_csis_scan_cback(BTA_DM_OBSERVE_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) {
log::warn("BTM_BleObserve failed. status {}", status);
if (bta_dm_search_cb.p_csis_scan_cback) {
tBTA_DM_SEARCH data{.observe_cmpl = {.num_resps = 0}};
bta_dm_search_cb.p_csis_scan_cback(BTA_DM_OBSERVE_CMPL_EVT, &data);
}
}
}
void bta_dm_ble_scan(bool start, uint8_t duration_sec,
bool low_latency_scan = false) {
if (!start) {
if (get_btm_client_interface().ble.BTM_BleObserve(
false, 0, NULL, NULL, false) != BTM_CMD_STARTED) {
log::warn("Unable to start ble observe");
}
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);
}
namespace bluetooth {
namespace legacy {
namespace testing {
void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p) {
::bta_dm_remname_cback(p);
}
void bta_dm_remote_name_cmpl(const tBTA_DM_REMOTE_NAME& remote_name_msg) {
::bta_dm_remote_name_cmpl(remote_name_msg);
}
} // 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(time_ms % MillisPerSecond));
}
} // namespace
struct tSEARCH_STATE_HISTORY {
const tBTA_DM_DEVICE_SEARCH_STATE state;
const tBTA_DM_DEV_SEARCH_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
search_state_history_(kSearchStateHistorySize);
/*******************************************************************************
*
* Function bta_dm_search_sm_execute
*
* Description State machine event handling function for DM
*
*
* Returns void
*
******************************************************************************/
static void bta_dm_search_sm_execute(tBTA_DM_DEV_SEARCH_EVT event,
std::unique_ptr msg) {
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,
});
switch (bta_dm_search_get_state()) {
case BTA_DM_SEARCH_IDLE:
switch (event) {
case BTA_DM_API_SEARCH_EVT:
bta_dm_search_set_state(BTA_DM_SEARCH_ACTIVE);
log::assert_that(std::holds_alternative(*msg),
"bad message type: {}", msg->index());
bta_dm_search_start(std::get(*msg));
break;
case BTA_DM_API_SEARCH_CANCEL_EVT:
bta_dm_search_clear_queue();
bta_dm_search_cancel_notify();
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 (event) {
case BTA_DM_REMT_NAME_EVT:
log::assert_that(std::holds_alternative(*msg),
"bad message type: {}", msg->index());
bta_dm_remote_name_cmpl(std::get(*msg));
break;
case BTA_DM_SEARCH_CMPL_EVT:
bta_dm_search_cmpl();
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 (event) {
case BTA_DM_API_SEARCH_EVT:
log::assert_that(std::holds_alternative(*msg),
"bad message type: {}", msg->index());
bta_dm_queue_search(std::get(*msg));
break;
case BTA_DM_API_SEARCH_CANCEL_EVT:
bta_dm_search_clear_queue();
bta_dm_search_cancel_notify();
break;
case BTA_DM_REMT_NAME_EVT:
case BTA_DM_SEARCH_CMPL_EVT:
bta_dm_search_set_state(BTA_DM_SEARCH_IDLE);
bta_dm_search_cancel_notify();
bta_dm_execute_queued_search_request();
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;
}
}
static void bta_dm_disable_search(void) {
switch (bta_dm_search_get_state()) {
case BTA_DM_SEARCH_IDLE:
break;
case BTA_DM_SEARCH_ACTIVE:
case BTA_DM_SEARCH_CANCELLING:
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();
}
}
void bta_dm_disc_start_device_discovery(tBTA_DM_SEARCH_CBACK* p_cback) {
if (!com::android::bluetooth::flags::
separate_service_and_device_discovery()) {
bta_dm_disc_legacy::bta_dm_disc_start_device_discovery(p_cback);
return;
}
bta_dm_search_sm_execute(BTA_DM_API_SEARCH_EVT,
std::make_unique(
tBTA_DM_API_SEARCH{.p_cback = p_cback}));
}
void bta_dm_disc_stop_device_discovery() {
if (!com::android::bluetooth::flags::
separate_service_and_device_discovery()) {
bta_dm_disc_legacy::bta_dm_disc_stop_device_discovery();
return;
}
bta_dm_search_sm_execute(BTA_DM_API_SEARCH_CANCEL_EVT, nullptr);
}
static void bta_dm_disc_init_search_cb(tBTA_DM_SEARCH_CB& bta_dm_search_cb) {
bta_dm_search_cb = {};
bta_dm_search_cb.search_state = BTA_DM_SEARCH_IDLE;
}
static void bta_dm_search_reset() {
bta_dm_search_cb.p_pending_search.reset();
bta_dm_disc_init_search_cb(::bta_dm_search_cb);
}
void bta_dm_search_stop() {
if (!com::android::bluetooth::flags::
separate_service_and_device_discovery()) {
log::info("no-op when flag is disabled");
return;
}
bta_dm_search_reset();
}
void bta_dm_disc_discover_next_device() {
if (!com::android::bluetooth::flags::
separate_service_and_device_discovery()) {
bta_dm_disc_legacy::bta_dm_disc_discover_next_device();
return;
}
bta_dm_discover_next_device();
}
#define DUMPSYS_TAG "shim::legacy::bta::dm"
void DumpsysBtaDmSearch(int fd) {
if (!com::android::bluetooth::flags::
separate_service_and_device_discovery()) {
log::info("no-op when flag is disabled");
return;
}
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);
}
void bta_dm_discover_next_device() { ::bta_dm_discover_next_device(); }
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;
}
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_inq_cmpl() { ::bta_dm_inq_cmpl(); }
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_API_SEARCH& search) {
::bta_dm_queue_search(search);
}
void bta_dm_start_scan(uint8_t duration_sec, bool low_latency_scan = false) {
::bta_dm_start_scan(duration_sec, low_latency_scan);
}
} // namespace testing
} // namespace legacy
} // namespace bluetooth