【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 都要执行下面几步:

  1. 创建module 实体

    • Module* instance = module->ctor_();
  2. 将 当前 module 实体和 gd_stack_thread 线程绑定

    • set_registry_and_handler(instance, thread);
  3. 启动当前模块所依赖的所有子模块。

    • instance->ListDependencies(&instance->dependencies_);
    • Start(&instance->dependencies_, thread);
  4. 最后调用自己的 Start() 函数

    • instance->Start();
  5. 将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 实体

  1. 创建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 线程绑定

  1. 将 当前 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.启动当前模块所依赖的所有子模块

  1. 启动当前模块所依赖的所有子模块。
    • 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() 函数

  1. 最后调用自己的 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 对应的 handler
  impl_->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.cc

Module* 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 对应的 handler


  impl_->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.cc

  void 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.cc

void on_hci_event(EventView event) {
	...
	event_handlers_[event_code].Invoke(event); // 根据 event, 调用不同的 回调
}




  1. 我们首先会向 hidl 进程中注册 回调。
  2. 当 hidl 中上来数据时,会去调用 协议栈中的回调。 进而根据 不同的事件,调用不同的处理函数。
2. 都注册了那些事件和回调
EventCode::COMMAND_COMPLETE                                  impl::on_command_complete

EventCode::COMMAND_STATUS                                    impl::on_command_status

EventCode::DISCONNECTION_COMPLETE                            HciLayer::on_disconnection_complete

EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE          HciLayer::on_read_remote_version_complete

EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE                  impl::drop

EventCode::MAX_SLOTS_CHANGE                                  impl::drop


EventCode::LE_META_EVENT                                     impl::on_le_meta_event

5. 向 hal 模块注册 回调


hal->registerIncomingPacketCallback(hal_callbacks_);

当 hal 层收到 数据时,就会触发对应的回调。

// system/gd/hci/hci_layer.cc

struct 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_ 表示当前挂起命令的 OpCode
    if (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,也可用于 CommandStatus
  template <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_success
      command_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_view
      command_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_

  1. 将module 实体加入到 started_modules_
    • started_modules_[module] = instance;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值