Loading system/gd/hci/acl_manager.cc +52 −1 Original line number Diff line number Diff line Loading @@ -103,6 +103,9 @@ struct AclManager::impl { classic_impl_ = nullptr; } unknown_acl_alarm_.reset(); waiting_packets_.clear(); delete round_robin_scheduler_; hci_queue_end_ = nullptr; handler_ = nullptr; Loading @@ -110,8 +113,44 @@ struct AclManager::impl { acl_scheduler_ = nullptr; } void retry_unknown_acl(bool timed_out) { std::vector<AclView> unsent_packets; for (const auto& itr : waiting_packets_) { auto handle = itr.GetHandle(); if (!classic_impl_->send_packet_upward( handle, [itr](struct acl_manager::assembler* assembler) { assembler->on_incoming_packet(itr); }) && !le_impl_->send_packet_upward(handle, [itr](struct acl_manager::assembler* assembler) { assembler->on_incoming_packet(itr); })) { if (!timed_out) { unsent_packets.push_back(itr); } else { LOG_ERROR( "Dropping packet of size %zu to unknown connection 0x%0hx", itr.size(), itr.GetHandle()); } } } waiting_packets_ = std::move(unsent_packets); } static void on_unknown_acl_timer(struct AclManager::impl* impl) { LOG_INFO("Timer fired!"); impl->retry_unknown_acl(/* timed_out = */ true); impl->unknown_acl_alarm_.reset(); } // Invoked from some external Queue Reactable context 2 void dequeue_and_route_acl_packet_to_connection() { // Retry any waiting packets first if (!waiting_packets_.empty()) { retry_unknown_acl(/* timed_out = */ false); } auto packet = hci_queue_end_->TryDequeue(); ASSERT(packet != nullptr); if (!packet->IsValid()) { Loading @@ -126,7 +165,16 @@ struct AclManager::impl { if (le_impl_->send_packet_upward( handle, [&packet](struct acl_manager::assembler* assembler) { assembler->on_incoming_packet(*packet); })) return; LOG_INFO("Dropping packet of size %zu to unknown connection 0x%0hx", packet->size(), packet->GetHandle()); if (unknown_acl_alarm_ == nullptr) { unknown_acl_alarm_.reset(new os::Alarm(handler_)); } waiting_packets_.push_back(*packet); LOG_INFO( "Saving packet of size %zu to unknown connection 0x%0hx", packet->size(), packet->GetHandle()); unknown_acl_alarm_->Schedule( BindOnce(&on_unknown_acl_timer, common::Unretained(this)), kWaitBeforeDroppingUnknownAcl); } void Dump( Loading @@ -146,6 +194,9 @@ struct AclManager::impl { std::atomic_bool enqueue_registered_ = false; uint16_t default_link_policy_settings_ = 0xffff; mutable std::mutex dumpsys_mutex_; std::unique_ptr<os::Alarm> unknown_acl_alarm_; std::vector<AclView> waiting_packets_; static constexpr std::chrono::seconds kWaitBeforeDroppingUnknownAcl{1}; }; AclManager::AclManager() : pimpl_(std::make_unique<impl>(*this)) {} Loading system/gd/hci/acl_manager_test.cc +70 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include "hci/controller.h" #include "hci/hci_layer.h" #include "hci/hci_layer_fake.h" #include "os/fake_timer/fake_timerfd.h" #include "os/thread.h" #include "packet/raw_builder.h" Loading @@ -44,6 +45,7 @@ namespace { using common::BidiQueue; using common::BidiQueueEnd; using os::fake_timer::fake_timerfd_advance; using packet::kLittleEndian; using packet::PacketView; using packet::RawBuilder; Loading Loading @@ -405,6 +407,11 @@ class AclManagerWithLeConnectionTest : public AclManagerTest { } }); if (send_early_acl_) { LOG_INFO("Sending a packet with handle 0x%02x (0x%d)", handle_, handle_); test_hci_layer_->IncomingAclData(handle_); } test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( ErrorCode::SUCCESS, handle_, Loading Loading @@ -438,11 +445,20 @@ class AclManagerWithLeConnectionTest : public AclManagerTest { } uint16_t handle_ = 0x123; bool send_early_acl_ = false; std::shared_ptr<LeAclConnection> connection_; AddressWithType remote_with_type_; MockLeConnectionManagementCallbacks mock_le_connection_management_callbacks_; }; class AclManagerWithLateLeConnectionTest : public AclManagerWithLeConnectionTest { protected: void SetUp() override { send_early_acl_ = true; AclManagerWithLeConnectionTest::SetUp(); } }; // TODO: implement version of this test where controller supports Extended Advertising Feature in // GetLeLocalSupportedFeatures, and LE Extended Create Connection is used TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_connection_complete_success) { Loading Loading @@ -705,6 +721,60 @@ TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_queue_disco sync_client_handler(); } TEST_F(AclManagerWithLateLeConnectionTest, and_receive_nothing) {} TEST_F(AclManagerWithLateLeConnectionTest, receive_acl) { client_handler_->Post(common::BindOnce(fake_timerfd_advance, 1200)); auto queue_end = connection_->GetAclQueueEnd(); std::unique_ptr<PacketView<kLittleEndian>> received; do { received = queue_end->TryDequeue(); } while (received == nullptr); { ASSERT_EQ(received->size(), 10u); auto itr = received->begin(); ASSERT_EQ(itr.extract<uint16_t>(), 6u); // L2CAP PDU size ASSERT_EQ(itr.extract<uint16_t>(), 2u); // L2CAP CID ASSERT_EQ(itr.extract<uint16_t>(), handle_); ASSERT_GE(itr.extract<uint32_t>(), 0u); // packet number } } TEST_F(AclManagerWithLateLeConnectionTest, receive_acl_in_order) { // Send packet #2 from HCI (the first was sent in the test) test_hci_layer_->IncomingAclData(handle_); auto queue_end = connection_->GetAclQueueEnd(); std::unique_ptr<PacketView<kLittleEndian>> received; do { received = queue_end->TryDequeue(); } while (received == nullptr); uint32_t first_packet_number = 0; { ASSERT_EQ(received->size(), 10u); auto itr = received->begin(); ASSERT_EQ(itr.extract<uint16_t>(), 6u); // L2CAP PDU size ASSERT_EQ(itr.extract<uint16_t>(), 2u); // L2CAP CID ASSERT_EQ(itr.extract<uint16_t>(), handle_); first_packet_number = itr.extract<uint32_t>(); } do { received = queue_end->TryDequeue(); } while (received == nullptr); { ASSERT_EQ(received->size(), 10u); auto itr = received->begin(); ASSERT_EQ(itr.extract<uint16_t>(), 6u); // L2CAP PDU size ASSERT_EQ(itr.extract<uint16_t>(), 2u); // L2CAP CID ASSERT_EQ(itr.extract<uint16_t>(), handle_); ASSERT_GT(itr.extract<uint32_t>(), first_packet_number); } } TEST_F(AclManagerWithConnectionTest, invoke_registered_callback_disconnection_complete) { auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION; EXPECT_CALL(mock_connection_management_callbacks_, OnDisconnection(reason)); Loading Loading
system/gd/hci/acl_manager.cc +52 −1 Original line number Diff line number Diff line Loading @@ -103,6 +103,9 @@ struct AclManager::impl { classic_impl_ = nullptr; } unknown_acl_alarm_.reset(); waiting_packets_.clear(); delete round_robin_scheduler_; hci_queue_end_ = nullptr; handler_ = nullptr; Loading @@ -110,8 +113,44 @@ struct AclManager::impl { acl_scheduler_ = nullptr; } void retry_unknown_acl(bool timed_out) { std::vector<AclView> unsent_packets; for (const auto& itr : waiting_packets_) { auto handle = itr.GetHandle(); if (!classic_impl_->send_packet_upward( handle, [itr](struct acl_manager::assembler* assembler) { assembler->on_incoming_packet(itr); }) && !le_impl_->send_packet_upward(handle, [itr](struct acl_manager::assembler* assembler) { assembler->on_incoming_packet(itr); })) { if (!timed_out) { unsent_packets.push_back(itr); } else { LOG_ERROR( "Dropping packet of size %zu to unknown connection 0x%0hx", itr.size(), itr.GetHandle()); } } } waiting_packets_ = std::move(unsent_packets); } static void on_unknown_acl_timer(struct AclManager::impl* impl) { LOG_INFO("Timer fired!"); impl->retry_unknown_acl(/* timed_out = */ true); impl->unknown_acl_alarm_.reset(); } // Invoked from some external Queue Reactable context 2 void dequeue_and_route_acl_packet_to_connection() { // Retry any waiting packets first if (!waiting_packets_.empty()) { retry_unknown_acl(/* timed_out = */ false); } auto packet = hci_queue_end_->TryDequeue(); ASSERT(packet != nullptr); if (!packet->IsValid()) { Loading @@ -126,7 +165,16 @@ struct AclManager::impl { if (le_impl_->send_packet_upward( handle, [&packet](struct acl_manager::assembler* assembler) { assembler->on_incoming_packet(*packet); })) return; LOG_INFO("Dropping packet of size %zu to unknown connection 0x%0hx", packet->size(), packet->GetHandle()); if (unknown_acl_alarm_ == nullptr) { unknown_acl_alarm_.reset(new os::Alarm(handler_)); } waiting_packets_.push_back(*packet); LOG_INFO( "Saving packet of size %zu to unknown connection 0x%0hx", packet->size(), packet->GetHandle()); unknown_acl_alarm_->Schedule( BindOnce(&on_unknown_acl_timer, common::Unretained(this)), kWaitBeforeDroppingUnknownAcl); } void Dump( Loading @@ -146,6 +194,9 @@ struct AclManager::impl { std::atomic_bool enqueue_registered_ = false; uint16_t default_link_policy_settings_ = 0xffff; mutable std::mutex dumpsys_mutex_; std::unique_ptr<os::Alarm> unknown_acl_alarm_; std::vector<AclView> waiting_packets_; static constexpr std::chrono::seconds kWaitBeforeDroppingUnknownAcl{1}; }; AclManager::AclManager() : pimpl_(std::make_unique<impl>(*this)) {} Loading
system/gd/hci/acl_manager_test.cc +70 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include "hci/controller.h" #include "hci/hci_layer.h" #include "hci/hci_layer_fake.h" #include "os/fake_timer/fake_timerfd.h" #include "os/thread.h" #include "packet/raw_builder.h" Loading @@ -44,6 +45,7 @@ namespace { using common::BidiQueue; using common::BidiQueueEnd; using os::fake_timer::fake_timerfd_advance; using packet::kLittleEndian; using packet::PacketView; using packet::RawBuilder; Loading Loading @@ -405,6 +407,11 @@ class AclManagerWithLeConnectionTest : public AclManagerTest { } }); if (send_early_acl_) { LOG_INFO("Sending a packet with handle 0x%02x (0x%d)", handle_, handle_); test_hci_layer_->IncomingAclData(handle_); } test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( ErrorCode::SUCCESS, handle_, Loading Loading @@ -438,11 +445,20 @@ class AclManagerWithLeConnectionTest : public AclManagerTest { } uint16_t handle_ = 0x123; bool send_early_acl_ = false; std::shared_ptr<LeAclConnection> connection_; AddressWithType remote_with_type_; MockLeConnectionManagementCallbacks mock_le_connection_management_callbacks_; }; class AclManagerWithLateLeConnectionTest : public AclManagerWithLeConnectionTest { protected: void SetUp() override { send_early_acl_ = true; AclManagerWithLeConnectionTest::SetUp(); } }; // TODO: implement version of this test where controller supports Extended Advertising Feature in // GetLeLocalSupportedFeatures, and LE Extended Create Connection is used TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_connection_complete_success) { Loading Loading @@ -705,6 +721,60 @@ TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_queue_disco sync_client_handler(); } TEST_F(AclManagerWithLateLeConnectionTest, and_receive_nothing) {} TEST_F(AclManagerWithLateLeConnectionTest, receive_acl) { client_handler_->Post(common::BindOnce(fake_timerfd_advance, 1200)); auto queue_end = connection_->GetAclQueueEnd(); std::unique_ptr<PacketView<kLittleEndian>> received; do { received = queue_end->TryDequeue(); } while (received == nullptr); { ASSERT_EQ(received->size(), 10u); auto itr = received->begin(); ASSERT_EQ(itr.extract<uint16_t>(), 6u); // L2CAP PDU size ASSERT_EQ(itr.extract<uint16_t>(), 2u); // L2CAP CID ASSERT_EQ(itr.extract<uint16_t>(), handle_); ASSERT_GE(itr.extract<uint32_t>(), 0u); // packet number } } TEST_F(AclManagerWithLateLeConnectionTest, receive_acl_in_order) { // Send packet #2 from HCI (the first was sent in the test) test_hci_layer_->IncomingAclData(handle_); auto queue_end = connection_->GetAclQueueEnd(); std::unique_ptr<PacketView<kLittleEndian>> received; do { received = queue_end->TryDequeue(); } while (received == nullptr); uint32_t first_packet_number = 0; { ASSERT_EQ(received->size(), 10u); auto itr = received->begin(); ASSERT_EQ(itr.extract<uint16_t>(), 6u); // L2CAP PDU size ASSERT_EQ(itr.extract<uint16_t>(), 2u); // L2CAP CID ASSERT_EQ(itr.extract<uint16_t>(), handle_); first_packet_number = itr.extract<uint32_t>(); } do { received = queue_end->TryDequeue(); } while (received == nullptr); { ASSERT_EQ(received->size(), 10u); auto itr = received->begin(); ASSERT_EQ(itr.extract<uint16_t>(), 6u); // L2CAP PDU size ASSERT_EQ(itr.extract<uint16_t>(), 2u); // L2CAP CID ASSERT_EQ(itr.extract<uint16_t>(), handle_); ASSERT_GT(itr.extract<uint32_t>(), first_packet_number); } } TEST_F(AclManagerWithConnectionTest, invoke_registered_callback_disconnection_complete) { auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION; EXPECT_CALL(mock_connection_management_callbacks_, OnDisconnection(reason)); Loading