【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().

感兴趣可以参考如下文章:

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");
  }
}

上面的函数很简单总结下来有如下几步:

  1. 初始化全局变量结构体 sdp_cb
  2. 为每个连接分配定时器
  3. 配置 L2CAP MTU
  4. 设置属性列表与记录上限
  5. 设置默认日志级别
  6. 配置 L2CAP 回调函数集
  7. 注册 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 搜索流程中的典型状态转换
  1. 客户端发起连接

    • 设置 con_state = SDP_STATE_CONN_SETUP

    • 设置 con_flags |= SDP_FLAGS_IS_ORIG

  2. 收到 L2CAP 配置完成

    • 设置 con_flags |= SDP_FLAGS_MY_CFG_DONE | SDP_FLAGS_HIS_CFG_DONE

    • 设置 con_state = SDP_STATE_CONNECTED

  3. 开始服务发现

    • 设置 disc_state = SDP_DISC_WAIT_HANDLES
  4. 收到服务记录后开始逐个请求属性

    • 设置 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 的流程。

相关推荐
2501_915909062 小时前
iOS如何查看电池容量?理解系统限制与开发者级能耗调试方法
android·ios·小程序·https·uni-app·iphone·webview
梦否7 小时前
Android 代码热度统计(概述)
android
xchenhao11 小时前
基于 Flutter 的开源文本 TTS 朗读器(支持 Windows/macOS/Android)
android·windows·flutter·macos·openai·tts·朗读器
coder_pig11 小时前
跟🤡杰哥一起学Flutter (三十五、玩转Flutter滑动机制📱)
android·flutter·harmonyos
消失的旧时光-194312 小时前
OkHttp SSE 完整总结(最终版)
android·okhttp·okhttp sse
ansondroider13 小时前
OpenCV 4.10.0 移植 - Android
android·人工智能·opencv
hsx66616 小时前
Kotlin return@label到底怎么用
android
itgather17 小时前
安卓设备信息查看器 - 源码编译
android
whysqwhw17 小时前
OkHttp之buildSrc模块分析
android