【android bluetooth 框架分析 02】【Module详解 12】【 BidiQueue、BidiQueueEnd、Queue介绍】

1. BidiQueue 和 BidiQueueEnd

蓝牙协议栈里面有很多 BidiQueue ,本节就专门来梳理这块内容。

2. BidiQueue 介绍

BidiQueue,是 Host 与 Controller 层通信的中枢之一, acl_queue_sco_queue_iso_queue_ 都是 BidiQueue 类型。让我们一起看一下这个结构。

c 复制代码
// system/gd/hci/hci_layer.cc
struct HciLayer::impl {

  // Acl packets
  BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */};
  os::EnqueueBuffer<AclView> incoming_acl_buffer_{acl_queue_.GetDownEnd()};

  // SCO packets
  BidiQueue<ScoView, ScoBuilder> sco_queue_{3 /* TODO: Set queue depth */};
  os::EnqueueBuffer<ScoView> incoming_sco_buffer_{sco_queue_.GetDownEnd()};

  // ISO packets
  BidiQueue<IsoView, IsoBuilder> iso_queue_{3 /* TODO: Set queue depth */};
  os::EnqueueBuffer<IsoView> incoming_iso_buffer_{iso_queue_.GetDownEnd()};

}
c 复制代码
// system/gd/common/bidi_queue.h

template <typename TUP, typename TDOWN>
class BidiQueue {
 public:
  explicit BidiQueue(size_t capacity)
      : up_queue_(capacity),
        down_queue_(capacity),
        up_end_(&down_queue_, &up_queue_),
        down_end_(&up_queue_, &down_queue_) {}

  BidiQueueEnd<TDOWN, TUP>* GetUpEnd() {
    return &up_end_;
  }

  BidiQueueEnd<TUP, TDOWN>* GetDownEnd() {
    return &down_end_;
  }

 private:
  ::bluetooth::os::Queue<TUP> up_queue_;
  ::bluetooth::os::Queue<TDOWN> down_queue_;
  BidiQueueEnd<TDOWN, TUP> up_end_;
  BidiQueueEnd<TUP, TDOWN> down_end_;
};

BidiQueue 是一个"双向队列",允许:

  • 一端用于 接收下行数据(发往控制器)
  • 另一端用于 接收上行数据(来自控制器)

这个类是 蓝牙 Host 与 Controller 之间异步通信的基础设施,为不同方向的数据流提供独立的缓冲和控制。

1. 模版参数解释

c 复制代码
template <typename TUP, typename TDOWN>
  • TUP:上行数据类型(从 Controller -> Host)
  • TDOWN:下行数据类型(从 Host -> Controller)

举例:

c 复制代码
BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */};
  • acl_queue_ 的上行 数据包类型为 AclView
  • acl_queue_ 的下行 数据包类型为 AclBuilder

2. 构造函数

c 复制代码
explicit BidiQueue(size_t capacity)
      : up_queue_(capacity),
        down_queue_(capacity),
        up_end_(&down_queue_, &up_queue_),
        down_end_(&up_queue_, &down_queue_) {}
c 复制代码
  ::bluetooth::os::Queue<TUP> up_queue_;
  ::bluetooth::os::Queue<TDOWN> down_queue_;
  • 他们的类型都是 bluetooth::os::Queue
  • up_queue_ : 初始化 上行数据缓存队列, 队列最大 可以容纳 capacity 包数据, 这里是3
  • down_queue_ : 初始化 下行数据缓存队列, 队列最大 可以容纳 capacity 包数据, 这里是3
c 复制代码
  BidiQueueEnd<TDOWN, TUP> up_end_;
  BidiQueueEnd<TUP, TDOWN> down_end_;


up_end_(&down_queue_, &up_queue_);
down_end_(&up_queue_, &down_queue_);

1. 例如 acl_queue_

举个例子,我们用 acl_queue_ 来解释。

假设 ACL 数据的队列是:

c 复制代码
BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */};
  • acl_queue_ 的上行 数据包类型为 AclView
  • acl_queue_ 的下行 数据包类型为 AclBuilder
c 复制代码
explicit BidiQueue(size_t capacity)
      : up_queue_(capacity),
        down_queue_(capacity),
        up_end_(&down_queue_, &up_queue_),
        down_end_(&up_queue_, &down_queue_) {}
  • up_queue_ : 初始化 上行数据缓存队列, 队列最大 可以容纳 capacity 包数据, 这里是3
  • down_queue_ : 初始化 下行数据缓存队列, 队列最大 可以容纳 capacity 包数据, 这里是3

这个 up_end 是谁用的?

  • 答:协议栈中,偏上层使用例如 l2cap 侧使用
  • tx_ = &down_queue_:l2cap 侧 发送数据, 需要通过up_end 的 tx 放入down_queue_ 中, 此时 hcihal 侧的 down_end端,就会从 rx ,也就是down_queue_ 中读出数据, 然后通过 hal 发送给 controler.
  • rx_ = &up_queue_: hal 侧过来的数据 会通过down_end 端的 tx 放入 up_queue_ 中, up_end 只需要从 rx up_queue_ 里 去读,就可以拿到 hal 侧数据

这个 down_end 是谁用的?

  • 答: 协议栈中, 偏下层使用, hcihal 侧使用
  • tx_ = &up_queue_: hal 侧过来的数据 会通过down_end 端的 tx 放入 up_queue_ 中, up_end 只需要从 rx up_queue_ 里 去读,就可以拿到 hal 侧数据
  • rx_ = &down_queue_:l2cap 侧 发送数据, 需要通过up_end 的 tx 放入down_queue_ 中, 此时 hcihal 侧的 down_end端,就会从 rx ,也就是down_queue_ 中读出数据, 然后通过 hal 发送给 controler.

3. 获取上下端

c 复制代码
  BidiQueueEnd<TDOWN, TUP>* GetUpEnd() {
    return &up_end_;
  }

  BidiQueueEnd<TUP, TDOWN>* GetDownEnd() {
    return &down_end_;
  }

4. 小结

项目 描述
BidiQueue<TUP, TDOWN> 支持双向异步通信的队列
up_queue_ / down_queue_ 分别对应上行/下行缓存
up_end_ / down_end_ 用于向外暴露操作接口
RegisterDequeue() 异步消费机制的核心
用法示例 ACL 音频数据、事件通知、HCI Command 等

3. BidiQueueEnd 介绍

这个类是一个 方向接口类 :负责一端的收发。

c 复制代码
// system/gd/common/bidi_queue.h

template <typename TENQUEUE, typename TDEQUEUE>
class BidiQueueEnd : public ::bluetooth::os::IQueueEnqueue<TENQUEUE>, public ::bluetooth::os::IQueueDequeue<TDEQUEUE> {
 public:
  using EnqueueCallback = Callback<std::unique_ptr<TENQUEUE>()>;
  using DequeueCallback = Callback<void()>;

  BidiQueueEnd(::bluetooth::os::IQueueEnqueue<TENQUEUE>* tx, ::bluetooth::os::IQueueDequeue<TDEQUEUE>* rx)
      : tx_(tx), rx_(rx) {}

  void RegisterEnqueue(::bluetooth::os::Handler* handler, EnqueueCallback callback) override {
    tx_->RegisterEnqueue(handler, callback);
  }

  void UnregisterEnqueue() override {
    tx_->UnregisterEnqueue();
  }

  void RegisterDequeue(::bluetooth::os::Handler* handler, DequeueCallback callback) override {
    rx_->RegisterDequeue(handler, callback);
  }

  void UnregisterDequeue() override {
    rx_->UnregisterDequeue();
  }

  std::unique_ptr<TDEQUEUE> TryDequeue() override {
    return rx_->TryDequeue();
  }

 private:
  ::bluetooth::os::IQueueEnqueue<TENQUEUE>* tx_;
  ::bluetooth::os::IQueueDequeue<TDEQUEUE>* rx_;
};

1. 模版参数讲解

通俗理解 BidiQueueEnd<TENQUEUE, TDEQUEUE>

这个类是一个 方向接口类 :负责一端 的收发。

它继承了两个接口:

public IQueueEnqueue<TENQUEUE>, public IQueueDequeue<TDEQUEUE>

也就是说,这个类:

  • 允许你往某个队列"写"(enqueue)数据(用 TENQUEUE 类型)

  • 也允许你从某个队列"读"(dequeue)数据(用 TDEQUEUE 类型)

但注意:不是往同一个队列读写!它是两个方向!

你可以把它理解为一个"单端口",连接两个方向的队列:

2. tx_rx_

c 复制代码
  ::bluetooth::os::IQueueEnqueue<TENQUEUE>* tx_;
  ::bluetooth::os::IQueueDequeue<TDEQUEUE>* rx_;


  BidiQueueEnd(::bluetooth::os::IQueueEnqueue<TENQUEUE>* tx, ::bluetooth::os::IQueueDequeue<TDEQUEUE>* rx)
      : tx_(tx), rx_(rx) {}
  • tx_: BidiQueueEnd 要发的东西,会写入 tx 对应的 队列中

  • rx_: BidiQueueEnd 要接收的东西,会从 rx 对应的 队列中 去取

3. 如何 将数据加入到 tx

在 BidiQueueEnd 类中, 很奇怪, 只有如下几个函数, 只是注册 入队回调、 出队回调、 还有尝试出队。 没有看到, 具体入队 是如何入队的, 也就是如何 加入到 tx 对应的队列中, 没有专门的函数, 那我们是如何 操作的呢?

  • RegisterEnqueue
  • UnregisterEnqueue
  • RegisterDequeue
  • UnregisterDequeue
  • TryDequeue

其实 BidiQueueEnd 并不主动调用 Enqueue(),而是提供了 RegisterEnqueue() 给"生产者"注册数据生成器。然后由 Queue 本身决定何时调用回调来触发数据入队。

也就是说:

  • tx_ 是一个实现了 IQueueEnqueue<T> 接口的实际队列(如 Queue<T>
  • RegisterEnqueue(handler, callback) 注册了一个异步回调
  • 队列内部在"有空间时"会调用这个回调,向队列中拉取(enqueue)数据

这是一种 "拉"模式入队:不是你自己塞进去,而是注册一个"我要数据的时候你给我",由队列来决定何时触发。

c 复制代码
// system/gd/common/bidi_queue.h
  void RegisterEnqueue(::bluetooth::os::Handler* handler, EnqueueCallback callback) override {
    tx_->RegisterEnqueue(handler, callback); // 这里调用了 bluetooth::os::Queue 类中 RegisterEnqueue 函数
  }

具体细节 请看 bluetooth::os::Queue 类中 RegisterEnqueue 函数的解析。

4. 如何从 rx 上获取数据

其实 BidiQueueEnd 并不主动调用 dequeue(),而是提供了 RegisterDequeue() 给"消费者"注册数据消费回调。然后由 Queue 本身决定何时调用回调来触发数据出队。

c 复制代码
// system/gd/common/bidi_queue.h
  void RegisterDequeue(::bluetooth::os::Handler* handler, DequeueCallback callback) override {
    rx_->RegisterDequeue(handler, callback);
  }

  std::unique_ptr<TDEQUEUE> TryDequeue() override {
    return rx_->TryDequeue();
  }
  • 从 rx 上 读数据, 这里直接调用了 bluetooth::os::Queue::RegisterDequeue 和 TryDequeue 函数, 具体见 bluetooth::os::Queue 中的分析

这是一种 "拉"模式出队:不是你自己主动去出队数据包,而是注册一个"消费回调",由队列来决定何时让你消费,何时让你出队。

4. Queue 介绍

c 复制代码
  ::bluetooth::os::Queue<TUP> up_queue_;
  ::bluetooth::os::Queue<TDOWN> down_queue_;
  • 我们的 up_queue_ 和 down_queue_ 都是 Queue 类型

本节就来探索一下它的定义和实现。看明白他,就可以知道 BidiQueueEnd 中的 tx 和 rx 是如何 写数据和读数据的。

1. 定义

c 复制代码
// system/gd/os/queue.h
template <typename T>
class Queue : public IQueueEnqueue<T>, public IQueueDequeue<T> {
 public:
  // A function moving data from enqueue end buffer to queue, it will be continually be invoked until queue
  // is full. Enqueue end should make sure buffer isn't empty and UnregisterEnqueue when buffer become empty.
  using EnqueueCallback = common::Callback<std::unique_ptr<T>()>;
  // A function moving data form queue to dequeue end buffer, it will be continually be invoked until queue
  // is empty. TryDequeue should be use in this function to get data from queue.
  using DequeueCallback = common::Callback<void()>;
  // Create a queue with |capacity| is the maximum number of messages a queue can contain
  explicit Queue(size_t capacity);
  ~Queue();
  // Register |callback| that will be called on |handler| when the queue is able to enqueue one piece of data.
  // This will cause a crash if handler or callback has already been registered before.
  void RegisterEnqueue(Handler* handler, EnqueueCallback callback) override;
  // Unregister current EnqueueCallback from this queue, this will cause a crash if not registered yet.
  void UnregisterEnqueue() override;
  // Register |callback| that will be called on |handler| when the queue has at least one piece of data ready
  // for dequeue. This will cause a crash if handler or callback has already been registered before.
  void RegisterDequeue(Handler* handler, DequeueCallback callback) override;
  // Unregister current DequeueCallback from this queue, this will cause a crash if not registered yet.
  void UnregisterDequeue() override;

  // Try to dequeue an item from this queue. Return nullptr when there is nothing in the queue.
  std::unique_ptr<T> TryDequeue() override;

 private:
  void EnqueueCallbackInternal(EnqueueCallback callback);
  // An internal queue that holds at most |capacity| pieces of data
  std::queue<std::unique_ptr<T>> queue_;
  // A mutex that guards data in this queue
  std::mutex mutex_;

  class QueueEndpoint {
   public:
#ifdef OS_LINUX_GENERIC
    explicit QueueEndpoint(unsigned int initial_value)
        : reactive_semaphore_(initial_value), handler_(nullptr), reactable_(nullptr) {}
    ReactiveSemaphore reactive_semaphore_;
#endif
    Handler* handler_;
    Reactor::Reactable* reactable_;
  };

  QueueEndpoint enqueue_;
  QueueEndpoint dequeue_;
};
  • 他的实现部分在 system/gd/os/linux_generic/queue.tpp 中

2. 构建和析构

c 复制代码
template <typename T>
Queue<T>::Queue(size_t capacity) : enqueue_(capacity), dequeue_(0){};

template <typename T>
Queue<T>::~Queue() {
  ASSERT_LOG(enqueue_.handler_ == nullptr, "Enqueue is not unregistered");
  ASSERT_LOG(dequeue_.handler_ == nullptr, "Dequeue is not unregistered");
};
  • 构建和析构都比较简单,这里主要看一下 capacity , 我们之前在创建 Queue 时,这里传入的是 3
c 复制代码
  class QueueEndpoint {
   public:
#ifdef OS_LINUX_GENERIC
    explicit QueueEndpoint(unsigned int initial_value) // 这里传入的 3 其实是为了初始化信号量的
        : reactive_semaphore_(initial_value), handler_(nullptr), reactable_(nullptr) {}
    ReactiveSemaphore reactive_semaphore_;
#endif
    Handler* handler_;
    Reactor::Reactable* reactable_;
  };

  QueueEndpoint enqueue_;
  QueueEndpoint dequeue_;
};

3. RegisterEnqueue

BidiQueueEnd 在向

c 复制代码
template <typename T>
void Queue<T>::RegisterEnqueue(Handler* handler, EnqueueCallback callback) {
  std::lock_guard<std::mutex> lock(mutex_);
  ASSERT(enqueue_.handler_ == nullptr);
  ASSERT(enqueue_.reactable_ == nullptr);
  enqueue_.handler_ = handler;



  // 重点是这里 
  enqueue_.reactable_ = enqueue_.handler_->thread_->GetReactor()->Register(
      enqueue_.reactive_semaphore_.GetFd(),
      base::Bind(&Queue<T>::EnqueueCallbackInternal, base::Unretained(this), std::move(callback)),
      base::Closure());
}

这段干了三件事:

  • enqueue_.reactive_semaphore_.GetFd(): 获取 enqueue_ (入队) 的信号量文件描述符(fd), 是否大于3
  • 使用该 fd 向 Reactor 注册监听(类似 epoll 注册事件)
  • 一旦 fd 可写(信号量触发),就调用 EnqueueCallbackInternal

换句话说:RegisterEnqueue() 实际上是

  • "注册一个写入触发回调"
  • "在某个线程的事件循环(Reactor)上监听是否该执行回调"

4. EnqueueCallbackInternal

当 线程满足 信号量条件后,开始回调 EnqueueCallbackInternal 函数时:

c 复制代码
template <typename T>
void Queue<T>::EnqueueCallbackInternal(EnqueueCallback callback) {
  std::unique_ptr<T> data = callback.Run(); // 调用我们之前  调用tx->RegisterEnqueue 时传入的函数,回调返回时, 会返回一个包 
  ASSERT(data != nullptr);
  std::lock_guard<std::mutex> lock(mutex_);
  enqueue_.reactive_semaphore_.Decrease(); // 入对的(tx)   信号量 -1
  queue_.push(std::move(data)); // 将这个包 加入到 队列中。  这就是入队。
  dequeue_.reactive_semaphore_.Increase(); // 出对的(rx) 信号量 +1 
}
  • 这里就是真正 回调 callback 向 tx 对应的 队列中 写入数据的地方。
  • 这里采用异步的方式向 对列中加入数据。 如果 入队的 信号量 > 0, 在调用 RegisterEnqueue 时,会立马 向队列中 dequeue_ 加入包, 如何信号量 < 0 那么就会等等 >0 , 在写入队列。

5. RegisterDequeue

c 复制代码
template <typename T>
void Queue<T>::RegisterDequeue(Handler* handler, DequeueCallback callback) {
  std::lock_guard<std::mutex> lock(mutex_);
  ASSERT(dequeue_.handler_ == nullptr);
  ASSERT(dequeue_.reactable_ == nullptr);
  dequeue_.handler_ = handler;



   
  dequeue_.reactable_ = dequeue_.handler_->thread_->GetReactor()->Register(
      dequeue_.reactive_semaphore_.GetFd(), callback, base::Closure());
}
  • 这里和 RegisterEnqueue 异曲同工, 这里不过获取的是 出队的(rx)的 信号量, 当满足条件直接回调 当前的 callback

一般会在 callback 中调用 TryDequeue 函数

6. TryDequeue

c 复制代码
template <typename T>
std::unique_ptr<T> Queue<T>::TryDequeue() {
  std::lock_guard<std::mutex> lock(mutex_);

  if (queue_.empty()) {
    return nullptr;
  }

  dequeue_.reactive_semaphore_.Decrease(); // 出队 -1

  std::unique_ptr<T> data = std::move(queue_.front());
  queue_.pop(); // 从刚刚加入的 队列中出队 

  enqueue_.reactive_semaphore_.Increase(); // 入队 +1

  return data; // 将出队的数据返回
}
  • TryDequeue 函数是在 RegisterDequeue(callback) 的 callback 函数中调用的。
  • TryDequeue 返回 出队的包, 例如 hciLayer 中会将 这个包, 通过 hal 接口发送给 controller.

5. 用法案例分析

1. host 该如何将数据发送给 controller侧

上面我们已经介绍了 BidiQueue 和 BidiQueueEnd, 那我们就结合代码来实际探索一下,host 侧 该如何使用 Up_end 端的 tx 写入数据到 down_queue_ 中。

而 Down_end 端是如何 从 Rx 中, 取出数据 发送给 controller 的。

  • 再次强度 这里分析的 up_end_ .tx ==> down_queue_ ==> downd_end_.tx 他们是使用同一个 Queue 类型的对象 down_queue_

1. Down_end 注册 Rx 的回调

分析如何 从 down_queue_ 中读出数据包:

  • 在 HciLayer 模块的 Start 函数调用时, 我们有如下的代码:
c 复制代码
// system/gd/hci/hci_layer.cc
void HciLayer::Start() {

impl_->acl_queue_.GetDownEnd()->RegisterDequeue(handler, BindOn(impl_, &impl::on_outbound_acl_ready));

}
c 复制代码
// system/gd/common/bidi_queue.h
  BidiQueueEnd<TUP, TDOWN>* GetDownEnd() {
    return &down_end_;
  }

  void RegisterDequeue(::bluetooth::os::Handler* handler, DequeueCallback callback) override {
    rx_->RegisterDequeue(handler, callback);
  }
c 复制代码
explicit BidiQueue(size_t capacity)
      : up_queue_(capacity),
        down_queue_(capacity),
        up_end_(&down_queue_, &up_queue_),
        down_end_(&up_queue_, &down_queue_) {}
  • impl_->acl_queue_.GetDownEnd(): 首先获取到 acl_queue_ 的 down_end_
  • RegisterDequeue() : 向 acl_queue_ 的 down_end_ 的 Rx (对应 down_queue_ 队列) 注册了 callback 函数(impl::on_outbound_acl_ready)。

从上面代码可以清晰的看到, 当我们的 acl_queue_. down_queue_ 队列中有数据, 就会 自动 回调到 impl::on_outbound_acl_ready 函数。

c 复制代码
// system/gd/hci/hci_layer.cc
  void on_outbound_acl_ready() {
    auto packet = acl_queue_.GetDownEnd()->TryDequeue(); // // 尝试从acl_queue_ 的 down_end_ 的 Rx (对应 down_queue_ 队列)  中出队一包数据
    std::vector<uint8_t> bytes;
    BitInserter bi(bytes);
    packet->Serialize(bi);
    hal_->sendAclData(bytes); // 通过 HciHal module 发送给 controller
  }
c 复制代码
// system/gd/common/bidi_queue.h
  std::unique_ptr<TDEQUEUE> TryDequeue() override {
    return rx_->TryDequeue(); // 尝试从 rx 中出队一包数据
  }

2. 注册 upend.tx 回调

分析如何 向 down_queue_ 写入数据包:

c 复制代码
// system/gd/hci/hci_layer.cc

common::BidiQueueEnd<AclBuilder, AclView>* HciLayer::GetAclQueueEnd() {
  return impl_->acl_queue_.GetUpEnd();
}
c 复制代码
// system/gd/hci/acl_manager.cc

// 在加载 AclManager 时会触发 该函数调用,请看 AclManager 模块分析, 这里不展开讲解
struct AclManager::impl {
  impl(const AclManager& acl_manager) : acl_manager_(acl_manager) {}

  void Start() {
    hci_layer_ = acl_manager_.GetDependency<HciLayer>();
    handler_ = acl_manager_.GetHandler();
    controller_ = acl_manager_.GetDependency<Controller>();

    // 1.  这里通过 hci_layer_->GetAclQueueEnd 获取到了 acl_queue_.up_end
    round_robin_scheduler_ = new RoundRobinScheduler(handler_, controller_, hci_layer_->GetAclQueueEnd());

    hci_queue_end_ = hci_layer_->GetAclQueueEnd(); // 这里也获取到了 acl_queue_.up_end
    hci_queue_end_->RegisterDequeue(
        handler_, common::Bind(&impl::dequeue_and_route_acl_packet_to_connection, common::Unretained(this))); // 这里向 acl_queue_.up_end.rx 注册了回调,    



...

  }


// system/gd/hci/acl_manager/round_robin_scheduler.cc
RoundRobinScheduler::RoundRobinScheduler(
    os::Handler* handler, Controller* controller, common::BidiQueueEnd<AclBuilder, AclView>* hci_queue_end)
    : handler_(handler), controller_(controller), hci_queue_end_(hci_queue_end){...}
  • 这里看到 RoundRobinScheduler 构造函数里面, 将 acl_queue_.up_end 赋值给了 RoundRobinScheduler.hci_queue_end_
c 复制代码
// system/gd/common/bidi_queue.h
  void RegisterEnqueue(::bluetooth::os::Handler* handler, EnqueueCallback callback) override {
    tx_->RegisterEnqueue(handler, callback);
  }





// system/gd/hci/acl_manager/round_robin_scheduler.cc
void RoundRobinScheduler::send_next_fragment() {
  if (!enqueue_registered_.exchange(true)) {
    hci_queue_end_->RegisterEnqueue(
        handler_, common::Bind(&RoundRobinScheduler::handle_enqueue_next_fragment, common::Unretained(this)));
  }
}
  • 在 RoundRobinScheduler::send_next_fragment 函数中 我们向 acl_queue_.up_end.tx 注册了 回调函数 RoundRobinScheduler::handle_enqueue_next_fragment

根据 Queue.RegisterEnqueue 中我们介绍的, 当down_queue_ 满足条件,就会从 RoundRobinScheduler::handle_enqueue_next_fragment 函数中,索取 数据包 加入到 down_queue_ 队列中。

  • RoundRobinScheduler::send_next_fragment 如何调用的, 我们在其他 文章中分析。暂时不展开,可以只需要知道是如何 写入 down_queue_ 中即可。

2. controller 如何将数据传递给 host 侧

上面我们已经介绍了 BidiQueue 和 BidiQueueEnd, 那我们就结合代码来实际探索一下,controller 侧 该如何使用 downd_end 端的 tx 写入数据到 up_queue_ 中。

而 up_end 端是如何 从 Rx 中, 取出数据 发送给 controller 的。

  • 再次强度 这里分析的 downd_end_ .tx ==> up_queue_ ==> up_end_.tx 他们是使用同一个 Queue 类型的对象 up_queue_

1. 注册 up_queue_.tx 回调

  • 当controller 将数据发送给 就会触发 hcihalModule 回调之前注册到 HciLayer::hal_callbacks, 此时就会回调到 aclDataReceived 函数
c 复制代码
struct HciLayer::hal_callbacks : public hal::HciHalCallbacks {

  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)); // 将上报的数据放入 acl 中
    module_.impl_->incoming_acl_buffer_.Enqueue(move(acl), module_.GetHandler()); // 1. 这里是关键
  }



...
}

// system/gd/hci/hci_layer.cc
  os::EnqueueBuffer<AclView> incoming_acl_buffer_{acl_queue_.GetDownEnd()}; // 获取到  acl_queue_.downd_end


// system/gd/os/queue.h
  void Enqueue(std::unique_ptr<T> t, os::Handler* handler) {
    std::lock_guard<std::mutex> lock(mutex_);
    buffer_.push(std::move(t)); // 向将 收到的 acl 数据放入 buffer_ 中
    if (!enqueue_registered_.exchange(true)) {
      // 向 up_queue_.tx 注册回调   enqueue_callback
      queue_->RegisterEnqueue(handler, common::Bind(&EnqueueBuffer<T>::enqueue_callback, common::Unretained(this)));
    }
  }


// 当 up_queue_.tx 满足条件,就会触发回调, 向 up_queue_.tx  对应的队列 写入数据
// system/gd/os/queue.h
  std::unique_ptr<T> enqueue_callback() {
    std::lock_guard<std::mutex> lock(mutex_);
    std::unique_ptr<T> enqueued_t = std::move(buffer_.front()); // 从buffer_ 中获取 第一包数据
    buffer_.pop(); // 出队
    if (buffer_.empty() && enqueue_registered_.exchange(false)) {
      queue_->UnregisterEnqueue();
      if (!callback_on_empty_.is_null()) {
        std::move(callback_on_empty_).Run();
      }
    }
    return enqueued_t; // enqueued_t 将数据 内容返回, 此时在 Queue::EnqueueCallbackInternal  将返回的包,加入到 up_queue_ 队列中
  }

2. 注册 up_queue_.rx 回调

c 复制代码
// system/gd/hci/acl_manager.cc

// 在加载 AclManager 时会触发 该函数调用,请看 AclManager 模块分析, 这里不展开讲解
struct AclManager::impl {
  impl(const AclManager& acl_manager) : acl_manager_(acl_manager) {}

  void Start() {
    hci_layer_ = acl_manager_.GetDependency<HciLayer>();
    handler_ = acl_manager_.GetHandler();
    controller_ = acl_manager_.GetDependency<Controller>();

    // 1.  这里通过 hci_layer_->GetAclQueueEnd 获取到了 acl_queue_.up_end
    round_robin_scheduler_ = new RoundRobinScheduler(handler_, controller_, hci_layer_->GetAclQueueEnd());

    hci_queue_end_ = hci_layer_->GetAclQueueEnd(); // 这里也获取到了 acl_queue_.up_end
    hci_queue_end_->RegisterDequeue(
        handler_, common::Bind(&impl::dequeue_and_route_acl_packet_to_connection, common::Unretained(this))); // 这里向 acl_queue_.up_end.rx 注册了回调,    



...

  }
  • 这里向 acl_queue_.up_end.rx 注册了回调, dequeue_and_route_acl_packet_to_connection ,当 up_queue_ 中有数据时,将自动触发这个回调 调用。
c 复制代码
// system/gd/hci/acl_manager.cc
  void dequeue_and_route_acl_packet_to_connection() {
    auto packet = hci_queue_end_->TryDequeue(); // 从 HCI 层的 上行队列 中取出一包数据。
    ASSERT(packet != nullptr);
    if (!packet->IsValid()) { // 检查 HCI header 是否有效、数据是否溢出等。
      LOG_INFO("Dropping invalid packet of size %zu", packet->size());
      return;
    }
    uint16_t handle = packet->GetHandle(); // HCI ACL 包中有一个 12bit 的连接句柄字段,代表是哪个连接发送来的数据。
    if (handle == kQualcommDebugHandle) return;

    // 区分 classic / le 链接类型
    // 将数据 发往 上层 l2cap 层。
    if (classic_impl_->send_packet_upward(
            handle, [&packet](struct acl_manager::assembler* assembler) { assembler->on_incoming_packet(*packet); }))
      return;

	// 将数据 发往 上层 l2cap 层。
    if (le_impl_->send_packet_upward(
            handle, [&packet](struct acl_manager::assembler* assembler) { assembler->on_incoming_packet(*packet); }))
      return;
    LOG_INFO("Dropping packet of size %zu to unknown connection 0x%0hx", packet->size(), packet->GetHandle());
  }

这个函数从 HCI 上行队列中出队一个 ACL 数据包,然后:

  • 判断 packet 合法性
  • 根据 handle 查找对应连接(classic 或 le)
  • 如果找到了,就调用 assembler->on_incoming_packet() 进行分片组包
  • 最终,assembler 会将完整的 L2CAP 包上交给 L2CAP 层处理

其实讲到这里大家应该就对 BidiQueue BidiQueueEnd 已经彻底理解了。 接下来的内容感兴趣 就看,不感兴趣就忽略。 上面的数据,既然都已经 发到 acl 侧了, 那是如何 进一步上报到 l2cap 层的。那我们接着分析一下。

1. 如何继续转发到更高层
c 复制代码
classic_impl_->send_packet_upward(
            handle, 
            [&packet](struct acl_manager::assembler* assembler) { 
	            assembler->on_incoming_packet(*packet); 
            }
            
);
  • classic_impl_ 是 classic ACL 管理器
  • send_packet_upward(handle, callback) 的意思是:
    • 找到该连接对应的 assembler
    • 如果找到了,就执行传入的 lambda,也就是调用 assembler->on_incoming_packet(*packet)
    • 如果没找到,就返回 false(进入 le_impl_ 检查)
c 复制代码
assembler->on_incoming_packet(*packet);

这一步是关键:

  • assembler 会把 packet 的 payload 提取出来
  • 如果这个 packet 是分片的一部分,会暂存
  • 如果它是最后一个 fragment(根据 HCI header + L2CAP header 判断),就把这些 fragment 拼成一个完整 L2CAP PDU

一旦完整包拼好,assembler 会调用:

这个 channel 就是 L2CAP 的 DynamicChannel,它会把 payload 进一步交给:

SDP

RFCOMM

AVCTP

或者你车机上跑的 HFP、PBAP 等 profile 协议

既然 struct assembler 这么重要, 那我们就单独分析一下

struct assembler

assembler 是什么?

  • 从 controller(通过 HCI 层)收集 ACL 包,将分片的 L2CAP PDU 重新组合成完整的数据包,并准备好送入 L2CAP 层
c 复制代码
// system/gd/hci/acl_manager/assembler.h
struct assembler {
  assembler(AddressWithType address_with_type, AclConnection::QueueDownEnd* down_end, os::Handler* handler)
      : address_with_type_(address_with_type), down_end_(down_end), handler_(handler) {
      
AddressWithType address_with_type_;
AclConnection::QueueDownEnd* down_end_;
os::Handler* handler_;
PacketViewForRecombination recombination_stage_;
size_t remaining_sdu_continuation_packet_size_;
std::queue<packet::PacketView<packet::kLittleEndian>> incoming_queue_;

}      
成员名 作用
address_with_type_ 该连接对应的远端地址
down_end_ 和 L2CAP 对应的数据下发端(BidiQueue DownEnd)
handler_ 事件派发线程
recombination_stage_ 临时拼接分片使用的缓存
remaining_sdu_continuation_packet_size_ 还差多少 bytes 才能拼完一个完整 L2CAP 包
incoming_queue_ 一旦拼接好,存放完整 L2CAP PDU 的地方
enqueue_registered_ 标志是否已注册向下层(L2CAP)出队的处理回调

on_incoming_packet 这个函数是 ACL 包传入时的入口 ,由 HciLayer → AclManager 调用。

我们来一步步走它做了什么。

c 复制代码
  void on_incoming_packet(AclView packet) {
    PacketView<packet::kLittleEndian> payload = packet.GetPayload();
    auto payload_size = payload.size();

    // ACL 包头中带广播标记的要丢弃。
    auto broadcast_flag = packet.GetBroadcastFlag();
    if (broadcast_flag == BroadcastFlag::ACTIVE_PERIPHERAL_BROADCAST) {
      LOG_WARN("Dropping broadcast from remote");
      return;
    }


    auto packet_boundary_flag = packet.GetPacketBoundaryFlag();
    if (packet_boundary_flag == PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE) {
      LOG_ERROR("Controller is not allowed to send FIRST_NON_AUTOMATICALLY_FLUSHABLE to host except loopback mode");
      return;
    }


    // 判断是否是 分片, CONTINUING_FRAGMENT 表示是续包
    
    if (packet_boundary_flag == PacketBoundaryFlag::CONTINUING_FRAGMENT) {
      if (remaining_sdu_continuation_packet_size_ < payload_size) {
        LOG_WARN("Remote sent unexpected L2CAP PDU. Drop the entire L2CAP PDU");
        recombination_stage_ =
            PacketViewForRecombination(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
        remaining_sdu_continuation_packet_size_ = 0;
        return;
      }

      // 减去剩余的待拼接字节数
      remaining_sdu_continuation_packet_size_ -= payload_size;
      // 将 fragment 的 payload 加入临时缓存 recombination_stage_
      recombination_stage_.AppendPacketView(payload);
      if (remaining_sdu_continuation_packet_size_ != 0) {
        return; // 如果还没拼完,直接返回
      } else {
        // 否则拼好了,就继续后续处理
        payload = recombination_stage_;
        recombination_stage_ =
            PacketViewForRecombination(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
      }
    } else if (packet_boundary_flag == PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE) { // FIRST_AUTOMATICALLY_FLUSHABLE(首包)


      if (recombination_stage_.size() > 0) {
        LOG_ERROR("Controller sent a starting packet without finishing previous packet. Drop previous one.");
      }
      auto l2cap_pdu_size = GetL2capPduSize(packet); // 提取出 L2CAP header 的 length 字段(L2CAP payload 的总长)

      // 如果一包就能收完,直接处理
      remaining_sdu_continuation_packet_size_ = l2cap_pdu_size - (payload_size - kL2capBasicFrameHeaderSize);
      if (remaining_sdu_continuation_packet_size_ > 0) { // 表示一包处理不了,需要分包处理
        recombination_stage_ = payload; // 将数据加入 缓存 recombination_stage_
        return;
      }
    
    }
    if (incoming_queue_.size() > kMaxQueuedPacketsPerConnection) {
      LOG_ERROR("Dropping packet from %s due to congestion", address_with_type_.ToString().c_str());
      return;
    }
    // 一旦拼好,放入 incoming_queue_ , 放入的是完整的一包 ,此时 payload 是一个 **完整的 L2CAP PDU**(包括 L2CAP Header)
    incoming_queue_.push(payload);
    if (!enqueue_registered_->exchange(true)) {

      // 注册 Enqueue 回调 → 通知 L2CAP 来取
      down_end_->RegisterEnqueue(handler_,
                                 common::Bind(&assembler::on_le_incoming_data_ready, common::Unretained(this)));
    }
  }
c 复制代码
if (!enqueue_registered_->exchange(true)) {
  down_end_->RegisterEnqueue(handler_,
     common::Bind(&assembler::on_le_incoming_data_ready, common::Unretained(this)));
}
  • 看到这里是不是笑了, 也就是说 hciLayer 和 acl_manager 之间 有一个 通道,互为了 up_end 和 downd_end, 现在 acl_manager 和 l2cap 之间还有另外一个 通道互为 up_end 和 downd_end.
c 复制代码
// system/gd/hci/acl_manager/assembler.h
if (!enqueue_registered_->exchange(true)) {
  down_end_->RegisterEnqueue(handler_,
     common::Bind(&assembler::on_le_incoming_data_ready, common::Unretained(this)));
}
  • 这里是向 acl_manager 和 l2cap 通道, 中的down_end 的 tx 中注册回调。 当满足条件后, 通过 回调 on_le_incoming_data_ready 将数据写入 down_end 的 tx 队列中。
c 复制代码
  // Invoked from some external Queue Reactable context
  std::unique_ptr<packet::PacketView<packet::kLittleEndian>> on_le_incoming_data_ready() {
    auto packet = incoming_queue_.front();
    incoming_queue_.pop(); // 出队
    if (incoming_queue_.empty() && enqueue_registered_->exchange(false)) {
      down_end_->UnregisterEnqueue();
    }
    return std::make_unique<PacketView<packet::kLittleEndian>>(packet); // 返回一包
  } // 返回的数据,被 Queue::EnqueueCallbackInternal 放入了 tx 对应的队列中了。

如果要找到 l2cap 是哪里读的, 那就需要弄清楚 acl_manager 和 l2cap 之间的通道是谁。

请看初始化:

c 复制代码
// system/gd/hci/acl_manager/classic_impl.h

  void create_and_announce_connection(
      ConnectionCompleteView connection_complete, Role current_role, Initiator initiator) {
...
    auto queue = std::make_shared<AclConnection::Queue>(10); // 创建了一个  queue
    auto queue_down_end = queue->GetDownEnd(); // 关注这个
    round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, queue);
    std::unique_ptr<ClassicAclConnection> connection(
        new ClassicAclConnection(std::move(queue)/*将这个 queue 传入了 ClassicAclConnection 中*/, acl_connection_interface_, handle, address));
    connection->locally_initiated_ = initiator == Initiator::LOCALLY_INITIATED;
    connections.add(
        handle,
        AddressWithType{address, AddressType::PUBLIC_DEVICE_ADDRESS},
        queue_down_end, // 关注这个
        handler_,
        connection->GetEventCallbacks([this](uint16_t handle) { this->connections.invalidate(handle); }));
...
  }


    void add(
        uint16_t handle,
        const AddressWithType& remote_address,
        AclConnection::QueueDownEnd* queue_end,
        os::Handler* handler,
        ConnectionManagementCallbacks* connection_management_callbacks) {
      std::unique_lock<std::mutex> lock(acl_connections_guard_);
      auto emplace_pair = acl_connections_.emplace(
          std::piecewise_construct,
          std::forward_as_tuple(handle),
          std::forward_as_tuple(remote_address, queue_end, handler)); // 这个地方 会创建一个  acl_connection 对象, 传入了 queue_end
      ASSERT(emplace_pair.second);  // Make sure the connection is unique
      emplace_pair.first->second.connection_management_callbacks_ = connection_management_callbacks;
    }


// 在 acl_connection 构造函数中 new acl_manager::assembler
// system/gd/hci/acl_manager/classic_impl.h
acl_connection(AddressWithType address_with_type, AclConnection::QueueDownEnd* queue_down_end, os::Handler* handler)
      : address_with_type_(address_with_type),
        assembler_(new acl_manager::assembler(address_with_type, queue_down_end, handler)) {}


// 在 assembler 构造函数中 传入了 down_end , 最终赋值给了 down_end_
assembler(AddressWithType address_with_type, AclConnection::QueueDownEnd* down_end, os::Handler* handler)
      : address_with_type_(address_with_type), down_end_(down_end), handler_(handler) {} 
  • 从上述的代码中我们不难发现, 最终assembler.down_end_ 来源于 create_and_announce_connection 函数中:
    • auto queue = std::make_sharedAclConnection::Queue(10); // 创建了一个 queue
    • new ClassicAclConnection(std::move(queue) /将这个 queue 传入了 ClassicAclConnection 中/,

有了上述的信息, 我们就可以顺利找到, 该通道的 upend:

c 复制代码
// system/gd/hci/acl_manager/classic_acl_connection.cc
ClassicAclConnection::ClassicAclConnection(std::shared_ptr<Queue> queue,
                                           AclConnectionInterface* acl_connection_interface, uint16_t handle,
                                           Address address)
    : AclConnection(queue->GetUpEnd()/*在这里获取到了 对应的upend*/, handle), acl_connection_interface_(acl_connection_interface), address_(address) {
  pimpl_ = new ClassicAclConnection::impl(acl_connection_interface, std::move(queue), address, handle);
}


// system/gd/hci/acl_manager/acl_connection.h
AclConnection(QueueUpEnd* queue_up_end, uint16_t handle) : queue_up_end_(queue_up_end), handle_(handle) {}


// ClassicAclConnection 是继承于 AclConnection
// system/gd/hci/acl_manager/acl_connection.cc
AclConnection::QueueUpEnd* AclConnection::GetAclQueueEnd() const {
  return queue_up_end_;
}

那 queue->GetUpEnd() 他对应的 rx 的注册回调又在哪里呢???

c 复制代码
// system/main/shim/acl.cc
  ClassicShimAclConnection(
      SendDataUpwards send_data_upwards, OnDisconnect on_disconnect,
      const shim::legacy::acl_classic_link_interface_t& interface,
      os::Handler* handler,
      std::unique_ptr<hci::acl_manager::ClassicAclConnection> connection,
      CreationTime creation_time)
      : ShimAclConnection(connection->GetHandle(), send_data_upwards /*先记住这里*/, handler,
                          connection->GetAclQueueEnd()/*这里获取了 upend*/, creation_time),
        on_disconnect_(on_disconnect),
        interface_(interface),
        connection_(std::move(connection)) {}


// system/main/shim/acl.cc
  ShimAclConnection(const HciHandle handle, SendDataUpwards send_data_upwards,
                    os::Handler* handler,
                    hci::acl_manager::AclConnection::QueueUpEnd* queue_up_end,
                    CreationTime creation_time)
      : handle_(handle),
        handler_(handler),
        send_data_upwards_(send_data_upwards),
        queue_up_end_(queue_up_end), // 将 up_end 赋值给了 queue_up_end_
        creation_time_(creation_time) {
    // 最终向 up_end 的rx 注册了回调。
    queue_up_end_->RegisterDequeue(
        handler_, common::Bind(&ShimAclConnection::data_ready_callback,
                               common::Unretained(this)));
  }
  • 看到这里我们就找到了 通道对应的 rx 回调。

当 acl_manager 将数据写入 downd_end .tx 时, up_end.rx 将会调用 这里的 ShimAclConnection::data_ready_callback 函数

c 复制代码
  void data_ready_callback() {
    auto packet = queue_up_end_->TryDequeue(); // 从 upend.rx 队列中拿出数据
    uint16_t length = packet->size();
    std::vector<uint8_t> preamble;
    preamble.push_back(LowByte(handle_));
    preamble.push_back(HighByte(handle_));
    preamble.push_back(LowByte(length));
    preamble.push_back(HighByte(length));
    BT_HDR* p_buf = MakeLegacyBtHdrPacket(std::move(packet), preamble); // 封装为 p_buf
    ASSERT_LOG(p_buf != nullptr,
               "Unable to allocate BT_HDR legacy packet handle:%04x", handle_);
    if (send_data_upwards_ == nullptr) {
      LOG_WARN("Dropping ACL data with no callback");
      osi_free(p_buf);
    } else if (do_in_main_thread(FROM_HERE,
                                 base::Bind(send_data_upwards_ /*继续调用这里加数据向上传*/, p_buf)) !=
               BT_STATUS_SUCCESS) {
      osi_free(p_buf);
    }
  }
  • send_data_upwards_ 赋值是在 创建 ShimAclConnection 对象时赋值的,
c 复制代码
// system/main/shim/acl.cc
void shim::legacy::Acl::OnConnectSuccess(
    std::unique_ptr<hci::acl_manager::ClassicAclConnection> connection) {
  ASSERT(connection != nullptr);
  auto handle = connection->GetHandle();
  bool locally_initiated = connection->locally_initiated_;
  const hci::Address remote_address = connection->GetAddress();
  const RawAddress bd_addr = ToRawAddress(remote_address);

  pimpl_->handle_to_classic_connection_map_.emplace(
      handle, std::make_unique<ClassicShimAclConnection>(
                  acl_interface_.on_send_data_upwards /* send_data_upwards_ 就是 它   */,
                  std::bind(&shim::legacy::Acl::OnClassicLinkDisconnected, this,
                            std::placeholders::_1, std::placeholders::_2),
                  acl_interface_.link.classic, handler_, std::move(connection),
                  std::chrono::system_clock::now()));
...
}
c 复制代码
// system/main/shim/acl_legacy_interface.cc
const acl_interface_t GetAclInterface() {
  acl_interface_t acl_interface{
      .on_send_data_upwards = acl_rcv_acl_data,  
  • 所以最终会回调到这里 acl_rcv_acl_data
c 复制代码
// system/stack/acl/btm_acl.cc
void acl_rcv_acl_data(BT_HDR* p_msg) {
  acl_header_t acl_header{
      .handle = HCI_INVALID_HANDLE,
      .hci_len = 0,
  };
  const uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;

  STREAM_TO_UINT16(acl_header.handle, p);
  acl_header.handle = HCID_GET_HANDLE(acl_header.handle);

  STREAM_TO_UINT16(acl_header.hci_len, p);
  if (acl_header.hci_len < L2CAP_PKT_OVERHEAD ||
      acl_header.hci_len != p_msg->len - sizeof(acl_header)) {
    LOG_WARN("Received mismatched hci header length:%u data_len:%zu",
             acl_header.hci_len, p_msg->len - sizeof(acl_header));
    osi_free(p_msg);
    return;
  }
  l2c_rcv_acl_data(p_msg); // 最终将 数据传入 l2cap
}


// system/stack/l2cap/l2c_main.cc

/*******************************************************************************
 *
 * Function         l2c_rcv_acl_data
 *
 * Description      This function is called from the HCI Interface when an ACL
 *                  data packet is received.
 *
 * Returns          void
 *
 ******************************************************************************/
void l2c_rcv_acl_data(BT_HDR* p_msg) {
  uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;

  /* Extract the handle */
  uint16_t handle;
  STREAM_TO_UINT16(handle, p);
  uint8_t pkt_type = HCID_GET_EVENT(handle);
  handle = HCID_GET_HANDLE(handle);

  /* Since the HCI Transport is putting segmented packets back together, we */
  /* should never get a valid packet with the type set to "continuation"    */
  if (pkt_type == L2CAP_PKT_CONTINUE) {
    L2CAP_TRACE_WARNING("L2CAP - received packet continuation");
    osi_free(p_msg);
    return;
  }

  uint16_t hci_len;
  STREAM_TO_UINT16(hci_len, p);
  if (hci_len < L2CAP_PKT_OVERHEAD || hci_len != p_msg->len - 4) {
    /* Remote-declared packet size must match HCI_ACL size - ACL header (4) */
    L2CAP_TRACE_WARNING("L2CAP - got incorrect hci header");
    osi_free(p_msg);
    return;
  }

  uint16_t l2cap_len, rcv_cid;
  STREAM_TO_UINT16(l2cap_len, p);
  STREAM_TO_UINT16(rcv_cid, p);

  /* Find the LCB based on the handle */
  tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle);
  if (!p_lcb) {
    /* There is a slight possibility (specifically with USB) that we get an */
    /* L2CAP connection request before we get the HCI connection complete.  */
    /* So for these types of messages, hold them for up to 2 seconds.       */
    if (l2cap_len == 0) {
      L2CAP_TRACE_WARNING("received empty L2CAP packet");
      osi_free(p_msg);
      return;
    }
    uint8_t cmd_code;
    STREAM_TO_UINT8(cmd_code, p);

    if ((p_msg->layer_specific != 0) || (rcv_cid != L2CAP_SIGNALLING_CID) ||
        (cmd_code != L2CAP_CMD_INFO_REQ && cmd_code != L2CAP_CMD_CONN_REQ)) {
      bool qcom_debug_log = (handle == 3804 && ((rcv_cid & 0xff) == 0xff) &&
                             p_msg->layer_specific == 0);

      if (!qcom_debug_log) {
        L2CAP_TRACE_ERROR(
            "L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur "
            "count:%d",
            handle, p_msg->layer_specific, rcv_cid, cmd_code,
            list_length(l2cb.rcv_pending_q));
      }

      osi_free(p_msg);
      return;
    }

    L2CAP_TRACE_WARNING(
        "L2CAP - holding ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur "
        "count:%d",
        handle, p_msg->layer_specific, rcv_cid, cmd_code,
        list_length(l2cb.rcv_pending_q));
    p_msg->layer_specific = 2;
    list_append(l2cb.rcv_pending_q, p_msg);

    if (list_length(l2cb.rcv_pending_q) == 1) {
      alarm_set_on_mloop(l2cb.receive_hold_timer, BT_1SEC_TIMEOUT_MS,
                         l2c_receive_hold_timer_timeout, NULL);
    }
    return;
  }
  • l2c_rcv_acl_data 函数在 l2cap 章节分析, 这里先记录

5. 小结

该模型广泛应用于 Android 蓝牙协议栈中:

  • 管理 ACL 数据(L2CAP)
  • 控制器事件处理(Command/Event)
  • 同样逻辑适用于 SCO、ISO 通道(共享同一模式)
    每种通道(ACL/SCO/ISO)都使用一组独立的 BidiQueue,实现高度解耦、线程安全的数据通路。
相关推荐
_一条咸鱼_1 小时前
Android Picasso 请求构建模块深度剖析(一)
android·面试·android jetpack
_一条咸鱼_1 小时前
Android Picasso 显示模块深度剖析(六)
android·面试·android jetpack
氦客2 小时前
kotlin知识体系(六) : Flow核心概念与与操作符指南
android·开发语言·kotlin·协程·flow·冷流·热流
WebInfra2 小时前
🔥 Midscene 重磅更新:支持 AI 驱动的 Android 自动化
android·前端·测试
虽千万人 吾往矣4 小时前
golang context源码
android·开发语言·golang
李新_5 小时前
Android 多进程并发控制如何实现
android·java
ll_god5 小时前
Android 应用wifi direct连接通信实现
android
氦客6 小时前
kotlin知识体系(五) :Android 协程全解析,从作用域到异常处理的全面指南
android·开发语言·kotlin·协程·coroutine·suspend·functions
Mr YiRan7 小时前
Android Gradle多渠道打包
android