【Bluedroid】btif_av_sink_execute_service之服务器禁用源码流程解析
本文围绕 Bluedroid 蓝牙协议栈中音频接收端(Sink)服务的禁用流程展开,系统解析从 BTIF 层触发注销到 BTA 层状态机驱动、底层协议栈(AVDT/AVCT)解注册的完整链路。重点分析
DeregisterAllBtaHandles
触发 BTA 层消息分发、bta_av_api_deregister
启动流会话注销、bta_av_do_close
关闭音频流、bta_av_dereg_comp
清理资源及底层协议栈解注册等核心步骤,揭示蓝牙服务禁用过程中 “分层协作、状态机驱动、资源安全释放” 的设计逻辑。
一、概述
蓝牙音频接收端的服务禁用是资源管理的关键环节,涉及多模块协作:从 BTIF 层感知禁用事件并触发 BTA 层注销,到 BTA 层通过状态机驱动流会话关闭、清理 SDP 记录及连接,最终到底层协议栈(AVDT/AVCT)解注册,确保所有资源(如连接、定时器、缓冲区)彻底释放。流程核心目标是:避免资源泄漏、保持状态一致、保障协议交互可靠性。
1.1 触发阶段:BTIF 层发起注销
BTIF 层通过DeregisterAllBtaHandles
遍历维护的设备 ID 与 BTA 句柄映射表(peer_id2bta_handle_
),调用BTA_AvDeregister
触发 BTA 层注销流程,并清空映射表避免资源残留。
1.2 消息分发:BTA 层异步处理
BTA_AvDeregister
将注销请求封装为BTA_AV_API_DEREGISTER_EVT
消息,通过bta_sys_sendmsg
提交至 BTA 主线程消息队列。主线程事件循环分发事件至bta_av_hdl_event
,最终调用bta_av_api_deregister
启动流会话(SCB)注销。
1.3 流会话注销:状态机驱动关闭
bta_av_api_deregister
通过句柄定位流会话控制块(SCB),标记deregistering
状态后,调用bta_av_ssm_execute
触发状态机的BTA_AV_API_CLOSE_EVT
事件,驱动bta_av_do_close
执行流关闭:
-
停止运行中的流(
bta_av_str_stopped
); -
取消信令定时器、清理流状态;
-
刷新 L2CAP 通道、发送 AVDT 关闭请求;
-
设置超时定时器处理关闭失败。
1.4 资源清理:SDP 记录与 SCB 释放
流关闭完成后,bta_av_dereg_comp
执行最终清理:
-
释放 SCB 关联的音频缓冲区队列;
-
删除无活跃流时的 A2DP/AVRCP SDP 记录;
-
释放 SCB 内存并更新全局状态(
bta_av_cb
); -
从 AVDT/AVCT 底层协议栈解注册(
AVDT_Deregister
/AVCT_Deregister
),释放 L2CAP 资源。
1.5 全局状态重置:服务禁用完成
最终通过bta_av_disable
关闭所有 AVRC 控制连接、释放设备发现数据库,并标记禁用状态为完成,确保系统回到初始一致状态。
二、源码解析
btif_av_sink_execute_service 禁用服务
【Bluedroid】btif_av_sink_execute_service之服务器启用源码流程解析-CSDN博客主要分析了btif_av_sink_execute_service的启用服务部分的流程,本篇主要分析btif_av_sink_execute_service禁用服务的流程。
btif_av_sink.DeregisterAllBtaHandles
packages/modules/Bluetooth/system/btif/src/btif_av.cc
std::map<uint8_t, tBTA_AV_HNDL> peer_id2bta_handle_;void BtifAvSink::DeregisterAllBtaHandles() {// 1. 遍历映射表,注销所有 BTA 句柄for (auto it : peer_id2bta_handle_) {tBTA_AV_HNDL bta_handle = it.second;BTA_AvDeregister(bta_handle);}// 2. 清空映射表peer_id2bta_handle_.clear();
}
当蓝牙音频接收端需要清理资源(如设备断开连接、模块卸载或系统关闭)时,遍历全局维护的对等设备 ID 与 BTA 音频 / 视频句柄的映射表(peer_id2bta_handle_
),调用 BTA 层的注销接口(BTA_AvDeregister
)注销所有已注册的音频 / 视频服务,并清空映射表,避免资源泄漏。
BTA_AvDeregister
packages/modules/Bluetooth/system/bta/av/bta_av_api.cc
/********************************************************************************* Function BTA_AvDeregister** Description Deregister the audio or video service** Returns void*******************************************************************************/
void BTA_AvDeregister(tBTA_AV_HNDL hndl) {BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));p_buf->layer_specific = hndl;p_buf->event = BTA_AV_API_DEREGISTER_EVT;bta_sys_sendmsg(p_buf);
}
蓝牙 AV 子系统的 “注销入口函数”,其核心作用是:
-
接口抽象:向上层应用提供简单的注销接口,隐藏底层复杂逻辑。
-
消息封装:将注销请求参数封装为 BTA 层可识别的消息,确保跨线程传递的可靠性。
-
流程触发:触发 BTA 层的注销流程(
bta_av_api_deregister
),最终实现服务的资源释放、SDP 记录删除及连接关闭。
体现了蓝牙协议栈 “接口简洁性” 和 “底层复杂性封装” 的设计思想,是音频 / 视频服务生命周期管理的关键纽带。
bta_sys_sendmsg(BTA_AV_API_DEREGISTER_EVT)
BTA 系统的消息发送函数(【Bluedroid】btif_av_sink_execute_service之服务器启用源码流程解析-CSDN博客分析过),将消息提交到 BTA 主线程的消息队列。BTA 主线程通过事件循环(bta_sys_event
)分发事件到 AV 子系统的事件处理函数(bta_av_hdl_event
),最终调用 bta_av_api_deregister
执行具体的注销逻辑。
bta_av_api_deregister
packages/modules/Bluetooth/system/bta/av/bta_av_main.cc
/********************************************************************************* Function bta_av_api_deregister** Description de-register a channel*** Returns void*******************************************************************************/
void bta_av_api_deregister(tBTA_AV_DATA* p_data) {tBTA_AV_SCB* p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);if (p_scb) {p_scb->deregistering = true; // 标记SCB正在注销bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, p_data); // 执行状态机的关闭事件} else {bta_av_dereg_comp(p_data); // SCB不存在时,直接完成注销}
}// 句柄掩码(二进制低6位)
#define BTA_AV_HNDL_MSK 0x3F/* maximum number of streams created */
#ifndef BTA_AV_NUM_STRS
#define BTA_AV_NUM_STRS 6
#endif// 服务句柄(tBTA_AV_HNDL)转换为对应的 SCB 指针,实现 “句柄→SCB” 的快速映射
/********************************************************************************* Function bta_av_hndl_to_scb** Description find the stream control block by the handle** Returns void*******************************************************************************/
tBTA_AV_SCB* bta_av_hndl_to_scb(uint16_t handle) {tBTA_AV_HNDL hndl = (tBTA_AV_HNDL)handle;tBTA_AV_SCB* p_scb = NULL;uint8_t idx = (hndl & BTA_AV_HNDL_MSK); // 提取句柄的低6位作为索引if (idx && (idx <= BTA_AV_NUM_STRS)) {p_scb = bta_av_cb.p_scb[idx - 1];}return p_scb;
}
通过服务句柄(tBTA_AV_HNDL
)定位对应的流控制块(SCB,tBTA_AV_SCB
),并触发 SCB 的注销流程(如断开连接、释放资源),确保音频 / 视频服务的完整退出。
bta_av_do_close
packages/modules/Bluetooth/system/bta/av/bta_av_aact.cc
/* the timer in milliseconds to guard against link busy and AVDT_CloseReq failed* to be sent */
#ifndef BTA_AV_CLOSE_REQ_TIME_VAL
#define BTA_AV_CLOSE_REQ_TIME_VAL 4000
#endif/********************************************************************************* Function bta_av_do_close** Description Close stream.** Returns void*******************************************************************************/
void bta_av_do_close(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {log::verbose("p_scb->co_started={}", p_scb->co_started);// 1. 停止运行中的流(若已启动)/* stop stream if started */if (p_scb->co_started) {bta_av_str_stopped(p_scb, NULL);}// 2. 取消信令定时器alarm_cancel(p_scb->link_signalling_timer);// 3. 清理流状态/* close stream */p_scb->started = false;p_scb->use_rtp_header_marker_bit = false;// 4. 刷新 L2CAP 通道,丢弃队列数据/* drop the buffers queued in L2CAP */L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);// 5. 发送 AVDT 关闭请求AVDT_CloseReq(p_scb->avdt_handle);// 6. 设置超时定时器,处理关闭请求失败/* just in case that the link is congested, link is flow controled by peer or* for whatever reason the the close request can not be sent in time.* when this timer expires, AVDT_DisconnectReq will be called to disconnect* the link*/bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_CLOSE_REQ_TIME_VAL,BTA_AV_API_CLOSE_EVT, p_scb->hndl);
}
当需要关闭音频流(如设备断开连接、用户主动停止播放)时,通过一系列操作(停止流、清理状态、刷新通道、发送关闭请求)确保音频流的彻底终止,并通过定时器机制处理可能的延迟或失败,避免连接残留或资源泄漏。它是音频流生命周期管理(启动→运行→关闭)的 “终止环节”。
其核心作用是:
-
流停止:终止音频数据传输,释放运行时资源(如编解码器、定时器)。
-
通道清理:刷新 L2CAP 通道,丢弃残留数据,保障数据完整性。
-
连接关闭:通过 AVDT 层通知对端关闭流,并通过定时器处理可能的失败,确保连接可靠释放。
体现了蓝牙协议栈 “优雅关闭”“可靠性保障” 和 “状态严谨性” 的设计原则,是音频流稳定运行的关键保障。
bta_av_dereg_comp
packages/modules/Bluetooth/system/bta/av/bta_av_act.cc
/********************************************************************************* Function bta_av_dereg_comp** Description deregister complete. free the stream control block.** Returns void*******************************************************************************/
void bta_av_dereg_comp(tBTA_AV_DATA* p_data) {tBTA_AV_CB* p_cb = &bta_av_cb;tBTA_AV_SCB* p_scb;tBTA_UTL_COD cod = {.minor = BTM_COD_MINOR_UNCLASSIFIED,.major = BTM_COD_MAJOR_UNCLASSIFIED,.service = 0,};uint8_t mask;BT_HDR* p_buf;// 1. 查找流控制块(SCB)/* find the stream control block */p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);if (p_scb) {log::verbose("deregistered {}(h{})", p_scb->chnl, p_scb->hndl);// 2. 清理音频流注册 / 连接状态mask = BTA_AV_HNDL_TO_MSK(p_scb->hdi);p_cb->reg_audio &= ~mask;if ((p_cb->conn_audio & mask) && p_cb->audio_open_cnt) {/* this channel is still marked as open. decrease the count */p_cb->audio_open_cnt--;}p_cb->conn_audio &= ~mask;// 3. 释放音频缓冲区队列if (p_scb->q_tag == BTA_AV_Q_TAG_STREAM && p_scb->a2dp_list) {/* make sure no buffers are in a2dp_list */while (!list_is_empty(p_scb->a2dp_list)) {p_buf = (BT_HDR*)list_front(p_scb->a2dp_list);list_remove(p_scb->a2dp_list, p_buf);osi_free(p_buf);}}// 4. 删除 A2DP/SDP 记录(无活跃流时)/* remove the A2DP SDP record, if no more audio stream is left */if (!p_cb->reg_audio) { // 无注册的音频流时// 若未启用新AVRCP,删除AVRC SDP记录/* Only remove the SDP record if we're the ones that created it */if (is_new_avrcp_enabled()) {log::verbose("newavrcp is the owner of the AVRCP Target SDP record. Don't dereg ""the SDP record");} else {log::verbose("newavrcp is not enabled. Remove SDP record");bta_ar_dereg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL);}// 删除A2DP源的SDP记录(若存在)if (p_cb->sdp_a2dp_handle) {bta_av_del_sdp_rec(&p_cb->sdp_a2dp_handle);p_cb->sdp_a2dp_handle = 0;bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE); // 从系统中移除源UUID}// 删除A2DP接收端的SDP记录(若存在)if (p_cb->sdp_a2dp_snk_handle) {bta_av_del_sdp_rec(&p_cb->sdp_a2dp_snk_handle);p_cb->sdp_a2dp_snk_handle = 0;bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK);}}// 5. 释放流控制块(SCB)bta_av_free_scb(p_scb);}log::verbose("audio 0x{:x}, disable:{}", p_cb->reg_audio, p_cb->disabling);// 6. 从底层协议栈解注册(无活跃流时)/* if no stream control block is active */if (p_cb->reg_audio == 0) {/* deregister from AVDT */bta_ar_dereg_avdt();/* deregister from AVCT */bta_ar_dereg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET);bta_ar_dereg_avct();// 7. 重置系统状态(禁用时)if (p_cb->disabling) {p_cb->disabling = false;// reset enabling parametersp_cb->features = 0;p_cb->sec_mask = 0;bta_av_cb.sink_features = 0;bta_av_cb.reg_role = 0;}// 8. 更新设备服务类信息/* Clear the Capturing service class bit */cod.service = BTM_COD_SERVICE_CAPTURING;utl_set_device_class(&cod, BTA_UTL_CLR_COD_SERVICE_CLASS);}
}
在服务注销流程的最后阶段,清理与音频流相关的所有资源(如缓冲区、SDP 记录、流控制块),并更新全局状态,确保系统回到一致的初始状态。其核心职责是:
-
资源清理:释放流控制块(SCB)关联的缓冲区、SDP 记录等资源。
-
状态重置:更新全局控制块(
bta_av_cb
)中的注册 / 连接状态,确保系统状态一致性。 -
模块解注册:从 AVDT(音频 / 视频分发传输协议)、AVCT(音频 / 视频控制传输协议)等底层模块注销,释放协议栈资源。
bta_ar_dereg_avrc
packages/modules/Bluetooth/system/bta/ar/bta_ar.cc
/******************************************************************************** Function bta_ar_dereg_avrc** Description This function is called to de-register/delete an SDP record* for AVRCP.** Returns void******************************************************************************/
void bta_ar_dereg_avrc(uint16_t service_uuid) {uint8_t mask = BTA_AR_AV_MASK;uint16_t categories = 0;uint8_t temp[8], *p;// 场景 1:注销 AVRCP 目标设备(Target)的 SDP 记录if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) {if (bta_ar_cb.sdp_tg_handle && mask == bta_ar_cb.tg_registered) {bta_ar_cb.tg_registered = 0;get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(bta_ar_cb.sdp_tg_handle); // 删除目标设备的 SDP 记录bta_ar_cb.sdp_tg_handle = 0; // 清除目标设备的注册状态bta_sys_remove_uuid(service_uuid); // 从系统中移除该服务 UUID}} // 场景 2:注销 AVRCP 控制器(Controller)的 SDP 记录else if (service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) {if (bta_ar_cb.sdp_ct_handle) {bta_ar_cb.ct_categories[mask - 1] = 0;categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1];if (!categories) {// 彻底删除控制器的 SDP 记录,清空句柄并移除 UUID/* no CT is still registered - cleaup */get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(bta_ar_cb.sdp_ct_handle);bta_ar_cb.sdp_ct_handle = 0;bta_sys_remove_uuid(service_uuid);} else { // 仍有其他类别注册/* change supported categories to the remaning one */p = temp;UINT16_TO_BE_STREAM(p, categories);// 将剩余类别写入get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,(uint32_t)2, (uint8_t*)temp);}}}
}
根据服务类型(目标 / 控制器)和当前注册状态,决定是彻底删除 SDP 记录还是仅更新属性,确保资源高效利用和状态同步。
bta_sys_remove_uuid
packages/modules/Bluetooth/system/bta/sys/bta_sys_conn.cc
/********************************************************************************* Function bta_sys_remove_uuid** Description Called by BTA subsystems to indicate to DM that the service* class UUID is removed.** Returns void*******************************************************************************/
void bta_sys_remove_uuid(uint16_t uuid16) {if (bta_sys_cb.eir_cb) {bta_sys_cb.eir_cb(uuid16, false);}
}
当 AVRCP 的 SDP 记录被删除后(如目标设备或控制器的服务不再可用),必须同步通知系统移除该服务的 UUID:
-
避免其他设备通过蓝牙查询(如 Inquiry 过程)发现已失效的服务,导致错误的连接尝试。
-
确保设备广播的 EIR 数据(包含支持的服务 UUID 列表)与实际运行的服务状态一致,提升互操作性。
bta_av_free_scb
packages/modules/Bluetooth/system/bta/av/bta_av_main.cc
void bta_av_free_scb(tBTA_AV_SCB* p_scb) {if (p_scb == nullptr) return;uint8_t scb_index = p_scb->hdi;CHECK(scb_index < BTA_AV_NUM_STRS);CHECK(p_scb == bta_av_cb.p_scb[scb_index]);bta_av_cb.p_scb[scb_index] = nullptr;alarm_free(p_scb->avrc_ct_timer);list_free(p_scb->a2dp_list);p_scb->a2dp_list = NULL;// TODO: After tBTA_AV_SCB is changed to a proper class, the entry// here should be de-allocated by C++ 'delete' statement.osi_free(p_scb);
}
通过严格的状态校验、资源分级释放、全局状态同步,确保了 AV 会话销毁时的资源完整性:
-
防御性检查(空指针、索引越界、状态一致性)避免了运行时崩溃;
-
资源分层释放(定时器→列表→SCB 本体)确保所有关联资源被回收,防止内存泄漏;
-
全局状态清理(置空全局数组指针)保证了模块上下文的准确性,为后续会话分配提供可靠的状态基础。
bta_ar_dereg_avdt
packages/modules/Bluetooth/system/bta/ar/bta_ar.cc
/********************************************************************************* Function bta_ar_dereg_avdt** Description This function is called to de-register from AVDTP.** Returns void*******************************************************************************/
void bta_ar_dereg_avdt() {// 1. 清理回调指针bta_ar_cb.p_av_conn_cback = NULL;// 2. 更新 AVDTP 注册状态bta_ar_cb.avdt_registered &= ~BTA_AR_AV_MASK;// 3. 触发底层注销(仅当无剩余服务时)if (bta_ar_cb.avdt_registered == 0) AVDT_Deregister();
}
通过清理回调、更新状态、条件触发底层注销三步操作,实现了 AVDTP 服务的高效注销管理,确保资源释放的准确性和协议栈交互的可靠性。
AVDT_Deregister
packages/modules/Bluetooth/system/stack/avdt/avdt_api.cc
/* PSM for AVDT */
#define AVDT_PSM 0x0019/********************************************************************************* Function AVDT_Deregister** Description This function is called to deregister use AVDTP protocol.* It is called when AVDTP is no longer being used by any* application in the system. Before this function can be* called, all streams must be removed with* AVDT_RemoveStream().*** Returns void*******************************************************************************/
void AVDT_Deregister(void) {/* deregister PSM with L2CAP */L2CA_Deregister(AVDT_PSM);
}
当系统中所有使用 AVDTP 的应用(如 AR 模块、A2DP 音频流)均已停止,且所有 AVDTP 流(Stream)已通过 AVDT_RemoveStream()
移除后调用。从 L2CAP 层注销 AVDTP 的协议标识(PSM),释放底层传输资源(如通道、端口),确保协议栈资源的彻底回收。
bta_ar_dereg_avct
packages/modules/Bluetooth/system/bta/ar/bta_ar.cc
/********************************************************************************* Function bta_ar_dereg_avct** Description This function is called to deregister from AVCTP.** Returns void*******************************************************************************/
void bta_ar_dereg_avct() {// 清除 AV 类型服务的注册标志bta_ar_cb.avct_registered &= ~BTA_AR_AV_MASK;// 触发底层注销(仅当无剩余服务时)if (bta_ar_cb.avct_registered == 0) AVCT_Deregister();
}
通过位掩码状态管理和条件触发底层注销,实现了 AVCTP 服务的高效注销逻辑。其核心是通过精细化的状态标记,避免冗余操作,确保协议栈资源释放的准确性和高效性,是蓝牙协议栈中 “多服务类型动态管理” 的典型实现。
AVCT_Deregister
packages/modules/Bluetooth/system/stack/avct/avct_api.c
/* PSM for AVCT. */
#define AVCT_PSM 0x0017/********************************************************************************* Function AVCT_Deregister** Description This function is called to deregister use AVCTP protocol.* It is called when AVCTP is no longer being used by any* application in the system. Before this function can be* called, all connections must be removed with* AVCT_RemoveConn().*** Returns void*******************************************************************************/
void AVCT_Deregister(void) {log::verbose("AVCT_Deregister");/* deregister PSM with L2CAP */L2CA_Deregister(AVCT_PSM);
}
当系统中所有使用 AVCTP 的应用(如 AR 模块、AVRCP 控制器)均停止使用该协议,且所有 AVCTP 连接已通过 AVCT_RemoveConn()
移除后调用。从 L2CAP 层注销 AVCTP 的协议标识(PSM),释放底层控制传输资源(如控制通道、端口),确保协议栈资源的彻底回收。
utl_set_device_class(BTA_UTL_CLR_COD_SERVICE_CLASS)
packages/modules/Bluetooth/system/bta/sys/utl.cc
/********************************************************************************* Function utl_set_device_class** Description This function updates the local Device Class.** Parameters:* p_cod - Pointer to the device class to set to** cmd - the fields of the device class to update.* BTA_UTL_SET_COD_MAJOR_MINOR, - overwrite major,* minor class* BTA_UTL_SET_COD_SERVICE_CLASS - set the bits in* the input* BTA_UTL_CLR_COD_SERVICE_CLASS - clear the bits in* the input* BTA_UTL_SET_COD_ALL - overwrite major, minor, set* the bits in service class* BTA_UTL_INIT_COD - overwrite major, minor, and* service class** Returns true if successful, Otherwise false*******************************************************************************/
bool utl_set_device_class(tBTA_UTL_COD* p_cod, uint8_t cmd) {uint16_t service;uint8_t minor, major;DEV_CLASS old_class;old_class = BTM_ReadDeviceClass(); // 读取当前设备类BTM_COD_SERVICE_CLASS(service, old_class); // 提取当前服务类位(service)BTM_COD_MINOR_CLASS(minor, old_class);BTM_COD_MAJOR_CLASS(major, old_class);switch (cmd) {case BTA_UTL_SET_COD_MAJOR_MINOR:minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;break;case BTA_UTL_SET_COD_SERVICE_CLASS:/* clear out the bits that is not SERVICE_CLASS bits */p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;service = service | p_cod->service;break;case BTA_UTL_CLR_COD_SERVICE_CLASS:// 输入服务类位的有效性过滤p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;// 清除当前服务类中的指定位// 当前服务类位与取反后的输入位按位与,结果是将当前服务类中与输入位对应的位置 0,其他位保持不变service = service & (~p_cod->service);break;case BTA_UTL_SET_COD_ALL:minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;service = service | p_cod->service;break;case BTA_UTL_INIT_COD:minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;service = p_cod->service & BTM_COD_SERVICE_CLASS_MASK;break;default:return false;}/* convert the fields into the device class type */DEV_CLASS dev_class;FIELDS_TO_COD(dev_class, minor, major, service); // 组合为设备类格式if (BTM_SetDeviceClass(dev_class) == BTM_SUCCESS) return true; // 写入蓝牙底层模块return false;
}
BTA_UTL_CLR_COD_SERVICE_CLASS
是蓝牙协议栈中精确清除设备服务类能力的核心命令,通过位运算和有效性校验,确保设备类的服务信息与实际功能一致,是蓝牙设备对外能力宣称的关键管理接口。
应用场景示例:
假设设备当前通过服务类位宣称支持 “音频(0x0020)” 和 “信息(0x0010)” 服务(
service = 0x0030
):
当设备停止提供音频服务时,上层模块调用
utl_set_device_class
,传入p_cod->service = 0x0020
(要清除的音频服务位),命令为BTA_UTL_CLR_COD_SERVICE_CLASS
。函数执行后,服务类位变为
0x0010
(仅保留信息服务),设备广播 / 查询响应中的服务类将更新,其他设备发现该设备时,将不再感知到音频服务能力。
BTA_AvDisable
packages/modules/Bluetooth/system/bta/av/bta_av_api.cc
/********************************************************************************* Function BTA_AvDisable** Description Disable the advanced audio/video service.** Returns void*******************************************************************************/
void BTA_AvDisable(void) {BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));// 注销系统服务注册bta_sys_deregister(BTA_ID_AV);p_buf->event = BTA_AV_API_DISABLE_EVT;// 发送异步消息bta_sys_sendmsg(p_buf);
}
禁用高级音频 / 视频(A2DP/AVRCP 等)服务,主要通过系统级注销和消息机制触发服务的异步清理流程。
bta_sys_deregister
packages/modules/Bluetooth/system/bta/sys/bta_sys_main.cc
/********************************************************************************* Function bta_sys_deregister** Description Called by other BTA subsystems to de-register* handler.*** Returns void*******************************************************************************/
void bta_sys_deregister(uint8_t id) { bta_sys_cb.is_reg[id] = false; }
维护全局的子系统注册状态表,确保系统模块(如消息分发、服务发现)能正确识别活跃子系统,避免处理已注销子系统的请求。
bta_sys_sendmsg(BTA_AV_API_DISABLE_EVT)
BTA 系统的消息发送函数(【Bluedroid】btif_av_sink_execute_service之服务器启用源码流程解析-CSDN博客分析过),将消息提交到 BTA 主线程的消息队列。BTA 主线程通过事件循环(bta_sys_event
)分发事件到 AV 子系统的事件处理函数(bta_av_hdl_event
),最终调用 bta_av_disable
执行具体的注销逻辑。
bta_av_disable
packages/modules/Bluetooth/system/bta/av/bta_av_act.cc
/********************************************************************************* Function bta_av_disable** Description disable AV.** Returns void*******************************************************************************/
void bta_av_disable(tBTA_AV_CB* p_cb, UNUSED_ATTR tBTA_AV_DATA* p_data) {BT_HDR_RIGID hdr;bool disabling_in_progress = false;uint16_t xx;// 1. 标记禁用状态p_cb->disabling = true;// 2. 关闭所有远程控制连接bta_av_close_all_rc(p_cb);// 3. 释放设备发现数据库osi_free_and_reset((void**)&p_cb->p_disc_db);// 4. 遍历并注销所有流通道/* disable audio/video - de-register all channels,* expect BTA_AV_DEREG_COMP_EVT when deregister is complete */for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {if (p_cb->p_scb[xx] != NULL) { // 存在活跃的流会话控制块(SCB)// Free signalling timersalarm_free(p_cb->p_scb[xx]->link_signalling_timer);p_cb->p_scb[xx]->link_signalling_timer = NULL;alarm_free(p_cb->p_scb[xx]->accept_signalling_timer);p_cb->p_scb[xx]->accept_signalling_timer = NULL;// 构造消息并触发底层注销hdr.layer_specific = xx + 1;bta_av_api_deregister((tBTA_AV_DATA*)&hdr);disabling_in_progress = true;}}// Since All channels are deregistering by API_DEREGISTER, the DEREG_COMP_EVT// would come first before API_DISABLE if there is no connections, and it is// no needed to setup this disabling flag.// 5. 更新禁用状态标志p_cb->disabling = disabling_in_progress;}
关闭所有活跃的 AV 连接(如 AVRCP 控制、A2DP 流),释放关联资源,并通知底层协议栈注销通道。
分阶段清理 AV 服务的核心资源(控制连接→发现数据→传输流),通过标记状态、释放定时器、触发底层注销,确保服务禁用的可靠性和资源释放的彻底性。
bta_av_close_all_rc
packages/modules/Bluetooth/system/bta/av/bta_av_act.cc
/* maximum number of streams created */
#ifndef BTA_AV_NUM_STRS
#define BTA_AV_NUM_STRS 6
#endif#define BTA_AV_NUM_RCB (BTA_AV_NUM_STRS + 2)/********************************************************************************* Function bta_av_close_all_rc** Description close the all AVRC handle.** Returns void*******************************************************************************/
static void bta_av_close_all_rc(tBTA_AV_CB* p_cb) {int i;// 遍历所有 AVRC 控制块for (i = 0; i < BTA_AV_NUM_RCB; i++) {// 检查是否需要关闭当前控制块if ((p_cb->disabling) || (bta_av_cb.rcb[i].shdl != 0))bta_av_del_rc(&bta_av_cb.rcb[i]); // 关闭具体连接}
}
在 AV 服务禁用或清理时,遍历并断开所有活跃的 AVRC 控制连接。
bta_av_del_rc
packages/modules/Bluetooth/system/bta/av/bta_av_act.cc
/********************************************************************************* Function bta_av_del_rc** Description delete the given AVRC handle.** Returns void*******************************************************************************/
void bta_av_del_rc(tBTA_AV_RCB* p_rcb) {tBTA_AV_SCB* p_scb;uint8_t rc_handle; /* connected AVRCP handle */// 1. 校验 AVRC 句柄有效性p_scb = NULL;if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {// 2. 清理关联的流会话控制块(SCB)if (p_rcb->shdl) {/* Validate array index*/if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS) {p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];}if (p_scb) {log::verbose("shdl:{}, srch:{} rc_handle:{}", p_rcb->shdl,p_scb->rc_handle, p_rcb->handle);// 清除SCB中对当前AVRC句柄的引用if (p_scb->rc_handle == p_rcb->handle)p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;/* just in case the RC timer is activeif (bta_av_cb.features & BTA_AV_FEAT_RCCT && p_scb->chnl ==BTA_AV_CHNL_AUDIO) */alarm_cancel(p_scb->avrc_ct_timer); // 取消AVRC控制定时器(避免后续触发)}}log::verbose("handle: {} status=0x{:x}, rc_acp_handle:{}, idx:{}",p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle,bta_av_cb.rc_acp_idx);// 3. 根据状态清理 RCBrc_handle = p_rcb->handle;if (!(p_rcb->status & BTA_AV_RC_CONN_MASK) || // 未连接状态((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)) { // 内部角色p_rcb->status = 0;p_rcb->handle = BTA_AV_RC_HANDLE_NONE;p_rcb->shdl = 0;p_rcb->lidx = 0;}// 4. 调用底层协议栈关闭 AVRC 连接/* else ACP && connected. do not clear the handle yet */AVRC_Close(rc_handle);// 5. 清理 ACPH 句柄引用if (rc_handle == bta_av_cb.rc_acp_handle)bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;log::verbose("end del_rc handle: {} status=0x{:x}, rc_acp_handle:{}, lidx:{}",p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, p_rcb->lidx);}
}
清理 AVRC 控制块(RCB)关联的资源(如会话引用、定时器),并调用底层协议栈关闭连接。
AVRC_Close
packages/modules/Bluetooth/system/stack/avrc/avrc_api.cc
/******************************************************************************** Function AVRC_Close** Description Close a connection opened with AVRC_Open().* This function is called when the* application is no longer using a connection.** Input Parameters:* handle: Handle of this connection.** Output Parameters:* None.** Returns AVRC_SUCCESS if successful.* AVRC_BAD_HANDLE if handle is invalid.******************************************************************************/
uint16_t AVRC_Close(uint8_t handle) {log::verbose("handle:{}", handle);avrc_flush_cmd_q(handle);return AVCT_RemoveConn(handle);
}
理本层未完成的命令队列,并通过底层 AVCTP 协议栈移除控制连接。
avrc_flush_cmd_q
packages/modules/Bluetooth/system/stack/avrc/avrc_api.cc
/* Flags for avrc_cb.ccb_int[].flags */
#define AVRC_CB_FLAGS_RSP_PENDING 0x01 /* Waiting for AVRC response *//******************************************************************************** Function avrc_flush_cmd_q** Description Flush command queue for the specified avrc handle** Returns Nothing.******************************************************************************/
void avrc_flush_cmd_q(uint8_t handle) {log::verbose("AVRC: Flushing command queue for handle=0x{:02x}", handle);avrc_cb.ccb_int[handle].flags &= ~AVRC_CB_FLAGS_RSP_PENDING;alarm_cancel(avrc_cb.ccb_int[handle].tle);// 彻底清理该连接的未处理命令(如 “暂停”“下一曲” 等未发送或未确认的命令),避免内存泄漏fixed_queue_free(avrc_cb.ccb_int[handle].cmd_q, osi_free);avrc_cb.ccb_int[handle].cmd_q = NULL;
}
通过清理标志→取消定时器→释放队列的流程,实现 AVRC 连接命令队列的安全清空。在连接关闭前清理未处理的命令,避免资源泄漏或状态混乱。
AVCT_RemoveConn
根据连接句柄定位控制块,触发逻辑链路解绑定或直接释放资源,确保连接的安全移除。
bta_av_api_deregister
packages/modules/Bluetooth/system/bta/av/bta_av_main.cc
/********************************************************************************* Function bta_av_api_deregister** Description de-register a channel*** Returns void*******************************************************************************/
void bta_av_api_deregister(tBTA_AV_DATA* p_data) {// 1. 定位目标流会话(SCB)tBTA_AV_SCB* p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);// 2. 标记流会话为 “注销中”if (p_scb) {p_scb->deregistering = true;// 3. 触发状态机执行关闭事件bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, p_data);} // 4. 处理 SCB 不存在的情况else {bta_av_dereg_comp(p_data);}
}
AV 服务注销流程的 “启动器”,通过定位流会话→标记状态→状态机驱动关闭→异常处理的流程,确保音频 / 视频流通道的安全注销。
三、总结
禁用服务本质是逆向的生命周期管理:
1. 分层解耦设计
-
BTIF提供简洁接口 → BTA封装复杂状态机 → 底层协议栈执行资源释放
-
通过
bta_sys_sendmsg
实现跨线程异步通信
2. 防御性资源管理
-
句柄有效性校验(
bta_av_hndl_to_scb
) -
定时器守护关闭流程(
BTA_AV_CLOSE_REQ_TIME_VAL
) -
位掩码跟踪状态(
reg_audio
标记活跃流)
3. 关键优化点
-
条件解注册:仅当无活跃流时删除SDP记录(避免冗余操作)
-
资源分级释放:先停流→清缓冲区→删SDP→最后解注册协议
-
COD动态更新:按需清除服务类位,确保设备能力实时同步
架构启示:协议栈通过
SCB状态机
驱动注销流程,以peer_id2bta_handle_
全局映射表为核心枢纽,结合bta_av_cb
统一管理跨层状态,实现高可靠的服务生命周期管理。