Loading system/gd/hci/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ filegroup { "hci_layer.cc", "le_advertising_manager.cc", "le_scanning_manager.cc", "round_robin_scheduler.cc", ], } Loading system/gd/hci/acl_manager.cc +18 −141 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include "hci/acl_fragmenter.h" #include "hci/controller.h" #include "hci/hci_layer.h" #include "hci/round_robin_scheduler.h" #include "security/security_module.h" namespace bluetooth { Loading Loading @@ -77,10 +78,6 @@ struct AclManager::acl_connection { // For LE Connection parameter update from L2CAP common::OnceCallback<void(ErrorCode)> on_connection_update_complete_callback_; os::Handler* on_connection_update_complete_callback_handler_ = nullptr; // Round-robin: Track if dequeue is registered for this connection bool is_registered_ = false; // Credits: Track the number of packets which have been sent to the controller uint16_t number_of_sent_packets_ = 0; PacketViewForRecombination recombination_stage_{std::make_shared<std::vector<uint8_t>>()}; int remaining_sdu_continuation_packet_size_ = 0; std::atomic_bool enqueue_registered_ = false; Loading Loading @@ -162,11 +159,7 @@ struct AclManager::impl : public security::ISecurityManagerListener { hci_layer_ = acl_manager_.GetDependency<HciLayer>(); handler_ = acl_manager_.GetHandler(); controller_ = acl_manager_.GetDependency<Controller>(); max_acl_packet_credits_ = controller_->GetControllerNumAclPacketBuffers(); acl_packet_credits_ = max_acl_packet_credits_; acl_buffer_length_ = controller_->GetControllerAclPacketLength(); controller_->RegisterCompletedAclPacketsCallback( common::Bind(&impl::incoming_acl_credits, common::Unretained(this)), handler_); round_robin_scheduler_ = new RoundRobinScheduler(handler_, controller_, hci_layer_->GetAclQueueEnd()); // TODO: determine when we should reject connection should_accept_connection_ = common::Bind([](Address, ClassOfDevice) { return true; }); Loading Loading @@ -216,7 +209,6 @@ struct AclManager::impl : public security::ISecurityManagerListener { hci_layer_->RegisterEventHandler(EventCode::LINK_SUPERVISION_TIMEOUT_CHANGED, Bind(&impl::on_link_supervision_timeout_changed, common::Unretained(this)), handler_); hci_mtu_ = controller_->GetControllerAclPacketLength(); } void Stop() { Loading @@ -227,11 +219,10 @@ struct AclManager::impl : public security::ISecurityManagerListener { hci_layer_->UnregisterEventHandler(EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE); hci_layer_->UnregisterEventHandler(EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE); hci_queue_end_->UnregisterDequeue(); unregister_all_connections(); delete round_robin_scheduler_; if (enqueue_registered_.exchange(false)) { hci_queue_end_->UnregisterEnqueue(); } controller_->UnregisterCompletedAclPacketsCallback(); acl_connections_.clear(); hci_queue_end_ = nullptr; handler_ = nullptr; Loading @@ -239,111 +230,6 @@ struct AclManager::impl : public security::ISecurityManagerListener { security_manager_.reset(); } void incoming_acl_credits(uint16_t handle, uint16_t credits) { auto connection_pair = acl_connections_.find(handle); if (connection_pair == acl_connections_.end()) { LOG_INFO("Dropping %hx received credits to unknown connection 0x%0hx", credits, handle); return; } if (connection_pair->second.is_disconnected_) { LOG_INFO("Dropping %hx received credits to disconnected connection 0x%0hx", credits, handle); return; } connection_pair->second.number_of_sent_packets_ -= credits; acl_packet_credits_ += credits; ASSERT(acl_packet_credits_ <= max_acl_packet_credits_); if (acl_packet_credits_ == credits) { start_round_robin(); } } // Round-robin scheduler void start_round_robin() { if (acl_packet_credits_ == 0) { return; } if (!fragments_to_send_.empty()) { send_next_fragment(); return; } for (auto connection_pair = acl_connections_.begin(); connection_pair != acl_connections_.end(); connection_pair = std::next(connection_pair)) { if (connection_pair->second.is_registered_) { continue; } connection_pair->second.is_registered_ = true; connection_pair->second.queue_->GetDownEnd()->RegisterDequeue( handler_, common::Bind(&impl::handle_dequeue_from_upper, common::Unretained(this), connection_pair)); } } void handle_dequeue_from_upper(std::map<uint16_t, acl_connection>::iterator connection_pair) { current_connection_pair_ = connection_pair; buffer_packet(); } void unregister_all_connections() { for (auto connection_pair = acl_connections_.begin(); connection_pair != acl_connections_.end(); connection_pair = std::next(connection_pair)) { if (connection_pair->second.is_registered_) { connection_pair->second.is_registered_ = false; connection_pair->second.queue_->GetDownEnd()->UnregisterDequeue(); } } } void buffer_packet() { unregister_all_connections(); BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT; // Wrap packet and enqueue it uint16_t handle = current_connection_pair_->first; auto packet = current_connection_pair_->second.queue_->GetDownEnd()->TryDequeue(); ASSERT(packet != nullptr); if (packet->size() <= hci_mtu_) { fragments_to_send_.push_front(AclPacketBuilder::Create(handle, PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, broadcast_flag, std::move(packet))); } else { auto fragments = AclFragmenter(hci_mtu_, std::move(packet)).GetFragments(); PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE; for (size_t i = 0; i < fragments.size(); i++) { fragments_to_send_.push_back( AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(fragments[i]))); packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT; } } ASSERT(fragments_to_send_.size() > 0); current_connection_pair_->second.number_of_sent_packets_ += fragments_to_send_.size(); send_next_fragment(); } void send_next_fragment() { if (!enqueue_registered_.exchange(true)) { hci_queue_end_->RegisterEnqueue(handler_, common::Bind(&impl::handle_enqueue_next_fragment, common::Unretained(this))); } } // Invoked from some external Queue Reactable context 1 std::unique_ptr<AclPacketBuilder> handle_enqueue_next_fragment() { ASSERT(acl_packet_credits_ > 0); if (acl_packet_credits_ == 1 || fragments_to_send_.size() == 1) { if (enqueue_registered_.exchange(false)) { hci_queue_end_->UnregisterEnqueue(); } if (fragments_to_send_.size() == 1) { handler_->Post(common::BindOnce(&impl::start_round_robin, common::Unretained(this))); } } ASSERT(fragments_to_send_.size() > 0); auto raw_pointer = fragments_to_send_.front().release(); acl_packet_credits_ -= 1; fragments_to_send_.pop_front(); return std::unique_ptr<AclPacketBuilder>(raw_pointer); } // Invoked from some external Queue Reactable context 2 void dequeue_and_route_acl_packet_to_connection() { auto packet = hci_queue_end_->TryDequeue(); Loading Loading @@ -424,9 +310,9 @@ struct AclManager::impl : public security::ISecurityManagerListener { ASSERT(acl_connections_.count(handle) == 0); acl_connections_.emplace(std::piecewise_construct, std::forward_as_tuple(handle), std::forward_as_tuple(address_with_type, handler_)); if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) { start_round_robin(); } hci_layer_->GetHciHandler()->Post(common::BindOnce(&RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), handle, check_and_get_connection(handle).queue_->GetDownEnd())); auto role = connection_complete.GetRole(); std::unique_ptr<AclConnection> connection_proxy( new AclConnection(&acl_manager_, handle, address, peer_address_type, role)); Loading Loading @@ -458,9 +344,9 @@ struct AclManager::impl : public security::ISecurityManagerListener { ASSERT(acl_connections_.count(handle) == 0); acl_connections_.emplace(std::piecewise_construct, std::forward_as_tuple(handle), std::forward_as_tuple(reporting_address_with_type, handler_)); if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) { start_round_robin(); } hci_layer_->GetHciHandler()->Post(common::BindOnce(&RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), handle, check_and_get_connection(handle).queue_->GetDownEnd())); auto role = connection_complete.GetRole(); std::unique_ptr<AclConnection> connection_proxy( new AclConnection(&acl_manager_, handle, address, peer_address_type, role)); Loading @@ -485,9 +371,9 @@ struct AclManager::impl : public security::ISecurityManagerListener { acl_connections_.emplace( std::piecewise_construct, std::forward_as_tuple(handle), std::forward_as_tuple(AddressWithType{address, AddressType::PUBLIC_DEVICE_ADDRESS}, handler_)); if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) { start_round_robin(); } hci_layer_->GetHciHandler()->Post(common::BindOnce(&RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), handle, check_and_get_connection(handle).queue_->GetDownEnd())); std::unique_ptr<AclConnection> connection_proxy(new AclConnection(&acl_manager_, handle, address)); client_handler_->Post(common::BindOnce(&ConnectionCallbacks::OnConnectSuccess, common::Unretained(client_callbacks_), std::move(connection_proxy))); Loading Loading @@ -516,11 +402,10 @@ struct AclManager::impl : public security::ISecurityManagerListener { ASSERT(acl_connections_.count(handle) == 1); auto& acl_connection = acl_connections_.find(handle)->second; acl_connection.is_disconnected_ = true; hci_layer_->GetHciHandler()->Post( common::BindOnce(&RoundRobinScheduler::SetDisconnect, common::Unretained(round_robin_scheduler_), handle)); acl_connection.disconnect_reason_ = disconnection_complete.GetReason(); acl_connection.call_disconnect_callback(); // Reclaim outstanding packets acl_packet_credits_ += acl_connection.number_of_sent_packets_; acl_connection.number_of_sent_packets_ = 0; } else { std::string error_code = ErrorCodeText(status); LOG_ERROR("Received disconnection complete with error code %s, handle 0x%02hx", error_code.c_str(), handle); Loading Loading @@ -1482,11 +1367,7 @@ struct AclManager::impl : public security::ISecurityManagerListener { void cleanup(uint16_t handle) { ASSERT(acl_connections_.count(handle) == 1); auto& acl_connection = acl_connections_.find(handle)->second; if (acl_connection.is_registered_) { acl_connection.is_registered_ = false; acl_connection.queue_->GetDownEnd()->UnregisterDequeue(); } acl_connections_.erase(handle); } Loading Loading @@ -1906,6 +1787,8 @@ struct AclManager::impl : public security::ISecurityManagerListener { void Finish(uint16_t handle) { auto& connection = check_and_get_connection(handle); ASSERT_LOG(connection.is_disconnected_, "Finish must be invoked after disconnection (handle 0x%04hx)", handle); hci_layer_->GetHciHandler()->Post( common::BindOnce(&RoundRobinScheduler::Unregister, common::Unretained(round_robin_scheduler_), handle)); handler_->Post(BindOnce(&impl::cleanup, common::Unretained(this), handle)); } Loading @@ -1915,14 +1798,9 @@ struct AclManager::impl : public security::ISecurityManagerListener { static constexpr uint16_t kMaximumCeLength = 0x0C00; Controller* controller_ = nullptr; uint16_t max_acl_packet_credits_ = 0; uint16_t acl_packet_credits_ = 0; uint16_t acl_buffer_length_ = 0; std::list<std::unique_ptr<AclPacketBuilder>> fragments_to_send_; std::map<uint16_t, acl_connection>::iterator current_connection_pair_; HciLayer* hci_layer_ = nullptr; RoundRobinScheduler* round_robin_scheduler_ = nullptr; std::unique_ptr<security::SecurityManager> security_manager_; os::Handler* handler_ = nullptr; ConnectionCallbacks* client_callbacks_ = nullptr; Loading @@ -1940,7 +1818,6 @@ struct AclManager::impl : public security::ISecurityManagerListener { std::set<AddressWithType> connecting_le_; common::Callback<bool(Address, ClassOfDevice)> should_accept_connection_; std::queue<std::pair<Address, std::unique_ptr<CreateConnectionBuilder>>> pending_outgoing_connections_; size_t hci_mtu_{0}; }; AclConnection::QueueUpEnd* AclConnection::GetAclQueueEnd() const { Loading system/gd/hci/hci_layer.cc +4 −0 Original line number Diff line number Diff line Loading @@ -578,6 +578,10 @@ void HciLayer::ListDependencies(ModuleList* list) { list->add<hal::HciHal>(); } os::Handler* HciLayer::GetHciHandler() { return GetHandler(); } void HciLayer::Start() { impl_->Start(GetDependency<hal::HciHal>()); } Loading system/gd/hci/hci_layer.h +2 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,8 @@ class HciLayer : public Module { void Stop() override; os::Handler* GetHciHandler(); std::string ToString() const override; static constexpr std::chrono::milliseconds kHciTimeoutMs = std::chrono::milliseconds(2000); Loading system/gd/hci/round_robin_scheduler.cc 0 → 100644 +174 −0 Original line number Diff line number Diff line /* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "hci/round_robin_scheduler.h" #include "hci/acl_fragmenter.h" namespace bluetooth { namespace hci { RoundRobinScheduler::RoundRobinScheduler(os::Handler* handler, Controller* controller, common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* hci_queue_end) : handler_(handler), controller_(controller), hci_queue_end_(hci_queue_end) { max_acl_packet_credits_ = controller_->GetControllerNumAclPacketBuffers(); acl_packet_credits_ = max_acl_packet_credits_; hci_mtu_ = controller_->GetControllerAclPacketLength(); controller_->RegisterCompletedAclPacketsCallback( common::Bind(&RoundRobinScheduler::IncomingAclCredits, common::Unretained(this)), handler_); } RoundRobinScheduler::~RoundRobinScheduler() { UnregisterAllConnections(); controller_->UnregisterCompletedAclPacketsCallback(); } void RoundRobinScheduler::Register(uint16_t handle, AclConnection::QueueDownEnd* queue_down_end) { acl_queue_handler acl_queue_handler = {queue_down_end, false, 0, false}; acl_queue_handlers_.insert(std::pair<uint16_t, RoundRobinScheduler::acl_queue_handler>(handle, acl_queue_handler)); if (fragments_to_send_.size() == 0) { StartRoundRobin(); } } void RoundRobinScheduler::Unregister(uint16_t handle) { ASSERT(acl_queue_handlers_.count(handle) == 1); auto acl_queue_handler = acl_queue_handlers_.find(handle)->second; if (acl_queue_handler.dequeue_is_registered_) { acl_queue_handler.dequeue_is_registered_ = false; acl_queue_handler.queue_down_end_->UnregisterDequeue(); } acl_queue_handlers_.erase(handle); starting_point_ = acl_queue_handlers_.begin(); } void RoundRobinScheduler::SetDisconnect(uint16_t handle) { auto acl_queue_handler = acl_queue_handlers_.find(handle)->second; acl_queue_handler.is_disconnected_ = true; // Reclaim outstanding packets acl_packet_credits_ += acl_queue_handler.number_of_sent_packets_; acl_queue_handler.number_of_sent_packets_ = 0; } void RoundRobinScheduler::StartRoundRobin() { if (acl_packet_credits_ == 0) { return; } if (!fragments_to_send_.empty()) { SendNextFragment(); return; } if (acl_queue_handlers_.size() == 1 || starting_point_ == acl_queue_handlers_.end()) { starting_point_ = acl_queue_handlers_.begin(); } size_t count = acl_queue_handlers_.size(); for (auto acl_queue_handler = starting_point_; count > 0; count--) { if (!acl_queue_handler->second.dequeue_is_registered_) { acl_queue_handler->second.dequeue_is_registered_ = true; acl_queue_handler->second.queue_down_end_->RegisterDequeue( handler_, common::Bind(&RoundRobinScheduler::BufferPacket, common::Unretained(this), acl_queue_handler)); } acl_queue_handler = std::next(acl_queue_handler); if (acl_queue_handler == acl_queue_handlers_.end()) { acl_queue_handler = acl_queue_handlers_.begin(); } } starting_point_ = std::next(starting_point_); } void RoundRobinScheduler::BufferPacket(std::map<uint16_t, acl_queue_handler>::iterator acl_queue_handler) { BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT; // Wrap packet and enqueue it uint16_t handle = acl_queue_handler->first; auto packet = acl_queue_handler->second.queue_down_end_->TryDequeue(); ASSERT(packet != nullptr); if (packet->size() <= hci_mtu_) { fragments_to_send_.push(AclPacketBuilder::Create(handle, PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, broadcast_flag, std::move(packet))); } else { auto fragments = AclFragmenter(hci_mtu_, std::move(packet)).GetFragments(); PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE; for (size_t i = 0; i < fragments.size(); i++) { fragments_to_send_.push( AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(fragments[i]))); packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT; } } ASSERT(fragments_to_send_.size() > 0); UnregisterAllConnections(); acl_queue_handler->second.number_of_sent_packets_ += fragments_to_send_.size(); SendNextFragment(); } void RoundRobinScheduler::UnregisterAllConnections() { for (auto acl_queue_handler = acl_queue_handlers_.begin(); acl_queue_handler != acl_queue_handlers_.end(); acl_queue_handler = std::next(acl_queue_handler)) { if (acl_queue_handler->second.dequeue_is_registered_) { acl_queue_handler->second.dequeue_is_registered_ = false; acl_queue_handler->second.queue_down_end_->UnregisterDequeue(); } } } void RoundRobinScheduler::SendNextFragment() { if (!enqueue_registered_.exchange(true)) { hci_queue_end_->RegisterEnqueue( handler_, common::Bind(&RoundRobinScheduler::HandleEnqueueNextFragment, common::Unretained(this))); } } // Invoked from some external Queue Reactable context 1 std::unique_ptr<AclPacketBuilder> RoundRobinScheduler::HandleEnqueueNextFragment() { ASSERT(acl_packet_credits_ > 0); if (acl_packet_credits_ == 1 || fragments_to_send_.size() == 1) { if (enqueue_registered_.exchange(false)) { hci_queue_end_->UnregisterEnqueue(); } } ASSERT(fragments_to_send_.size() > 0); auto raw_pointer = fragments_to_send_.front().release(); acl_packet_credits_ -= 1; fragments_to_send_.pop(); if (fragments_to_send_.empty()) { handler_->Post(common::BindOnce(&RoundRobinScheduler::StartRoundRobin, common::Unretained(this))); } return std::unique_ptr<AclPacketBuilder>(raw_pointer); } void RoundRobinScheduler::IncomingAclCredits(uint16_t handle, uint16_t credits) { auto acl_queue_handler = acl_queue_handlers_.find(handle); if (acl_queue_handler == acl_queue_handlers_.end()) { LOG_INFO("Dropping %hx received credits to unknown connection 0x%0hx", credits, handle); return; } if (acl_queue_handler->second.is_disconnected_) { LOG_INFO("Dropping %hx received credits to disconnected connection 0x%0hx", credits, handle); return; } acl_queue_handler->second.number_of_sent_packets_ -= credits; acl_packet_credits_ += credits; ASSERT(acl_packet_credits_ <= max_acl_packet_credits_); if (acl_packet_credits_ == credits) { StartRoundRobin(); } } } // namespace hci } // namespace bluetooth No newline at end of file Loading
system/gd/hci/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ filegroup { "hci_layer.cc", "le_advertising_manager.cc", "le_scanning_manager.cc", "round_robin_scheduler.cc", ], } Loading
system/gd/hci/acl_manager.cc +18 −141 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include "hci/acl_fragmenter.h" #include "hci/controller.h" #include "hci/hci_layer.h" #include "hci/round_robin_scheduler.h" #include "security/security_module.h" namespace bluetooth { Loading Loading @@ -77,10 +78,6 @@ struct AclManager::acl_connection { // For LE Connection parameter update from L2CAP common::OnceCallback<void(ErrorCode)> on_connection_update_complete_callback_; os::Handler* on_connection_update_complete_callback_handler_ = nullptr; // Round-robin: Track if dequeue is registered for this connection bool is_registered_ = false; // Credits: Track the number of packets which have been sent to the controller uint16_t number_of_sent_packets_ = 0; PacketViewForRecombination recombination_stage_{std::make_shared<std::vector<uint8_t>>()}; int remaining_sdu_continuation_packet_size_ = 0; std::atomic_bool enqueue_registered_ = false; Loading Loading @@ -162,11 +159,7 @@ struct AclManager::impl : public security::ISecurityManagerListener { hci_layer_ = acl_manager_.GetDependency<HciLayer>(); handler_ = acl_manager_.GetHandler(); controller_ = acl_manager_.GetDependency<Controller>(); max_acl_packet_credits_ = controller_->GetControllerNumAclPacketBuffers(); acl_packet_credits_ = max_acl_packet_credits_; acl_buffer_length_ = controller_->GetControllerAclPacketLength(); controller_->RegisterCompletedAclPacketsCallback( common::Bind(&impl::incoming_acl_credits, common::Unretained(this)), handler_); round_robin_scheduler_ = new RoundRobinScheduler(handler_, controller_, hci_layer_->GetAclQueueEnd()); // TODO: determine when we should reject connection should_accept_connection_ = common::Bind([](Address, ClassOfDevice) { return true; }); Loading Loading @@ -216,7 +209,6 @@ struct AclManager::impl : public security::ISecurityManagerListener { hci_layer_->RegisterEventHandler(EventCode::LINK_SUPERVISION_TIMEOUT_CHANGED, Bind(&impl::on_link_supervision_timeout_changed, common::Unretained(this)), handler_); hci_mtu_ = controller_->GetControllerAclPacketLength(); } void Stop() { Loading @@ -227,11 +219,10 @@ struct AclManager::impl : public security::ISecurityManagerListener { hci_layer_->UnregisterEventHandler(EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE); hci_layer_->UnregisterEventHandler(EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE); hci_queue_end_->UnregisterDequeue(); unregister_all_connections(); delete round_robin_scheduler_; if (enqueue_registered_.exchange(false)) { hci_queue_end_->UnregisterEnqueue(); } controller_->UnregisterCompletedAclPacketsCallback(); acl_connections_.clear(); hci_queue_end_ = nullptr; handler_ = nullptr; Loading @@ -239,111 +230,6 @@ struct AclManager::impl : public security::ISecurityManagerListener { security_manager_.reset(); } void incoming_acl_credits(uint16_t handle, uint16_t credits) { auto connection_pair = acl_connections_.find(handle); if (connection_pair == acl_connections_.end()) { LOG_INFO("Dropping %hx received credits to unknown connection 0x%0hx", credits, handle); return; } if (connection_pair->second.is_disconnected_) { LOG_INFO("Dropping %hx received credits to disconnected connection 0x%0hx", credits, handle); return; } connection_pair->second.number_of_sent_packets_ -= credits; acl_packet_credits_ += credits; ASSERT(acl_packet_credits_ <= max_acl_packet_credits_); if (acl_packet_credits_ == credits) { start_round_robin(); } } // Round-robin scheduler void start_round_robin() { if (acl_packet_credits_ == 0) { return; } if (!fragments_to_send_.empty()) { send_next_fragment(); return; } for (auto connection_pair = acl_connections_.begin(); connection_pair != acl_connections_.end(); connection_pair = std::next(connection_pair)) { if (connection_pair->second.is_registered_) { continue; } connection_pair->second.is_registered_ = true; connection_pair->second.queue_->GetDownEnd()->RegisterDequeue( handler_, common::Bind(&impl::handle_dequeue_from_upper, common::Unretained(this), connection_pair)); } } void handle_dequeue_from_upper(std::map<uint16_t, acl_connection>::iterator connection_pair) { current_connection_pair_ = connection_pair; buffer_packet(); } void unregister_all_connections() { for (auto connection_pair = acl_connections_.begin(); connection_pair != acl_connections_.end(); connection_pair = std::next(connection_pair)) { if (connection_pair->second.is_registered_) { connection_pair->second.is_registered_ = false; connection_pair->second.queue_->GetDownEnd()->UnregisterDequeue(); } } } void buffer_packet() { unregister_all_connections(); BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT; // Wrap packet and enqueue it uint16_t handle = current_connection_pair_->first; auto packet = current_connection_pair_->second.queue_->GetDownEnd()->TryDequeue(); ASSERT(packet != nullptr); if (packet->size() <= hci_mtu_) { fragments_to_send_.push_front(AclPacketBuilder::Create(handle, PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, broadcast_flag, std::move(packet))); } else { auto fragments = AclFragmenter(hci_mtu_, std::move(packet)).GetFragments(); PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE; for (size_t i = 0; i < fragments.size(); i++) { fragments_to_send_.push_back( AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(fragments[i]))); packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT; } } ASSERT(fragments_to_send_.size() > 0); current_connection_pair_->second.number_of_sent_packets_ += fragments_to_send_.size(); send_next_fragment(); } void send_next_fragment() { if (!enqueue_registered_.exchange(true)) { hci_queue_end_->RegisterEnqueue(handler_, common::Bind(&impl::handle_enqueue_next_fragment, common::Unretained(this))); } } // Invoked from some external Queue Reactable context 1 std::unique_ptr<AclPacketBuilder> handle_enqueue_next_fragment() { ASSERT(acl_packet_credits_ > 0); if (acl_packet_credits_ == 1 || fragments_to_send_.size() == 1) { if (enqueue_registered_.exchange(false)) { hci_queue_end_->UnregisterEnqueue(); } if (fragments_to_send_.size() == 1) { handler_->Post(common::BindOnce(&impl::start_round_robin, common::Unretained(this))); } } ASSERT(fragments_to_send_.size() > 0); auto raw_pointer = fragments_to_send_.front().release(); acl_packet_credits_ -= 1; fragments_to_send_.pop_front(); return std::unique_ptr<AclPacketBuilder>(raw_pointer); } // Invoked from some external Queue Reactable context 2 void dequeue_and_route_acl_packet_to_connection() { auto packet = hci_queue_end_->TryDequeue(); Loading Loading @@ -424,9 +310,9 @@ struct AclManager::impl : public security::ISecurityManagerListener { ASSERT(acl_connections_.count(handle) == 0); acl_connections_.emplace(std::piecewise_construct, std::forward_as_tuple(handle), std::forward_as_tuple(address_with_type, handler_)); if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) { start_round_robin(); } hci_layer_->GetHciHandler()->Post(common::BindOnce(&RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), handle, check_and_get_connection(handle).queue_->GetDownEnd())); auto role = connection_complete.GetRole(); std::unique_ptr<AclConnection> connection_proxy( new AclConnection(&acl_manager_, handle, address, peer_address_type, role)); Loading Loading @@ -458,9 +344,9 @@ struct AclManager::impl : public security::ISecurityManagerListener { ASSERT(acl_connections_.count(handle) == 0); acl_connections_.emplace(std::piecewise_construct, std::forward_as_tuple(handle), std::forward_as_tuple(reporting_address_with_type, handler_)); if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) { start_round_robin(); } hci_layer_->GetHciHandler()->Post(common::BindOnce(&RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), handle, check_and_get_connection(handle).queue_->GetDownEnd())); auto role = connection_complete.GetRole(); std::unique_ptr<AclConnection> connection_proxy( new AclConnection(&acl_manager_, handle, address, peer_address_type, role)); Loading @@ -485,9 +371,9 @@ struct AclManager::impl : public security::ISecurityManagerListener { acl_connections_.emplace( std::piecewise_construct, std::forward_as_tuple(handle), std::forward_as_tuple(AddressWithType{address, AddressType::PUBLIC_DEVICE_ADDRESS}, handler_)); if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) { start_round_robin(); } hci_layer_->GetHciHandler()->Post(common::BindOnce(&RoundRobinScheduler::Register, common::Unretained(round_robin_scheduler_), handle, check_and_get_connection(handle).queue_->GetDownEnd())); std::unique_ptr<AclConnection> connection_proxy(new AclConnection(&acl_manager_, handle, address)); client_handler_->Post(common::BindOnce(&ConnectionCallbacks::OnConnectSuccess, common::Unretained(client_callbacks_), std::move(connection_proxy))); Loading Loading @@ -516,11 +402,10 @@ struct AclManager::impl : public security::ISecurityManagerListener { ASSERT(acl_connections_.count(handle) == 1); auto& acl_connection = acl_connections_.find(handle)->second; acl_connection.is_disconnected_ = true; hci_layer_->GetHciHandler()->Post( common::BindOnce(&RoundRobinScheduler::SetDisconnect, common::Unretained(round_robin_scheduler_), handle)); acl_connection.disconnect_reason_ = disconnection_complete.GetReason(); acl_connection.call_disconnect_callback(); // Reclaim outstanding packets acl_packet_credits_ += acl_connection.number_of_sent_packets_; acl_connection.number_of_sent_packets_ = 0; } else { std::string error_code = ErrorCodeText(status); LOG_ERROR("Received disconnection complete with error code %s, handle 0x%02hx", error_code.c_str(), handle); Loading Loading @@ -1482,11 +1367,7 @@ struct AclManager::impl : public security::ISecurityManagerListener { void cleanup(uint16_t handle) { ASSERT(acl_connections_.count(handle) == 1); auto& acl_connection = acl_connections_.find(handle)->second; if (acl_connection.is_registered_) { acl_connection.is_registered_ = false; acl_connection.queue_->GetDownEnd()->UnregisterDequeue(); } acl_connections_.erase(handle); } Loading Loading @@ -1906,6 +1787,8 @@ struct AclManager::impl : public security::ISecurityManagerListener { void Finish(uint16_t handle) { auto& connection = check_and_get_connection(handle); ASSERT_LOG(connection.is_disconnected_, "Finish must be invoked after disconnection (handle 0x%04hx)", handle); hci_layer_->GetHciHandler()->Post( common::BindOnce(&RoundRobinScheduler::Unregister, common::Unretained(round_robin_scheduler_), handle)); handler_->Post(BindOnce(&impl::cleanup, common::Unretained(this), handle)); } Loading @@ -1915,14 +1798,9 @@ struct AclManager::impl : public security::ISecurityManagerListener { static constexpr uint16_t kMaximumCeLength = 0x0C00; Controller* controller_ = nullptr; uint16_t max_acl_packet_credits_ = 0; uint16_t acl_packet_credits_ = 0; uint16_t acl_buffer_length_ = 0; std::list<std::unique_ptr<AclPacketBuilder>> fragments_to_send_; std::map<uint16_t, acl_connection>::iterator current_connection_pair_; HciLayer* hci_layer_ = nullptr; RoundRobinScheduler* round_robin_scheduler_ = nullptr; std::unique_ptr<security::SecurityManager> security_manager_; os::Handler* handler_ = nullptr; ConnectionCallbacks* client_callbacks_ = nullptr; Loading @@ -1940,7 +1818,6 @@ struct AclManager::impl : public security::ISecurityManagerListener { std::set<AddressWithType> connecting_le_; common::Callback<bool(Address, ClassOfDevice)> should_accept_connection_; std::queue<std::pair<Address, std::unique_ptr<CreateConnectionBuilder>>> pending_outgoing_connections_; size_t hci_mtu_{0}; }; AclConnection::QueueUpEnd* AclConnection::GetAclQueueEnd() const { Loading
system/gd/hci/hci_layer.cc +4 −0 Original line number Diff line number Diff line Loading @@ -578,6 +578,10 @@ void HciLayer::ListDependencies(ModuleList* list) { list->add<hal::HciHal>(); } os::Handler* HciLayer::GetHciHandler() { return GetHandler(); } void HciLayer::Start() { impl_->Start(GetDependency<hal::HciHal>()); } Loading
system/gd/hci/hci_layer.h +2 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,8 @@ class HciLayer : public Module { void Stop() override; os::Handler* GetHciHandler(); std::string ToString() const override; static constexpr std::chrono::milliseconds kHciTimeoutMs = std::chrono::milliseconds(2000); Loading
system/gd/hci/round_robin_scheduler.cc 0 → 100644 +174 −0 Original line number Diff line number Diff line /* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "hci/round_robin_scheduler.h" #include "hci/acl_fragmenter.h" namespace bluetooth { namespace hci { RoundRobinScheduler::RoundRobinScheduler(os::Handler* handler, Controller* controller, common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* hci_queue_end) : handler_(handler), controller_(controller), hci_queue_end_(hci_queue_end) { max_acl_packet_credits_ = controller_->GetControllerNumAclPacketBuffers(); acl_packet_credits_ = max_acl_packet_credits_; hci_mtu_ = controller_->GetControllerAclPacketLength(); controller_->RegisterCompletedAclPacketsCallback( common::Bind(&RoundRobinScheduler::IncomingAclCredits, common::Unretained(this)), handler_); } RoundRobinScheduler::~RoundRobinScheduler() { UnregisterAllConnections(); controller_->UnregisterCompletedAclPacketsCallback(); } void RoundRobinScheduler::Register(uint16_t handle, AclConnection::QueueDownEnd* queue_down_end) { acl_queue_handler acl_queue_handler = {queue_down_end, false, 0, false}; acl_queue_handlers_.insert(std::pair<uint16_t, RoundRobinScheduler::acl_queue_handler>(handle, acl_queue_handler)); if (fragments_to_send_.size() == 0) { StartRoundRobin(); } } void RoundRobinScheduler::Unregister(uint16_t handle) { ASSERT(acl_queue_handlers_.count(handle) == 1); auto acl_queue_handler = acl_queue_handlers_.find(handle)->second; if (acl_queue_handler.dequeue_is_registered_) { acl_queue_handler.dequeue_is_registered_ = false; acl_queue_handler.queue_down_end_->UnregisterDequeue(); } acl_queue_handlers_.erase(handle); starting_point_ = acl_queue_handlers_.begin(); } void RoundRobinScheduler::SetDisconnect(uint16_t handle) { auto acl_queue_handler = acl_queue_handlers_.find(handle)->second; acl_queue_handler.is_disconnected_ = true; // Reclaim outstanding packets acl_packet_credits_ += acl_queue_handler.number_of_sent_packets_; acl_queue_handler.number_of_sent_packets_ = 0; } void RoundRobinScheduler::StartRoundRobin() { if (acl_packet_credits_ == 0) { return; } if (!fragments_to_send_.empty()) { SendNextFragment(); return; } if (acl_queue_handlers_.size() == 1 || starting_point_ == acl_queue_handlers_.end()) { starting_point_ = acl_queue_handlers_.begin(); } size_t count = acl_queue_handlers_.size(); for (auto acl_queue_handler = starting_point_; count > 0; count--) { if (!acl_queue_handler->second.dequeue_is_registered_) { acl_queue_handler->second.dequeue_is_registered_ = true; acl_queue_handler->second.queue_down_end_->RegisterDequeue( handler_, common::Bind(&RoundRobinScheduler::BufferPacket, common::Unretained(this), acl_queue_handler)); } acl_queue_handler = std::next(acl_queue_handler); if (acl_queue_handler == acl_queue_handlers_.end()) { acl_queue_handler = acl_queue_handlers_.begin(); } } starting_point_ = std::next(starting_point_); } void RoundRobinScheduler::BufferPacket(std::map<uint16_t, acl_queue_handler>::iterator acl_queue_handler) { BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT; // Wrap packet and enqueue it uint16_t handle = acl_queue_handler->first; auto packet = acl_queue_handler->second.queue_down_end_->TryDequeue(); ASSERT(packet != nullptr); if (packet->size() <= hci_mtu_) { fragments_to_send_.push(AclPacketBuilder::Create(handle, PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, broadcast_flag, std::move(packet))); } else { auto fragments = AclFragmenter(hci_mtu_, std::move(packet)).GetFragments(); PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE; for (size_t i = 0; i < fragments.size(); i++) { fragments_to_send_.push( AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(fragments[i]))); packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT; } } ASSERT(fragments_to_send_.size() > 0); UnregisterAllConnections(); acl_queue_handler->second.number_of_sent_packets_ += fragments_to_send_.size(); SendNextFragment(); } void RoundRobinScheduler::UnregisterAllConnections() { for (auto acl_queue_handler = acl_queue_handlers_.begin(); acl_queue_handler != acl_queue_handlers_.end(); acl_queue_handler = std::next(acl_queue_handler)) { if (acl_queue_handler->second.dequeue_is_registered_) { acl_queue_handler->second.dequeue_is_registered_ = false; acl_queue_handler->second.queue_down_end_->UnregisterDequeue(); } } } void RoundRobinScheduler::SendNextFragment() { if (!enqueue_registered_.exchange(true)) { hci_queue_end_->RegisterEnqueue( handler_, common::Bind(&RoundRobinScheduler::HandleEnqueueNextFragment, common::Unretained(this))); } } // Invoked from some external Queue Reactable context 1 std::unique_ptr<AclPacketBuilder> RoundRobinScheduler::HandleEnqueueNextFragment() { ASSERT(acl_packet_credits_ > 0); if (acl_packet_credits_ == 1 || fragments_to_send_.size() == 1) { if (enqueue_registered_.exchange(false)) { hci_queue_end_->UnregisterEnqueue(); } } ASSERT(fragments_to_send_.size() > 0); auto raw_pointer = fragments_to_send_.front().release(); acl_packet_credits_ -= 1; fragments_to_send_.pop(); if (fragments_to_send_.empty()) { handler_->Post(common::BindOnce(&RoundRobinScheduler::StartRoundRobin, common::Unretained(this))); } return std::unique_ptr<AclPacketBuilder>(raw_pointer); } void RoundRobinScheduler::IncomingAclCredits(uint16_t handle, uint16_t credits) { auto acl_queue_handler = acl_queue_handlers_.find(handle); if (acl_queue_handler == acl_queue_handlers_.end()) { LOG_INFO("Dropping %hx received credits to unknown connection 0x%0hx", credits, handle); return; } if (acl_queue_handler->second.is_disconnected_) { LOG_INFO("Dropping %hx received credits to disconnected connection 0x%0hx", credits, handle); return; } acl_queue_handler->second.number_of_sent_packets_ -= credits; acl_packet_credits_ += credits; ASSERT(acl_packet_credits_ <= max_acl_packet_credits_); if (acl_packet_credits_ == credits) { StartRoundRobin(); } } } // namespace hci } // namespace bluetooth No newline at end of file