You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
586 lines
30 KiB
586 lines
30 KiB
/*
|
|
* Copyright 2018 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/le/internal/link_manager.h"
|
|
|
|
#include <future>
|
|
#include <thread>
|
|
|
|
#include "common/bind.h"
|
|
#include "common/testing/bind_test_util.h"
|
|
#include "hci/acl_manager_mock.h"
|
|
#include "hci/address.h"
|
|
#include "l2cap/cid.h"
|
|
#include "l2cap/internal/parameter_provider_mock.h"
|
|
#include "l2cap/le/fixed_channel_manager.h"
|
|
#include "l2cap/le/internal/fixed_channel_service_impl_mock.h"
|
|
#include "l2cap/le/internal/fixed_channel_service_manager_impl_mock.h"
|
|
#include "os/handler.h"
|
|
#include "os/thread.h"
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
namespace bluetooth {
|
|
namespace l2cap {
|
|
namespace le {
|
|
namespace internal {
|
|
namespace {
|
|
|
|
using hci::testing::MockAclManager;
|
|
using hci::testing::MockLeAclConnection;
|
|
using l2cap::internal::testing::MockParameterProvider;
|
|
using ::testing::_; // Matcher to any value
|
|
using ::testing::ByMove;
|
|
using ::testing::DoAll;
|
|
using testing::MockFixedChannelServiceImpl;
|
|
using testing::MockFixedChannelServiceManagerImpl;
|
|
using ::testing::Return;
|
|
using ::testing::SaveArg;
|
|
|
|
constexpr static auto kTestIdleDisconnectTimeoutLong = std::chrono::milliseconds(1000);
|
|
constexpr static auto kTestIdleDisconnectTimeoutShort = std::chrono::milliseconds(1000);
|
|
|
|
class L2capLeLinkManagerTest : public ::testing::Test {
|
|
public:
|
|
static void SyncHandler(os::Handler* handler) {
|
|
std::promise<void> promise;
|
|
auto future = promise.get_future();
|
|
handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
|
|
future.wait_for(std::chrono::milliseconds(3));
|
|
}
|
|
|
|
protected:
|
|
void SetUp() override {
|
|
thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
|
|
l2cap_handler_ = new os::Handler(thread_);
|
|
user_handler_ = new os::Handler(thread_);
|
|
mock_parameter_provider_ = new MockParameterProvider;
|
|
EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
|
|
.WillRepeatedly(Return(kTestIdleDisconnectTimeoutLong));
|
|
}
|
|
|
|
void TearDown() override {
|
|
delete mock_parameter_provider_;
|
|
l2cap_handler_->Clear();
|
|
delete l2cap_handler_;
|
|
user_handler_->Clear();
|
|
delete user_handler_;
|
|
delete thread_;
|
|
}
|
|
|
|
os::Thread* thread_ = nullptr;
|
|
os::Handler* l2cap_handler_ = nullptr;
|
|
os::Handler* user_handler_ = nullptr;
|
|
MockParameterProvider* mock_parameter_provider_ = nullptr;
|
|
};
|
|
|
|
TEST_F(L2capLeLinkManagerTest, connect_fixed_channel_service_without_acl) {
|
|
MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
|
|
MockAclManager mock_acl_manager;
|
|
hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
|
|
hci::AddressType::RANDOM_DEVICE_ADDRESS);
|
|
|
|
// Step 1: Verify callback registration with HCI
|
|
hci::acl_manager::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
|
|
os::Handler* hci_callback_handler = nullptr;
|
|
EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
|
|
.WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
|
|
LinkManager le_link_manager(
|
|
l2cap_handler_,
|
|
&mock_acl_manager,
|
|
&mock_le_fixed_channel_service_manager,
|
|
nullptr,
|
|
mock_parameter_provider_);
|
|
EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
|
|
EXPECT_EQ(hci_callback_handler, l2cap_handler_);
|
|
|
|
// Register fake services
|
|
MockFixedChannelServiceImpl mock_service_1, mock_service_2;
|
|
std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
|
|
results.emplace_back(kSmpBrCid, &mock_service_1);
|
|
results.emplace_back(kConnectionlessCid, &mock_service_2);
|
|
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
|
|
|
|
// Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
|
|
EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(1);
|
|
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
|
|
.handler_ = user_handler_,
|
|
.on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
|
|
le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
|
|
|
|
// Step 3: ACL connection success event should trigger channel creation for all registered services
|
|
std::unique_ptr<MockLeAclConnection> acl_connection = std::make_unique<MockLeAclConnection>();
|
|
EXPECT_CALL(*acl_connection, GetRemoteAddress()).WillRepeatedly(Return(address_with_type));
|
|
hci::acl_manager::LeConnectionManagementCallbacks* connection_management_callbacks = nullptr;
|
|
os::Handler* connection_management_handler = nullptr;
|
|
EXPECT_CALL(*acl_connection, RegisterCallbacks(_, _))
|
|
.WillOnce(DoAll(SaveArg<0>(&connection_management_callbacks), SaveArg<1>(&connection_management_handler)));
|
|
std::unique_ptr<FixedChannel> channel_1, channel_2;
|
|
std::promise<void> promise_1, promise_2;
|
|
auto future_1 = promise_1.get_future();
|
|
auto future_2 = promise_2.get_future();
|
|
EXPECT_CALL(mock_service_1, NotifyChannelCreation(_))
|
|
.WillOnce([&channel_1, &promise_1](std::unique_ptr<FixedChannel> channel) {
|
|
channel_1 = std::move(channel);
|
|
promise_1.set_value();
|
|
});
|
|
EXPECT_CALL(mock_service_2, NotifyChannelCreation(_))
|
|
.WillOnce([&channel_2, &promise_2](std::unique_ptr<FixedChannel> channel) {
|
|
channel_2 = std::move(channel);
|
|
promise_2.set_value();
|
|
});
|
|
hci_callback_handler->Post(common::BindOnce(&hci::acl_manager::LeConnectionCallbacks::OnLeConnectSuccess,
|
|
common::Unretained(hci_le_connection_callbacks), address_with_type,
|
|
std::move(acl_connection)));
|
|
SyncHandler(hci_callback_handler);
|
|
connection_management_handler->Post(common::BindOnce(
|
|
&hci::acl_manager::LeConnectionManagementCallbacks::OnReadRemoteVersionInformationComplete,
|
|
common::Unretained(connection_management_callbacks),
|
|
hci::ErrorCode::SUCCESS,
|
|
0,
|
|
0,
|
|
0));
|
|
auto future_1_status = future_1.wait_for(kTestIdleDisconnectTimeoutShort);
|
|
EXPECT_EQ(future_1_status, std::future_status::ready);
|
|
auto future_2_status = future_2.wait_for(kTestIdleDisconnectTimeoutShort);
|
|
EXPECT_EQ(future_2_status, std::future_status::ready);
|
|
ASSERT_NE(channel_1, nullptr);
|
|
ASSERT_NE(channel_2, nullptr);
|
|
|
|
// Step 4: Calling ConnectServices() to the same device will not trigger another connection attempt
|
|
FixedChannelManager::ConnectionResult my_result;
|
|
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection_2{
|
|
.handler_ = user_handler_,
|
|
.on_fail_callback_ = common::testing::BindLambdaForTesting(
|
|
[&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
|
|
le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection_2));
|
|
SyncHandler(user_handler_);
|
|
EXPECT_EQ(my_result.connection_result_code,
|
|
FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL);
|
|
|
|
// Step 5: Register new service will cause new channels to be created during ConnectServices()
|
|
MockFixedChannelServiceImpl mock_service_3;
|
|
results.emplace_back(kSmpBrCid + 1, &mock_service_3);
|
|
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
|
|
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection_3{
|
|
.handler_ = user_handler_,
|
|
.on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
|
|
std::unique_ptr<FixedChannel> channel_3;
|
|
std::promise<void> promise_3;
|
|
auto future_3 = promise_3.get_future();
|
|
EXPECT_CALL(mock_service_3, NotifyChannelCreation(_))
|
|
.WillOnce([&channel_3, &promise_3](std::unique_ptr<FixedChannel> channel) {
|
|
channel_3 = std::move(channel);
|
|
promise_3.set_value();
|
|
});
|
|
le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection_3));
|
|
auto future_3_status = future_3.wait_for(kTestIdleDisconnectTimeoutShort);
|
|
EXPECT_EQ(future_3_status, std::future_status::ready);
|
|
EXPECT_NE(channel_3, nullptr);
|
|
|
|
connection_management_handler->Post(common::BindOnce(
|
|
&hci::acl_manager::LeConnectionManagementCallbacks::OnDisconnection,
|
|
common::Unretained(connection_management_callbacks), hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION));
|
|
SyncHandler(connection_management_handler);
|
|
}
|
|
|
|
TEST_F(L2capLeLinkManagerTest, connect_fixed_channel_service_without_acl_with_no_service) {
|
|
MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
|
|
MockAclManager mock_acl_manager;
|
|
hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
|
|
hci::AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
|
|
// Step 1: Verify callback registration with HCI
|
|
hci::acl_manager::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
|
|
os::Handler* hci_callback_handler = nullptr;
|
|
EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
|
|
.WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
|
|
LinkManager le_link_manager(
|
|
l2cap_handler_,
|
|
&mock_acl_manager,
|
|
&mock_le_fixed_channel_service_manager,
|
|
nullptr,
|
|
mock_parameter_provider_);
|
|
EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
|
|
EXPECT_EQ(hci_callback_handler, l2cap_handler_);
|
|
|
|
// Make sure no service is registered
|
|
std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
|
|
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
|
|
|
|
// Step 2: Connect to fixed channel without any service registered will result in failure
|
|
EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(0);
|
|
FixedChannelManager::ConnectionResult my_result;
|
|
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
|
|
.handler_ = user_handler_,
|
|
.on_fail_callback_ = common::testing::BindLambdaForTesting(
|
|
[&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
|
|
le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
|
|
SyncHandler(user_handler_);
|
|
EXPECT_EQ(my_result.connection_result_code, FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED);
|
|
|
|
}
|
|
|
|
TEST_F(L2capLeLinkManagerTest, connect_fixed_channel_service_without_acl_with_hci_failure) {
|
|
MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
|
|
MockAclManager mock_acl_manager;
|
|
hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
|
|
hci::AddressType::RANDOM_DEVICE_ADDRESS);
|
|
|
|
// Step 1: Verify callback registration with HCI
|
|
hci::acl_manager::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
|
|
os::Handler* hci_callback_handler = nullptr;
|
|
EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
|
|
.WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
|
|
LinkManager le_link_manager(
|
|
l2cap_handler_,
|
|
&mock_acl_manager,
|
|
&mock_le_fixed_channel_service_manager,
|
|
nullptr,
|
|
mock_parameter_provider_);
|
|
EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
|
|
EXPECT_EQ(hci_callback_handler, l2cap_handler_);
|
|
|
|
// Register fake services
|
|
MockFixedChannelServiceImpl mock_service_1;
|
|
std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
|
|
results.emplace_back(kSmpBrCid, &mock_service_1);
|
|
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
|
|
|
|
// Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
|
|
EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(1);
|
|
FixedChannelManager::ConnectionResult my_result;
|
|
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
|
|
.handler_ = user_handler_,
|
|
.on_fail_callback_ = common::testing::BindLambdaForTesting(
|
|
[&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
|
|
le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
|
|
|
|
// Step 3: ACL connection failure event should trigger connection failure callback
|
|
EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).Times(0);
|
|
hci_callback_handler->Post(common::BindOnce(&hci::acl_manager::LeConnectionCallbacks::OnLeConnectFail,
|
|
common::Unretained(hci_le_connection_callbacks), address_with_type,
|
|
hci::ErrorCode::PAGE_TIMEOUT));
|
|
SyncHandler(hci_callback_handler);
|
|
SyncHandler(user_handler_);
|
|
EXPECT_EQ(my_result.connection_result_code, FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR);
|
|
EXPECT_EQ(my_result.hci_error, hci::ErrorCode::PAGE_TIMEOUT);
|
|
}
|
|
|
|
TEST_F(L2capLeLinkManagerTest, not_acquiring_channels_should_disconnect_acl_after_timeout) {
|
|
EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
|
|
.WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
|
|
MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
|
|
MockAclManager mock_acl_manager;
|
|
hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
|
|
hci::AddressType::RANDOM_DEVICE_ADDRESS);
|
|
|
|
// Step 1: Verify callback registration with HCI
|
|
hci::acl_manager::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
|
|
os::Handler* hci_callback_handler = nullptr;
|
|
EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
|
|
.WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
|
|
LinkManager le_link_manager(
|
|
l2cap_handler_,
|
|
&mock_acl_manager,
|
|
&mock_le_fixed_channel_service_manager,
|
|
nullptr,
|
|
mock_parameter_provider_);
|
|
EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
|
|
EXPECT_EQ(hci_callback_handler, l2cap_handler_);
|
|
|
|
// Register fake services
|
|
MockFixedChannelServiceImpl mock_service_1, mock_service_2;
|
|
std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
|
|
results.emplace_back(kSmpBrCid, &mock_service_1);
|
|
results.emplace_back(kConnectionlessCid, &mock_service_2);
|
|
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
|
|
|
|
// Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
|
|
EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(1);
|
|
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
|
|
.handler_ = user_handler_,
|
|
.on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
|
|
le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
|
|
|
|
// Step 3: ACL connection success event should trigger channel creation for all registered services
|
|
auto* raw_acl_connection = new MockLeAclConnection();
|
|
std::unique_ptr<MockLeAclConnection> acl_connection(raw_acl_connection);
|
|
EXPECT_CALL(*acl_connection, GetRemoteAddress()).WillRepeatedly(Return(address_with_type));
|
|
hci::acl_manager::LeConnectionManagementCallbacks* connection_management_callbacks = nullptr;
|
|
os::Handler* connection_management_handler = nullptr;
|
|
EXPECT_CALL(*acl_connection, RegisterCallbacks(_, _))
|
|
.WillOnce(DoAll(SaveArg<0>(&connection_management_callbacks), SaveArg<1>(&connection_management_handler)));
|
|
std::unique_ptr<FixedChannel> channel_1, channel_2;
|
|
std::promise<void> promise_1, promise_2;
|
|
auto future_1 = promise_1.get_future();
|
|
auto future_2 = promise_2.get_future();
|
|
EXPECT_CALL(mock_service_1, NotifyChannelCreation(_))
|
|
.WillOnce([&channel_1, &promise_1](std::unique_ptr<FixedChannel> channel) {
|
|
channel_1 = std::move(channel);
|
|
promise_1.set_value();
|
|
});
|
|
EXPECT_CALL(mock_service_2, NotifyChannelCreation(_))
|
|
.WillOnce([&channel_2, &promise_2](std::unique_ptr<FixedChannel> channel) {
|
|
channel_2 = std::move(channel);
|
|
promise_2.set_value();
|
|
});
|
|
hci_callback_handler->Post(common::BindOnce(&hci::acl_manager::LeConnectionCallbacks::OnLeConnectSuccess,
|
|
common::Unretained(hci_le_connection_callbacks), address_with_type,
|
|
std::move(acl_connection)));
|
|
SyncHandler(hci_callback_handler);
|
|
connection_management_handler->Post(common::BindOnce(
|
|
&hci::acl_manager::LeConnectionManagementCallbacks::OnReadRemoteVersionInformationComplete,
|
|
common::Unretained(connection_management_callbacks),
|
|
hci::ErrorCode::SUCCESS,
|
|
0,
|
|
0,
|
|
0));
|
|
auto future_1_status = future_1.wait_for(kTestIdleDisconnectTimeoutShort);
|
|
EXPECT_EQ(future_1_status, std::future_status::ready);
|
|
EXPECT_NE(channel_1, nullptr);
|
|
auto future_2_status = future_2.wait_for(kTestIdleDisconnectTimeoutShort);
|
|
EXPECT_EQ(future_2_status, std::future_status::ready);
|
|
EXPECT_NE(channel_2, nullptr);
|
|
hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
|
|
channel_1->RegisterOnCloseCallback(
|
|
user_handler_, common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
|
|
hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
|
|
channel_2->RegisterOnCloseCallback(
|
|
user_handler_, common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
|
|
|
|
// Step 4: Leave channel IDLE long enough, they will disconnect
|
|
EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(1);
|
|
std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 1.2);
|
|
connection_management_handler->Post(common::BindOnce(
|
|
&hci::acl_manager::LeConnectionManagementCallbacks::OnDisconnection,
|
|
common::Unretained(connection_management_callbacks), hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST));
|
|
SyncHandler(connection_management_handler);
|
|
|
|
// Step 5: Link disconnect will trigger all callbacks
|
|
SyncHandler(user_handler_);
|
|
EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
|
|
EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
|
|
}
|
|
|
|
TEST_F(L2capLeLinkManagerTest, acquiring_channels_should_not_disconnect_acl_after_timeout) {
|
|
EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
|
|
.WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
|
|
MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
|
|
MockAclManager mock_acl_manager;
|
|
hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
|
|
hci::AddressType::RANDOM_DEVICE_ADDRESS);
|
|
|
|
// Step 1: Verify callback registration with HCI
|
|
hci::acl_manager::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
|
|
os::Handler* hci_callback_handler = nullptr;
|
|
EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
|
|
.WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
|
|
LinkManager le_link_manager(
|
|
l2cap_handler_,
|
|
&mock_acl_manager,
|
|
&mock_le_fixed_channel_service_manager,
|
|
nullptr,
|
|
mock_parameter_provider_);
|
|
EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
|
|
EXPECT_EQ(hci_callback_handler, l2cap_handler_);
|
|
|
|
// Register fake services
|
|
MockFixedChannelServiceImpl mock_service_1, mock_service_2;
|
|
std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
|
|
results.emplace_back(kSmpBrCid, &mock_service_1);
|
|
results.emplace_back(kConnectionlessCid, &mock_service_2);
|
|
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
|
|
|
|
// Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
|
|
EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(1);
|
|
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
|
|
.handler_ = user_handler_,
|
|
.on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
|
|
le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
|
|
|
|
// Step 3: ACL connection success event should trigger channel creation for all registered services
|
|
auto* raw_acl_connection = new MockLeAclConnection();
|
|
std::unique_ptr<MockLeAclConnection> acl_connection(raw_acl_connection);
|
|
EXPECT_CALL(*acl_connection, GetRemoteAddress()).WillRepeatedly(Return(address_with_type));
|
|
hci::acl_manager::LeConnectionManagementCallbacks* connection_management_callbacks = nullptr;
|
|
os::Handler* connection_management_handler = nullptr;
|
|
EXPECT_CALL(*acl_connection, RegisterCallbacks(_, _))
|
|
.WillOnce(DoAll(SaveArg<0>(&connection_management_callbacks), SaveArg<1>(&connection_management_handler)));
|
|
std::unique_ptr<FixedChannel> channel_1, channel_2;
|
|
std::promise<void> promise_1, promise_2;
|
|
auto future_1 = promise_1.get_future();
|
|
auto future_2 = promise_2.get_future();
|
|
EXPECT_CALL(mock_service_1, NotifyChannelCreation(_))
|
|
.WillOnce([&channel_1, &promise_1](std::unique_ptr<FixedChannel> channel) {
|
|
channel_1 = std::move(channel);
|
|
promise_1.set_value();
|
|
});
|
|
EXPECT_CALL(mock_service_2, NotifyChannelCreation(_))
|
|
.WillOnce([&channel_2, &promise_2](std::unique_ptr<FixedChannel> channel) {
|
|
channel_2 = std::move(channel);
|
|
promise_2.set_value();
|
|
});
|
|
hci_callback_handler->Post(common::BindOnce(&hci::acl_manager::LeConnectionCallbacks::OnLeConnectSuccess,
|
|
common::Unretained(hci_le_connection_callbacks), address_with_type,
|
|
std::move(acl_connection)));
|
|
SyncHandler(hci_callback_handler);
|
|
connection_management_handler->Post(common::BindOnce(
|
|
&hci::acl_manager::LeConnectionManagementCallbacks::OnReadRemoteVersionInformationComplete,
|
|
common::Unretained(connection_management_callbacks),
|
|
hci::ErrorCode::SUCCESS,
|
|
0,
|
|
0,
|
|
0));
|
|
auto future_1_status = future_1.wait_for(kTestIdleDisconnectTimeoutShort);
|
|
EXPECT_EQ(future_1_status, std::future_status::ready);
|
|
EXPECT_NE(channel_1, nullptr);
|
|
auto future_2_status = future_2.wait_for(kTestIdleDisconnectTimeoutShort);
|
|
EXPECT_EQ(future_2_status, std::future_status::ready);
|
|
EXPECT_NE(channel_2, nullptr);
|
|
hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
|
|
channel_1->RegisterOnCloseCallback(
|
|
user_handler_, common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
|
|
hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
|
|
channel_2->RegisterOnCloseCallback(
|
|
user_handler_, common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
|
|
|
|
channel_1->Acquire();
|
|
|
|
// Step 4: ave channel IDLE, it won't disconnect to due acquired channel 1
|
|
EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(0);
|
|
std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 2);
|
|
|
|
// Step 5: Link disconnect will trigger all callbacks
|
|
connection_management_handler->Post(common::BindOnce(
|
|
&hci::acl_manager::LeConnectionManagementCallbacks::OnDisconnection,
|
|
common::Unretained(connection_management_callbacks), hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST));
|
|
SyncHandler(connection_management_handler);
|
|
SyncHandler(user_handler_);
|
|
EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
|
|
EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
|
|
}
|
|
|
|
TEST_F(L2capLeLinkManagerTest, acquiring_and_releasing_channels_should_eventually_disconnect_acl) {
|
|
EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
|
|
.WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
|
|
MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
|
|
MockAclManager mock_acl_manager;
|
|
hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
|
|
hci::AddressType::PUBLIC_IDENTITY_ADDRESS);
|
|
|
|
// Step 1: Verify callback registration with HCI
|
|
hci::acl_manager::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
|
|
os::Handler* hci_callback_handler = nullptr;
|
|
EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
|
|
.WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
|
|
LinkManager le_link_manager(
|
|
l2cap_handler_,
|
|
&mock_acl_manager,
|
|
&mock_le_fixed_channel_service_manager,
|
|
nullptr,
|
|
mock_parameter_provider_);
|
|
EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
|
|
EXPECT_EQ(hci_callback_handler, l2cap_handler_);
|
|
|
|
// Register fake services
|
|
MockFixedChannelServiceImpl mock_service_1, mock_service_2;
|
|
std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
|
|
results.emplace_back(kSmpBrCid, &mock_service_1);
|
|
results.emplace_back(kConnectionlessCid, &mock_service_2);
|
|
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
|
|
|
|
// Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
|
|
EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(1);
|
|
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
|
|
.handler_ = user_handler_,
|
|
.on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
|
|
le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
|
|
|
|
// Step 3: ACL connection success event should trigger channel creation for all registered services
|
|
auto* raw_acl_connection = new MockLeAclConnection();
|
|
std::unique_ptr<MockLeAclConnection> acl_connection(raw_acl_connection);
|
|
EXPECT_CALL(*acl_connection, GetRemoteAddress()).WillRepeatedly(Return(address_with_type));
|
|
hci::acl_manager::LeConnectionManagementCallbacks* connection_management_callbacks = nullptr;
|
|
os::Handler* connection_management_handler = nullptr;
|
|
EXPECT_CALL(*acl_connection, RegisterCallbacks(_, _))
|
|
.WillOnce(DoAll(SaveArg<0>(&connection_management_callbacks), SaveArg<1>(&connection_management_handler)));
|
|
std::unique_ptr<FixedChannel> channel_1, channel_2;
|
|
std::promise<void> promise_1, promise_2;
|
|
auto future_1 = promise_1.get_future();
|
|
auto future_2 = promise_2.get_future();
|
|
EXPECT_CALL(mock_service_1, NotifyChannelCreation(_))
|
|
.WillOnce([&channel_1, &promise_1](std::unique_ptr<FixedChannel> channel) {
|
|
channel_1 = std::move(channel);
|
|
promise_1.set_value();
|
|
});
|
|
EXPECT_CALL(mock_service_2, NotifyChannelCreation(_))
|
|
.WillOnce([&channel_2, &promise_2](std::unique_ptr<FixedChannel> channel) {
|
|
channel_2 = std::move(channel);
|
|
promise_2.set_value();
|
|
});
|
|
hci_callback_handler->Post(common::BindOnce(&hci::acl_manager::LeConnectionCallbacks::OnLeConnectSuccess,
|
|
common::Unretained(hci_le_connection_callbacks), address_with_type,
|
|
std::move(acl_connection)));
|
|
SyncHandler(hci_callback_handler);
|
|
connection_management_handler->Post(common::BindOnce(
|
|
&hci::acl_manager::LeConnectionManagementCallbacks::OnReadRemoteVersionInformationComplete,
|
|
common::Unretained(connection_management_callbacks),
|
|
hci::ErrorCode::SUCCESS,
|
|
0,
|
|
0,
|
|
0));
|
|
auto future_1_status = future_1.wait_for(kTestIdleDisconnectTimeoutShort);
|
|
EXPECT_EQ(future_1_status, std::future_status::ready);
|
|
EXPECT_NE(channel_1, nullptr);
|
|
auto future_2_status = future_2.wait_for(kTestIdleDisconnectTimeoutShort);
|
|
EXPECT_EQ(future_2_status, std::future_status::ready);
|
|
EXPECT_NE(channel_2, nullptr);
|
|
hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
|
|
channel_1->RegisterOnCloseCallback(
|
|
user_handler_, common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
|
|
hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
|
|
channel_2->RegisterOnCloseCallback(
|
|
user_handler_, common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
|
|
|
|
channel_1->Acquire();
|
|
|
|
// Step 4: ave channel IDLE, it won't disconnect to due acquired channel 1
|
|
EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(0);
|
|
std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 2);
|
|
|
|
// Step 5: ave channel IDLE long enough, they will disconnect
|
|
channel_1->Release();
|
|
EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(1);
|
|
std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 1.2);
|
|
|
|
// Step 6: Link disconnect will trigger all callbacks
|
|
connection_management_handler->Post(common::BindOnce(
|
|
&hci::acl_manager::LeConnectionManagementCallbacks::OnDisconnection,
|
|
common::Unretained(connection_management_callbacks), hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST));
|
|
SyncHandler(connection_management_handler);
|
|
SyncHandler(user_handler_);
|
|
EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
|
|
EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace internal
|
|
} // namespace le
|
|
} // namespace l2cap
|
|
} // namespace bluetooth
|