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