当前位置: 首页 > news >正文

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

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

  1. 初始化全局变量结构体 sdp_cb
  2. 为每个连接分配定时器
  3. 配置 L2CAP MTU
  4. 设置属性列表与记录上限
  5. 设置默认日志级别
  6. 配置 L2CAP 回调函数集
  7. 注册 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_cfgtL2CAP_CFG_INFOSDP 本地 L2CAP 配置(如 MTU)
ccb[]tCONN_CB[]每个 SDP 连接的上下文(状态、CID、定时器)
server_dbtSDP_DB本地 SDP Server 服务数据库
reg_infotL2CAP_APPL_INFO向 L2CAP 注册的回调集合
max_attr_list_sizeuint16_t每次搜索返回属性的最大字节数
max_recs_per_searchuint16_t每次搜索允许返回的最大服务记录数
trace_leveluint8_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 中使用场景
resultuint16_t仅用于 config 确认(confirm)消息中的返回码(如 L2CAP_CFG_OK间接使用SDP 在发送 config confirm 时使用,确认配置是否接受
mtu_presentbool表示是否携带 mtu 字段使用SDP 明确设置 mtu_present = true,用于控制数据包最大长度
mtuuint16_t指定对端发送数据的最大传输单元(MTU)使用SDP 设置为 SDP_MTU_SIZE(如 672),控制单次可接收数据最大值
qos_presentbool是否携带 qos 字段❌ 不使用SDP 不关心 QoS,设置为 false
qosFLOW_SPECQoS 参数(延迟、带宽等)❌ 不使用SDP 协议无需 QoS 支持
flush_to_presentbool是否携带 flush_to 字段❌ 不使用SDP 数据传输无需 flush 控制
flush_touint16_tFlush timeout 值❌ 不使用同上
fcr_presentbool是否使用 FCR(Frame-based Transmission)模式❌ 不使用SDP 使用基本模式(Basic Mode),不使用 FCR
fcrtL2CAP_FCR_OPTSFCR 参数(模式、窗口大小、重传)❌ 不使用SDP 只使用基本 L2CAP,FCR 模式适用于 AVRCP、AVCTP 等需要重传的协议
fcs_presentbool是否显式启用/禁用 FCS 检查❌ 通常不使用SDP 默认按标准 FCS 行为执行,不主动配置
fcsuint8_t如果为 0 则关闭 FCS 校验,1 为启用❌ 通常不使用同上
ext_flow_spec_presentbool是否包含扩展 flow spec❌ 不使用SDP 无需 HCI 层高级流控制
ext_flow_spectHCI_EXT_FLOW_SPECHCI 扩展流量规格❌ 不使用高级流量控制,用于 BLE Audio 等场景
flagsuint16_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_stateuint8_t连接当前状态(如空闲、配置中、已连接)用于状态机控制 SDP 连接生命周期(从连接建立到服务查询结束)
con_flagsuint8_t连接标志位集合,如是否本端发起、配置完成标志控制连接角色(客户端/服务端)与是否已完成 L2CAP 配置交换
device_addressRawAddress远端设备蓝牙地址标识连接目标设备,用于查找已有连接或发起新连接
sdp_conn_timeralarm_t*SDP 连接的超时定时器控制连接等待、配置、搜索等阶段的超时,防止卡死
rem_mtu_sizeuint16_t对端提供的 L2CAP MTU用于限制 SDP 响应包大小,确保不会超出对端接收能力
connection_iduint16_tL2CAP 分配的 connection ID(CID)标识 SDP 会话使用的 L2CAP 信道,用于数据发送接收匹配
list_lenuint16_tSDP 响应数据的总长度(来自远端)用于计算响应接收进度(特别是 continuation 情况)
rsp_listuint8_t*存储接收 SDP 响应数据的缓冲区保存从对端接收的原始服务记录,用于后续解析
p_dbtSDP_DISCOVERY_DB*本地发现数据库指针SDP 客户端用来保存搜索结果(服务记录、属性)
p_cbtSDP_DISC_CMPL_CB*SDP 发现完成后的回调函数在服务搜索完成时通知上层模块(如 A2DP、PBAP)
p_cb2tSDP_DISC_CMPL_CB2*带用户数据的回调版本支持用户传入 context 数据(如模块私有状态)
user_dataconst void*用户数据(piggyback)结合 p_cb2 使用,便于调用者传入自定义上下文
handles[SDP_MAX_DISC_SERVER_RECS]uint32_t[]存储搜索到的服务记录 handle在 SDP search response 中保存每条服务记录 ID
num_handlesuint16_t已发现的服务记录个数handles[] 配合,限制返回数量(如不超过 21)
cur_handleuint16_t当前正在查询属性的服务记录 handleattribute request 阶段循环查询每条记录
transaction_iduint16_tSDP 协议事务 ID每个 request/request pair 都使用独立的 ID 匹配请求和响应
disconnect_reasonuint16_t断开连接原因保存 L2CAP 或上层触发断开的原因,用于诊断
disc_stateuint8_t当前 discovery 状态(等待连接、服务记录、属性等)控制 SDP 客户端的状态机,如正在执行哪一类 SDP 请求
is_attr_searchuint8_t当前是否是 attribute 搜索类型区分是 search (按 UUID) 还是 search+attr(按属性)操作
cont_offsetuint16_tcontinuation 响应中的 offset用于 SDP continuation 响应拼接判断
cont_infotSDP_CONT_INFOcontinuation 状态信息结构体保存服务端返回的 continuation token,用于发送下一段请求
tCONN_CB()构造函数默认构造函数用于初始化对象
tCONN_CB(const tCONN_CB&) = delete;删除拷贝构造禁止拷贝避免连接状态被意外复制
宏名数值含义
SDP_STATE_IDLE0空闲状态,未使用连接
SDP_STATE_CONN_SETUP1正在建立 L2CAP 连接
SDP_STATE_CFG_SETUP2L2CAP 配置交换中
SDP_STATE_CONNECTED3已连接并可发送 SDP 请求
SDP_STATE_CONN_PEND4被动等待对端建立连接中(一般是服务端)
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

/* 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_handleuint32_t表示 Device ID Profile 的主服务记录句柄(Primary record),如果没有则为 0用于区分是否存在 Device ID 主记录。部分设备/平台实现了 Device ID Profile,可用于标识厂商、产品、版本号等。当远端搜索设备 ID 服务时,SDP Server 会返回该记录
num_recordsuint16_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 Profiledi_primary_handle通过 SDP_SetDeviceID()SDP_CreateRecord() 添加 Device ID Profile 时,会设置 di_primary_handle
响应远端服务搜索record[], num_records, di_primary_handleSDP 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_CbtL2CA_CONNECT_IND_CB*接收连接指示的回调函数(远端发起连接)✅ 是SDP Server 用于响应远端(如手机)发起的 SDP 连接
pL2CA_ConnectCfm_CbtL2CA_CONNECT_CFM_CB*本地发起连接后的确认回调✅ 是SDP 客户端用来确认连接是否建立成功(如车机主动发起 SDP 查询)
pL2CA_ConfigInd_CbtL2CA_CONFIG_IND_CB*接收对方发来的配置请求回调✅ 是SDP Server 接收 L2CAP 配置请求(如 MTU 设置)并响应
pL2CA_ConfigCfm_CbtL2CA_CONFIG_CFM_CB*本地发送配置请求后的确认回调✅ 是SDP 客户端确认对方是否接受本端配置(如设置的 MTU)
pL2CA_DisconnectInd_CbtL2CA_DISCONNECT_IND_CB*接收到对方断开连接通知的回调✅ 是SDP Server 被动接收远端断开请求时触发
pL2CA_DisconnectCfm_CbtL2CA_DISCONNECT_CFM_CB*本地断开连接后,收到对方确认的回调✅ 是SDP 客户端断开连接后,收到远端确认响应时使用
pL2CA_DataInd_CbtL2CA_DATA_IND_CB*接收对方发送的数据包✅ 是SDP 接收远端 SDP 请求时处理数据内容的入口
pL2CA_CongestionStatus_CbtL2CA_CONGESTION_STATUS_CB*L2CAP 信道拥塞状态改变回调❌ 否SDP 不使用流控,也不处理拥塞状态
pL2CA_TxComplete_CbtL2CA_TX_COMPLETE_CB*L2CAP 数据发送完成通知❌ 否SDP 请求和响应数据量小,通常一次完成发送,不关注此事件
pL2CA_Error_CbtL2CA_ERROR_CB*L2CAP 出现错误的回调(如 CRC 错误)✅ 是SDP Server 或 Client 出现通道异常时记录错误日志
pL2CA_CreditBasedConnectInd_CbtL2CA_CREDIT_BASED_CONNECT_IND_CB*接收 LE Credit-Based 连接的请求(LE)❌ 否SDP 运行在 BR/EDR 基本模式,不使用 LE 信道
pL2CA_CreditBasedConnectCfm_CbtL2CA_CREDIT_BASED_CONNECT_CFM_CB*确认 LE Credit-Based 连接建立成功❌ 否同上,不适用于 SDP
pL2CA_CreditBasedReconfigCompleted_CbtL2CA_CREDIT_BASED_RECONFIG_COMPLETED_CB*LE 信道重配置完成通知❌ 否SDP 不涉及重配置场景
pL2CA_CreditBasedCollisionInd_CbtL2CA_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 的流程。

http://www.dtcms.com/a/275802.html

相关文章:

  • Operation Blackout 2025: Smoke Mirrors
  • Windows符号链接解决vscode和pycharm占用C盘空间太大的问题
  • NX二次开发——导入模型是常遇见的问题(导入模型原点的确定导入模型坐标的确定)
  • BERT:双向Transformer革命 | 重塑自然语言理解的预训练范式
  • 深入理解大语言模型:从核心技术到极简实现
  • 洛谷题解 | UVA1485 Permutation Counting
  • jenkins自动化部署前端vue+docker项目
  • 前端面试宝典---项目难点2-智能问答对话框采用虚拟列表动态渲染可视区域元素(10万+条数据)
  • 自动化运维工具jenkins问题
  • Ubuntu安装Jenkins
  • java堆的创建与基础代码解析(图文)
  • Classifier guidance与Classifier-free guidance的原理和公式推导
  • 深大计算机游戏开发实验三
  • 深度学习图像分类数据集—害虫识别分类
  • 分布式数据库系统模式结构深度解析
  • Nginx 中的负载均衡策略
  • 数据统计及透视表
  • 使用Java完成下面项目
  • 引入了模块但没有使用”,会不会被打包进去
  • 【科研绘图系列】R语言绘制小提琴图
  • 基于定制开发开源AI智能名片S2B2C商城小程序的社群游戏定制策略研究
  • cuDNN 的 IMPLICIT_GEMM 算法
  • 【数据结构初阶】--顺序表(二)
  • 浅谈 Pydantic v2 的 RootModel 与联合类型——构建多请求结构的统一入口模型
  • 钉钉企业应用开发实战:从零构建组织级业务工具
  • 【LeetCode453.最小操作次数使数组元素相等】
  • leetcode-链表排序
  • Matlab中optimoptions的用法
  • docker 443错误 lookup docker.mirrors.ustc.edu.cn: no such host
  • Hap包引用的Hsp报签名错误怎么解决