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