【android bluetooth 框架分析 02】【Module详解 5】【HciLayer 模块介绍】
1. 背景
我们在 gd_shim_module 介绍章节中,看到 我们将 HciLayer 模块加入到了 modules 中。
// system/main/shim/stack.cc
modules.add<hci::HciLayer>();
在 ModuleRegistry::Start 函数中我们对 加入的所有 module 挨个初始化。
而在该函数中启动一个 module 都要执行下面几步:
-
创建module 实体
- Module* instance = module->ctor_();
-
将 当前 module 实体和 gd_stack_thread 线程绑定
- set_registry_and_handler(instance, thread);
-
启动当前模块所依赖的所有子模块。
- instance->ListDependencies(&instance->dependencies_);
- Start(&instance->dependencies_, thread);
-
最后调用自己的 Start() 函数
- instance->Start();
-
将module 实体加入到 started_modules_
- started_modules_[module] = instance;
本篇文章就拿 hal::HciLayer 模块来具体分析一下 他的启动。
2. modules.add
我们先来看一下 在调用 modules.add 时, 到底做了那些事情。
modules.add<hal::HciLayer>();
class ModuleList {friend Module;friend ModuleRegistry;public:template <class T>void add() {list_.push_back(&T::Factory); // add 时 添加的是 hal::HciLayer::Factory}private:std::vector<const ModuleFactory*> list_;
};
- 从代码中不难发现, 我们是将 hal::HciLayer::Factory 加入到 list_ 中的。
// system/gd/hci/hci_layer.cc
const ModuleFactory HciLayer::Factory = ModuleFactory([]() { return new HciLayer(); });// 这里在创建 ModuleFactory 对象时, 传入了一个 函数, 这个函数 去 new HciLayer 对象
- 这里在创建 ModuleFactory 对象时, 传入了一个 函数,但是并没有去调用这个函数。
- 这个函数的目的是 去 new HciLayer 对象
class ModuleFactory {friend ModuleRegistry;friend FuzzTestModuleRegistry;public:ModuleFactory(std::function<Module*()> ctor);private:std::function<Module*()> ctor_;
};// system/gd/module.cc
ModuleFactory::ModuleFactory(std::function<Module*()> ctor) : ctor_(ctor) {
}
- 在创建 ModuleFactory 对象时, 也仅仅是将 如下的函数赋值给了 ModuleFactory::ctor_ 函数指针。
[]() { return new HciLayer(); }
3. 模块具体启动流程
1. 创建module 实体
- 创建module 实体
- Module* instance = module->ctor_();
[]() { return new HciLayer(); }
- 这里就会去实际触发 该函数,去创建 HciLayer 对象。
- 也就是说, modules.addhal::HciLayer() 模块对应的 实体其实是HciLayer对象。
class HciLayer : public Module, public CommandInterface<CommandBuilder>
{}
- HciLayer 继承 Module 和 CommandInterface
2. 将 当前 module 实体和 gd_stack_thread 线程绑定
- 将 当前 module 实体和 gd_stack_thread 线程绑定
- set_registry_and_handler(instance, thread);
void ModuleRegistry::set_registry_and_handler(Module* instance, Thread* thread) const {instance->registry_ = this;instance->handler_ = new Handler(thread);
}
- 将我们的 gd_stack_thread 对应的 handle 直接保存在 Module->handler_ 中。
Handler* Module::GetHandler() const {ASSERT_LOG(handler_ != nullptr, "Can't get handler when it's not started");return handler_;
}
- 通过 Module::GetHandler() 来获取当前 handler_
3.启动当前模块所依赖的所有子模块
- 启动当前模块所依赖的所有子模块。
- instance->ListDependencies(&instance->dependencies_);
- Start(&instance->dependencies_, thread);
// system/gd/hci/hci_layer.cc
void HciLayer::ListDependencies(ModuleList* list) const {list->add<hal::HciHal>();list->add<storage::StorageModule>();
}
- HciLayer 模块依赖 HciHal 模块和 StorageModule 模块。
- 而HciHal 模块 已经 在这之前启动了。
- 那这里就会去先加载 StorageModule 模块。
- 下一小节 专门来介绍 StorageModule 模块
4. 最后调用自己的 Start() 函数
- 最后调用自己的 Start() 函数
- instance->Start();
HciLayer::Start 函数是 HciLayer
类的启动函数,负责初始化 HCI 层。这一层位于 Host 层与 Controller 层之间,是上层协议(如 L2CAP)与底层硬件通信的桥梁。
它的作用是初始化 HCI 层(Host Controller Interface Layer),包括数据队列注册、事件处理器注册、与 HAL 层的连接、以及发送 HCI Reset 命令
// system/gd/hci/hci_layer.cc
void HciLayer::Start() {auto hal = GetDependency<hal::HciHal>(); // 获取 HAL 层的 HCI 接口(一般通过 HIDL 或 AIDL 提供)。impl_ = new impl(hal, *this); // 创建一个 impl 实例,这是 HciLayer 的内部实现类,封装了具体的逻辑。hal_callbacks_ = new hal_callbacks(*this); // 注册 HAL 层回调对象,用于接收底层 HCI 数据包。// 为三种数据通道注册出队回调(ACL, SCO, ISO)。Handler* handler = GetHandler(); // 获取 gd_stack_thread 对应的 handlerimpl_->acl_queue_.GetDownEnd()->RegisterDequeue(handler, BindOn(impl_, &impl::on_outbound_acl_ready)); // ACL (Asynchronous Connection-Less):用于一般数据传输,如文件或音频流。impl_->sco_queue_.GetDownEnd()->RegisterDequeue(handler, BindOn(impl_, &impl::on_outbound_sco_ready)); // SCO (Synchronous Connection-Oriented):用于语音数据(如通话)。impl_->iso_queue_.GetDownEnd()->RegisterDequeue(handler, BindOn(impl_, &impl::on_outbound_iso_ready)); // ISO (Isochronous):用于 LE Audio 新协议的音频流。// 注册各种 HCI 事件的处理器// 车机与手机蓝牙握手过程的事件非常多,这里统一注册处理方式,保持事件驱动的异步架构。RegisterEventHandler(EventCode::COMMAND_COMPLETE, handler->BindOn(impl_, &impl::on_command_complete)); // 处理指令执行结果。RegisterEventHandler(EventCode::COMMAND_STATUS, handler->BindOn(impl_, &impl::on_command_status)); // 处理指令执行结果。RegisterLeMetaEventHandler(handler->BindOn(impl_, &impl::on_le_meta_event)); // 处理低功耗蓝牙相关事件(如连接完成、扫描结果)。RegisterEventHandler(EventCode::DISCONNECTION_COMPLETE, handler->BindOn(this, &HciLayer::on_disconnection_complete)); // 设备断开连接时触发。RegisterEventHandler(EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE,handler->BindOn(this, &HciLayer::on_read_remote_version_complete)); // 读取远端设备版本信息(如芯片厂商、固件版本)// 对一些无需处理的事件直接丢弃。auto drop_packet = handler->BindOn(impl_, &impl::drop);RegisterEventHandler(EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE, drop_packet);RegisterEventHandler(EventCode::MAX_SLOTS_CHANGE, drop_packet);// HAL 层一旦收到 HCI 数据包,就通过这个回调通知上层处理(异步机制)。hal->registerIncomingPacketCallback(hal_callbacks_);/* Sometimes HCI LE_SET_EVNET_MASK command may be sent before Bluetooth stack receives* HCI RESET CC event for previous HCI_RESET command.* This results into ASSERT in "waiting_command_(LE_SET_EVENT_MASK)!=opcode(RESET)"* when to handle HCI event in "handle_command_response", so that Bluetooth process raises* exception. */std::promise<void> reset_ready_promise;auto reset_ready_future = reset_ready_promise.get_future();// 发送 HCI Reset 命令,确保控制器状态清零EnqueueCommand(ResetBuilder::Create()/*构造一个 HCI Reset 命令*/, handler->BindOnce(&fail_if_reset_complete_not_success, std::move(reset_ready_promise)));reset_ready_future.wait(); // 阻塞等待 Reset 成功,确保控制器已经准备就绪。/*有时控制器处于“残留状态”,例如上次未正常退出或发生断电重启。Reset 可确保蓝牙控制器进入一个可预测、干净的初始状态。比如车机冷启动过程中发送 Reset,可以避免某些手机连接不上或蓝牙设备状态异常。*/
}
模块 | 作用 | 实际应用场景(车机) |
---|---|---|
获取 HAL 依赖 | 建立与硬件通信的通道 | 启动蓝牙控制器,等待连接 |
注册数据通道 | 处理不同类型的蓝牙数据 | 音乐、语音、LE Audio |
注册事件处理 | 响应蓝牙状态变更 | 设备连接、断开、扫描等 |
注册 HAL 回调 | 异步接收数据包 | 蓝牙数据实时上传上层 |
发送 Reset 命令 | 控制器初始化 | 避免“蓝牙失灵”、连接失败 |
1. 如何获取 hal 层接口
为什么 可以通过 GetDependency 就可以获取到 我们之前已经初始化完的 HciHal 模块?
auto hal = GetDependency<hal::HciHal>(); // 获取 HAL 层的 HCI 接口(一般通过 HIDL 或 AIDL 提供)。
// system/gd/hal/hci_hal_android_hidl.cc
const ModuleFactory HciHal::Factory = ModuleFactory([]() { return new HciHalHidl(); }); // 这里在创建 ModuleFactory 对象时, 传入了一个 函数, 这个函数 去 new HciHalHidl 对象// system/gd/module.h
class Module {template <class T>T* GetDependency() const {return static_cast<T*>(GetDependency(&T::Factory)); // 这里继续调用 GetDependency(&HciHal::Factory)}}// system/gd/module.cc
Module* Module::GetDependency(const ModuleFactory* module) const {/** 前面 HciLayer::ListDependencies 时,已经将 HciHal 加入到 HciLayer::dependencies_ 中了。*/for (auto& dependency : dependencies_.list_) {if (dependency == module) {return registry_->Get(module); // 这里的 registry_ 是谁? 是在初始化模块时 通过 set_registry_and_handler 传入的 ModuleRegistry 对象}}ASSERT_LOG(false, "Module was not listed as a dependency in ListDependencies");
}// system/gd/module.cc
Module* ModuleRegistry::Get(const ModuleFactory* module) const {auto instance = started_modules_.find(module); // 最终是从 ModuleRegistry::started_modules_ 模块中找到已经初始化的模块ASSERT_LOG(instance != started_modules_.end(), "Request for module not started up, maybe not in Start(ModuleList)?");return instance->second;
}class Module {const ModuleRegistry* registry_; // 而这里的 registry_ 指向 初始化模块时传入的 ModuleRegistry 对象, 通过他就可以找到started_modules_
}
最终 Module::GetDependency(const ModuleFactory* module) 是通过 registry_ 获取到了 HciLayer, 那为何 可以通过 registry_ 可以获取?
// 1. 模块初始化时,会调用如下代码// system/gd/module.ccModule* ModuleRegistry::Start(const ModuleFactory* module, Thread* thread) {Module* instance = module->ctor_();LOG_INFO("Starting of %s", instance->ToString().c_str());last_instance_ = "starting " + instance->ToString();set_registry_and_handler(instance, thread); // 2. 将 ModuleRegistry 对象赋值给 模块的registry_ 中。 这样每一个初始化的模块, 就可以通过 registry_ 访问到 例如 started_modules_ 对象。LOG_INFO("Starting dependencies of %s", instance->ToString().c_str());instance->ListDependencies(&instance->dependencies_);Start(&instance->dependencies_, thread);LOG_INFO("Finished starting dependencies and calling Start() of %s", instance->ToString().c_str());instance->Start();start_order_.push_back(module);started_modules_[module] = instance; // 3. 只要 模块启动完成后, 都会将 模块实例化加入到 started_modules_ 中LOG_INFO("Started %s", instance->ToString().c_str());return instance;
}// system/gd/module.h
class ModuleRegistry {std::map<const ModuleFactory*, Module*> started_modules_;
}void ModuleRegistry::set_registry_and_handler(Module* instance, Thread* thread) const {instance->registry_ = this; // 这里 赋值给 registry_instance->handler_ = new Handler(thread);
}
2. 创建 HciLayer::impl 对象
// system/gd/hci/hci_layer.cc
struct HciLayer::impl {impl(hal::HciHal* hal, HciLayer& module) : hal_(hal), module_(module) {hci_timeout_alarm_ = new Alarm(module.GetHandler());}
- 在 构建impl 对象时, 我们只是创建了一个 hci_timeout_alarm_ 定时器, 但是并没有启动。
- 从 new Alarm(module.GetHandler()) 中,可以看到 定时器线程也是跑在 gd_stack_thread 线程中的。
3. 注册出队处理函数(数据通道绑定)
// 为三种数据通道注册出队回调(ACL, SCO, ISO)。Handler* handler = GetHandler(); // 获取 gd_stack_thread 对应的 handlerimpl_->acl_queue_.GetDownEnd()->RegisterDequeue(handler, BindOn(impl_, &impl::on_outbound_acl_ready)); // ACL (Asynchronous Connection-Less):用于一般数据传输,如文件或音频流。impl_->sco_queue_.GetDownEnd()->RegisterDequeue(handler, BindOn(impl_, &impl::on_outbound_sco_ready)); // SCO (Synchronous Connection-Oriented):用于语音数据(如通话)。impl_->iso_queue_.GetDownEnd()->RegisterDequeue(handler, BindOn(impl_, &impl::on_outbound_iso_ready)); // ISO (Isochronous):用于 LE Audio 新协议的音频流。
-
目的:为三种数据通道注册出队回调(ACL, SCO, ISO)。
-
ACL (Asynchronous Connection-Less):用于一般数据传输,如文件或音频流。
-
SCO (Synchronous Connection-Oriented):用于语音数据(如通话)。
-
ISO (Isochronous):用于 LE Audio 新协议的音频流。
实际场景:
-
ACL:你在车机上播放手机的音乐就是通过 ACL 传输的 A2DP 数据。
-
SCO:你在车里接电话,语音通过 SCO 通道实时传输。
-
ISO:用于未来车机支持 LE Audio 的场景(低延迟高质量音频)。
这里 我们针对 acl 的队列 做介绍, 其他通道类似:
impl_->acl_queue_.GetDownEnd()->RegisterDequeue(handler, BindOn(impl_, &impl::on_outbound_acl_ready));void on_outbound_acl_ready() {auto packet = acl_queue_.GetDownEnd()->TryDequeue(); // 从 acl_queue_ 下行段 队列中,出一个包std::vector<uint8_t> bytes;BitInserter bi(bytes);packet->Serialize(bi); // 包经过 序列化后,调用 hal 层发送函数,发送hal_->sendAclData(bytes); }
-
上面代码的含义是 为 ACL 数据发送队列的“下行端”注册一个出队回调函数,当队列有数据准备好可以发送时,
on_outbound_acl_ready
就会被调用,进而将数据通过 HCI 发送到底层蓝牙控制器。 请看对于 BidiQueue、BidiQueueEnd、Queue介绍 -
hal_->sendAclData(bytes)
// system/gd/hal/hci_hal_android_hidl.ccvoid sendAclData(HciPacket packet) override {// 将我们 发送的内容通过 btsnoop 记录下来btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ACL);if (common::init_flags::btaa_hci_is_enabled()) {btaa_logger_->Capture(packet, SnoopLogger::PacketType::ACL);}bt_hci_->sendAclData(packet); // 这里直接调用 hidl 的接口,直接返送给 hal 进程。}// bt_hci_ 是获取到的 hal 服务
bt_hci_ = IBluetoothHci_1_0::getService(instance);
4. 注册各种 HCI 事件的处理器
在 Start() 函数中有如下代码,
// 车机与手机蓝牙握手过程的事件非常多,这里统一注册处理方式,保持事件驱动的异步架构。RegisterEventHandler(EventCode::COMMAND_COMPLETE, handler->BindOn(impl_, &impl::on_command_complete)); // 处理指令执行结果。RegisterEventHandler(EventCode::COMMAND_STATUS, handler->BindOn(impl_, &impl::on_command_status)); // 处理指令执行结果。RegisterLeMetaEventHandler(handler->BindOn(impl_, &impl::on_le_meta_event)); // 处理低功耗蓝牙相关事件(如连接完成、扫描结果)。RegisterEventHandler(EventCode::DISCONNECTION_COMPLETE, handler->BindOn(this, &HciLayer::on_disconnection_complete)); // 设备断开连接时触发。RegisterEventHandler(EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE,handler->BindOn(this, &HciLayer::on_read_remote_version_complete)); // 读取远端设备版本信息(如芯片厂商、固件版本)// 对一些无需处理的事件直接丢弃。auto drop_packet = handler->BindOn(impl_, &impl::drop);RegisterEventHandler(EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE, drop_packet);RegisterEventHandler(EventCode::MAX_SLOTS_CHANGE, drop_packet);
1. RegisterEventHandler
void HciLayer::RegisterEventHandler(EventCode event, ContextualCallback<void(EventView)> handler) {CallOn(impl_, &impl::register_event, event, handler);
}
void register_event(EventCode event, ContextualCallback<void(EventView)> handler) {event_handlers_[event] = handler;}std::map<EventCode, ContextualCallback<void(EventView)>> event_handlers_;
- event_handlers_ 是一个 map 类型, RegisterEventHandler 目的就是向 这个 map 中, 根据不同的事件类型,注册不同的回调函数。
- 既然有注册的地方,那该如何使用它?
1. 如何使用 event_handlers_
// 在 HciLayer::Start() 方法中,会向 hal 注册这个回调, 当hal 进程有数据上来时,就会回调到 hal_callbacks_ 对象。
hal_callbacks_ = new hal_callbacks(*this);hal->registerIncomingPacketCallback(hal_callbacks_);
// system/gd/hci/hci_layer.cc// 下面是HciLayer::hal_callbacks 的定义
struct HciLayer::hal_callbacks : public hal::HciHalCallbacks {...void hciEventReceived(hal::HciPacket event_bytes) override {auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(event_bytes));EventView event = EventView::Create(packet);module_.CallOn(module_.impl_, &impl::on_hci_event, move(event)); // 这里会触发调用 on_hci_event }...
};
// system/gd/hci/hci_layer.ccvoid on_hci_event(EventView event) {...event_handlers_[event_code].Invoke(event); // 根据 event, 调用不同的 回调
}
- 我们首先会向 hidl 进程中注册 回调。
- 当 hidl 中上来数据时,会去调用 协议栈中的回调。 进而根据 不同的事件,调用不同的处理函数。
2. 都注册了那些事件和回调
EventCode::COMMAND_COMPLETE impl::on_command_completeEventCode::COMMAND_STATUS impl::on_command_statusEventCode::DISCONNECTION_COMPLETE HciLayer::on_disconnection_completeEventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE HciLayer::on_read_remote_version_completeEventCode::PAGE_SCAN_REPETITION_MODE_CHANGE impl::dropEventCode::MAX_SLOTS_CHANGE impl::dropEventCode::LE_META_EVENT impl::on_le_meta_event
5. 向 hal 模块注册 回调
hal->registerIncomingPacketCallback(hal_callbacks_);
当 hal 层收到 数据时,就会触发对应的回调。
// system/gd/hci/hci_layer.ccstruct HciLayer::hal_callbacks : public hal::HciHalCallbacks {hal_callbacks(HciLayer& module) : module_(module) {}void hciEventReceived(hal::HciPacket event_bytes) override {...}void aclDataReceived(hal::HciPacket data_bytes) override {}void scoDataReceived(hal::HciPacket data_bytes) override {...}void isoDataReceived(hal::HciPacket data_bytes) override {...}HciLayer& module_;
};
- 上面 hciEventReceived 已经在前面分析过了, 暂不赘述
1. aclDataReceived
void aclDataReceived(hal::HciPacket data_bytes) override {auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(move(data_bytes)));auto acl = std::make_unique<AclView>(AclView::Create(packet));module_.impl_->incoming_acl_buffer_.Enqueue(move(acl), module_.GetHandler());}
请先阅读 这篇,即可理解 上述代码的含义BidiQueue、BidiQueueEnd、Queue介绍
2. scoDataReceived
void scoDataReceived(hal::HciPacket data_bytes) override {auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(move(data_bytes)));auto sco = std::make_unique<ScoView>(ScoView::Create(packet));module_.impl_->incoming_sco_buffer_.Enqueue(move(sco), module_.GetHandler());}
和 aclDataReceived 类似,不再赘述
3.isoDataReceived
void isoDataReceived(hal::HciPacket data_bytes) override {auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(move(data_bytes)));auto iso = std::make_unique<IsoView>(IsoView::Create(packet));module_.impl_->incoming_iso_buffer_.Enqueue(move(iso), module_.GetHandler());}
和 aclDataReceived 类似,不再赘述
6. 发送 reset 命令
有时控制器处于“残留状态”,例如上次未正常退出或发生断电重启。Reset 可确保蓝牙控制器进入一个可预测、干净的初始状态。
比如车机冷启动过程中发送 Reset,可以避免某些手机连接不上或蓝牙设备状态异常。
std::promise<void> reset_ready_promise;auto reset_ready_future = reset_ready_promise.get_future();EnqueueCommand(ResetBuilder::Create(), handler->BindOnce(&fail_if_reset_complete_not_success, std::move(reset_ready_promise)));reset_ready_future.wait();
1. EnqueueCommand
- 我们重点看一下 EnqueueCommand 函数
- 外部其他模块,也是通过 调用 EnqueueCommand 来发送命令的。
void HciLayer::EnqueueCommand(unique_ptr<CommandBuilder> command, ContextualOnceCallback<void(CommandCompleteView)> on_complete) {CallOn(impl_, &impl::enqueue_command<CommandCompleteView>, move(command), move(on_complete));
}void HciLayer::EnqueueCommand(unique_ptr<CommandBuilder> command, ContextualOnceCallback<void(CommandStatusView)> on_status) {CallOn(impl_, &impl::enqueue_command<CommandStatusView>, move(command), move(on_status));
}
EnqueueCommand 函数有两个实现, 那这里 应该调用那个?如何区分。 关键在 EnqueueCommand 函数的 第二个参数的签名。
EnqueueCommand(ResetBuilder::Create(), handler->BindOnce(&fail_if_reset_complete_not_success, std::move(reset_ready_promise)));
- handler->BindOnce(&fail_if_reset_complete_not_success, std::move(reset_ready_promise))
- fail_if_reset_complete_not_success
static void fail_if_reset_complete_not_success(std::promise<void> reset_ready_promise, CommandCompleteView complete) {auto reset_complete = ResetCompleteView::Create(complete);ASSERT(reset_complete.IsValid());ASSERT(reset_complete.GetStatus() == ErrorCode::SUCCESS);reset_ready_promise.set_value();
}
- fail_if_reset_complete_not_success 函数和 CommandCompleteView 相关。
- 所以这里调用的应该是
void HciLayer::EnqueueCommand(unique_ptr<CommandBuilder> command, ContextualOnceCallback<void(CommandCompleteView)> on_complete) {CallOn(impl_, &impl::enqueue_command<CommandCompleteView>, move(command), move(on_complete));
}
还有一种 办法可以区分:
你可以从 ResetBuilder::Create() 构造出来的命令对应的是哪类 HCI 命令来判断。
- 如果这个 HCI 命令会返回 Command Complete 事件,那就会调用第一个版本。
- 如果它只返回 Command Status,那就是第二个版本。
1. enqueue_command
template <typename TResponse>void enqueue_command(unique_ptr<CommandBuilder> command, ContextualOnceCallback<void(TResponse)> on_response) {command_queue_.emplace_back(move(command), move(on_response));send_next_command();}
- 将 命令 和 回调 加入到了 command_queue_ 中
- 调用 send_next_command 发送出去
2. CommandQueueEntry
如何进一步理解如下代码的含义:
command_queue_.emplace_back(move(command), move(on_response));
list::emplace_back
是 C++11 引入的一个 STL 容器成员函数,它用于在 std::list
的 尾部 直接构造一个元素,比 push_back
更高效,特别适用于构造开销大的对象。
std::list<CommandQueueEntry> command_queue_;
- 而 command_queue_ 是一个 CommandQueueEntry 类似的 list.
- 简单点说就是 创建了一个 CommandQueueEntry 对象。加入 command_queue_ 队列中。
传入的参数是:
- ResetBuilder::Create() 赋值给 CommandQueueEntry::command
- handler->BindOnce(&fail_if_reset_complete_not_success, std::move(reset_ready_promise)) 赋值给 CommandQueueEntry::on_complete
class CommandQueueEntry {public:CommandQueueEntry(unique_ptr<CommandBuilder> command_packet, ContextualOnceCallback<void(CommandCompleteView)> on_complete_function): command(move(command_packet)), waiting_for_status_(false), on_complete(move(on_complete_function)) {}CommandQueueEntry(unique_ptr<CommandBuilder> command_packet, ContextualOnceCallback<void(CommandStatusView)> on_status_function): command(move(command_packet)), waiting_for_status_(true), on_status(move(on_status_function)) {}unique_ptr<CommandBuilder> command;unique_ptr<CommandView> command_view;bool waiting_for_status_;ContextualOnceCallback<void(CommandStatusView)> on_status;ContextualOnceCallback<void(CommandCompleteView)> on_complete;template <typename TView>ContextualOnceCallback<void(TView)>* GetCallback() {return nullptr;}template <>ContextualOnceCallback<void(CommandStatusView)>* GetCallback<CommandStatusView>() {return &on_status;}template <>ContextualOnceCallback<void(CommandCompleteView)>* GetCallback<CommandCompleteView>() {return &on_complete;}
};
从上面就可以看到, fail_if_reset_complete_not_success 函数是通过 调用 CommandQueueEntry::GetCallback<CommandCompleteView>() 而触发的。
学习这个类,主要就是 要看清楚 fail_if_reset_complete_not_success 是如何被触发的。
3.send_next_command
我们继续分析 发送 函数 send_next_command
void send_next_command() {/*command_credits_ 是一个“令牌”机制,用来控制当前是否可以发起新命令(通常 HCI 层只允许同时处理一个命令).如果没有剩余 credit,则直接返回,不发送命令。*/if (command_credits_ == 0) {return;}// 如果已经有一个命令在等待 Command Complete 或 Command Status,则不应继续发送。// waiting_command_ 表示当前挂起命令的 OpCodeif (waiting_command_ != OpCode::NONE) {return;}// 如果没有任何命令排队,也无需继续执行,直接返回if (command_queue_.size() == 0) {return;}// 创建一个共享的字节缓冲区,承载序列化后的命令数据// 使用 shared_ptr 可能是因为这个缓冲区会跨多个异步处理生命周期std::shared_ptr<std::vector<uint8_t>> bytes = std::make_shared<std::vector<uint8_t>>();// BitInserter 是一个工具类,负责将 HCI 命令按比特插入到 bytes 缓冲区中BitInserter bi(*bytes);// 从队首取出一个命令对象并序列化到 bytes 缓冲区中// command 是一个实现了 Serialize() 的对象,代表某种 HCI 命令(如 Reset, Read Buffer Size, 等)command_queue_.front().command->Serialize(bi); hal_->sendHciCommand(*bytes); // 通过底层的 HAL 层发送 HCI 命令数据, 实际会通过 UART/USB/SDIO 接口发到蓝牙芯片// 把发送出去的字节缓冲区封装为一个 CommandView 对象, 这个对象可以用来获取 OpCode、参数字段等信息auto cmd_view = CommandView::Create(PacketView<kLittleEndian>(bytes));ASSERT(cmd_view.IsValid());OpCode op_code = cmd_view.GetOpCode(); // 获取该命令对应的 OpCode(操作码),用于后续识别是哪条命令// 将刚构造好的 CommandView 保存到队首元素中,方便后续处理 CommandComplete 时查找上下文command_queue_.front().command_view = std::make_unique<CommandView>(std::move(cmd_view));// 这些是调试日志或统计用途的// 记录此命令被发送的行为与初始状态(如 pairing 命令的状态)log_link_layer_connection_command(command_queue_.front().command_view);log_classic_pairing_command_status(command_queue_.front().command_view, ErrorCode::STATUS_UNKNOWN);// 设置当前等待响应的命令为此 op_code,防止并发发命令waiting_command_ = op_code;// 消费掉 credit// 表示当前只能发一个命令,在收到 CommandComplete 前不允许发下一个command_credits_ = 0; // Only allow one outstanding command// 设置 HCI 命令超时定时器if (hci_timeout_alarm_ != nullptr) {// 定时器超时时会调用 on_hci_timeout(),说明命令迟迟没有返回(可能设备失联)hci_timeout_alarm_->Schedule(BindOnce(&impl::on_hci_timeout, common::Unretained(this), op_code), kHciTimeoutMs);} else {LOG_WARN("%s sent without an hci-timeout timer", OpCodeText(op_code).c_str());}}
此时我们已经将 reset cmd 发送给了 controler.
1. 回复成功
假设我们将 reset cmd 发送给了 , controller. 并且成功处理, 上报一个完成事件。
此时就会回调到, 之前我们注册好的 on_command_complete 函数中。
RegisterEventHandler(EventCode::COMMAND_COMPLETE, handler->BindOn(impl_, &impl::on_command_complete));
// 接收到 Command Complete 事件后调用此函数。void on_command_complete(EventView event) {// 内部调用了模板函数 handle_command_response,并传入 CommandCompleteView 类型作为视图解析器,以及 "complete" 日志标识符handle_command_response<CommandCompleteView>(event, "complete");}// 这是模板函数,既用于处理 CommandComplete,也可用于 CommandStatustemplate <typename TResponse>void handle_command_response(EventView event, std::string logging_id) {// 调用对应类型(如 CommandCompleteView)的 Create() 静态方法,基于原始事件数据构建响应视图对象TResponse response_view = TResponse::Create(event);ASSERT(response_view.IsValid());// 获取 Controller 返回的“命令信用额度”,表明 Controller 目前还能接收多少个新命令// 通常 Bluetooth Controller 只允许一个命令并发(也就是 credit=1),此值会用于决定是否可以继续发下一个命令command_credits_ = response_view.GetNumHciCommandPackets();// 从响应中提取操作码(OpCode),用来判断这个响应是对应哪个命令OpCode op_code = response_view.GetCommandOpCode();if (op_code == OpCode::NONE) {// 如果没有合法的 OpCode,说明响应无效(可能是非命令事件),直接尝试发送下一个命令// 通常不会发生,可能用于容错处理send_next_command();return;}bool is_status = logging_id == "status"; // 根据传入参数判断当前处理的是 status 事件还是 complete 事件// 如果没有命令正在等待响应(但 Controller 发回了事件),说明程序逻辑错误,直接崩溃退出(DEBUG 模式),表示出现“不该收到”的响应ASSERT_LOG(!command_queue_.empty(), "Unexpected %s event with OpCode 0x%02hx (%s)", logging_id.c_str(), op_code,OpCodeText(op_code).c_str());// 如果正在等待 CONTROLLER_DEBUG_INFO 命令的响应,但收到的是其它 OpCode,说明前一个命令已经超时, 打日志并丢弃此次响应if (waiting_command_ == OpCode::CONTROLLER_DEBUG_INFO && op_code != OpCode::CONTROLLER_DEBUG_INFO) {LOG_ERROR("Discarding event that came after timeout 0x%02hx (%s)", op_code, OpCodeText(op_code).c_str());return;}// 确保我们收到的响应的 OpCode 与当前挂起的命令一致ASSERT_LOG(waiting_command_ == op_code, "Waiting for 0x%02hx (%s), got 0x%02hx (%s)", waiting_command_,OpCodeText(waiting_command_).c_str(), op_code, OpCodeText(op_code).c_str());// 判断是否是 vendor-specific 命令 + 处理兼容性bool is_vendor_specific = static_cast<int>(op_code) & (0x3f << 10);CommandStatusView status_view = CommandStatusView::Create(event);// 处理某些厂商命令特殊场景 —— 例如明明期望的是 CommandComplete,但 Controller 返回了 CommandStatus 且为 UNKNOWN_HCI_COMMAND 错误if (is_vendor_specific && (is_status && !command_queue_.front().waiting_for_status_) &&(status_view.IsValid() && status_view.GetStatus() == ErrorCode::UNKNOWN_HCI_COMMAND)) {/*这个复杂条件的意思是:收到的是 CommandStatus;当前命令期待的是 CommandComplete(而不是 Status);并且这个命令是厂商命令;并且响应表示“不支持该命令”。*/// 这种情况下,系统构造一个“空”的 CommandCompleteView 对象,模拟后续 CommandComplete 的回调CommandCompleteView command_complete_view = CommandCompleteView::Create(EventView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>(std::vector<uint8_t>()))));// 这里调用 CommandQueueEntry::GetCallback()->Invoke(), 触发调用回调, 例如调用 fail_if_reset_complete_not_successcommand_queue_.front().GetCallback<CommandCompleteView>()->Invoke(move(command_complete_view));} else {// 正常回调处理路径, 如果不是特殊兼容路径,就会执行这段逻辑:// 先确认事件类型是否与期望匹配(等待 status 结果就应该收到 status);ASSERT_LOG(command_queue_.front().waiting_for_status_ == is_status,"0x%02hx (%s) was not expecting %s event",op_code,OpCodeText(op_code).c_str(),logging_id.c_str());// 然后调用之前注册的 callback,这里调用 CommandQueueEntry::GetCallback()->Invoke(), 触发调用回调, 例如调用 fail_if_reset_complete_not_success// 传入解析好的 response_viewcommand_queue_.front().GetCallback<TResponse>()->Invoke(move(response_view));}// 响应处理完毕,移除命令队首元素command_queue_.pop_front();// 清空当前等待命令状态,表示可以继续发下一个命令waiting_command_ = OpCode::NONE;if (hci_timeout_alarm_ != nullptr) {// 命令已经响应,不需要再等超时, 取消超时定时hci_timeout_alarm_->Cancel();send_next_command(); // 启动 send_next_command(),继续处理队列中下一个命令}}
2. 超时处理
假如 我们发送的命令,controller 没有响应, 此时就会触发超时。
- 参数 op_code:表示哪个 HCI 命令超时了
- 这是一个 错误处理路径,系统会执行一系列恢复操作(清空队列、尝试 Reset、计划 Abort 等)
void on_hci_timeout(OpCode op_code) {// 打印当前 Stopwatch 记录的日志,方便定位哪个命令耗时太久// StopWatch 一般用于测量命令执行耗时,有助于调试common::StopWatch::DumpStopWatchLog();// 打印错误日志,指明哪个命令(OpCode)超时。LOG_ERROR("Timed out waiting for 0x%02hx (%s)", op_code, OpCodeText(op_code).c_str());// TODO: LogMetricHciTimeoutEvent(static_cast<uint32_t>(op_code));// 打日志,提示即将清空命令队列LOG_ERROR("Flushing %zd waiting commands", command_queue_.size());// Clear any waiting commands (there is an abort coming anyway)command_queue_.clear(); // 清空命令队列(因为这些命令都已经没用了);command_credits_ = 1; // 重置 controller 的命令 credit(假定为 1,防止系统不再发命令)waiting_command_ = OpCode::NONE; // 清除 waiting_command_,代表当前没有挂起的命令了// 构造同步机制,用于后续执行 Reset 命令,并等待其完成std::promise<void> reset_ready_promise;auto reset_ready_future = reset_ready_promise.get_future();// 构建一个 ControllerDebugInfo 命令(此处当作重置使用)// 注册一个回调函数 fail_if_reset_complete_not_success, 回调函数内部会在命令响应时调用 reset_ready_promise.set_value(),通知主线程继续enqueue_command(ControllerDebugInfoBuilder::Create(), module_.GetHandler()->BindOnce(&fail_if_reset_complete_not_success,std::move(reset_ready_promise)));// 主线程等待 Reset 命令执行完成, 如果 controller 死机或无法响应,这里可能会卡住(但通常有超时机制)reset_ready_future.wait();// Don't time out for this one;if (hci_timeout_alarm_ != nullptr) {// 如果之前设置了超时定时器,取消并释放资源, 避免出现“多个命令并发计时”的逻辑错误hci_timeout_alarm_->Cancel();delete hci_timeout_alarm_;hci_timeout_alarm_ = nullptr;}if (hci_abort_alarm_ == nullptr) {// 设置一个新的 abort 计时器,用于处理 Reset 后依然无法恢复的场景hci_abort_alarm_ = new Alarm(module_.GetHandler());// abort_after_time_out() 是终极恢复逻辑,可能会导致整个 Bluetooth Stack 重启hci_abort_alarm_->Schedule(BindOnce(&abort_after_time_out, op_code), kHciTimeoutRestartMs);} else {// 如果已经存在 abort 计时器,记录警告日志LOG_WARN("Unable to schedul abort timer");}}
static void abort_after_time_out(OpCode op_code) {bluetooth::os::LogMetricHciTimeoutEvent(static_cast<uint32_t>(op_code));ASSERT_LOG(false, "Done waiting for debug information after HCI timeout (%s)", OpCodeText(op_code).c_str());
}
- 一旦进入 abort_after_time_out , 协议栈直接 crash. 退出
5.将module 实体加入到 started_modules_
- 将module 实体加入到 started_modules_
- started_modules_[module] = instance;