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

Commit 58c4db62 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

le_impl: Fix for unnecessary connect cancel

With this patch connection manager will not cancel create connection when
device which is trying to connect is already connecting with high scan
paramerters e.g. when direct connect is called after direct connect or
background connect is done after direct connect

Bug: 356594223
Bug: 356593752
Test: atest bluetooth_gd_unit_test
Flag: com.android.bluetooth.flags.improve_create_connection_for_already_connecting_device

Change-Id: I4083381b9f516d07044b3d47f5c74e92331a27d6
parent 0597c91d
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>

#include <cstdint>
#include <memory>
@@ -953,6 +954,17 @@ public:
        add_device_to_accept_list(address_with_type);
      }

      if (com::android::bluetooth::flags::
                  improve_create_connection_for_already_connecting_device()) {
        bool in_accept_list_due_to_direct_connect =
                direct_connections_.find(address_with_type) != direct_connections_.end();

        if (already_in_accept_list && (in_accept_list_due_to_direct_connect || !is_direct)) {
          log::info("Device {} already in accept list. Stop here.", address_with_type);
          return;
        }
      }

      if (is_direct) {
        direct_connect_add(address_with_type);
      }
+180 −140
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "hci/acl_manager/le_impl.h"

#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
@@ -278,7 +279,168 @@ protected:
    hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
  }

  void test_direct_connection_after_background_connection() {
    set_random_device_address_policy();

    hci::AddressWithType address({0x21, 0x22, 0x23, 0x24, 0x25, 0x26},
                                 AddressType::PUBLIC_DEVICE_ADDRESS);

    // arrange: Create background connection. Remember that acl_manager adds device background list
    le_impl_->add_device_to_background_connection_list(address);
    le_impl_->create_le_connection(address, true, /* is_direct */ false);
    hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
    hci_layer_->IncomingEvent(
            LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
    auto raw_bg_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
    hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
    sync_handler();

    // act: Create direct connection
    le_impl_->create_le_connection(address, true, /* is_direct */ true);
    auto cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
    if (cancel_connection.IsValid()) {
      hci_layer_->IncomingEvent(
              LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
      hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
              ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL,
              AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000,
              ClockAccuracy::PPM_30));
    }
    auto raw_direct_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);

    // assert
    auto bg_create_connection =
            LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(
                    AclCommandView::Create(raw_bg_create_connection)));
    EXPECT_TRUE(bg_create_connection.IsValid());
    auto direct_create_connection =
            LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(
                    AclCommandView::Create(raw_direct_create_connection)));
    EXPECT_TRUE(direct_create_connection.IsValid());
    log::info("Scan Interval {}", direct_create_connection.GetLeScanInterval());
    ASSERT_NE(direct_create_connection.GetLeScanInterval(),
              bg_create_connection.GetLeScanInterval());

    hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
    sync_handler();

    // Check state is ARMED
    ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);

    // Simulate timeout on direct connect. Verify background connect is still in place
    EXPECT_CALL(mock_le_connection_callbacks_,
                OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT))
            .Times(1);
    le_impl_->on_create_connection_timeout(address);
    sync_handler();
    cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
    hci_layer_->IncomingEvent(
            LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
    hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
            ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL,
            AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000,
            ClockAccuracy::PPM_30));
    EXPECT_TRUE(cancel_connection.IsValid());
    raw_bg_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
    bg_create_connection = LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(
            AclCommandView::Create(raw_bg_create_connection)));
    EXPECT_TRUE(bg_create_connection.IsValid());
    sync_handler();
    ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty());

    hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
    sync_handler();

    // Check state is ARMED
    ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);
  }

  void test_direct_connect_after_direct_connect() {
    set_random_device_address_policy();

    hci::AddressWithType address({0x21, 0x22, 0x23, 0x24, 0x25, 0x26},
                                 AddressType::PUBLIC_DEVICE_ADDRESS);

    // Create first direct connection
    le_impl_->create_le_connection(address, true, /* is_direct */ true);
    hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
    hci_layer_->IncomingEvent(
            LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
    auto raw_direct_1_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
    hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
    sync_handler();

    // Check state is ARMED
    ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);

    // assert
    auto direct_1_create_connection =
            LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(
                    AclCommandView::Create(raw_direct_1_create_connection)));
    EXPECT_TRUE(direct_1_create_connection.IsValid());

    log::info("Second direct connect to the same device");

    // Create second direct connection
    le_impl_->create_le_connection(address, true, /* is_direct */ true);
    sync_handler();

    CommandView cancel_connection = CommandView::Create(
            PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
    ;

    if (!com::android::bluetooth::flags::
                improve_create_connection_for_already_connecting_device()) {
      cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
      if (cancel_connection.IsValid()) {
        hci_layer_->IncomingEvent(
                LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
        hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
                ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL,
                AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000,
                ClockAccuracy::PPM_30));
      }

      auto raw_direct_2_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);

      auto direct_2_create_connection =
              LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(
                      AclCommandView::Create(raw_direct_2_create_connection)));
      EXPECT_TRUE(direct_2_create_connection.IsValid());
      hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
      sync_handler();
    } else {
      hci_layer_->AssertNoQueuedCommand();
    }

    log::info("Simulate timeout");

    EXPECT_CALL(mock_le_connection_callbacks_,
                OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT))
            .Times(1);
    le_impl_->on_create_connection_timeout(address);
    sync_handler();
    cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
    EXPECT_TRUE(cancel_connection.IsValid());
    hci_layer_->IncomingEvent(
            LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
    hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
            ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL,
            AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000,
            ClockAccuracy::PPM_30));
    sync_handler();
    ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty());

    hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
    hci_layer_->IncomingEvent(
            LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
    hci_layer_->AssertNoQueuedCommand();
    ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_);
  }

  void TearDown() override {
    com::android::bluetooth::flags::provider_->reset_flags();

    // We cannot teardown our structure without unregistering
    // from our own structure we created.
    if (le_impl_->address_manager_registered) {
@@ -1419,151 +1581,29 @@ TEST_F(LeImplTest, DisconnectionAcceptlistCallback) {
}

TEST_F(LeImplTest, direct_connection_after_background_connection) {
  set_random_device_address_policy();

  hci::AddressWithType address({0x21, 0x22, 0x23, 0x24, 0x25, 0x26},
                               AddressType::PUBLIC_DEVICE_ADDRESS);

  // arrange: Create background connection. Remember that acl_manager adds device background list
  le_impl_->add_device_to_background_connection_list(address);
  le_impl_->create_le_connection(address, true, /* is_direct */ false);
  hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
  hci_layer_->IncomingEvent(
          LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
  auto raw_bg_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
  hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
  sync_handler();

  // act: Create direct connection
  le_impl_->create_le_connection(address, true, /* is_direct */ true);
  auto cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
  if (cancel_connection.IsValid()) {
    hci_layer_->IncomingEvent(
            LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
    hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
            ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL,
            AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000,
            ClockAccuracy::PPM_30));
  // TODO b/356593752  - remove when test removing flag
  com::android::bluetooth::flags::provider_
          ->improve_create_connection_for_already_connecting_device(false);
  test_direct_connection_after_background_connection();
}
  auto raw_direct_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);

  // assert
  auto bg_create_connection =
          LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(
                  AclCommandView::Create(raw_bg_create_connection)));
  EXPECT_TRUE(bg_create_connection.IsValid());
  auto direct_create_connection =
          LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(
                  AclCommandView::Create(raw_direct_create_connection)));
  EXPECT_TRUE(direct_create_connection.IsValid());
  log::info("Scan Interval {}", direct_create_connection.GetLeScanInterval());
  ASSERT_NE(direct_create_connection.GetLeScanInterval(), bg_create_connection.GetLeScanInterval());

  hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
  sync_handler();

  // Check state is ARMED
  ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);

  // Simulate timeout on direct connect. Verify background connect is still in place
  EXPECT_CALL(mock_le_connection_callbacks_,
              OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT))
          .Times(1);
  le_impl_->on_create_connection_timeout(address);
  sync_handler();
  cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
  hci_layer_->IncomingEvent(
          LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
  hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
          ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL,
          AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000,
          ClockAccuracy::PPM_30));
  EXPECT_TRUE(cancel_connection.IsValid());
  raw_bg_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
  bg_create_connection = LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(
          AclCommandView::Create(raw_bg_create_connection)));
  EXPECT_TRUE(bg_create_connection.IsValid());
  sync_handler();
  ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty());

  hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
  sync_handler();

  // Check state is ARMED
  ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);
TEST_F(LeImplTest, direct_connection_after_background_connection_with_improvement) {
  com::android::bluetooth::flags::provider_
          ->improve_create_connection_for_already_connecting_device(true);
  test_direct_connection_after_background_connection();
}

TEST_F(LeImplTest, direct_connection_after_direct_connection) {
  set_random_device_address_policy();

  hci::AddressWithType address({0x21, 0x22, 0x23, 0x24, 0x25, 0x26},
                               AddressType::PUBLIC_DEVICE_ADDRESS);

  // Create first direct connection
  le_impl_->create_le_connection(address, true, /* is_direct */ true);
  hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
  hci_layer_->IncomingEvent(
          LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
  auto raw_direct_1_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
  hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
  sync_handler();

  // Check state is ARMED
  ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);

  log::info("Second direct connect to the same device");

  // Create second direct connection
  le_impl_->create_le_connection(address, true, /* is_direct */ true);
  sync_handler();

  auto cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
  if (cancel_connection.IsValid()) {
    hci_layer_->IncomingEvent(
            LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
    hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
            ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL,
            AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000,
            ClockAccuracy::PPM_30));
  // TODO b/356593752  - remove when test removing flag
  com::android::bluetooth::flags::provider_
          ->improve_create_connection_for_already_connecting_device(false);
  test_direct_connect_after_direct_connect();
}

  auto raw_direct_2_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);

  // assert
  auto direct_1_create_connection =
          LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(
                  AclCommandView::Create(raw_direct_1_create_connection)));
  EXPECT_TRUE(direct_1_create_connection.IsValid());
  auto direct_2_create_connection =
          LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(
                  AclCommandView::Create(raw_direct_2_create_connection)));
  EXPECT_TRUE(direct_2_create_connection.IsValid());
  hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
  sync_handler();

  log::info("Simulate timeout");

  EXPECT_CALL(mock_le_connection_callbacks_,
              OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT))
          .Times(1);
  le_impl_->on_create_connection_timeout(address);
  sync_handler();
  cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
  EXPECT_TRUE(cancel_connection.IsValid());
  hci_layer_->IncomingEvent(
          LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
  hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
          ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL,
          AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000,
          ClockAccuracy::PPM_30));
  sync_handler();
  ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty());

  hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
  hci_layer_->IncomingEvent(
          LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
  hci_layer_->AssertNoQueuedCommand();
  ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_);
TEST_F(LeImplTest, direct_connection_after_direct_connection_with_improvement) {
  com::android::bluetooth::flags::provider_
          ->improve_create_connection_for_already_connecting_device(true);
  test_direct_connect_after_direct_connect();
}

}  // namespace acl_manager