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