【Bluedroid】蓝牙启动之 GAP_Init 流程源码解析
蓝牙 GAP(通用访问配置文件)模块是蓝牙协议栈的核心组件,负责设备发现、连接管理及基础属性暴露等关键功能。本文围绕 Android蓝牙协议栈 GAP 模块的初始化流程与连接管理实现展开,结合代码解析其核心函数(GAP_Init
、gap_conn_init
、gap_attr_db_init
)的功能逻辑,以及关键数据结构(tGAP_CONN
、tGAP_CCB
、tGAP_ATTR
等)的设计意图。通过分析 GAP 模块与 L2CAP 层的协议交互、连接状态机管理,以及 GATT 属性数据库的初始化过程,揭示 GAP 模块在蓝牙设备发现、配对及连接中的基础支撑作用。
一、概述
蓝牙 GAP 模块作为协议栈的 “入口”,其核心目标是为上层应用提供统一的设备管理接口,并确保底层协议(如 L2CAP、GATT)的高效协作。本文聚焦以下核心内容:
1.1 GAP 模块初始化流程:GAP_Init
GAP_Init
是 GAP 模块的基础初始化入口函数,设计上确保 “每次栈调用仅执行一次”。其通过调用两个子函数完成初始化:
-
gap_conn_init
:初始化 GAP 连接管理模块,通过注册 L2CAP 层事件回调(如连接请求、数据到达)建立与 L2CAP 的协议交互通道; -
gap_attr_db_init
:初始化 GAP 的 GATT 属性数据库,向外暴露 BLE 设备的基础属性(如设备名称、图标、地址解析状态),支撑设备发现与配对。
1.2 连接管理核心:gap_conn_init
与数据结构
gap_conn_init
的核心任务是初始化连接管理的全局状态,并建立与 L2CAP 层的事件交互。通过memset
清零全局结构体tGAP_CONN
确保初始状态可控,随后为reg_info
成员注册 L2CAP 事件回调(如gap_connect_ind
处理连接请求、gap_data_ind
处理数据到达),实现对 L2CAP 事件的响应。
关键数据结构tGAP_CONN
通过ccb_pool
数组管理最多 30 个并发连接(GAP_MAX_CONNECTIONS
),每个连接由tGAP_CCB
结构体控制。tGAP_CCB
通过状态机(con_state
,如IDLE→LISTENING→CONNECTED
)和标志位(con_flags
,如配置完成、安全验证完成)严格管理连接生命周期,并通过队列(tx_queue
、rx_queue
)实现流量控制,确保数据可靠传输。
1.3 属性数据库初始化:gap_attr_db_init
gap_attr_db_init
的核心是在 GATT 服务器中创建 GAP 服务,并初始化其属性数据库,向外暴露 BLE 设备的基础信息。通过以下步骤实现:
-
注册 GATT 服务:通过
GATT_Register
创建应用实例,获取 GATT 接口句柄gatt_if
; -
定义服务与特征:声明主服务(UUID 0x1800),并添加设备名称(0x2A00)、图标(0x2A01)、地址解析(0x2AA6)等特征,部分场景(外设模式)添加首选连接参数(0x2A04)特征;
-
绑定属性缓存:将 GATT 服务器分配的特征句柄与本地数组
gatt_attr
绑定,便于后续快速访问或修改属性值(如更新设备名称)。
二、源码解析
GAP_Init
packages/modules/Bluetooth/system/stack/gap/gap_conn.cc
/** This routine should not be called except once per stack invocation.*/
void GAP_Init(void) {gap_conn_init();gap_attr_db_init();
}
GAP 模块的基础初始化,确保后续功能正确运行。
gap_conn_init
packages/modules/Bluetooth/system/stack/gap/gap_conn.cc
namespace {
tGAP_CONN conn;
} // namespace/********************************************************************************* Function gap_conn_init** Description This function is called to initialize GAP connection* management** Returns void*******************************************************************************/
void gap_conn_init(void) {memset(&conn, 0, sizeof(tGAP_CONN));// 注册 L2CAP 层回调函数:建立协议层交互通道conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;conn.reg_info.pL2CA_ConnectCfm_Cb = gap_connect_cfm;conn.reg_info.pL2CA_ConfigInd_Cb = gap_config_ind;conn.reg_info.pL2CA_ConfigCfm_Cb = gap_config_cfm;conn.reg_info.pL2CA_DisconnectInd_Cb = gap_disconnect_ind;conn.reg_info.pL2CA_DataInd_Cb = gap_data_ind;conn.reg_info.pL2CA_CongestionStatus_Cb = gap_congestion_ind;conn.reg_info.pL2CA_TxComplete_Cb = gap_tx_complete_ind;conn.reg_info.pL2CA_Error_Cb = gap_on_l2cap_error;
}
GAP模块的连接管理部分,主要实现 GAP 连接管理模块的初始化逻辑。为conn.reg_info
(注册信息结构体)中的L2CAP 层事件回调函数指针赋值,建立 GAP 模块与 L2CAP 层的事件交互通道。每个回调函数对应 L2CAP 层的一个关键事件:
回调函数指针 | 含义与作用 |
pL2CA_ConnectInd_Cb | L2CAP 连接请求指示回调。当底层收到 L2CAP 连接请求时,触发gap_connect_ind处理(如验证请求、分配资源)。 |
pL2CA_ConnectCfm_Cb | L2CAP 连接确认回调。当 L2CAP 连接成功建立后,触发gap_connect_cfm通知上层(如更新连接状态)。 |
pL2CA_ConfigInd_Cb | L2CAP 配置请求指示回调。当收到 L2CAP 连接参数配置请求时,触发gap_config_ind处理(如协商 MTU、QoS)。 |
pL2CA_ConfigCfm_Cb | L2CAP 配置确认回调。当配置完成后,触发gap_config_cfm同步最终配置结果。 |
pL2CA_DisconnectInd_Cb | L2CAP 断开连接指示回调。当 L2CAP 连接断开时,触发gap_disconnect_ind清理资源(如释放连接句柄)。 |
pL2CA_DataInd_Cb | L2CAP 数据到达指示回调。当收到 L2CAP 层数据时,触发gap_data_ind向上层传递数据(如 GATT/ATT 处理)。 |
pL2CA_CongestionStatus_Cb | L2CAP 拥塞状态变化回调。当底层发生拥塞或恢复时,触发gap_congestion_ind调整发送策略(如暂停发数据)。 |
pL2CA_TxComplete_Cb | L2CAP 数据发送完成回调。当数据成功发送到底层时,触发gap_tx_complete_ind释放发送缓冲区。 |
pL2CA_Error_Cb | L2CAP 错误通知回调。当 L2CAP 层发生错误(如协议异常)时,触发gap_on_l2cap_error处理错误(如断开连接)。 |
tGAP_CONN
packages/modules/Bluetooth/system/stack/gap/gap_conn.cc
// LE 信用模式(Credit-Based)连接的信用管理
// 背景:在蓝牙 LE 的 L2CAP 面向连接通道(CoC)中,信用模式(Credit-Based Flow Control)用于流量控制。发送方需根据接收方授予的信用值(每信用代表 1 个数据包)限制发送量
//作用:记录信用值的接收和消耗状态,确保发送方不会超出接收方的处理能力
struct tGAP_COC_CREDITS {uint16_t credits_received; // 已接收的信用值(对端允许发送的数据包数量)uint16_t credit_count; // 当前可用的信用值(剩余可发送的数据包数量)
};// GAP 连接事件回调数据联合体
union tGAP_CB_DATA {tGAP_COC_CREDITS coc_credits; // 当事件与LE信用模式相关时,存储信用值数据uint16_t l2cap_result; // 当事件与L2CAP操作结果相关时,存储结果状态(如成功/失败码)
};// GAP 连接事件回调函数指针
/** Callback function for connection services
*/
typedef void(tGAP_CONN_CALLBACK)(uint16_t gap_handle, uint16_t event,tGAP_CB_DATA* data);// 增强重传模式(ERTM)配置
// 背景:ERTM 是 L2CAP 的一种传输模式,支持重传和流量控制,用于提高数据传输可靠性
// 作用:配置连接的 ERTM 模式,影响 L2CAP 层的数据重传策略和错误处理方式
/* Define the structure that applications use to create or accept* connections with enhanced retransmission mode.*/
typedef struct {uint8_t preferred_mode; // 首选的ERTM模式(如基本模式、增强模式)
} tL2CAP_ERTM_INFO;typedef uint8_t tBT_TRANSPORT;// LE L2CAP 面向连接通道(CoC)配置
/* Define a structure to hold the configuration parameter for LE L2CAP* connection oriented channels.*/
struct tL2CAP_LE_CFG_INFO {uint16_t result; /* Only used in confirm messages */uint16_t mtu = 100;uint16_t mps = 100; // 最大数据包大小(字节),默认100字节uint16_t credits = L2CA_LeCreditDefault(); // 初始信用值(默认由L2CAP层定义)uint8_t number_of_channels = L2CAP_CREDIT_BASED_MAX_CIDS; // 最大支持的CoC通道数
};// 单个 L2CAP 连接的状态管理核心结构,存储连接的生命周期状态、配置参数和交互接口
/* Define the GAP Connection Control Block */
typedef struct {
// 通过状态迁移(如IDLE → LISTENING → CONN_SETUP → CFG_SETUP → CONNECTED)严格管理连接的生命周期,确保各阶段操作(如连接请求、参数协商)按顺序执行
#define GAP_CCB_STATE_IDLE 0
#define GAP_CCB_STATE_LISTENING 1
#define GAP_CCB_STATE_CONN_SETUP 2
#define GAP_CCB_STATE_CFG_SETUP 3
#define GAP_CCB_STATE_CONNECTED 5uint8_t con_state;// 通过位掩码快速标记连接的关键里程碑(如是否完成配置、安全验证),避免复杂的状态判断逻辑
#define GAP_CCB_FLAGS_IS_ORIG 0x01
#define GAP_CCB_FLAGS_HIS_CFG_DONE 0x02 // 标志位:对端配置已完成(对端参数协商完成)
#define GAP_CCB_FLAGS_MY_CFG_DONE 0x04 // 标志位:本地配置已完成(本地参数协商完成)
#define GAP_CCB_FLAGS_SEC_DONE 0x08
#define GAP_CCB_FLAGS_CONN_DONE 0x0Euint8_t con_flags;// 存储连接的基础标识信息(如句柄、CID、地址)和协商参数(如对端 MTU),用于在协议栈各层(GAP、L2CAP、BTM)间传递连接上下文uint8_t service_id; /* Used by BTM */uint16_t gap_handle; /* GAP handle */uint16_t connection_id; /* L2CAP CID */bool rem_addr_specified;uint8_t chan_mode_mask; /* Supported channel modes (FCR) */RawAddress rem_dev_address;uint16_t psm;uint16_t rem_mtu_size;// 流量控制与队列管理// 蓝牙底层可能因处理能力限制出现拥塞,需通过队列缓存数据并控制发送速率bool is_congested;fixed_queue_t* tx_queue; /* Queue of buffers waiting to be sent */fixed_queue_t* rx_queue; /* Queue of buffers waiting to be read */uint32_t rx_queue_size; /* Total data count in rx_queue */// 回调与配置参数tGAP_CONN_CALLBACK* p_callback; /* Users callback function */tL2CAP_CFG_INFO cfg; /* Configuration */tL2CAP_ERTM_INFO ertm_info; /* Pools and modes for ertm */tBT_TRANSPORT transport; /* Transport channel BR/EDR or BLE */tL2CAP_LE_CFG_INFO local_coc_cfg; /* local configuration for LE Coc */tL2CAP_LE_CFG_INFO peer_coc_cfg; /* local configuration for LE Coc */
} tGAP_CCB;/* The maximum number of simultaneous GAP L2CAP connections. */
#ifndef GAP_MAX_CONNECTIONS
#define GAP_MAX_CONNECTIONS 30
#endiftypedef struct {tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */tGAP_CCB ccb_pool[GAP_MAX_CONNECTIONS];
} tGAP_CONN;
GAP模块中与连接管理相关的核心数据结构,用于管理L2CAP连接的状态、配置及事件交互。
这些结构体共同构成了 GAP 连接管理模块的核心数据模型:
-
tGAP_CONN
:作为全局管理结构,通过reg_info
与 L2CAP 层交互,并通过ccb_pool
管理所有活动连接。 -
tGAP_CCB
:每个连接的 “状态控制器”,通过状态机(con_state
)、标志位(con_flags
)和配置参数(如local_coc_cfg
)管理连接的生命周期。 -
tGAP_CONN_CALLBACK
:上层应用的 “事件入口”,确保连接事件(如数据到达、断开)能被及时处理。
通过这套数据结构,GAP 模块实现了对 L2CAP 连接的高效管理(如连接建立、参数协商、流量控制),是蓝牙协议栈中连接层的核心基础。
gap_attr_db_init
packages/modules/Bluetooth/system/stack/gap/gap_ble.cc
// BLE 首选连接参数
typedef struct {uint16_t int_min; // 最小连接间隔(单位:1.25ms,范围:0x0006~0x0C80)uint16_t int_max; // 最大连接间隔(需≥int_min)uint16_t latency; // 从机延迟(允许从机跳过的连接事件数)uint16_t sp_tout; // 监督超时时间(单位:10ms,范围:0x000A~0x0C80)
} tGAP_BLE_PREF_PARAM;// GAP 属性值联合体
typedef union {tGAP_BLE_PREF_PARAM conn_param; // BLE首选连接参数(当属性类型为连接参数时)RawAddress reconn_bda; // 重连地址(当属性类型为重连地址时)uint16_t icon; // 设备图标类型(当属性类型为图标时)uint8_t* p_dev_name; // 设备名称指针(当属性类型为设备名称时)uint8_t addr_resolution; // 地址解析标志(当属性类型为地址解析时)
} tGAP_BLE_ATTR_VALUE;// GAP 属性描述结构体
typedef struct {uint16_t handle; // GATT属性句柄(唯一标识GATT数据库中的属性)uint16_t uuid; // 属性UUID(标识属性类型,如设备名称、图标)tGAP_BLE_ATTR_VALUE attr_value; // 属性值(根据UUID类型选择对应存储方式)
} tGAP_ATTR;constexpr int GAP_MAX_CHAR_NUM = 4; // GAP服务最多包含4个特征(属性)
/* LE GAP attribute database */
std::array<tGAP_ATTR, GAP_MAX_CHAR_NUM> gatt_attr; // 存储所有GAP属性的数组
tGATT_IF gatt_if; // GATT接口标识符(用于关联GATT服务器实例)/********************************************************************************* Function btm_ble_att_db_init** Description GAP ATT database initalization.** Returns void.*******************************************************************************/
void gap_attr_db_init(void) { // 1. 创建并注册 GATT 服务/* Fill our internal UUID with a fixed pattern 0x82 */std::array<uint8_t, Uuid::kNumBytes128> tmp; // 创建固定模式的128位UUID(用于应用标识)tmp.fill(0x82);Uuid app_uuid = Uuid::From128BitBE(tmp);gatt_attr.fill({});// 注册GATT服务,获取接口句柄gatt_ifgatt_if = GATT_Register(app_uuid, "Gap", &gap_cback, false);GATT_StartIf(gatt_if); // 启动GATT接口// 2. 定义 GAP 服务的 GATT 数据库元素Uuid svc_uuid = Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER); // GAP服务UUID(标准16位)Uuid name_uuid = Uuid::From16Bit(GATT_UUID_GAP_DEVICE_NAME); // 设备名称特征UUIDUuid icon_uuid = Uuid::From16Bit(GATT_UUID_GAP_ICON); // 设备图标特征UUIDUuid addr_res_uuid = Uuid::From16Bit(GATT_UUID_GAP_CENTRAL_ADDR_RESOL); // 地址解析特征UUID// 定义GATT数据库元素(服务+特征)btgatt_db_element_t service[] = {{ /* 主服务 */.uuid = svc_uuid,.type = BTGATT_DB_PRIMARY_SERVICE,},{ /* 设备名称特征 */.uuid = name_uuid,.type = BTGATT_DB_CHARACTERISTIC,.properties = GATT_CHAR_PROP_BIT_READ, // 可读属性.permissions = GATT_PERM_READ_IF_ENCRYPTED_OR_DISCOVERABLE}, // 加密或可发现时可读{ /* 设备图标特征 */.uuid = icon_uuid,.type = BTGATT_DB_CHARACTERISTIC,.properties = GATT_CHAR_PROP_BIT_READ,.permissions = GATT_PERM_READ // 无条件可读}, { /* 中心地址解析特征 */.uuid = addr_res_uuid,.type = BTGATT_DB_CHARACTERISTIC,.properties = GATT_CHAR_PROP_BIT_READ,.permissions = GATT_PERM_READ}
#if (BTM_PERIPHERAL_ENABLED == TRUE) /* Only needed for peripheral testing */,{ /* 首选连接参数特征(仅外设需要) */.uuid = Uuid::From16Bit(GATT_UUID_GAP_PREF_CONN_PARAM),.type = BTGATT_DB_CHARACTERISTIC,.properties = GATT_CHAR_PROP_BIT_READ,.permissions = GATT_PERM_READ}
#endif};// 3. 向 GATT 服务器添加服务// 将定义好的服务和特征添加到 GATT 服务器的数据库中,使其他设备(如手机)可以通过 GATT 协议发现并访问这些属性/* Add a GAP service */GATTS_AddService(gatt_if, service,sizeof(service) / sizeof(btgatt_db_element_t));// 4. 初始化本地属性缓存(gatt_attr)// 设备名称属性gatt_attr[0].uuid = GATT_UUID_GAP_DEVICE_NAME;gatt_attr[0].handle = service[1].attribute_handle; // 特征句柄(由GATT服务器分配)// 设备图标属性gatt_attr[1].uuid = GATT_UUID_GAP_ICON;gatt_attr[1].handle = service[2].attribute_handle;// 地址解析属性(初始值设为0)gatt_attr[2].uuid = GATT_UUID_GAP_CENTRAL_ADDR_RESOL;gatt_attr[2].handle = service[3].attribute_handle;gatt_attr[2].attr_value.addr_resolution = 0;#if (BTM_PERIPHERAL_ENABLED == TRUE) /* Only needed for peripheral testing */// 外设模式初始化连接参数gatt_attr[3].uuid = GATT_UUID_GAP_PREF_CONN_PARAM;// 默认最大间隔(6*1.25ms=7.5ms)gatt_attr[3].attr_value.conn_param.int_max = GAP_PREFER_CONN_INT_MAX; /* 6 */// 默认最小间隔(0*1.25ms=0ms,实际需≥6)gatt_attr[3].attr_value.conn_param.int_min = GAP_PREFER_CONN_INT_MIN; /* 0 */gatt_attr[3].attr_value.conn_param.latency = GAP_PREFER_CONN_LATENCY; /* 0 */// 默认监督超时(2000*10ms=20s)gatt_attr[3].attr_value.conn_param.sp_tout =GAP_PREFER_CONN_SP_TOUT; /* 2000 */gatt_attr[3].handle = service[4].attribute_handle;
#endif
}
完成GAP GATT 属性数据库的初始化,用于向外暴露 BLE 设备的基础属性(如设备名称、图标、地址解析状态等)。这些属性是 BLE 设备发现、配对和连接的基础,其他设备(如手机)通过读取这些属性可获取设备的基本信息和能力,从而完成后续交互(如连接参数协商)。
主服务(
BTGATT_DB_PRIMARY_SERVICE
):声明这是一个主 GAP 服务,UUID 为标准的UUID_SERVCLASS_GAP_SERVER
(0x1800)。特征(
BTGATT_DB_CHARACTERISTIC
):每个特征对应一个具体属性:
设备名称(
GATT_UUID_GAP_DEVICE_NAME
,0x2A00):存储设备的友好名称(如 “我的蓝牙耳机”);设备图标(
GATT_UUID_GAP_ICON
,0x2A01):标识设备类型的图标(如耳机图标对应的数值);中心地址解析(
GATT_UUID_GAP_CENTRAL_ADDR_RESOL
,0x2AA6):指示是否支持地址解析(隐私功能相关);首选连接参数(
GATT_UUID_GAP_PREF_CONN_PARAM
,0x2A04):仅在外设模式启用,存储设备希望的连接参数(如int_min
/int_max
)。
将 GATT 服务器分配的特征句柄(attribute_handle
)与本地gatt_attr
数组绑定,后续上层可通过gatt_attr
快速访问或修改属性值(如更新设备名称)。
GATT_Register、GATT_StartI f和 GATTS_AddService分析见【Bluedroid】蓝牙启动之gatt_init 流程源码解析
三、GAP 模块初始化流程图
四、GAP 模块初始化时序图
五、总结
蓝牙 GAP 模块通过 “初始化流程 - 连接管理 - 属性暴露” 的协同设计,实现了对蓝牙设备发现、连接建立及基础属性交互的核心支撑:
-
初始化流程(
GAP_Init
)确保模块在生命周期内仅执行一次基础配置,避免资源重复分配; -
连接管理(
gap_conn_init
与tGAP_CONN
/tGAP_CCB
)通过状态机、队列和协议回调,实现对 L2CAP 连接的高效控制(如参数协商、流量控制); -
属性数据库(
gap_attr_db_init
与gatt_attr
)通过 GATT 协议向外暴露设备信息,是其他设备(如手机)发现、配对和协商连接参数的基础。
这些设计共同保障了蓝牙设备间的互操作性与通信可靠性,是蓝牙协议栈中连接层的核心基础。