一、引言
上节内容 我已经向大家仔细介绍了 sdp 的协议细节:【android bluetooth 协议分析 07】【SDP详解 1】【SDP 介绍】不太清楚的同学可以点击查阅。
当我们了解了协议细节后, 接下来我们就来看一下在 aosp 中是如何一步步 将 sdp 跑起来的。
大家可以思考一下, sdp 初始化过程?都做了那些事情?
二、 sdp_init 函数
sdp_init
是初始化 SDP 协议栈的入口函数。
2.1 何时初始化sdp?
当应用侧调用enable()
时底层协议栈将触发调用 event_start_up_stack()
.
感兴趣可以参考如下文章:
c
// 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 层的注册。
c
// system/stack/sdp/sdp_main.cc
void 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_info
enable_snoop=true 表示允许 HCI snoop log(用于调试)
nullptr:无特殊 context
SDP_MTU_SIZE:MTU
BTM_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 介绍
c
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
c
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
c
/* 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 4
uint8_t con_state;
#define SDP_FLAGS_IS_ORIG 0x01
#define SDP_FLAGS_HIS_CFG_DONE 0x02
#define SDP_FLAGS_MY_CFG_DONE 0x04
uint8_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_t
handles[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 5
uint8_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 for
the 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
c
/* Define the SDP database */
typedef struct {
uint32_t
di_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 或属性的记录,并构造响应包返回 |
c
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
c
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 的流程。