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

Commit 16a771f3 authored by Archie Pusaka's avatar Archie Pusaka Committed by Archie Pusaka
Browse files

Don't send HCI disconnect repeatedly

It is possible for the host stack to send multiple HCI disconnect
commands for the same handle within a short time. Prevent such a
scenario by checking whether we have initiated disconnection for that
handle or not.

Bug: 374039861
Bug: 381175628
Test: m -j
Flag: com.android.bluetooth.flags.dont_send_hci_disconnect_repeatedly

Change-Id: I16900e883488eec0eaef3894168a2e4ec0b69b20
parent 54edfd68
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "hci/acl_manager/classic_acl_connection.h"

#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>

#include "hci/address.h"
#include "hci/event_checkers.h"
@@ -377,6 +378,14 @@ void ClassicAclConnection::RegisterCallbacks(ConnectionManagementCallbacks* call
}

bool ClassicAclConnection::Disconnect(DisconnectReason reason) {
  if (com::android::bluetooth::flags::dont_send_hci_disconnect_repeatedly()) {
    if (is_disconnecting_) {
      log::info("Already disconnecting {}", address_);
      return true;
    }
  }

  is_disconnecting_ = true;
  acl_connection_interface_->EnqueueCommand(
          DisconnectBuilder::Create(handle_, reason),
          pimpl_->tracker.client_handler_->BindOnce(check_status<DisconnectStatusView>));
+1 −0
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ public:

private:
  AclConnectionInterface* acl_connection_interface_;
  bool is_disconnecting_ = false;

protected:
  Address address_;
+6 −6
Original line number Diff line number Diff line
@@ -283,33 +283,31 @@ TEST_F(ClassicAclConnectionTest, simple) {

class ClassicAclConnectionWithCallbacksTest : public ClassicAclConnectionTest {
protected:
  void SetUp() override {
    ClassicAclConnectionTest::SetUp();
  void SetUpConnection() {
    connection_ = std::make_unique<ClassicAclConnection>(queue_, &acl_connection_interface_,
                                                         kConnectionHandle, address_);
    connection_->RegisterCallbacks(&callbacks_, handler_);
    is_callbacks_registered_ = true;
    connection_management_callbacks_ = connection_->GetEventCallbacks(
            [this](uint16_t /* hci_handle */) { is_callbacks_invalidated_ = true; });
    is_callbacks_invalidated_ = false;
  }

  void TearDown() override {
  void CleanConnection() {
    connection_.reset();
    ASSERT_TRUE(is_callbacks_invalidated_);
    ClassicAclConnectionTest::TearDown();
  }

protected:
  std::unique_ptr<ClassicAclConnection> connection_;
  ConnectionManagementCallbacks* connection_management_callbacks_;
  bool is_callbacks_registered_{false};
  bool is_callbacks_invalidated_{false};
};

TEST_F(ClassicAclConnectionWithCallbacksTest, Disconnect) {
  for (const auto& reason : disconnect_reason_vector) {
    SetUpConnection();
    ASSERT_TRUE(connection_->Disconnect(reason));
    CleanConnection();
  }

  for (const auto& reason : disconnect_reason_vector) {
@@ -324,7 +322,9 @@ TEST_F(ClassicAclConnectionWithCallbacksTest, Disconnect) {

TEST_F(ClassicAclConnectionWithCallbacksTest, OnDisconnection) {
  for (const auto& error_code : error_code_vector) {
    SetUpConnection();
    connection_management_callbacks_->OnDisconnection(error_code);
    CleanConnection();
  }

  sync_handler();
+9 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "hci/acl_manager/le_acl_connection.h"

#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>

#include "hci/acl_manager/le_connection_management_callbacks.h"
#include "hci/event_checkers.h"
@@ -186,6 +187,14 @@ void LeAclConnection::RegisterCallbacks(LeConnectionManagementCallbacks* callbac
}

void LeAclConnection::Disconnect(DisconnectReason reason) {
  if (com::android::bluetooth::flags::dont_send_hci_disconnect_repeatedly()) {
    if (is_disconnecting_) {
      log::info("Already disconnecting {}", remote_address_);
      return;
    }
  }

  is_disconnecting_ = true;
  pimpl_->tracker.le_acl_connection_interface_->EnqueueCommand(
          DisconnectBuilder::Create(handle_, reason),
          pimpl_->tracker.client_handler_->BindOnce([](CommandStatusView status) {
+1 −0
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ private:
  virtual bool check_connection_parameters(uint16_t conn_interval_min, uint16_t conn_interval_max,
                                           uint16_t expected_conn_latency,
                                           uint16_t expected_supervision_timeout);
  bool is_disconnecting_ = false;
  struct impl;
  struct impl* pimpl_ = nullptr;
};