Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 56d5308a authored by Chris Manton's avatar Chris Manton
Browse files

gd: Add Unregister::acl_manager classic/le

Synchronize stack shutdown

Bug: 176960731
Test: bluetooth_test_gd --gtest_filter=AclManagerLifeCycleTest.*
Test: gd/cert/run
Tag: #refactor
BYPASS_LONG_LINES_REASON: Bluetooth likes 120 lines

Change-Id: Iad2b6ce5f93f3aa3c9676179d9353cfa9f679fcd
parent efc79c85
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "hci/acl_manager.h"

#include <atomic>
#include <future>
#include <set>

#include "common/bidi_queue.h"
@@ -131,6 +132,15 @@ void AclManager::RegisterCallbacks(ConnectionCallbacks* callbacks, os::Handler*
                                      common::Unretained(handler)));
}

void AclManager::UnregisterCallbacks(ConnectionCallbacks* callbacks, std::promise<void> promise) {
  ASSERT(callbacks != nullptr);
  CallOn(
      pimpl_->classic_impl_,
      &classic_impl::handle_unregister_callbacks,
      common::Unretained(callbacks),
      std::move(promise));
}

void AclManager::RegisterLeCallbacks(LeConnectionCallbacks* callbacks, os::Handler* handler) {
  ASSERT(callbacks != nullptr && handler != nullptr);
  CallOn(
@@ -140,6 +150,11 @@ void AclManager::RegisterLeCallbacks(LeConnectionCallbacks* callbacks, os::Handl
      common::Unretained(handler));
}

void AclManager::UnregisterLeCallbacks(LeConnectionCallbacks* callbacks, std::promise<void> promise) {
  ASSERT(callbacks != nullptr);
  CallOn(pimpl_->le_impl_, &le_impl::handle_unregister_le_callbacks, common::Unretained(callbacks), std::move(promise));
}

void AclManager::CreateConnection(Address address) {
  CallOn(pimpl_->classic_impl_, &classic_impl::create_connection, address);
}
+3 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#pragma once

#include <functional>
#include <future>
#include <memory>

#include "common/bidi_queue.h"
@@ -65,9 +66,11 @@ public:
 // Should register only once when user module starts.
 // Generates OnConnectSuccess when an incoming connection is established.
 virtual void RegisterCallbacks(acl_manager::ConnectionCallbacks* callbacks, os::Handler* handler);
 virtual void UnregisterCallbacks(acl_manager::ConnectionCallbacks* callbacks, std::promise<void> promise);

 // Should register only once when user module starts.
 virtual void RegisterLeCallbacks(acl_manager::LeConnectionCallbacks* callbacks, os::Handler* handler);
 virtual void UnregisterLeCallbacks(acl_manager::LeConnectionCallbacks* callbacks, std::promise<void> promise);

 // Generates OnConnectSuccess if connected, or OnConnectFail otherwise
 virtual void CreateConnection(Address address);
+11 −0
Original line number Diff line number Diff line
@@ -149,6 +149,13 @@ struct classic_impl : public security::ISecurityManagerListener {
    client_handler_ = handler;
  }

  void handle_unregister_callbacks(ConnectionCallbacks* callbacks, std::promise<void> promise) {
    ASSERT_LOG(client_callbacks_ == callbacks, "Registered callback entity is different then unregister request");
    client_callbacks_ = nullptr;
    client_handler_ = nullptr;
    promise.set_value();
  }

  void on_incoming_connection(EventView packet) {
    ConnectionRequestView request = ConnectionRequestView::Create(packet);
    ASSERT(request.IsValid());
@@ -222,6 +229,10 @@ struct classic_impl : public security::ISecurityManagerListener {
      incoming_connecting_address_ = Address::kEmpty;
      current_role = Role::PERIPHERAL;
    }
    if (client_callbacks_ == nullptr) {
      LOG_WARN("No client callbacks registered for connection");
      return;
    }
    if (status != ErrorCode::SUCCESS) {
      client_handler_->Post(common::BindOnce(&ConnectionCallbacks::OnConnectFail, common::Unretained(client_callbacks_),
                                             address, status));
+21 −1
Original line number Diff line number Diff line
@@ -151,6 +151,11 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
      remove_device_from_connect_list(remote_address);
    }

    if (le_client_handler_ == nullptr) {
      LOG_ERROR("No callbacks to call");
      return;
    }

    if (status != ErrorCode::SUCCESS) {
      le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectFail,
                                                common::Unretained(le_client_callbacks_), remote_address, status));
@@ -205,6 +210,11 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
      remove_device_from_connect_list(remote_address);
    }

    if (le_client_handler_ == nullptr) {
      LOG_ERROR("No callbacks to call");
      return;
    }

    if (status != ErrorCode::SUCCESS) {
      le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectFail,
                                                common::Unretained(le_client_callbacks_), remote_address, status));
@@ -411,6 +421,10 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
      canceled_connections_.insert(address_with_type);
      return;
    }
    if (le_client_callbacks_ == nullptr) {
      LOG_ERROR("No callbacks to call");
      return;
    }

    uint16_t le_scan_interval = 0x0060;
    uint16_t le_scan_window = 0x0030;
@@ -421,7 +435,6 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
    uint16_t conn_interval_max = 0x0028;
    uint16_t conn_latency = 0x0000;
    uint16_t supervision_timeout = 0x001f4;
    ASSERT(le_client_callbacks_ != nullptr);
    ASSERT(check_connection_parameters(conn_interval_min, conn_interval_max, conn_latency, supervision_timeout));

    connecting_le_.insert(address_with_type);
@@ -543,6 +556,13 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
    le_client_handler_ = handler;
  }

  void handle_unregister_le_callbacks(LeConnectionCallbacks* callbacks, std::promise<void> promise) {
    ASSERT_LOG(le_client_callbacks_ == callbacks, "Registered le callback entity is different then unregister request");
    le_client_callbacks_ = nullptr;
    le_client_handler_ = nullptr;
    promise.set_value();
  }

  bool check_connection_parameters(
      uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout) {
    if (conn_interval_min < 0x0006 || conn_interval_min > 0x0C80 || conn_interval_max < 0x0006 ||
+137 −0
Original line number Diff line number Diff line
@@ -1322,6 +1322,143 @@ TEST_F(AclManagerWithResolvableAddressTest, create_connection_cancel_fail) {
  test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
}

class AclManagerLifeCycleTest : public AclManagerNoCallbacksTest {
 protected:
  void SetUp() override {
    AclManagerNoCallbacksTest::SetUp();
    acl_manager_->RegisterCallbacks(&mock_connection_callback_, client_handler_);
    acl_manager_->RegisterLeCallbacks(&mock_le_connection_callbacks_, client_handler_);
  }

  AddressWithType remote_with_type_;
  uint16_t handle_{0x123};
};

TEST_F(AclManagerLifeCycleTest, unregister_classic_after_create_connection) {
  // Inject create connection
  test_hci_layer_->SetCommandFuture();
  acl_manager_->CreateConnection(remote);
  auto connection_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);

  // Unregister callbacks after sending connection request
  auto promise = std::promise<void>();
  auto future = promise.get_future();
  acl_manager_->UnregisterCallbacks(&mock_connection_callback_, std::move(promise));
  future.get();

  // Inject peer sending connection complete
  auto connection_future = GetConnectionFuture();
  test_hci_layer_->IncomingEvent(
      ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, remote, LinkType::ACL, Enable::DISABLED));
  auto connection_future_status = connection_future.wait_for(kTimeout);
  ASSERT_NE(connection_future_status, std::future_status::ready);
}

TEST_F(AclManagerLifeCycleTest, unregister_classic_before_connection_request) {
  ClassOfDevice class_of_device;

  // Unregister callbacks before receiving connection request
  auto promise = std::promise<void>();
  auto future = promise.get_future();
  acl_manager_->UnregisterCallbacks(&mock_connection_callback_, std::move(promise));
  future.get();

  // Inject peer sending connection request
  auto connection_future = GetConnectionFuture();
  test_hci_layer_->IncomingEvent(
      ConnectionRequestBuilder::Create(remote, class_of_device, ConnectionRequestLinkType::ACL));
  auto connection_future_status = connection_future.wait_for(kTimeout);
  ASSERT_NE(connection_future_status, std::future_status::ready);

  test_hci_layer_->GetLastCommand(OpCode::REJECT_CONNECTION_REQUEST);
}

TEST_F(AclManagerLifeCycleTest, unregister_le_before_connection_complete) {
  AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
  test_hci_layer_->SetCommandFuture();
  acl_manager_->CreateLeConnection(remote_with_type);
  test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
  test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));

  test_hci_layer_->SetCommandFuture();
  auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
  auto le_connection_management_command_view =
      LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
  auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
  ASSERT_TRUE(command_view.IsValid());
  if (use_connect_list_) {
    ASSERT_EQ(command_view.GetPeerAddress(), hci::Address::kEmpty);
  } else {
    ASSERT_EQ(command_view.GetPeerAddress(), remote);
  }
  ASSERT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);

  // Unregister callbacks after sending connection request
  auto promise = std::promise<void>();
  auto future = promise.get_future();
  acl_manager_->UnregisterLeCallbacks(&mock_le_connection_callbacks_, std::move(promise));
  future.get();

  auto connection_future = GetLeConnectionFuture();
  test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
      ErrorCode::SUCCESS,
      0x123,
      Role::PERIPHERAL,
      AddressType::PUBLIC_DEVICE_ADDRESS,
      remote,
      0x0100,
      0x0010,
      0x0500,
      ClockAccuracy::PPM_30));

  auto connection_future_status = connection_future.wait_for(kTimeout);
  ASSERT_NE(connection_future_status, std::future_status::ready);
}

TEST_F(AclManagerLifeCycleTest, unregister_le_before_enhanced_connection_complete) {
  AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
  test_hci_layer_->SetCommandFuture();
  acl_manager_->CreateLeConnection(remote_with_type);
  test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
  test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));

  test_hci_layer_->SetCommandFuture();
  auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
  auto le_connection_management_command_view =
      LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
  auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
  ASSERT_TRUE(command_view.IsValid());
  if (use_connect_list_) {
    ASSERT_EQ(command_view.GetPeerAddress(), hci::Address::kEmpty);
  } else {
    ASSERT_EQ(command_view.GetPeerAddress(), remote);
  }
  ASSERT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);

  // Unregister callbacks after sending connection request
  auto promise = std::promise<void>();
  auto future = promise.get_future();
  acl_manager_->UnregisterLeCallbacks(&mock_le_connection_callbacks_, std::move(promise));
  future.get();

  auto connection_future = GetLeConnectionFuture();
  test_hci_layer_->IncomingLeMetaEvent(LeEnhancedConnectionCompleteBuilder::Create(
      ErrorCode::SUCCESS,
      0x123,
      Role::PERIPHERAL,
      AddressType::PUBLIC_DEVICE_ADDRESS,
      remote,
      Address::kEmpty,
      Address::kEmpty,
      0x0100,
      0x0010,
      0x0500,
      ClockAccuracy::PPM_30));

  auto connection_future_status = connection_future.wait_for(kTimeout);
  ASSERT_NE(connection_future_status, std::future_status::ready);
}

}  // namespace
}  // namespace acl_manager
}  // namespace hci