fix(bt/bluedroid): fixed SDP deinit race with pending callbacks

Cancel any active SDP search during disabling and mark the BTA SDP
callbacks inactive so late search completions are not propagated
after deinit. Guard BTC side SDP completion handling after cleanup
to avoid null references.
This commit is contained in:
Jin Cheng
2026-05-21 20:33:35 +08:00
committed by BOT
parent 9f2675935a
commit 5d0b77797b
2 changed files with 57 additions and 24 deletions
@@ -524,6 +524,12 @@ void bta_sdp_search(tBTA_SDP_MSG *p_data)
APPL_TRACE_DEBUG("SDP control block handle is null\n"); APPL_TRACE_DEBUG("SDP control block handle is null\n");
return; return;
} }
if (bta_sdp_cb.p_dm_cback == NULL) {
APPL_TRACE_DEBUG("SDP is not active\n");
return;
}
tBT_UUID *bta_sdp_search_uuid = osi_malloc(sizeof(tBT_UUID)); tBT_UUID *bta_sdp_search_uuid = osi_malloc(sizeof(tBT_UUID));
if (bta_sdp_search_uuid == NULL) { if (bta_sdp_search_uuid == NULL) {
APPL_TRACE_DEBUG("SDP search param malloc failed\n"); APPL_TRACE_DEBUG("SDP search param malloc failed\n");
@@ -638,8 +644,17 @@ void bta_sdp_disable(tBTA_SDP_MSG *p_data)
APPL_TRACE_DEBUG("%s()\n", __func__); APPL_TRACE_DEBUG("%s()\n", __func__);
tBTA_SDP bta_sdp; tBTA_SDP bta_sdp;
bta_sdp.status = BTA_SDP_SUCCESS; bta_sdp.status = BTA_SDP_SUCCESS;
if (bta_sdp_cb.p_dm_cback) { tBTA_SDP_DM_CBACK *dm_cbk = bta_sdp_cb.p_dm_cback;
bta_sdp_cb.p_dm_cback(BTA_SDP_DISABLE_EVT, &bta_sdp, NULL);
bta_sdp_cb.p_dm_cback = NULL;
if (p_bta_sdp_cfg->p_sdp_db && (bta_sdp_cb.sdp_active != BTA_SDP_ACTIVE_NONE)) {
if (!SDP_CancelServiceSearch(p_bta_sdp_cfg->p_sdp_db)) {
bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_NONE;
}
}
if (dm_cbk) {
dm_cbk(BTA_SDP_DISABLE_EVT, &bta_sdp, NULL);
} }
} }
@@ -64,6 +64,18 @@ static void btc_sdp_cleanup(void)
if (sdp_local_param_ptr) { if (sdp_local_param_ptr) {
#endif #endif
if (sdp_local_param.sdp_slot_mutex) { if (sdp_local_param.sdp_slot_mutex) {
osi_mutex_lock(&sdp_local_param.sdp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
for (int i = 0; i < SDP_MAX_RECORDS; i++) {
sdp_slot_t *slot = sdp_local_param.sdp_slots[i];
if (slot) {
if (slot->record_data) {
osi_free(slot->record_data);
}
osi_free(slot);
sdp_local_param.sdp_slots[i] = NULL;
}
}
osi_mutex_unlock(&sdp_local_param.sdp_slot_mutex);
osi_mutex_free(&sdp_local_param.sdp_slot_mutex); osi_mutex_free(&sdp_local_param.sdp_slot_mutex);
sdp_local_param.sdp_slot_mutex = NULL; sdp_local_param.sdp_slot_mutex = NULL;
} }
@@ -1221,7 +1233,7 @@ static void btc_sdp_deinit(void)
BTA_SdpRemoveRecordByUser((void*)i); BTA_SdpRemoveRecordByUser((void*)i);
} }
} }
BTA_SdpDisable(); ret = BTA_SdpDisable();
} while(0); } while(0);
if (ret != ESP_SDP_SUCCESS) { if (ret != ESP_SDP_SUCCESS) {
@@ -1407,34 +1419,40 @@ void btc_sdp_cb_handler(btc_msg_t *msg)
btc_sdp_cb_to_app(ESP_SDP_DEINIT_EVT, &param); btc_sdp_cb_to_app(ESP_SDP_DEINIT_EVT, &param);
break; break;
case BTA_SDP_SEARCH_COMP_EVT: case BTA_SDP_SEARCH_COMP_EVT:
// SDP search completed, now can be searched again if (is_sdp_init()) {
sdp_local_param.search_allowed = true; // SDP search completed, now can be searched again
sdp_local_param.search_allowed = true;
param.search.status = p_data->sdp_search_comp.status; param.search.status = p_data->sdp_search_comp.status;
memcpy(param.search.remote_addr, p_data->sdp_search_comp.remote_addr, sizeof(BD_ADDR)); memcpy(param.search.remote_addr, p_data->sdp_search_comp.remote_addr, sizeof(BD_ADDR));
bta_to_btc_uuid(&param.search.sdp_uuid, &p_data->sdp_search_comp.uuid); bta_to_btc_uuid(&param.search.sdp_uuid, &p_data->sdp_search_comp.uuid);
param.search.record_count = p_data->sdp_search_comp.record_count; param.search.record_count = p_data->sdp_search_comp.record_count;
param.search.records = (esp_bluetooth_sdp_record_t *)p_data->sdp_search_comp.records; param.search.records = (esp_bluetooth_sdp_record_t *)p_data->sdp_search_comp.records;
btc_sdp_cb_to_app(ESP_SDP_SEARCH_COMP_EVT, &param); btc_sdp_cb_to_app(ESP_SDP_SEARCH_COMP_EVT, &param);
}
break; break;
case BTA_SDP_CREATE_RECORD_USER_EVT: case BTA_SDP_CREATE_RECORD_USER_EVT:
param.create_record.status = p_data->sdp_create_record.status; if (is_sdp_init()) {
param.create_record.record_handle = p_data->sdp_create_record.handle; param.create_record.status = p_data->sdp_create_record.status;
btc_sdp_cb_to_app(ESP_SDP_CREATE_RECORD_COMP_EVT, &param); param.create_record.record_handle = p_data->sdp_create_record.handle;
btc_sdp_cb_to_app(ESP_SDP_CREATE_RECORD_COMP_EVT, &param);
}
break; break;
case BTA_SDP_REMOVE_RECORD_USER_EVT: case BTA_SDP_REMOVE_RECORD_USER_EVT:
if (p_data->sdp_remove_record.status == BTA_SDP_SUCCESS) { if (is_sdp_init()) {
int slot_id = get_sdp_slot_id_by_handle(p_data->sdp_remove_record.handle); if (p_data->sdp_remove_record.status == BTA_SDP_SUCCESS) {
if (slot_id < 0) { int slot_id = get_sdp_slot_id_by_handle(p_data->sdp_remove_record.handle);
p_data->sdp_remove_record.status = ESP_SDP_NO_CREATE_RECORD; if (slot_id < 0) {
} else { p_data->sdp_remove_record.status = ESP_SDP_NO_CREATE_RECORD;
free_sdp_slot(slot_id); } else {
free_sdp_slot(slot_id);
}
} }
}
param.remove_record.status = p_data->sdp_remove_record.status; param.remove_record.status = p_data->sdp_remove_record.status;
param.remove_record.record_handle = p_data->sdp_remove_record.handle; param.remove_record.record_handle = p_data->sdp_remove_record.handle;
btc_sdp_cb_to_app(ESP_SDP_REMOVE_RECORD_COMP_EVT, &param); btc_sdp_cb_to_app(ESP_SDP_REMOVE_RECORD_COMP_EVT, &param);
}
break; break;
default: default:
BTC_TRACE_DEBUG("%s: Unhandled event (%d)!", __func__, msg->act); BTC_TRACE_DEBUG("%s: Unhandled event (%d)!", __func__, msg->act);