【android bluetooth 协议分析 07】【SDP详解 2】【SDP 初始化】
一、引言
上节内容 我已经向大家仔细介绍了 sdp 的协议细节:【android bluetooth 协议分析 07】【SDP详解 1】【SDP 介绍】不太清楚的同学可以点击查阅。
当我们了解了协议细节后, 接下来我们就来看一下在 aosp 中是如何一步步 将 sdp 跑起来的。
大家可以思考一下, sdp 初始化过程?都做了那些事情?
二、 sdp_init 函数
sdp_init
是初始化 SDP 协议栈的入口函数。
2.1 何时初始化sdp?
当应用侧调用enable()
时底层协议栈将触发调用 event_start_up_stack()
.
感兴趣可以参考如下文章:
- 【android bluetooth 框架分析 01】【关键线程 2】【bt_stack_manager_thread线程介绍】
// Synchronous function to start up the stack
static void event_start_up_stack(UNUSED_ATTR void* context) {...LOG_INFO("%s is bringing up the stack", __func__);// 初始化 l2cap 层l2c_init();// 初始化 sdp sdp_init();...LOG_INFO("%s finished", __func__);do_in_jni_thread(FROM_HERE, base::Bind(event_signal_stack_up, nullptr));
}
2.2 sdp_init 都做了那些事情?
sdp_init:
负责初始化 SDP 模块的内部数据结构、配置参数和与 L2CAP 层的注册。
// system/stack/sdp/sdp_main.ccvoid sdp_init(void) {/*将全局控制块 sdp_cb 清零(类似于构造函数的功能)。sdp_cb 是 SDP 模块的核心上下文结构,类型为 tSDP_CB,用于保存连接状态、配置信息、缓冲区等。
*/memset(&sdp_cb, 0, sizeof(tSDP_CB));/*SDP 支持多连接,对每个连接控制块(Connection Control Block)ccb[i],创建一个用于连接管理的定时器对象。定时器名为 "sdp.sdp_conn_timer",便于调试与日志跟踪。通常用于超时处理,例如:连接未完成、无回应等。
*/for (int i = 0; i < SDP_MAX_CONNECTIONS; i++) {sdp_cb.ccb[i].sdp_conn_timer = alarm_new("sdp.sdp_conn_timer");}/*设置 L2CAP 配置参数,表明 MTU 有效,并设置本端接收的最大传输单元为 SDP_MTU_SIZE。SDP_MTU_SIZE 是 SDP 数据包的最大长度,默认一般是 672 / 1024 字节。
*/sdp_cb.l2cap_my_cfg.mtu_present = true;sdp_cb.l2cap_my_cfg.mtu = SDP_MTU_SIZE;/*max_attr_list_size 是属性响应列表的最大大小,比 MTU 少 16 字节,预留头部空间。max_recs_per_search 限制搜索响应中返回的最大服务记录数,防止响应包过大或搜索效率过低。
*/sdp_cb.max_attr_list_size = SDP_MTU_SIZE - 16;sdp_cb.max_recs_per_search = SDP_MAX_DISC_SERVER_RECS; // 21/*设置日志输出级别为 WARNING。可根据调试需求设置为 DEBUG、INFO 等。
*/sdp_cb.trace_level = BT_TRACE_LEVEL_WARNING;/*这些是 SDP 协议与 L2CAP 层交互的回调函数,完成以下功能:ConnectInd: 收到连接请求(对方发起)ConnectCfm: 连接结果确认(本地发起)ConfigInd/Cfm: 连接配置过程中的交互DisconnectInd/Cfm: 断开连接的通知与确认DataInd: 收到数据包时的回调(SDP 协议数据)Error: 出错时回调,用于诊断问题
*/sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind;sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm;sdp_cb.reg_info.pL2CA_ConfigInd_Cb = sdp_config_ind;sdp_cb.reg_info.pL2CA_ConfigCfm_Cb = sdp_config_cfm;sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind;sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm;sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind;sdp_cb.reg_info.pL2CA_Error_Cb = sdp_on_l2cap_error;/*向 L2CAP 注册 SDP 服务协议:使用 PSM(Protocol/Service Multiplexer)值 BT_PSM_SDP(值为 0x0001)提供前面定义的回调函数集 reg_infoenable_snoop=true 表示允许 HCI snoop log(用于调试)nullptr:无特殊 contextSDP_MTU_SIZE:MTUBTM_SEC_NONE:无需认证或加密
*/if (!L2CA_Register2(BT_PSM_SDP, sdp_cb.reg_info, true /* enable_snoop */,nullptr, SDP_MTU_SIZE, 0, BTM_SEC_NONE)) {SDP_TRACE_ERROR("SDP Registration failed");}
}
上面的函数很简单总结下来有如下几步:
- 初始化全局变量结构体 sdp_cb
- 为每个连接分配定时器
- 配置 L2CAP MTU
- 设置属性列表与记录上限
- 设置默认日志级别
- 配置 L2CAP 回调函数集
- 注册 SDP 协议到 L2CAP 层
2.3 sdp_cb 介绍
tSDP_CB sdp_cb;/* The main SDP control block */
typedef struct {tL2CAP_CFG_INFO l2cap_my_cfg; /* My L2CAP config */tCONN_CB ccb[SDP_MAX_CONNECTIONS];tSDP_DB server_db;tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */uint16_t max_attr_list_size; /* Max attribute list size to use */uint16_t max_recs_per_search; /* Max records we want per seaarch */uint8_t trace_level;
} tSDP_CB;
这是 SDP 的全局控制结构体,用于保存运行时所有状态。它在 SDP 初始化阶段被清空(memset(&sdp_cb, 0, sizeof(tSDP_CB))
),并由各模块维护其字段。
tL2CAP_CFG_INFO l2cap_my_cfg :
tL2CAP_CFG_INFO
是 L2CAP 配置结构体,定义本端对 L2CAP 连接的参数。
tCONN_CB ccb[SDP_MAX_CONNECTIONS] :
tCONN_CB
表示 SDP 的连接控制块(Connection Control Block),每个连接一个实例。- 每一个主动或被动 SDP 连接(一次服务搜索或服务请求)对应一个
tCONN_CB
。 - SDP 支持多个连接同时存在(如多个手机同时访问车机 SDP Server)。
ccb[i]
保存:L2CAP CID、状态、定时器、请求缓存、接收缓冲等。
tSDP_DB server_db :
tSDP_DB
是本地 SDP 服务数据库,SDP Server 使用该结构响应 SDP 请求。- 保存本地注册的服务记录,例如:
- A2DP Sink/Source 服务
- HFP Audio Gateway 服务
- MAP、PBAP 等
- 每条服务记录由一组属性组成(如 UUID、Profile Version、L2CAP PSM、Protocol Descriptor List)
- 通常在服务启动时调用
SDP_AddRecord()
等函数往这个 DB 填数据 - Server 响应搜索请求时,会从此数据库中查找匹配项,并将其编码为 SDP 响应包发送给远程设备。
tL2CAP_APPL_INFO reg_info :
tL2CAP_APPL_INFO
是注册 L2CAP 协议时提供的一组回调函数指针结构体。- 这些函数由 SDP 模块实现,并通过
reg_info
统一注册给 L2CAP。
uint16_t max_attr_list_size :
- 表示 SDP 响应中属性列表的最大长度限制。
- SDP 查询结果通常是多个服务记录,每个记录下有多个属性。
- 每条属性数据需要打包发送回客户端。
- 为了防止超出 L2CAP MTU,这里设置一个最大限制值。
uint16_t max_recs_per_search :
- 限制 SDP 搜索响应中最多返回多少条服务记录。
- 远端请求搜索某个 UUID 服务时,如果匹配服务非常多(例如模拟服务),可能导致数据包非常大或内存溢出。
- 该字段限制返回记录数量,提高稳定性。
uint8_t trace_level :
- 控制 SDP 模块的日志输出级别,便于调试。
- 级别定义(取决于 BT_TRACE_LEVEL 宏):
BT_TRACE_LEVEL_NONE
:不输出BT_TRACE_LEVEL_ERROR
:仅输出错误BT_TRACE_LEVEL_WARNING
:输出警告 + 错误BT_TRACE_LEVEL_INFO
:输出正常流程日志BT_TRACE_LEVEL_DEBUG
:调试细节(建议调试时打开)
字段名 | 类型 | 功能作用 |
---|---|---|
l2cap_my_cfg | tL2CAP_CFG_INFO | SDP 本地 L2CAP 配置(如 MTU) |
ccb[] | tCONN_CB[] | 每个 SDP 连接的上下文(状态、CID、定时器) |
server_db | tSDP_DB | 本地 SDP Server 服务数据库 |
reg_info | tL2CAP_APPL_INFO | 向 L2CAP 注册的回调集合 |
max_attr_list_size | uint16_t | 每次搜索返回属性的最大字节数 |
max_recs_per_search | uint16_t | 每次搜索允许返回的最大服务记录数 |
trace_level | uint8_t | 日志打印级别控制 |
2.3.1 tL2CAP_CFG_INFO
typedef struct {uint16_t result; /* Only used in confirm messages */bool mtu_present;uint16_t mtu;bool qos_present;FLOW_SPEC qos;bool flush_to_present;uint16_t flush_to;bool fcr_present;tL2CAP_FCR_OPTS fcr;bool fcs_present; /* Optionally bypasses FCS checks */uint8_t fcs; /* '0' if desire is to bypass FCS, otherwise '1' */bool ext_flow_spec_present;tHCI_EXT_FLOW_SPEC ext_flow_spec;uint16_t flags; /* bit 0: 0-no continuation, 1-continuation */
} tL2CAP_CFG_INFO;
此结构体是 L2CAP 层在配置阶段用于交换配置信息的重要结构,特别是在连接建立后的 L2CA_ConfigInd()
/ L2CA_ConfigCfm()
回调中使用。
字段名 | 类型 | 说明 | 是否在 SDP 中使用 | SDP 中使用场景 |
---|---|---|---|---|
result | uint16_t | 仅用于 config 确认(confirm)消息中的返回码(如 L2CAP_CFG_OK ) | ✅ 间接使用 | SDP 在发送 config confirm 时使用,确认配置是否接受 |
mtu_present | bool | 表示是否携带 mtu 字段 | ✅ 使用 | SDP 明确设置 mtu_present = true ,用于控制数据包最大长度 |
mtu | uint16_t | 指定对端发送数据的最大传输单元(MTU) | ✅ 使用 | SDP 设置为 SDP_MTU_SIZE (如 672),控制单次可接收数据最大值 |
qos_present | bool | 是否携带 qos 字段 | ❌ 不使用 | SDP 不关心 QoS,设置为 false |
qos | FLOW_SPEC | QoS 参数(延迟、带宽等) | ❌ 不使用 | SDP 协议无需 QoS 支持 |
flush_to_present | bool | 是否携带 flush_to 字段 | ❌ 不使用 | SDP 数据传输无需 flush 控制 |
flush_to | uint16_t | Flush timeout 值 | ❌ 不使用 | 同上 |
fcr_present | bool | 是否使用 FCR(Frame-based Transmission)模式 | ❌ 不使用 | SDP 使用基本模式(Basic Mode),不使用 FCR |
fcr | tL2CAP_FCR_OPTS | FCR 参数(模式、窗口大小、重传) | ❌ 不使用 | SDP 只使用基本 L2CAP,FCR 模式适用于 AVRCP、AVCTP 等需要重传的协议 |
fcs_present | bool | 是否显式启用/禁用 FCS 检查 | ❌ 通常不使用 | SDP 默认按标准 FCS 行为执行,不主动配置 |
fcs | uint8_t | 如果为 0 则关闭 FCS 校验,1 为启用 | ❌ 通常不使用 | 同上 |
ext_flow_spec_present | bool | 是否包含扩展 flow spec | ❌ 不使用 | SDP 无需 HCI 层高级流控制 |
ext_flow_spec | tHCI_EXT_FLOW_SPEC | HCI 扩展流量规格 | ❌ 不使用 | 高级流量控制,用于 BLE Audio 等场景 |
flags | uint16_t | 控制配置是否支持 continuation | ❌ 通常不使用 | SDP 配置较简单,配置阶段不涉及拆包 continuation |
SDP 实际只使用的字段如下:
字段 | 描述 |
---|---|
mtu_present | 显示声明启用 MTU 配置 |
mtu | 指定 MTU 大小,例如 672 |
result | 在配置确认中使用,返回是否接受配置(如 L2CAP_CFG_OK ) |
SDP 是一个非常轻量级的协议,使用 L2CAP 基本模式,不涉及 QoS、流控、FCR、FCS 等复杂传输机制。
2.3.2 struct tCONN_CB
/* Define the SDP Connection Control Block */
struct tCONN_CB {
#define SDP_STATE_IDLE 0
#define SDP_STATE_CONN_SETUP 1
#define SDP_STATE_CFG_SETUP 2
#define SDP_STATE_CONNECTED 3
#define SDP_STATE_CONN_PEND 4uint8_t con_state;#define SDP_FLAGS_IS_ORIG 0x01
#define SDP_FLAGS_HIS_CFG_DONE 0x02
#define SDP_FLAGS_MY_CFG_DONE 0x04uint8_t con_flags;RawAddress device_address;alarm_t* sdp_conn_timer;uint16_t rem_mtu_size;uint16_t connection_id;uint16_t list_len; /* length of the response in the GKI buffer */uint8_t* rsp_list; /* pointer to GKI buffer holding response */tSDP_DISCOVERY_DB* p_db; /* Database to save info into */tSDP_DISC_CMPL_CB* p_cb; /* Callback for discovery done */tSDP_DISC_CMPL_CB2*p_cb2; /* Callback for discovery done piggy back with the user data */const void* user_data; /* piggy back user data */uint32_thandles[SDP_MAX_DISC_SERVER_RECS]; /* Discovered server record handles */uint16_t num_handles; /* Number of server handles */uint16_t cur_handle; /* Current handle being processed */uint16_t transaction_id;uint16_t disconnect_reason; /* Disconnect reason */#define SDP_DISC_WAIT_CONN 0
#define SDP_DISC_WAIT_HANDLES 1
#define SDP_DISC_WAIT_ATTR 2
#define SDP_DISC_WAIT_SEARCH_ATTR 3
#define SDP_DISC_WAIT_CANCEL 5uint8_t disc_state;uint8_t is_attr_search;uint16_t cont_offset; /* Continuation state data in the server response */tSDP_CONT_INFO cont_info; /* structure to hold continuation information forthe server response */tCONN_CB() = default;private:tCONN_CB(const tCONN_CB&) = delete;
};
字段名 | 类型 | 描述 | 在 SDP 中的作用 |
---|---|---|---|
con_state | uint8_t | 连接当前状态(如空闲、配置中、已连接) | 用于状态机控制 SDP 连接生命周期(从连接建立到服务查询结束) |
con_flags | uint8_t | 连接标志位集合,如是否本端发起、配置完成标志 | 控制连接角色(客户端/服务端)与是否已完成 L2CAP 配置交换 |
device_address | RawAddress | 远端设备蓝牙地址 | 标识连接目标设备,用于查找已有连接或发起新连接 |
sdp_conn_timer | alarm_t* | SDP 连接的超时定时器 | 控制连接等待、配置、搜索等阶段的超时,防止卡死 |
rem_mtu_size | uint16_t | 对端提供的 L2CAP MTU | 用于限制 SDP 响应包大小,确保不会超出对端接收能力 |
connection_id | uint16_t | L2CAP 分配的 connection ID(CID) | 标识 SDP 会话使用的 L2CAP 信道,用于数据发送接收匹配 |
list_len | uint16_t | SDP 响应数据的总长度(来自远端) | 用于计算响应接收进度(特别是 continuation 情况) |
rsp_list | uint8_t* | 存储接收 SDP 响应数据的缓冲区 | 保存从对端接收的原始服务记录,用于后续解析 |
p_db | tSDP_DISCOVERY_DB* | 本地发现数据库指针 | SDP 客户端用来保存搜索结果(服务记录、属性) |
p_cb | tSDP_DISC_CMPL_CB* | SDP 发现完成后的回调函数 | 在服务搜索完成时通知上层模块(如 A2DP、PBAP) |
p_cb2 | tSDP_DISC_CMPL_CB2* | 带用户数据的回调版本 | 支持用户传入 context 数据(如模块私有状态) |
user_data | const void* | 用户数据(piggyback) | 结合 p_cb2 使用,便于调用者传入自定义上下文 |
handles[SDP_MAX_DISC_SERVER_RECS] | uint32_t[] | 存储搜索到的服务记录 handle | 在 SDP search response 中保存每条服务记录 ID |
num_handles | uint16_t | 已发现的服务记录个数 | 与 handles[] 配合,限制返回数量(如不超过 21) |
cur_handle | uint16_t | 当前正在查询属性的服务记录 handle | 在 attribute request 阶段循环查询每条记录 |
transaction_id | uint16_t | SDP 协议事务 ID | 每个 request/request pair 都使用独立的 ID 匹配请求和响应 |
disconnect_reason | uint16_t | 断开连接原因 | 保存 L2CAP 或上层触发断开的原因,用于诊断 |
disc_state | uint8_t | 当前 discovery 状态(等待连接、服务记录、属性等) | 控制 SDP 客户端的状态机,如正在执行哪一类 SDP 请求 |
is_attr_search | uint8_t | 当前是否是 attribute 搜索类型 | 区分是 search (按 UUID) 还是 search+attr(按属性)操作 |
cont_offset | uint16_t | continuation 响应中的 offset | 用于 SDP continuation 响应拼接判断 |
cont_info | tSDP_CONT_INFO | continuation 状态信息结构体 | 保存服务端返回的 continuation token,用于发送下一段请求 |
tCONN_CB() | 构造函数 | 默认构造函数 | 用于初始化对象 |
tCONN_CB(const tCONN_CB&) = delete; | 删除拷贝构造 | 禁止拷贝 | 避免连接状态被意外复制 |
宏名 | 数值 | 含义 |
---|---|---|
SDP_STATE_IDLE | 0 | 空闲状态,未使用连接 |
SDP_STATE_CONN_SETUP | 1 | 正在建立 L2CAP 连接 |
SDP_STATE_CFG_SETUP | 2 | L2CAP 配置交换中 |
SDP_STATE_CONNECTED | 3 | 已连接并可发送 SDP 请求 |
SDP_STATE_CONN_PEND | 4 | 被动等待对端建立连接中(一般是服务端) |
SDP 搜索流程中的典型状态转换 |
-
客户端发起连接
-
设置
con_state = SDP_STATE_CONN_SETUP
-
设置
con_flags |= SDP_FLAGS_IS_ORIG
-
-
收到 L2CAP 配置完成
-
设置
con_flags |= SDP_FLAGS_MY_CFG_DONE | SDP_FLAGS_HIS_CFG_DONE
-
设置
con_state = SDP_STATE_CONNECTED
-
-
开始服务发现
- 设置
disc_state = SDP_DISC_WAIT_HANDLES
- 设置
-
收到服务记录后开始逐个请求属性
- 设置
disc_state = SDP_DISC_WAIT_ATTR
- 设置
tCONN_CB 的角色:
维度 | 说明 |
---|---|
管理连接生命周期 | 保存连接 ID、状态、配置、远端信息 |
支持客户端 SDP 发现流程 | 保存服务记录、属性响应、中间状态 |
控制超时机制 | 内含 alarm_t* 定时器,用于连接与 discovery 超时 |
提供回调与上下文挂载点 | 支持模块化的发现回调和上下文传递 |
支持 continuation 协议 | 支持 SDP 分片响应机制 |
2.3.3 tSDP_DB
/* Define the SDP database */
typedef struct {uint32_tdi_primary_handle; /* Device ID Primary record or NULL if nonexistent */uint16_t num_records;tSDP_RECORD record[SDP_MAX_RECORDS]; // 30
} tSDP_DB;
字段名 | 类型 | 描述 | 在 SDP 中的使用场景 |
---|---|---|---|
di_primary_handle | uint32_t | 表示 Device ID Profile 的主服务记录句柄(Primary record),如果没有则为 0 | 用于区分是否存在 Device ID 主记录。部分设备/平台实现了 Device ID Profile,可用于标识厂商、产品、版本号等。当远端搜索设备 ID 服务时,SDP Server 会返回该记录 |
num_records | uint16_t | 当前数据库中有效的服务记录数量 | SDP Server 用于遍历所有已注册服务记录,在处理 Service Search Request、Service Attribute Request、Service Search Attribute Request 等操作时使用。它限制了有效的 record[] 范围 |
record[SDP_MAX_RECORDS] | tSDP_RECORD[] | 服务记录数组,每一项表示一个注册的 SDP 服务(如 A2DP Sink、HFP、MAP 等) | 每个记录包含 UUID、服务类、协议列表、属性列表等信息。该数组是 SDP Server 处理查询请求时的主要数据源,通过匹配 UUID、属性 ID 来构造响应包 |
使用流程简述:
操作场景 | 涉及字段 | 描述 |
---|---|---|
本地注册服务记录(如 A2DP Sink) | record[] , num_records | 调用 SDP_AddRecord() 时将服务项写入 record[] 数组,同时更新 num_records 计数 |
注册 Device ID Profile | di_primary_handle | 通过 SDP_SetDeviceID() 或 SDP_CreateRecord() 添加 Device ID Profile 时,会设置 di_primary_handle |
响应远端服务搜索 | record[] , num_records , di_primary_handle | SDP Server 查找数据库中是否有匹配 UUID 或属性的记录,并构造响应包返回 |
tSDP_DB server_db;
├── num_records = 3
├── di_primary_handle = 0x10001
└── record[] = {[0] → A2DP Sink 服务[1] → HFP AG 服务[2] → Device ID 服务(记录句柄 == di_primary_handle)}
2.3.4 tL2CAP_APPL_INFO
typedef struct {tL2CA_CONNECT_IND_CB* pL2CA_ConnectInd_Cb;tL2CA_CONNECT_CFM_CB* pL2CA_ConnectCfm_Cb;tL2CA_CONFIG_IND_CB* pL2CA_ConfigInd_Cb;tL2CA_CONFIG_CFM_CB* pL2CA_ConfigCfm_Cb;tL2CA_DISCONNECT_IND_CB* pL2CA_DisconnectInd_Cb;tL2CA_DISCONNECT_CFM_CB* pL2CA_DisconnectCfm_Cb;tL2CA_DATA_IND_CB* pL2CA_DataInd_Cb;tL2CA_CONGESTION_STATUS_CB* pL2CA_CongestionStatus_Cb;tL2CA_TX_COMPLETE_CB* pL2CA_TxComplete_Cb;tL2CA_ERROR_CB* pL2CA_Error_Cb;tL2CA_CREDIT_BASED_CONNECT_IND_CB* pL2CA_CreditBasedConnectInd_Cb;tL2CA_CREDIT_BASED_CONNECT_CFM_CB* pL2CA_CreditBasedConnectCfm_Cb;tL2CA_CREDIT_BASED_RECONFIG_COMPLETED_CB*pL2CA_CreditBasedReconfigCompleted_Cb;tL2CA_CREDIT_BASED_COLLISION_IND_CB* pL2CA_CreditBasedCollisionInd_Cb;
} tL2CAP_APPL_INFO;
字段名 | 类型 | 描述 | 在 SDP 中是否使用 | SDP 中使用场景说明 |
---|---|---|---|---|
pL2CA_ConnectInd_Cb | tL2CA_CONNECT_IND_CB* | 接收连接指示的回调函数(远端发起连接) | ✅ 是 | SDP Server 用于响应远端(如手机)发起的 SDP 连接 |
pL2CA_ConnectCfm_Cb | tL2CA_CONNECT_CFM_CB* | 本地发起连接后的确认回调 | ✅ 是 | SDP 客户端用来确认连接是否建立成功(如车机主动发起 SDP 查询) |
pL2CA_ConfigInd_Cb | tL2CA_CONFIG_IND_CB* | 接收对方发来的配置请求回调 | ✅ 是 | SDP Server 接收 L2CAP 配置请求(如 MTU 设置)并响应 |
pL2CA_ConfigCfm_Cb | tL2CA_CONFIG_CFM_CB* | 本地发送配置请求后的确认回调 | ✅ 是 | SDP 客户端确认对方是否接受本端配置(如设置的 MTU) |
pL2CA_DisconnectInd_Cb | tL2CA_DISCONNECT_IND_CB* | 接收到对方断开连接通知的回调 | ✅ 是 | SDP Server 被动接收远端断开请求时触发 |
pL2CA_DisconnectCfm_Cb | tL2CA_DISCONNECT_CFM_CB* | 本地断开连接后,收到对方确认的回调 | ✅ 是 | SDP 客户端断开连接后,收到远端确认响应时使用 |
pL2CA_DataInd_Cb | tL2CA_DATA_IND_CB* | 接收对方发送的数据包 | ✅ 是 | SDP 接收远端 SDP 请求时处理数据内容的入口 |
pL2CA_CongestionStatus_Cb | tL2CA_CONGESTION_STATUS_CB* | L2CAP 信道拥塞状态改变回调 | ❌ 否 | SDP 不使用流控,也不处理拥塞状态 |
pL2CA_TxComplete_Cb | tL2CA_TX_COMPLETE_CB* | L2CAP 数据发送完成通知 | ❌ 否 | SDP 请求和响应数据量小,通常一次完成发送,不关注此事件 |
pL2CA_Error_Cb | tL2CA_ERROR_CB* | L2CAP 出现错误的回调(如 CRC 错误) | ✅ 是 | SDP Server 或 Client 出现通道异常时记录错误日志 |
pL2CA_CreditBasedConnectInd_Cb | tL2CA_CREDIT_BASED_CONNECT_IND_CB* | 接收 LE Credit-Based 连接的请求(LE) | ❌ 否 | SDP 运行在 BR/EDR 基本模式,不使用 LE 信道 |
pL2CA_CreditBasedConnectCfm_Cb | tL2CA_CREDIT_BASED_CONNECT_CFM_CB* | 确认 LE Credit-Based 连接建立成功 | ❌ 否 | 同上,不适用于 SDP |
pL2CA_CreditBasedReconfigCompleted_Cb | tL2CA_CREDIT_BASED_RECONFIG_COMPLETED_CB* | LE 信道重配置完成通知 | ❌ 否 | SDP 不涉及重配置场景 |
pL2CA_CreditBasedCollisionInd_Cb | tL2CA_CREDIT_BASED_COLLISION_IND_CB* | LE 信道连接碰撞通知 | ❌ 否 | 不适用于 SDP |
适用协议 | 使用字段 | 说明 |
---|---|---|
SDP(Service Discovery Protocol) | 前 7 个字段(Connect/Config/Disconnect/Data/Error 回调) | SDP 使用 BR/EDR 基本模式建立 L2CAP 信道,仅依赖基本事件 |
LE 信道协议(如 GATT over L2CAP) | 后 4 个 Credit-Based 字段 | 专用于 LE Credit-Based Channel,不适用于 SDP |
2.4 L2CA_Register2
sdp 向 l2cap 注册, 请参考如下内容:
【android bluetooth 协议分析 06】【l2cap详解 6】【L2CA_Register函数解析】
三、总结
本篇,算是 对 aosp sdp 源码分析的 第一篇,主要对 sdp 初始化流程 进行了介绍 。 并详细用表格整理出了 sdp 所涉及到的结构体。
在之后的文章,将那几个 具体的例子, 来详细介绍 sdp 的流程。