Loading system/gd/l2cap/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ filegroup { "classic/internal/dynamic_channel_service_manager_test.cc", "classic/internal/fixed_channel_impl_test.cc", "classic/internal/fixed_channel_service_manager_test.cc", "classic/internal/link_test.cc", "classic/internal/link_manager_test.cc", "classic/internal/signalling_manager_test.cc", "internal/basic_mode_channel_data_controller_test.cc", Loading system/gd/l2cap/classic/internal/link.cc +20 −4 Original line number Diff line number Diff line Loading @@ -47,8 +47,18 @@ Link::Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_c } void Link::OnAclDisconnected(hci::ErrorCode status) { signalling_manager_.CancelAlarm(); fixed_channel_allocator_.OnAclDisconnected(status); dynamic_channel_allocator_.OnAclDisconnected(status); DynamicChannelManager::ConnectionResult result{ .connection_result_code = DynamicChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = status, .l2cap_connection_response_result = ConnectionResponseResult::SUCCESS, }; while (!local_cid_to_pending_dynamic_channel_connection_map_.empty()) { auto entry = local_cid_to_pending_dynamic_channel_connection_map_.begin(); NotifyChannelFail(entry->first, result); } } void Link::Disconnect() { Loading Loading @@ -96,7 +106,15 @@ void Link::SendConnectionRequest(Psm psm, Cid local_cid, } void Link::OnOutgoingConnectionRequestFail(Cid local_cid) { local_cid_to_pending_dynamic_channel_connection_map_.erase(local_cid); if (local_cid_to_pending_dynamic_channel_connection_map_.find(local_cid) != local_cid_to_pending_dynamic_channel_connection_map_.end()) { DynamicChannelManager::ConnectionResult result{ .connection_result_code = DynamicChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = hci::ErrorCode::CONNECTION_TIMEOUT, .l2cap_connection_response_result = ConnectionResponseResult::SUCCESS, }; NotifyChannelFail(local_cid, result); } dynamic_channel_allocator_.FreeChannel(local_cid); } Loading Loading @@ -169,12 +187,10 @@ void Link::NotifyChannelCreation(Cid cid, std::unique_ptr<DynamicChannel> user_c local_cid_to_pending_dynamic_channel_connection_map_.erase(cid); } void Link::NotifyChannelFail(Cid cid) { void Link::NotifyChannelFail(Cid cid, DynamicChannelManager::ConnectionResult result) { ASSERT(local_cid_to_pending_dynamic_channel_connection_map_.find(cid) != local_cid_to_pending_dynamic_channel_connection_map_.end()); auto& pending_dynamic_channel_connection = local_cid_to_pending_dynamic_channel_connection_map_[cid]; // TODO(cmanton) Pass proper connection falure result to user DynamicChannelManager::ConnectionResult result; pending_dynamic_channel_connection.handler_->Post( common::BindOnce(std::move(pending_dynamic_channel_connection.on_fail_callback_), result)); local_cid_to_pending_dynamic_channel_connection_map_.erase(cid); Loading system/gd/l2cap/classic/internal/link.h +1 −1 Original line number Diff line number Diff line Loading @@ -108,7 +108,7 @@ class Link : public l2cap::internal::ILink { virtual void RefreshRefCount(); virtual void NotifyChannelCreation(Cid cid, std::unique_ptr<DynamicChannel> channel); virtual void NotifyChannelFail(Cid cid); virtual void NotifyChannelFail(Cid cid, DynamicChannelManager::ConnectionResult result); // Information received from signaling channel virtual void SetRemoteConnectionlessMtu(Mtu mtu); Loading system/gd/l2cap/classic/internal/link_test.cc 0 → 100644 +137 −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 "l2cap/classic/internal/link.h" #include "hci/acl_manager_mock.h" #include "hci/address.h" #include "l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h" #include "l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h" #include "l2cap/internal/parameter_provider_mock.h" #include <gmock/gmock-nice-strict.h> #include <gmock/gmock.h> #include <gtest/gtest.h> using ::testing::NiceMock; namespace bluetooth { namespace l2cap { namespace classic { namespace internal { namespace { constexpr Psm kPsm = 123; constexpr Cid kCid = 456; using classic::internal::testing::MockDynamicChannelServiceManagerImpl; using hci::testing::MockAclConnection; using l2cap::internal::testing::MockParameterProvider; using testing::MockFixedChannelServiceManagerImpl; class L2capClassicLinkTest : public ::testing::Test { public: void OnOpen(std::unique_ptr<DynamicChannel> channel) { on_open_promise_.set_value(); } void OnFail(DynamicChannelManager::ConnectionResult result) { on_fail_promise_.set_value(); } void OnDequeueCallbackForTest() { std::unique_ptr<BasePacketBuilder> data = raw_acl_connection_->acl_queue_.GetDownEnd()->TryDequeue(); if (data != nullptr) { dequeue_promise_.set_value(); } } void EnqueueCallbackForTest() { raw_acl_connection_->acl_queue_.GetDownEnd()->RegisterDequeue( handler_, common::Bind(&L2capClassicLinkTest::OnDequeueCallbackForTest, common::Unretained(this))); } void DequeueCallback() { raw_acl_connection_->acl_queue_.GetDownEnd()->UnregisterDequeue(); } protected: void SetUp() override { thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL); handler_ = new os::Handler(thread_); signalling_handler_ = new os::Handler(thread_); raw_acl_connection_ = new NiceMock<MockAclConnection>(); link_ = new Link(signalling_handler_, std::unique_ptr<MockAclConnection>(raw_acl_connection_), &mock_parameter_provider_, &mock_classic_dynamic_channel_service_manager_, &mock_classic_fixed_channel_service_manager_); } void TearDown() override { delete link_; signalling_handler_->Clear(); delete signalling_handler_; handler_->Clear(); delete handler_; delete thread_; } os::Thread* thread_ = nullptr; os::Handler* handler_ = nullptr; os::Handler* signalling_handler_ = nullptr; MockAclConnection* raw_acl_connection_ = nullptr; std::unique_ptr<MockAclConnection> acl_connection_; NiceMock<MockParameterProvider> mock_parameter_provider_; MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager_; MockDynamicChannelServiceManagerImpl mock_classic_dynamic_channel_service_manager_; std::promise<void> on_open_promise_; std::promise<void> on_fail_promise_; std::promise<void> dequeue_promise_; Link* link_; }; TEST_F(L2capClassicLinkTest, pending_channels_get_notified_on_acl_disconnect) { EnqueueCallbackForTest(); Link::PendingDynamicChannelConnection pending_dynamic_channel_connection{ .handler_ = handler_, .on_open_callback_ = common::Bind(&L2capClassicLinkTest::OnOpen, common::Unretained(this)), .on_fail_callback_ = common::Bind(&L2capClassicLinkTest::OnFail, common::Unretained(this)), .configuration_ = DynamicChannelConfigurationOption(), }; auto future = on_fail_promise_.get_future(); link_->SendConnectionRequest(kPsm, kCid, std::move(pending_dynamic_channel_connection)); link_->OnAclDisconnected(hci::ErrorCode::UNKNOWN_HCI_COMMAND); future.wait(); auto dequeue_future = dequeue_promise_.get_future(); dequeue_future.wait(); DequeueCallback(); } } // namespace } // namespace internal } // namespace classic } // namespace l2cap } // namespace bluetooth system/gd/l2cap/classic/internal/signalling_manager.cc +4 −0 Original line number Diff line number Diff line Loading @@ -111,6 +111,10 @@ void ClassicSignallingManager::SendEchoRequest(std::unique_ptr<packet::RawBuilde LOG_WARN("Not supported"); } void ClassicSignallingManager::CancelAlarm() { alarm_.Cancel(); } void ClassicSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid) { if (!IsPsmValid(psm)) { LOG_WARN("Invalid psm received from remote psm:%d remote_cid:%d", psm, remote_cid); Loading Loading
system/gd/l2cap/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ filegroup { "classic/internal/dynamic_channel_service_manager_test.cc", "classic/internal/fixed_channel_impl_test.cc", "classic/internal/fixed_channel_service_manager_test.cc", "classic/internal/link_test.cc", "classic/internal/link_manager_test.cc", "classic/internal/signalling_manager_test.cc", "internal/basic_mode_channel_data_controller_test.cc", Loading
system/gd/l2cap/classic/internal/link.cc +20 −4 Original line number Diff line number Diff line Loading @@ -47,8 +47,18 @@ Link::Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_c } void Link::OnAclDisconnected(hci::ErrorCode status) { signalling_manager_.CancelAlarm(); fixed_channel_allocator_.OnAclDisconnected(status); dynamic_channel_allocator_.OnAclDisconnected(status); DynamicChannelManager::ConnectionResult result{ .connection_result_code = DynamicChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = status, .l2cap_connection_response_result = ConnectionResponseResult::SUCCESS, }; while (!local_cid_to_pending_dynamic_channel_connection_map_.empty()) { auto entry = local_cid_to_pending_dynamic_channel_connection_map_.begin(); NotifyChannelFail(entry->first, result); } } void Link::Disconnect() { Loading Loading @@ -96,7 +106,15 @@ void Link::SendConnectionRequest(Psm psm, Cid local_cid, } void Link::OnOutgoingConnectionRequestFail(Cid local_cid) { local_cid_to_pending_dynamic_channel_connection_map_.erase(local_cid); if (local_cid_to_pending_dynamic_channel_connection_map_.find(local_cid) != local_cid_to_pending_dynamic_channel_connection_map_.end()) { DynamicChannelManager::ConnectionResult result{ .connection_result_code = DynamicChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = hci::ErrorCode::CONNECTION_TIMEOUT, .l2cap_connection_response_result = ConnectionResponseResult::SUCCESS, }; NotifyChannelFail(local_cid, result); } dynamic_channel_allocator_.FreeChannel(local_cid); } Loading Loading @@ -169,12 +187,10 @@ void Link::NotifyChannelCreation(Cid cid, std::unique_ptr<DynamicChannel> user_c local_cid_to_pending_dynamic_channel_connection_map_.erase(cid); } void Link::NotifyChannelFail(Cid cid) { void Link::NotifyChannelFail(Cid cid, DynamicChannelManager::ConnectionResult result) { ASSERT(local_cid_to_pending_dynamic_channel_connection_map_.find(cid) != local_cid_to_pending_dynamic_channel_connection_map_.end()); auto& pending_dynamic_channel_connection = local_cid_to_pending_dynamic_channel_connection_map_[cid]; // TODO(cmanton) Pass proper connection falure result to user DynamicChannelManager::ConnectionResult result; pending_dynamic_channel_connection.handler_->Post( common::BindOnce(std::move(pending_dynamic_channel_connection.on_fail_callback_), result)); local_cid_to_pending_dynamic_channel_connection_map_.erase(cid); Loading
system/gd/l2cap/classic/internal/link.h +1 −1 Original line number Diff line number Diff line Loading @@ -108,7 +108,7 @@ class Link : public l2cap::internal::ILink { virtual void RefreshRefCount(); virtual void NotifyChannelCreation(Cid cid, std::unique_ptr<DynamicChannel> channel); virtual void NotifyChannelFail(Cid cid); virtual void NotifyChannelFail(Cid cid, DynamicChannelManager::ConnectionResult result); // Information received from signaling channel virtual void SetRemoteConnectionlessMtu(Mtu mtu); Loading
system/gd/l2cap/classic/internal/link_test.cc 0 → 100644 +137 −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 "l2cap/classic/internal/link.h" #include "hci/acl_manager_mock.h" #include "hci/address.h" #include "l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h" #include "l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h" #include "l2cap/internal/parameter_provider_mock.h" #include <gmock/gmock-nice-strict.h> #include <gmock/gmock.h> #include <gtest/gtest.h> using ::testing::NiceMock; namespace bluetooth { namespace l2cap { namespace classic { namespace internal { namespace { constexpr Psm kPsm = 123; constexpr Cid kCid = 456; using classic::internal::testing::MockDynamicChannelServiceManagerImpl; using hci::testing::MockAclConnection; using l2cap::internal::testing::MockParameterProvider; using testing::MockFixedChannelServiceManagerImpl; class L2capClassicLinkTest : public ::testing::Test { public: void OnOpen(std::unique_ptr<DynamicChannel> channel) { on_open_promise_.set_value(); } void OnFail(DynamicChannelManager::ConnectionResult result) { on_fail_promise_.set_value(); } void OnDequeueCallbackForTest() { std::unique_ptr<BasePacketBuilder> data = raw_acl_connection_->acl_queue_.GetDownEnd()->TryDequeue(); if (data != nullptr) { dequeue_promise_.set_value(); } } void EnqueueCallbackForTest() { raw_acl_connection_->acl_queue_.GetDownEnd()->RegisterDequeue( handler_, common::Bind(&L2capClassicLinkTest::OnDequeueCallbackForTest, common::Unretained(this))); } void DequeueCallback() { raw_acl_connection_->acl_queue_.GetDownEnd()->UnregisterDequeue(); } protected: void SetUp() override { thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL); handler_ = new os::Handler(thread_); signalling_handler_ = new os::Handler(thread_); raw_acl_connection_ = new NiceMock<MockAclConnection>(); link_ = new Link(signalling_handler_, std::unique_ptr<MockAclConnection>(raw_acl_connection_), &mock_parameter_provider_, &mock_classic_dynamic_channel_service_manager_, &mock_classic_fixed_channel_service_manager_); } void TearDown() override { delete link_; signalling_handler_->Clear(); delete signalling_handler_; handler_->Clear(); delete handler_; delete thread_; } os::Thread* thread_ = nullptr; os::Handler* handler_ = nullptr; os::Handler* signalling_handler_ = nullptr; MockAclConnection* raw_acl_connection_ = nullptr; std::unique_ptr<MockAclConnection> acl_connection_; NiceMock<MockParameterProvider> mock_parameter_provider_; MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager_; MockDynamicChannelServiceManagerImpl mock_classic_dynamic_channel_service_manager_; std::promise<void> on_open_promise_; std::promise<void> on_fail_promise_; std::promise<void> dequeue_promise_; Link* link_; }; TEST_F(L2capClassicLinkTest, pending_channels_get_notified_on_acl_disconnect) { EnqueueCallbackForTest(); Link::PendingDynamicChannelConnection pending_dynamic_channel_connection{ .handler_ = handler_, .on_open_callback_ = common::Bind(&L2capClassicLinkTest::OnOpen, common::Unretained(this)), .on_fail_callback_ = common::Bind(&L2capClassicLinkTest::OnFail, common::Unretained(this)), .configuration_ = DynamicChannelConfigurationOption(), }; auto future = on_fail_promise_.get_future(); link_->SendConnectionRequest(kPsm, kCid, std::move(pending_dynamic_channel_connection)); link_->OnAclDisconnected(hci::ErrorCode::UNKNOWN_HCI_COMMAND); future.wait(); auto dequeue_future = dequeue_promise_.get_future(); dequeue_future.wait(); DequeueCallback(); } } // namespace } // namespace internal } // namespace classic } // namespace l2cap } // namespace bluetooth
system/gd/l2cap/classic/internal/signalling_manager.cc +4 −0 Original line number Diff line number Diff line Loading @@ -111,6 +111,10 @@ void ClassicSignallingManager::SendEchoRequest(std::unique_ptr<packet::RawBuilde LOG_WARN("Not supported"); } void ClassicSignallingManager::CancelAlarm() { alarm_.Cancel(); } void ClassicSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid) { if (!IsPsmValid(psm)) { LOG_WARN("Invalid psm received from remote psm:%d remote_cid:%d", psm, remote_cid); Loading