1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "hci/acl_manager/round_robin_scheduler.h"
18
19 #include <com_android_bluetooth_flags.h>
20 #include <gtest/gtest.h>
21
22 #include "common/bidi_queue.h"
23 #include "common/callback.h"
24 #include "hci/controller.h"
25 #include "hci/hci_packets.h"
26 #include "os/handler.h"
27 #include "packet/raw_builder.h"
28
29 using ::bluetooth::common::BidiQueue;
30 using ::bluetooth::common::Callback;
31 using ::bluetooth::os::Handler;
32 using ::bluetooth::os::Thread;
33
34 using namespace std::chrono_literals;
35
36 namespace bluetooth {
37 namespace hci {
38 namespace acl_manager {
39 namespace {
40
41 class TestController : public Controller {
42 public:
GetNumAclPacketBuffers() const43 uint16_t GetNumAclPacketBuffers() const { return max_acl_packet_credits_; }
44
GetAclPacketLength() const45 uint16_t GetAclPacketLength() const { return hci_mtu_; }
46
GetLeBufferSize() const47 LeBufferSize GetLeBufferSize() const {
48 LeBufferSize le_buffer_size;
49 le_buffer_size.le_data_packet_length_ = le_hci_mtu_;
50 le_buffer_size.total_num_le_packets_ = le_max_acl_packet_credits_;
51 return le_buffer_size;
52 }
53
RegisterCompletedAclPacketsCallback(CompletedAclPacketsCallback cb)54 void RegisterCompletedAclPacketsCallback(CompletedAclPacketsCallback cb) {
55 acl_credits_callback_ = cb;
56 }
57
SendCompletedAclPacketsCallback(uint16_t handle,uint16_t credits)58 void SendCompletedAclPacketsCallback(uint16_t handle, uint16_t credits) {
59 acl_credits_callback_(handle, credits);
60 }
61
UnregisterCompletedAclPacketsCallback()62 void UnregisterCompletedAclPacketsCallback() { acl_credits_callback_ = {}; }
63
64 const uint16_t max_acl_packet_credits_ = 10;
65 const uint16_t hci_mtu_ = 1024;
66 const uint16_t le_max_acl_packet_credits_ = 15;
67 const uint16_t le_hci_mtu_ = 27;
68
69 private:
70 CompletedAclPacketsCallback acl_credits_callback_;
71 };
72
73 class RoundRobinSchedulerTest : public ::testing::Test {
74 public:
SetUp()75 void SetUp() override {
76 thread_ = new Thread("thread", Thread::Priority::NORMAL);
77 handler_ = new Handler(thread_);
78 controller_ = new TestController();
79 round_robin_scheduler_ = new RoundRobinScheduler(handler_, controller_, hci_queue_.GetUpEnd());
80 hci_queue_.GetDownEnd()->RegisterDequeue(
81 handler_,
82 common::Bind(&RoundRobinSchedulerTest::HciDownEndDequeue, common::Unretained(this)));
83 }
84
TearDown()85 void TearDown() override {
86 hci_queue_.GetDownEnd()->UnregisterDequeue();
87 delete round_robin_scheduler_;
88 delete controller_;
89 handler_->Clear();
90 delete handler_;
91 delete thread_;
92 }
93
sync_handler()94 void sync_handler() {
95 log::assert_that(thread_ != nullptr, "assert failed: thread_ != nullptr");
96 log::assert_that(thread_->GetReactor()->WaitForIdle(2s),
97 "assert failed: thread_->GetReactor()->WaitForIdle(2s)");
98 }
99
EnqueueAclUpEnd(AclConnection::QueueUpEnd * queue_up_end,std::vector<uint8_t> packet)100 void EnqueueAclUpEnd(AclConnection::QueueUpEnd* queue_up_end, std::vector<uint8_t> packet) {
101 if (enqueue_promise_ != nullptr) {
102 enqueue_future_->wait();
103 }
104 enqueue_promise_ = std::make_unique<std::promise<void>>();
105 enqueue_future_ = std::make_unique<std::future<void>>(enqueue_promise_->get_future());
106 queue_up_end->RegisterEnqueue(handler_,
107 common::Bind(&RoundRobinSchedulerTest::enqueue_callback,
108 common::Unretained(this), queue_up_end, packet));
109 }
110
enqueue_callback(AclConnection::QueueUpEnd * queue_up_end,std::vector<uint8_t> packet)111 std::unique_ptr<packet::BasePacketBuilder> enqueue_callback(
112 AclConnection::QueueUpEnd* queue_up_end, std::vector<uint8_t> packet) {
113 auto packet_one = std::make_unique<packet::RawBuilder>(2000);
114 packet_one->AddOctets(packet);
115 queue_up_end->UnregisterEnqueue();
116 enqueue_promise_->set_value();
117 return packet_one;
118 }
119
HciDownEndDequeue()120 void HciDownEndDequeue() {
121 auto packet = hci_queue_.GetDownEnd()->TryDequeue();
122 // Convert from a Builder to a View
123 auto bytes = std::make_shared<std::vector<uint8_t>>();
124 bluetooth::packet::BitInserter i(*bytes);
125 bytes->reserve(packet->size());
126 packet->Serialize(i);
127 auto packet_view = bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian>(bytes);
128 AclView acl_packet_view = AclView::Create(packet_view);
129 ASSERT_TRUE(acl_packet_view.IsValid());
130 PacketView<true> count_view = acl_packet_view.GetPayload();
131 sent_acl_packets_.push(acl_packet_view);
132
133 packet_count_--;
134 if (packet_count_ == 0) {
135 std::promise<void>* prom = packet_promise_.release();
136 prom->set_value();
137 delete prom;
138 }
139 }
140
VerifyPacket(uint16_t handle,std::vector<uint8_t> packet)141 void VerifyPacket(uint16_t handle, std::vector<uint8_t> packet) {
142 auto acl_packet_view = sent_acl_packets_.front();
143 ASSERT_EQ(handle, acl_packet_view.GetHandle());
144 auto payload = acl_packet_view.GetPayload();
145 for (size_t i = 0; i < payload.size(); i++) {
146 ASSERT_EQ(payload[i], packet[i]);
147 }
148 sent_acl_packets_.pop();
149 }
150
SetPacketFuture(uint16_t count)151 void SetPacketFuture(uint16_t count) {
152 ASSERT_EQ(packet_promise_, nullptr) << "Promises, Promises, ... Only one at a time.";
153 packet_count_ = count;
154 packet_promise_ = std::make_unique<std::promise<void>>();
155 packet_future_ = std::make_unique<std::future<void>>(packet_promise_->get_future());
156 }
157
158 BidiQueue<AclView, AclBuilder> hci_queue_{3};
159 Thread* thread_;
160 Handler* handler_;
161 TestController* controller_;
162 RoundRobinScheduler* round_robin_scheduler_;
163 std::queue<AclView> sent_acl_packets_;
164 uint16_t packet_count_;
165 std::unique_ptr<std::promise<void>> packet_promise_;
166 std::unique_ptr<std::future<void>> packet_future_;
167 std::unique_ptr<std::promise<void>> enqueue_promise_;
168 std::unique_ptr<std::future<void>> enqueue_future_;
169 };
170
TEST_F(RoundRobinSchedulerTest,startup_teardown)171 TEST_F(RoundRobinSchedulerTest, startup_teardown) {}
172
TEST_F(RoundRobinSchedulerTest,register_unregister_connection)173 TEST_F(RoundRobinSchedulerTest, register_unregister_connection) {
174 uint16_t handle = 0x01;
175 auto connection_queue = std::make_shared<AclConnection::Queue>(10);
176 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle,
177 connection_queue);
178 round_robin_scheduler_->Unregister(handle);
179 }
180
TEST_F(RoundRobinSchedulerTest,buffer_packet)181 TEST_F(RoundRobinSchedulerTest, buffer_packet) {
182 uint16_t handle = 0x01;
183 auto connection_queue = std::make_shared<AclConnection::Queue>(10);
184 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle,
185 connection_queue);
186
187 ASSERT_NO_FATAL_FAILURE(SetPacketFuture(2));
188 AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
189 std::vector<uint8_t> packet1 = {0x01, 0x02, 0x03};
190 std::vector<uint8_t> packet2 = {0x04, 0x05, 0x06};
191 EnqueueAclUpEnd(queue_up_end, packet1);
192 EnqueueAclUpEnd(queue_up_end, packet2);
193
194 packet_future_->wait();
195 VerifyPacket(handle, packet1);
196 VerifyPacket(handle, packet2);
197 ASSERT_EQ(round_robin_scheduler_->GetCredits(), controller_->max_acl_packet_credits_ - 2);
198
199 round_robin_scheduler_->Unregister(handle);
200 }
201
TEST_F(RoundRobinSchedulerTest,buffer_packet_from_two_connections)202 TEST_F(RoundRobinSchedulerTest, buffer_packet_from_two_connections) {
203 uint16_t handle = 0x01;
204 uint16_t le_handle = 0x02;
205 auto connection_queue = std::make_shared<AclConnection::Queue>(10);
206 auto le_connection_queue = std::make_shared<AclConnection::Queue>(10);
207
208 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle,
209 connection_queue);
210 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle,
211 le_connection_queue);
212
213 ASSERT_NO_FATAL_FAILURE(SetPacketFuture(2));
214 AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
215 AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd();
216 std::vector<uint8_t> packet = {0x01, 0x02, 0x03};
217 std::vector<uint8_t> le_packet = {0x04, 0x05, 0x06};
218 EnqueueAclUpEnd(le_queue_up_end, le_packet);
219 EnqueueAclUpEnd(queue_up_end, packet);
220
221 packet_future_->wait();
222 VerifyPacket(le_handle, le_packet);
223 VerifyPacket(handle, packet);
224 ASSERT_EQ(round_robin_scheduler_->GetCredits(), controller_->max_acl_packet_credits_ - 1);
225 ASSERT_EQ(round_robin_scheduler_->GetLeCredits(), controller_->le_max_acl_packet_credits_ - 1);
226
227 round_robin_scheduler_->Unregister(handle);
228 round_robin_scheduler_->Unregister(le_handle);
229 }
230
TEST_F(RoundRobinSchedulerTest,do_not_register_when_credits_is_zero)231 TEST_F(RoundRobinSchedulerTest, do_not_register_when_credits_is_zero) {
232 uint16_t handle = 0x01;
233 auto connection_queue = std::make_shared<AclConnection::Queue>(15);
234 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle,
235 connection_queue);
236
237 ASSERT_NO_FATAL_FAILURE(SetPacketFuture(10));
238 AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
239 for (uint8_t i = 0; i < 15; i++) {
240 std::vector<uint8_t> packet = {0x01, 0x02, 0x03, i};
241 EnqueueAclUpEnd(queue_up_end, packet);
242 }
243
244 packet_future_->wait();
245 for (uint8_t i = 0; i < 10; i++) {
246 std::vector<uint8_t> packet = {0x01, 0x02, 0x03, i};
247 VerifyPacket(handle, packet);
248 }
249 ASSERT_EQ(round_robin_scheduler_->GetCredits(), 0);
250
251 ASSERT_NO_FATAL_FAILURE(SetPacketFuture(5));
252 controller_->SendCompletedAclPacketsCallback(0x01, 10);
253 sync_handler();
254 packet_future_->wait();
255 for (uint8_t i = 10; i < 15; i++) {
256 std::vector<uint8_t> packet = {0x01, 0x02, 0x03, i};
257 VerifyPacket(handle, packet);
258 }
259 ASSERT_EQ(round_robin_scheduler_->GetCredits(), 5);
260
261 round_robin_scheduler_->Unregister(handle);
262 }
263
TEST_F(RoundRobinSchedulerTest,reveived_completed_callback_with_unknown_handle)264 TEST_F(RoundRobinSchedulerTest, reveived_completed_callback_with_unknown_handle) {
265 controller_->SendCompletedAclPacketsCallback(0x00, 1);
266 sync_handler();
267 EXPECT_EQ(round_robin_scheduler_->GetCredits(), controller_->max_acl_packet_credits_);
268 EXPECT_EQ(round_robin_scheduler_->GetLeCredits(), controller_->le_max_acl_packet_credits_);
269 }
270
TEST_F(RoundRobinSchedulerTest,buffer_packet_intervally)271 TEST_F(RoundRobinSchedulerTest, buffer_packet_intervally) {
272 uint16_t handle1 = 0x01;
273 uint16_t handle2 = 0x02;
274 uint16_t le_handle1 = 0x03;
275 uint16_t le_handle2 = 0x04;
276 auto connection_queue1 = std::make_shared<AclConnection::Queue>(10);
277 auto connection_queue2 = std::make_shared<AclConnection::Queue>(10);
278 auto le_connection_queue1 = std::make_shared<AclConnection::Queue>(10);
279 auto le_connection_queue2 = std::make_shared<AclConnection::Queue>(10);
280
281 ASSERT_NO_FATAL_FAILURE(SetPacketFuture(18));
282 AclConnection::QueueUpEnd* queue_up_end1 = connection_queue1->GetUpEnd();
283 AclConnection::QueueUpEnd* queue_up_end2 = connection_queue2->GetUpEnd();
284 AclConnection::QueueUpEnd* le_queue_up_end1 = le_connection_queue1->GetUpEnd();
285 AclConnection::QueueUpEnd* le_queue_up_end2 = le_connection_queue2->GetUpEnd();
286
287 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle1,
288 connection_queue1);
289 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle2,
290 connection_queue2);
291 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle1,
292 le_connection_queue1);
293 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle2,
294 le_connection_queue2);
295
296 std::vector<uint8_t> packet = {0x01, 0x02, 0x03};
297 EnqueueAclUpEnd(queue_up_end1, packet);
298 EnqueueAclUpEnd(le_queue_up_end2, packet);
299 for (uint8_t i = 0; i < 4; i++) {
300 std::vector<uint8_t> packet1 = {0x01, 0x02, 0x03, i};
301 std::vector<uint8_t> packet2 = {0x02, 0x02, 0x03, i};
302 std::vector<uint8_t> le_packet1 = {0x04, 0x05, 0x06, i};
303 std::vector<uint8_t> le_packet2 = {0x05, 0x05, 0x06, i};
304 EnqueueAclUpEnd(queue_up_end1, packet1);
305 EnqueueAclUpEnd(queue_up_end2, packet2);
306 EnqueueAclUpEnd(le_queue_up_end1, le_packet1);
307 EnqueueAclUpEnd(le_queue_up_end2, le_packet2);
308 }
309
310 packet_future_->wait();
311 VerifyPacket(handle1, packet);
312 VerifyPacket(le_handle2, packet);
313 for (uint8_t i = 0; i < 4; i++) {
314 std::vector<uint8_t> packet1 = {0x01, 0x02, 0x03, i};
315 std::vector<uint8_t> packet2 = {0x02, 0x02, 0x03, i};
316 std::vector<uint8_t> le_packet1 = {0x04, 0x05, 0x06, i};
317 std::vector<uint8_t> le_packet2 = {0x05, 0x05, 0x06, i};
318 VerifyPacket(handle1, packet1);
319 VerifyPacket(handle2, packet2);
320 VerifyPacket(le_handle1, le_packet1);
321 VerifyPacket(le_handle2, le_packet2);
322 }
323
324 ASSERT_EQ(round_robin_scheduler_->GetCredits(), controller_->max_acl_packet_credits_ - 9);
325 ASSERT_EQ(round_robin_scheduler_->GetLeCredits(), controller_->le_max_acl_packet_credits_ - 9);
326
327 round_robin_scheduler_->Unregister(handle1);
328 round_robin_scheduler_->Unregister(handle2);
329 round_robin_scheduler_->Unregister(le_handle1);
330 round_robin_scheduler_->Unregister(le_handle2);
331 }
332
TEST_F(RoundRobinSchedulerTest,send_fragments_without_interval)333 TEST_F(RoundRobinSchedulerTest, send_fragments_without_interval) {
334 uint16_t handle = 0x01;
335 uint16_t le_handle = 0x02;
336 auto connection_queue = std::make_shared<AclConnection::Queue>(10);
337 auto le_connection_queue = std::make_shared<AclConnection::Queue>(10);
338
339 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle,
340 connection_queue);
341 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle,
342 le_connection_queue);
343
344 ASSERT_NO_FATAL_FAILURE(SetPacketFuture(5));
345 AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
346 AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd();
347 std::vector<uint8_t> packet(controller_->hci_mtu_, 0xff);
348 std::vector<uint8_t> packet_part1(controller_->hci_mtu_, 0xff);
349 std::vector<uint8_t> packet_part2 = {0x03, 0x02, 0x01};
350 packet.insert(packet.end(), packet_part2.begin(), packet_part2.end());
351
352 std::vector<uint8_t> le_packet;
353 std::vector<uint8_t> le_packet_part1;
354 std::vector<uint8_t> le_packet_part2;
355 std::vector<uint8_t> le_packet_part3;
356 for (uint8_t i = 0; i < controller_->le_hci_mtu_; i++) {
357 le_packet.push_back(i);
358 le_packet_part1.push_back(i);
359 le_packet_part2.push_back(i * 2);
360 le_packet_part3.push_back(i * 3);
361 }
362 le_packet.insert(le_packet.end(), le_packet_part2.begin(), le_packet_part2.end());
363 le_packet.insert(le_packet.end(), le_packet_part3.begin(), le_packet_part3.end());
364
365 EnqueueAclUpEnd(le_queue_up_end, le_packet);
366 EnqueueAclUpEnd(queue_up_end, packet);
367
368 packet_future_->wait();
369 VerifyPacket(le_handle, le_packet_part1);
370 VerifyPacket(le_handle, le_packet_part2);
371 VerifyPacket(le_handle, le_packet_part3);
372 VerifyPacket(handle, packet_part1);
373 VerifyPacket(handle, packet_part2);
374 ASSERT_EQ(round_robin_scheduler_->GetCredits(), controller_->max_acl_packet_credits_ - 2);
375 ASSERT_EQ(round_robin_scheduler_->GetLeCredits(), controller_->le_max_acl_packet_credits_ - 3);
376
377 round_robin_scheduler_->Unregister(handle);
378 round_robin_scheduler_->Unregister(le_handle);
379 }
380
TEST_F(RoundRobinSchedulerTest,receive_le_credit_when_next_fragment_is_classic)381 TEST_F(RoundRobinSchedulerTest, receive_le_credit_when_next_fragment_is_classic) {
382 uint16_t handle = 0x01;
383 uint16_t le_handle = 0x02;
384 auto connection_queue = std::make_shared<AclConnection::Queue>(20);
385 auto le_connection_queue = std::make_shared<AclConnection::Queue>(20);
386
387 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle,
388 connection_queue);
389 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle,
390 le_connection_queue);
391
392 ASSERT_NO_FATAL_FAILURE(SetPacketFuture(controller_->le_max_acl_packet_credits_ +
393 controller_->max_acl_packet_credits_));
394 AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
395 AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd();
396 std::vector<uint8_t> huge_packet(2000);
397 std::vector<uint8_t> packet = {0x01, 0x02, 0x03};
398 std::vector<uint8_t> le_packet = {0x04, 0x05, 0x06};
399
400 // Make le_acl_packet_credits_ = 0;
401 for (uint16_t i = 0; i < controller_->le_max_acl_packet_credits_; i++) {
402 EnqueueAclUpEnd(le_queue_up_end, le_packet);
403 }
404
405 // Make acl_packet_credits_ = 0 and remain 1 acl fragment in fragments_to_send_
406 for (uint16_t i = 0; i < controller_->max_acl_packet_credits_ - 1; i++) {
407 EnqueueAclUpEnd(queue_up_end, packet);
408 }
409 EnqueueAclUpEnd(queue_up_end, huge_packet);
410
411 packet_future_->wait();
412
413 // Trigger start_round_robin
414 controller_->SendCompletedAclPacketsCallback(0x02, 1);
415 std::this_thread::sleep_for(std::chrono::milliseconds(20));
416
417 ASSERT_EQ(round_robin_scheduler_->GetCredits(), 0);
418 ASSERT_EQ(round_robin_scheduler_->GetLeCredits(), 1);
419
420 round_robin_scheduler_->Unregister(handle);
421 round_robin_scheduler_->Unregister(le_handle);
422 }
423
TEST_F(RoundRobinSchedulerTest,unregister_reclaim_credits)424 TEST_F(RoundRobinSchedulerTest, unregister_reclaim_credits) {
425 com::android::bluetooth::flags::provider_->drop_acl_fragment_on_disconnect(true);
426
427 uint16_t handle = 0x01;
428 auto connection_queue = std::make_shared<AclConnection::Queue>(20);
429 auto new_connection_queue = std::make_shared<AclConnection::Queue>(20);
430
431 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle,
432 connection_queue);
433
434 ASSERT_NO_FATAL_FAILURE(SetPacketFuture(controller_->max_acl_packet_credits_));
435
436 AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
437
438 std::vector<uint8_t> huge_packet(2000);
439 std::vector<uint8_t> packet = {0x01, 0x02, 0x03};
440 std::vector<uint8_t> new_packet = {0x04, 0x05, 0x06};
441
442 // Make acl_packet_credits_ = 0 and remain 1 acl fragment in fragments_to_send_
443 for (uint16_t i = 0; i < controller_->max_acl_packet_credits_ - 1; i++) {
444 EnqueueAclUpEnd(queue_up_end, packet);
445 }
446 EnqueueAclUpEnd(queue_up_end, huge_packet);
447
448 packet_future_->wait();
449 ASSERT_EQ(round_robin_scheduler_->GetCredits(), 0);
450
451 // Credits should be reclaimed
452 round_robin_scheduler_->Unregister(handle);
453 ASSERT_EQ(round_robin_scheduler_->GetCredits(), controller_->max_acl_packet_credits_);
454
455 while (!sent_acl_packets_.empty()) {
456 sent_acl_packets_.pop();
457 }
458
459 round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle,
460 new_connection_queue);
461 ASSERT_NO_FATAL_FAILURE(SetPacketFuture(controller_->max_acl_packet_credits_));
462
463 AclConnection::QueueUpEnd* new_queue_up_end = new_connection_queue->GetUpEnd();
464 for (uint16_t i = 0; i < controller_->max_acl_packet_credits_; i++) {
465 EnqueueAclUpEnd(new_queue_up_end, new_packet);
466 }
467
468 packet_future_->wait();
469
470 // Pending fragments shouldn't be sent
471 for (uint16_t i = 0; i < controller_->max_acl_packet_credits_; i++) {
472 VerifyPacket(handle, new_packet);
473 }
474 round_robin_scheduler_->Unregister(handle);
475 }
476
477 } // namespace
478 } // namespace acl_manager
479 } // namespace hci
480 } // namespace bluetooth
481