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 <bluetooth/log.h>
20 
21 #include "hci/acl_manager/acl_fragmenter.h"
22 namespace bluetooth {
23 namespace hci {
24 namespace acl_manager {
25 
RoundRobinScheduler(os::Handler * handler,Controller * controller,common::BidiQueueEnd<AclBuilder,AclView> * hci_queue_end)26 RoundRobinScheduler::RoundRobinScheduler(
27     os::Handler* handler, Controller* controller, common::BidiQueueEnd<AclBuilder, AclView>* hci_queue_end)
28     : handler_(handler), controller_(controller), hci_queue_end_(hci_queue_end) {
29   max_acl_packet_credits_ = controller_->GetNumAclPacketBuffers();
30   acl_packet_credits_ = max_acl_packet_credits_;
31   hci_mtu_ = controller_->GetAclPacketLength();
32   LeBufferSize le_buffer_size = controller_->GetLeBufferSize();
33   le_max_acl_packet_credits_ = le_buffer_size.total_num_le_packets_;
34   le_acl_packet_credits_ = le_max_acl_packet_credits_;
35   le_hci_mtu_ = le_buffer_size.le_data_packet_length_;
36   controller_->RegisterCompletedAclPacketsCallback(handler->BindOn(this, &RoundRobinScheduler::incoming_acl_credits));
37 }
38 
~RoundRobinScheduler()39 RoundRobinScheduler::~RoundRobinScheduler() {
40   unregister_all_connections();
41   controller_->UnregisterCompletedAclPacketsCallback();
42 }
43 
Register(ConnectionType connection_type,uint16_t handle,std::shared_ptr<acl_manager::AclConnection::Queue> queue)44 void RoundRobinScheduler::Register(ConnectionType connection_type, uint16_t handle,
45                                    std::shared_ptr<acl_manager::AclConnection::Queue> queue) {
46   log::assert_that(
47       acl_queue_handlers_.count(handle) == 0,
48       "assert failed: acl_queue_handlers_.count(handle) == 0");
49   acl_queue_handler acl_queue_handler = {connection_type, std::move(queue), false, 0};
50   acl_queue_handlers_.insert(std::pair<uint16_t, RoundRobinScheduler::acl_queue_handler>(handle, acl_queue_handler));
51   if (fragments_to_send_.size() == 0) {
52     start_round_robin();
53   }
54 }
55 
Unregister(uint16_t handle)56 void RoundRobinScheduler::Unregister(uint16_t handle) {
57   log::assert_that(
58       acl_queue_handlers_.count(handle) == 1,
59       "assert failed: acl_queue_handlers_.count(handle) == 1");
60   auto acl_queue_handler = acl_queue_handlers_.find(handle)->second;
61   // Reclaim outstanding packets
62   if (acl_queue_handler.connection_type_ == ConnectionType::CLASSIC) {
63     acl_packet_credits_ += acl_queue_handler.number_of_sent_packets_;
64   } else {
65     le_acl_packet_credits_ += acl_queue_handler.number_of_sent_packets_;
66   }
67   acl_queue_handler.number_of_sent_packets_ = 0;
68 
69   if (acl_queue_handler.dequeue_is_registered_) {
70     acl_queue_handler.dequeue_is_registered_ = false;
71     acl_queue_handler.queue_->GetDownEnd()->UnregisterDequeue();
72   }
73   acl_queue_handlers_.erase(handle);
74   starting_point_ = acl_queue_handlers_.begin();
75 }
76 
SetLinkPriority(uint16_t handle,bool high_priority)77 void RoundRobinScheduler::SetLinkPriority(uint16_t handle, bool high_priority) {
78   auto acl_queue_handler = acl_queue_handlers_.find(handle);
79   if (acl_queue_handler == acl_queue_handlers_.end()) {
80     log::warn("handle {} is invalid", handle);
81     return;
82   }
83   acl_queue_handler->second.high_priority_ = high_priority;
84 }
85 
GetCredits()86 uint16_t RoundRobinScheduler::GetCredits() {
87   return acl_packet_credits_;
88 }
89 
GetLeCredits()90 uint16_t RoundRobinScheduler::GetLeCredits() {
91   return le_acl_packet_credits_;
92 }
93 
start_round_robin()94 void RoundRobinScheduler::start_round_robin() {
95   if (acl_packet_credits_ == 0 && le_acl_packet_credits_ == 0) {
96     return;
97   }
98   if (!fragments_to_send_.empty()) {
99     auto connection_type = fragments_to_send_.front().first;
100     bool classic_buffer_full = acl_packet_credits_ == 0 && connection_type == ConnectionType::CLASSIC;
101     bool le_buffer_full = le_acl_packet_credits_ == 0 && connection_type == ConnectionType::LE;
102     if (classic_buffer_full || le_buffer_full) {
103       log::warn("Buffer of connection_type {} is full", connection_type);
104       return;
105     }
106     send_next_fragment();
107     return;
108   }
109   if (acl_queue_handlers_.empty()) {
110     log::info("No any acl connection");
111     return;
112   }
113 
114   if (acl_queue_handlers_.size() == 1 || starting_point_ == acl_queue_handlers_.end()) {
115     starting_point_ = acl_queue_handlers_.begin();
116   }
117   size_t count = acl_queue_handlers_.size();
118 
119   for (auto acl_queue_handler = starting_point_; count > 0; count--) {
120     // Prevent registration when credits is zero
121     bool classic_buffer_full =
122         acl_packet_credits_ == 0 && acl_queue_handler->second.connection_type_ == ConnectionType::CLASSIC;
123     bool le_buffer_full =
124         le_acl_packet_credits_ == 0 && acl_queue_handler->second.connection_type_ == ConnectionType::LE;
125     if (!acl_queue_handler->second.dequeue_is_registered_ && !classic_buffer_full && !le_buffer_full) {
126       acl_queue_handler->second.dequeue_is_registered_ = true;
127       uint16_t acl_handle = acl_queue_handler->first;
128       acl_queue_handler->second.queue_->GetDownEnd()->RegisterDequeue(
129           handler_, common::Bind(&RoundRobinScheduler::buffer_packet, common::Unretained(this), acl_handle));
130     }
131     acl_queue_handler = std::next(acl_queue_handler);
132     if (acl_queue_handler == acl_queue_handlers_.end()) {
133       acl_queue_handler = acl_queue_handlers_.begin();
134     }
135   }
136 
137   starting_point_ = std::next(starting_point_);
138 }
139 
buffer_packet(uint16_t acl_handle)140 void RoundRobinScheduler::buffer_packet(uint16_t acl_handle) {
141   BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
142   auto acl_queue_handler = acl_queue_handlers_.find(acl_handle);
143   if( acl_queue_handler == acl_queue_handlers_.end()) {
144     log::error("Ignore since ACL connection vanished with handle: 0x{:X}", acl_handle);
145     return;
146   }
147 
148   // Wrap packet and enqueue it
149   uint16_t handle = acl_queue_handler->first;
150   auto packet = acl_queue_handler->second.queue_->GetDownEnd()->TryDequeue();
151   log::assert_that(packet != nullptr, "assert failed: packet != nullptr");
152 
153   ConnectionType connection_type = acl_queue_handler->second.connection_type_;
154   size_t mtu = connection_type == ConnectionType::CLASSIC ? hci_mtu_ : le_hci_mtu_;
155   PacketBoundaryFlag packet_boundary_flag = (packet->IsFlushable())
156                                                 ? PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE
157                                                 : PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE;
158 
159   int acl_priority = acl_queue_handler->second.high_priority_ ? 1 : 0;
160   if (packet->size() <= mtu) {
161     fragments_to_send_.push(
162         std::make_pair(
163             connection_type, AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(packet))),
164         acl_priority);
165   } else {
166     auto fragments = AclFragmenter(mtu, std::move(packet)).GetFragments();
167     for (size_t i = 0; i < fragments.size(); i++) {
168       fragments_to_send_.push(
169           std::make_pair(
170               connection_type,
171               AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(fragments[i]))),
172           acl_priority);
173       packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT;
174     }
175   }
176   log::assert_that(fragments_to_send_.size() > 0, "assert failed: fragments_to_send_.size() > 0");
177   unregister_all_connections();
178 
179   acl_queue_handler->second.number_of_sent_packets_ += fragments_to_send_.size();
180   send_next_fragment();
181 }
182 
unregister_all_connections()183 void RoundRobinScheduler::unregister_all_connections() {
184   for (auto acl_queue_handler = acl_queue_handlers_.begin(); acl_queue_handler != acl_queue_handlers_.end();
185        acl_queue_handler = std::next(acl_queue_handler)) {
186     if (acl_queue_handler->second.dequeue_is_registered_) {
187       acl_queue_handler->second.dequeue_is_registered_ = false;
188       acl_queue_handler->second.queue_->GetDownEnd()->UnregisterDequeue();
189     }
190   }
191 }
192 
send_next_fragment()193 void RoundRobinScheduler::send_next_fragment() {
194   if (!enqueue_registered_.exchange(true)) {
195     hci_queue_end_->RegisterEnqueue(
196         handler_, common::Bind(&RoundRobinScheduler::handle_enqueue_next_fragment, common::Unretained(this)));
197   }
198 }
199 
200 // Invoked from some external Queue Reactable context 1
handle_enqueue_next_fragment()201 std::unique_ptr<AclBuilder> RoundRobinScheduler::handle_enqueue_next_fragment() {
202   ConnectionType connection_type = fragments_to_send_.front().first;
203   if (connection_type == ConnectionType::CLASSIC) {
204     log::assert_that(acl_packet_credits_ > 0, "assert failed: acl_packet_credits_ > 0");
205     acl_packet_credits_ -= 1;
206   } else {
207     log::assert_that(le_acl_packet_credits_ > 0, "assert failed: le_acl_packet_credits_ > 0");
208     le_acl_packet_credits_ -= 1;
209   }
210 
211   auto raw_pointer = fragments_to_send_.front().second.release();
212   fragments_to_send_.pop();
213   if (fragments_to_send_.empty()) {
214     if (enqueue_registered_.exchange(false)) {
215       hci_queue_end_->UnregisterEnqueue();
216     }
217     handler_->Post(common::BindOnce(&RoundRobinScheduler::start_round_robin, common::Unretained(this)));
218   } else {
219     ConnectionType next_connection_type = fragments_to_send_.front().first;
220     bool classic_buffer_full = next_connection_type == ConnectionType::CLASSIC && acl_packet_credits_ == 0;
221     bool le_buffer_full = next_connection_type == ConnectionType::LE && le_acl_packet_credits_ == 0;
222     if ((classic_buffer_full || le_buffer_full) && enqueue_registered_.exchange(false)) {
223       hci_queue_end_->UnregisterEnqueue();
224     }
225   }
226   return std::unique_ptr<AclBuilder>(raw_pointer);
227 }
228 
incoming_acl_credits(uint16_t handle,uint16_t credits)229 void RoundRobinScheduler::incoming_acl_credits(uint16_t handle, uint16_t credits) {
230   auto acl_queue_handler = acl_queue_handlers_.find(handle);
231   if (acl_queue_handler == acl_queue_handlers_.end()) {
232     return;
233   }
234 
235   if (acl_queue_handler->second.number_of_sent_packets_ >= credits) {
236     acl_queue_handler->second.number_of_sent_packets_ -= credits;
237   } else {
238     log::warn("receive more credits than we sent");
239     acl_queue_handler->second.number_of_sent_packets_ = 0;
240   }
241 
242   bool credit_was_zero = false;
243   if (acl_queue_handler->second.connection_type_ == ConnectionType::CLASSIC) {
244     if (acl_packet_credits_ == 0) {
245       credit_was_zero = true;
246     }
247     acl_packet_credits_ += credits;
248     if (acl_packet_credits_ > max_acl_packet_credits_) {
249       acl_packet_credits_ = max_acl_packet_credits_;
250       log::warn("acl packet credits overflow due to receive {} credits", credits);
251     }
252   } else {
253     if (le_acl_packet_credits_ == 0) {
254       credit_was_zero = true;
255     }
256     le_acl_packet_credits_ += credits;
257     if (le_acl_packet_credits_ > le_max_acl_packet_credits_) {
258       le_acl_packet_credits_ = le_max_acl_packet_credits_;
259       log::warn("le acl packet credits overflow due to receive {} credits", credits);
260     }
261   }
262   if (credit_was_zero) {
263     start_round_robin();
264   }
265 }
266 
267 }  // namespace acl_manager
268 }  // namespace hci
269 }  // namespace bluetooth
270