【Bluedroid】 BLE连接源码分析(一)
BLE链接过程分析见【Bluedroid】BLE连接过程详解-CSDN博客,本篇主要围绕HCI_LE_Create_Connection展开。基于Android14源码进行分析。在蓝牙低功耗技术中,设备之间建立连接是进行数据传输等操作的前提。HCI LE Extended Create Connection Command 提供了一种更灵活、功能更丰富的方式来创建连接,相比传统的连接创建命令,它能支持更多的参数配置和功能特性,以满足不同应用场景下的连接需求。
一、创建连接指令下发(HCI_LE_Create_Connection)过程
- 主设备发起:主设备发送 HCI LE Extended Create Connection Command 命令,其中包含了指定的连接参数等信息,如连接间隔和连接延迟等。
- 从设备响应:从设备接收到命令后,会根据自身的能力和配置来决定是否接受连接。如果从设备支持主设备所请求的连接参数,并且当前资源允许,它会发送一个响应消息,表示接受连接请求。
- 连接建立:双方根据协商好的连接参数开始建立连接,按照设定的连接间隔进行数据交互等操作,从设备会根据连接延迟参数来控制自身的休眠和唤醒时间,以实现节能和数据传输的平衡。
二、源码分析
BTM_AcceptlistAdd
从BTM_AcceptlistAdd开始分析:
/packages/modules/Bluetooth/system/stack/btm/btm_ble_bgconn.cc
bool BTM_AcceptlistAdd(const RawAddress& address) {
return BTM_AcceptlistAdd(address, false);
}
bool BTM_AcceptlistAdd(const RawAddress& address, bool is_direct) {
if (!controller_get_interface()->SupportsBle()) {
log::warn("Controller does not support Le");
return false;
}
return bluetooth::shim::ACL_AcceptLeConnectionFrom(
BTM_Sec_GetAddressWithType(address), is_direct);
}
BTM_AcceptlistAdd将对端地址添加到BLE连接列表中。由于BLE连接的建立是异步的,因此即使这个函数返回了 true,也并不意味着连接已经成功建立,而只是表示连接请求已经被接受并开始处理。
另外,is_direct 参数可能用于指示连接请求是否是通过某种直接方式(如通过已知的设备地址发起连接)发出的。
bluetooth::shim::ACL_AcceptLeConnectionFrom
/packages/modules/Bluetooth/system/main/shim/acl_api.cc
bool bluetooth::shim::ACL_AcceptLeConnectionFrom(
const tBLE_BD_ADDR& legacy_address_with_type, bool is_direct) {
std::promise<bool> promise; // 用于异步操作的对象
// 调用promise.get_future()获取与promise关联的future对象。future用于在异步操作完成后获取结果值
auto future = promise.get_future();
// 调用 AcceptLeConnectionFrom 方法
Stack::GetInstance()->GetAcl()->AcceptLeConnectionFrom(
ToAddressWithTypeFromLegacy(legacy_address_with_type), is_direct,
std::move(promise));
//调用future.get()等待异步操作完成并获取结果。future.get()会阻塞当前线程,直到异步操作完成并设置了结果值
return future.get();
}
接受来自特定蓝牙低功耗(BLE)设备的连接请求。它使用 std::promise 和 std::future 实现了异步操作的同步等待,确保在接受连接请求的操作完成后,返回操作结果(是否成功接受连接)。
-
注意:由于BLE连接的建立是一个异步过程,即使这个函数返回true,也不意味着连接已经成功建立。只是表示连接请求已经被接受,并且连接建立过程已经开始。
shim::legacy::Acl::AcceptLeConnectionFrom
/packages/modules/Bluetooth/system/main/shim/acl.cc
void shim::legacy::Acl::AcceptLeConnectionFrom(
const hci::AddressWithType& address_with_type, bool is_direct,
std::promise<bool> promise) {
LOG_DEBUG("AcceptLeConnectionFrom %s",
ADDRESS_TO_LOGGABLE_CSTR(address_with_type.GetAddress()));
handler_->CallOn(pimpl_.get(), &Acl::impl::accept_le_connection_from,
address_with_type, is_direct, std::move(promise));
}
将实际的处理逻辑委托给 Acl::impl 类的 accept_le_connection_from 方法,并使用 handler_ 来确保操作在合适的线程或上下文环境中执行。
-
pimpl_.get():使用了指向 Acl::impl 实现的智能指针,并通过 get() 方法获取原始指针。这是一种实现隐藏(Pimpl Idiom)的常见方式,用于在接口和实现之间提供清晰的分离。
-
&Acl::impl::accept_le_connection_from:指向 Acl::impl 类中 accept_le_connection_from 成员函数的指针。
-
address_with_type, is_direct, std::move(promise):这些是传递给 accept_le_connection_from 函数的参数。注意,promise 参数被 std::move 了,意味着它的所有权被转移给了 CallOn 方法。
关于 std::promise<bool> 的使用:
std::promise<bool> 被用作异步操作的结果传递机制。当 accept_le_connection_from 函数完成其工作时,它应该调用 promise.set_value(some_bool_value) 来设置结果,其中 some_bool_value 表示操作的成功或失败。然后,任何持有与 promise 相关联的 std::future<bool> 的代码都可以调用 future.get() 来等待结果并获取它。