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

Commit 32187a43 authored by Chris Manton's avatar Chris Manton Committed by Gerrit Code Review
Browse files

Merge changes Iaec80ec6,I39fa842d

* changes:
  le_impl: Disarm connectability only when fully ARMED
  Extended le_impl capabilities for testing
parents a16a517d 60f1bc70
Loading
Loading
Loading
Loading
+49 −23
Original line number Original line Diff line number Diff line
@@ -685,28 +685,43 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
        address_with_type.ToPeerAddressType(), address_with_type.GetAddress());
        address_with_type.ToPeerAddressType(), address_with_type.GetAddress());
  }
  }


  void on_extended_create_connection(CommandStatusView status) {
  void update_connectability_state_after_armed(const ErrorCode& status) {
    ASSERT(status.IsValid());
    switch (connectability_state_) {
    ASSERT(status.GetCommandOpCode() == OpCode::LE_EXTENDED_CREATE_CONNECTION);
      case ConnectabilityState::DISARMED:
    if (connectability_state_ != ConnectabilityState::ARMING) {
      case ConnectabilityState::ARMED:
      case ConnectabilityState::DISARMING:
        LOG_ERROR(
        LOG_ERROR(
          "Received connectability arm notification for unexpected state:%s",
            "Received connectability arm notification for unexpected state:%s status:%s",
          connectability_state_machine_text(connectability_state_).c_str());
            connectability_state_machine_text(connectability_state_).c_str(),
            ErrorCodeText(status).c_str());
        break;
      case ConnectabilityState::ARMING:
        if (status != ErrorCode::SUCCESS) {
          LOG_ERROR("Le connection state machine armed failed status:%s", ErrorCodeText(status).c_str());
        }
        }
        connectability_state_ =
        connectability_state_ =
        (status.GetStatus() == ErrorCode::SUCCESS) ? ConnectabilityState::ARMED : ConnectabilityState::DISARMED;
            (status == ErrorCode::SUCCESS) ? ConnectabilityState::ARMED : ConnectabilityState::DISARMED;
        LOG_INFO(
            "Le connection state machine armed state:%s status:%s",
            connectability_state_machine_text(connectability_state_).c_str(),
            ErrorCodeText(status).c_str());
        if (disarmed_while_arming_) {
          disarmed_while_arming_ = false;
          disarm_connectability();
        }
    }
  }

  void on_extended_create_connection(CommandStatusView status) {
    ASSERT(status.IsValid());
    ASSERT(status.GetCommandOpCode() == OpCode::LE_EXTENDED_CREATE_CONNECTION);
    update_connectability_state_after_armed(status.GetStatus());
  }
  }


  void on_create_connection(CommandStatusView status) {
  void on_create_connection(CommandStatusView status) {
    ASSERT(status.IsValid());
    ASSERT(status.IsValid());
    ASSERT(status.GetCommandOpCode() == OpCode::LE_CREATE_CONNECTION);
    ASSERT(status.GetCommandOpCode() == OpCode::LE_CREATE_CONNECTION);
    if (connectability_state_ != ConnectabilityState::ARMING) {
    update_connectability_state_after_armed(status.GetStatus());
      LOG_ERROR(
          "Received connectability arm notification for unexpected state:%s",
          connectability_state_machine_text(connectability_state_).c_str());
    }
    connectability_state_ =
        (status.GetStatus() == ErrorCode::SUCCESS) ? ConnectabilityState::ARMED : ConnectabilityState::DISARMED;
  }
  }


  void arm_connectability() {
  void arm_connectability() {
@@ -819,16 +834,26 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
  }
  }


  void disarm_connectability() {
  void disarm_connectability() {
    if (connectability_state_ != ConnectabilityState::ARMED && connectability_state_ != ConnectabilityState::ARMING) {
    switch (connectability_state_) {
      LOG_ERROR(
      case ConnectabilityState::ARMED:
          "Attempting to disarm le connection state machine in unexpected state:%s",
        LOG_INFO("Disarming LE connection state machine with create connection cancel");
          connectability_state_machine_text(connectability_state_).c_str());
      return;
    }
        connectability_state_ = ConnectabilityState::DISARMING;
        connectability_state_ = ConnectabilityState::DISARMING;
        le_acl_connection_interface_->EnqueueCommand(
        le_acl_connection_interface_->EnqueueCommand(
            LeCreateConnectionCancelBuilder::Create(),
            LeCreateConnectionCancelBuilder::Create(),
            handler_->BindOnce(&le_impl::on_create_connection_cancel_complete, common::Unretained(this)));
            handler_->BindOnce(&le_impl::on_create_connection_cancel_complete, common::Unretained(this)));
        break;

      case ConnectabilityState::ARMING:
        LOG_INFO("Queueing cancel connect until after connection state machine is armed");
        disarmed_while_arming_ = true;
        break;
      case ConnectabilityState::DISARMING:
      case ConnectabilityState::DISARMED:
        LOG_ERROR(
            "Attempting to disarm le connection state machine in unexpected state:%s",
            connectability_state_machine_text(connectability_state_).c_str());
        break;
    }
  }
  }


  void create_le_connection(AddressWithType address_with_type, bool add_to_connect_list, bool is_direct) {
  void create_le_connection(AddressWithType address_with_type, bool add_to_connect_list, bool is_direct) {
@@ -1094,6 +1119,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
  bool address_manager_registered = false;
  bool address_manager_registered = false;
  bool ready_to_unregister = false;
  bool ready_to_unregister = false;
  bool pause_connection = false;
  bool pause_connection = false;
  bool disarmed_while_arming_ = false;
  ConnectabilityState connectability_state_{ConnectabilityState::DISARMED};
  ConnectabilityState connectability_state_{ConnectabilityState::DISARMED};
  std::map<AddressWithType, os::Alarm> create_connection_timeout_alarms_;
  std::map<AddressWithType, os::Alarm> create_connection_timeout_alarms_;
};
};
+236 −2
Original line number Original line Diff line number Diff line
@@ -26,12 +26,14 @@
#include "common/callback.h"
#include "common/callback.h"
#include "common/testing/log_capture.h"
#include "common/testing/log_capture.h"
#include "hci/acl_manager.h"
#include "hci/acl_manager.h"
#include "hci/acl_manager/le_connection_callbacks.h"
#include "hci/acl_manager/le_connection_management_callbacks.h"
#include "hci/acl_manager/le_connection_management_callbacks.h"
#include "hci/address_with_type.h"
#include "hci/address_with_type.h"
#include "hci/controller.h"
#include "hci/controller.h"
#include "hci/hci_packets.h"
#include "hci/hci_packets.h"
#include "os/handler.h"
#include "os/handler.h"
#include "os/log.h"
#include "os/log.h"
#include "packet/bit_inserter.h"
#include "packet/raw_builder.h"
#include "packet/raw_builder.h"


using namespace bluetooth;
using namespace bluetooth;
@@ -41,6 +43,8 @@ using ::bluetooth::common::BidiQueue;
using ::bluetooth::common::Callback;
using ::bluetooth::common::Callback;
using ::bluetooth::os::Handler;
using ::bluetooth::os::Handler;
using ::bluetooth::os::Thread;
using ::bluetooth::os::Thread;
using ::bluetooth::packet::BitInserter;
using ::bluetooth::packet::RawBuilder;
using ::bluetooth::testing::LogCapture;
using ::bluetooth::testing::LogCapture;


namespace {
namespace {
@@ -53,6 +57,86 @@ constexpr char kRemoteAddress[] = "00:11:22:33:44:55";
[[maybe_unused]] constexpr ::bluetooth::crypto_toolbox::Octet16 kRotationIrk = {};
[[maybe_unused]] constexpr ::bluetooth::crypto_toolbox::Octet16 kRotationIrk = {};
[[maybe_unused]] constexpr std::chrono::milliseconds kMinimumRotationTime(14 * 1000);
[[maybe_unused]] constexpr std::chrono::milliseconds kMinimumRotationTime(14 * 1000);
[[maybe_unused]] constexpr std::chrono::milliseconds kMaximumRotationTime(16 * 1000);
[[maybe_unused]] constexpr std::chrono::milliseconds kMaximumRotationTime(16 * 1000);
[[maybe_unused]] constexpr std::array<uint8_t, 16> kPeerIdentityResolvingKey({
    0x00,
    0x01,
    0x02,
    0x03,
    0x04,
    0x05,
    0x06,
    0x07,
    0x08,
    0x09,
    0x0a,
    0x0b,
    0x0c,
    0x0d,
    0x0e,
    0x0f,
});
[[maybe_unused]] constexpr std::array<uint8_t, 16> kLocalIdentityResolvingKey({
    0x80,
    0x81,
    0x82,
    0x83,
    0x84,
    0x85,
    0x86,
    0x87,
    0x88,
    0x89,
    0x8a,
    0x8b,
    0x8c,
    0x8d,
    0x8e,
    0x8f,
});

// Generic template for all commands
template <typename T, typename U>
T CreateCommand(U u) {
  T command;
  return command;
}

template <>
[[maybe_unused]] hci::LeSetAddressResolutionEnableView CreateCommand(std::shared_ptr<std::vector<uint8_t>> bytes) {
  return hci::LeSetAddressResolutionEnableView::Create(
      hci::LeSecurityCommandView::Create(hci::CommandView::Create(hci::PacketView<hci::kLittleEndian>(bytes))));
}

template <>
[[maybe_unused]] hci::LeAddDeviceToResolvingListView CreateCommand(std::shared_ptr<std::vector<uint8_t>> bytes) {
  return hci::LeAddDeviceToResolvingListView::Create(
      hci::LeSecurityCommandView::Create(hci::CommandView::Create(hci::PacketView<hci::kLittleEndian>(bytes))));
}

template <>
[[maybe_unused]] hci::LeSetPrivacyModeView CreateCommand(std::shared_ptr<std::vector<uint8_t>> bytes) {
  return hci::LeSetPrivacyModeView::Create(
      hci::LeSecurityCommandView::Create(hci::CommandView::Create(hci::PacketView<hci::kLittleEndian>(bytes))));
}

[[maybe_unused]] hci::CommandCompleteView ReturnCommandComplete(hci::OpCode op_code, hci::ErrorCode error_code) {
  std::vector<uint8_t> success_vector{static_cast<uint8_t>(error_code)};
  auto bytes = std::make_shared<std::vector<uint8_t>>();
  BitInserter bi(*bytes);
  auto builder = hci::CommandCompleteBuilder::Create(uint8_t{1}, op_code, std::make_unique<RawBuilder>(success_vector));
  builder->Serialize(bi);
  return hci::CommandCompleteView::Create(hci::EventView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
}

[[maybe_unused]] hci::CommandStatusView ReturnCommandStatus(hci::OpCode op_code, hci::ErrorCode error_code) {
  std::vector<uint8_t> success_vector{static_cast<uint8_t>(error_code)};
  auto bytes = std::make_shared<std::vector<uint8_t>>();
  BitInserter bi(*bytes);
  auto builder = hci::CommandStatusBuilder::Create(
      hci::ErrorCode::SUCCESS, uint8_t{1}, op_code, std::make_unique<RawBuilder>(success_vector));
  builder->Serialize(bi);
  return hci::CommandStatusView::Create(hci::EventView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
}


}  // namespace
}  // namespace


@@ -107,6 +191,12 @@ class TestController : public Controller {
    acl_credits_callback_ = {};
    acl_credits_callback_ = {};
  }
  }


  bool SupportsBlePrivacy() const override {
    return supports_ble_privacy_;
  }
  bool supports_ble_privacy_{false};

 public:
  const uint16_t max_acl_packet_credits_ = 10;
  const uint16_t max_acl_packet_credits_ = 10;
  const uint16_t hci_mtu_ = 1024;
  const uint16_t hci_mtu_ = 1024;
  const uint16_t le_max_acl_packet_credits_ = 15;
  const uint16_t le_max_acl_packet_credits_ = 15;
@@ -162,6 +252,7 @@ class TestHciLayer : public HciLayer {
    }
    }
  }
  }


 public:
  std::unique_ptr<CommandBuilder> DequeueCommand() {
  std::unique_ptr<CommandBuilder> DequeueCommand() {
    const std::lock_guard<std::mutex> lock(command_queue_mutex_);
    const std::lock_guard<std::mutex> lock(command_queue_mutex_);
    auto packet = std::move(command_queue_.front());
    auto packet = std::move(command_queue_.front());
@@ -187,7 +278,6 @@ class TestHciLayer : public HciLayer {
    return command_queue_.size();
    return command_queue_.size();
  }
  }


 public:
  void SetCommandFuture() {
  void SetCommandFuture() {
    ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
    ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
    command_promise_ = std::make_unique<std::promise<void>>();
    command_promise_ = std::make_unique<std::promise<void>>();
@@ -274,8 +364,16 @@ class TestHciLayer : public HciLayer {
  CommandInterfaceImpl<AclCommandBuilder> le_acl_connection_manager_interface_{*this};
  CommandInterfaceImpl<AclCommandBuilder> le_acl_connection_manager_interface_{*this};
};
};


class LeImplTest : public ::testing::Test {
class LeConnectionCallbacksTest : public LeConnectionCallbacks {
 public:
 public:
  virtual ~LeConnectionCallbacksTest() = default;
  virtual void OnLeConnectSuccess(
      AddressWithType address_with_type, std::unique_ptr<LeAclConnection> connection) override {}
  virtual void OnLeConnectFail(AddressWithType address_with_type, ErrorCode reason) override {}
};

class LeImplTest : public ::testing::Test {
 protected:
  void SetUp() override {
  void SetUp() override {
    thread_ = new Thread("thread", Thread::Priority::NORMAL);
    thread_ = new Thread("thread", Thread::Priority::NORMAL);
    handler_ = new Handler(thread_);
    handler_ = new Handler(thread_);
@@ -316,6 +414,14 @@ class LeImplTest : public ::testing::Test {
  }
  }


  void TearDown() override {
  void TearDown() override {
    // We cannot teardown our structure without unregistering
    // from our own structure we created.
    if (le_impl_->address_manager_registered) {
      le_impl_->ready_to_unregister = true;
      le_impl_->check_for_unregister();
      sync_handler();
    }

    sync_handler();
    sync_handler();
    delete le_impl_;
    delete le_impl_;


@@ -391,9 +497,22 @@ class LeImplTest : public ::testing::Test {
  TestController* controller_;
  TestController* controller_;
  RoundRobinScheduler* round_robin_scheduler_{nullptr};
  RoundRobinScheduler* round_robin_scheduler_{nullptr};


  LeConnectionCallbacksTest connection_callbacks_;
  struct le_impl* le_impl_;
  struct le_impl* le_impl_;
};
};


class LeImplWithCallbacksTest : public LeImplTest {
 protected:
  void SetUp() override {
    LeImplTest::SetUp();
    le_impl_->handle_register_le_callbacks(&connection_callbacks_, handler_);
  }

  void TearDown() override {
    LeImplTest::TearDown();
  }
};

TEST_F(LeImplTest, nop) {}
TEST_F(LeImplTest, nop) {}


TEST_F(LeImplTest, add_device_to_connect_list) {
TEST_F(LeImplTest, add_device_to_connect_list) {
@@ -643,6 +762,121 @@ TEST_F(LeImplTest, register_with_address_manager__AddressPolicyNotSet) {
      std::move(log_capture)));
      std::move(log_capture)));
}
}


TEST_F(LeImplTest, disarm_connectability_DISARMED) {
  bluetooth::common::InitFlags::SetAllForTesting();
  std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();

  le_impl_->connectability_state_ = ConnectabilityState::DISARMED;
  le_impl_->disarm_connectability();
  ASSERT_FALSE(le_impl_->disarmed_while_arming_);

  le_impl_->on_create_connection(ReturnCommandStatus(OpCode::LE_CREATE_CONNECTION, ErrorCode::SUCCESS));

  ASSERT_TRUE(log_capture->Rewind()->Find("Attempting to disarm le connection"));
  ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMED"));
}

TEST_F(LeImplTest, disarm_connectability_DISARMED_extended) {
  bluetooth::common::InitFlags::SetAllForTesting();
  std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();

  le_impl_->connectability_state_ = ConnectabilityState::DISARMED;
  le_impl_->disarm_connectability();
  ASSERT_FALSE(le_impl_->disarmed_while_arming_);

  le_impl_->on_extended_create_connection(
      ReturnCommandStatus(OpCode::LE_EXTENDED_CREATE_CONNECTION, ErrorCode::SUCCESS));

  ASSERT_TRUE(log_capture->Rewind()->Find("Attempting to disarm le connection"));
  ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMED"));
}

TEST_F(LeImplTest, disarm_connectability_ARMING) {
  bluetooth::common::InitFlags::SetAllForTesting();
  std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();

  le_impl_->connectability_state_ = ConnectabilityState::ARMING;
  le_impl_->disarm_connectability();
  ASSERT_TRUE(le_impl_->disarmed_while_arming_);
  le_impl_->on_create_connection(ReturnCommandStatus(OpCode::LE_CREATE_CONNECTION, ErrorCode::SUCCESS));

  ASSERT_TRUE(log_capture->Rewind()->Find("Queueing cancel connect until"));
  ASSERT_TRUE(log_capture->Rewind()->Find("Le connection state machine armed state"));
}

TEST_F(LeImplTest, disarm_connectability_ARMING_extended) {
  bluetooth::common::InitFlags::SetAllForTesting();
  std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();

  le_impl_->connectability_state_ = ConnectabilityState::ARMING;
  le_impl_->disarm_connectability();
  ASSERT_TRUE(le_impl_->disarmed_while_arming_);

  le_impl_->on_extended_create_connection(
      ReturnCommandStatus(OpCode::LE_EXTENDED_CREATE_CONNECTION, ErrorCode::SUCCESS));

  ASSERT_TRUE(log_capture->Rewind()->Find("Queueing cancel connect until"));
  ASSERT_TRUE(log_capture->Rewind()->Find("Le connection state machine armed state"));
}

TEST_F(LeImplTest, disarm_connectability_ARMED) {
  bluetooth::common::InitFlags::SetAllForTesting();
  std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();

  le_impl_->connectability_state_ = ConnectabilityState::ARMED;
  le_impl_->disarm_connectability();
  ASSERT_FALSE(le_impl_->disarmed_while_arming_);

  le_impl_->on_create_connection(ReturnCommandStatus(OpCode::LE_CREATE_CONNECTION, ErrorCode::SUCCESS));

  ASSERT_TRUE(log_capture->Rewind()->Find("Disarming LE connection state machine"));
  ASSERT_TRUE(log_capture->Rewind()->Find("Disarming LE connection state machine with create connection"));
}

TEST_F(LeImplTest, disarm_connectability_ARMED_extended) {
  bluetooth::common::InitFlags::SetAllForTesting();
  std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();

  le_impl_->connectability_state_ = ConnectabilityState::ARMED;
  le_impl_->disarm_connectability();
  ASSERT_FALSE(le_impl_->disarmed_while_arming_);

  le_impl_->on_extended_create_connection(
      ReturnCommandStatus(OpCode::LE_EXTENDED_CREATE_CONNECTION, ErrorCode::SUCCESS));

  ASSERT_TRUE(log_capture->Rewind()->Find("Disarming LE connection state machine"));
  ASSERT_TRUE(log_capture->Rewind()->Find("Disarming LE connection state machine with create connection"));
}

TEST_F(LeImplTest, disarm_connectability_DISARMING) {
  bluetooth::common::InitFlags::SetAllForTesting();
  std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();

  le_impl_->connectability_state_ = ConnectabilityState::DISARMING;
  le_impl_->disarm_connectability();
  ASSERT_FALSE(le_impl_->disarmed_while_arming_);

  le_impl_->on_create_connection(ReturnCommandStatus(OpCode::LE_CREATE_CONNECTION, ErrorCode::SUCCESS));

  ASSERT_TRUE(log_capture->Rewind()->Find("Attempting to disarm le connection"));
  ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMING"));
}

TEST_F(LeImplTest, disarm_connectability_DISARMING_extended) {
  bluetooth::common::InitFlags::SetAllForTesting();
  std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();

  le_impl_->connectability_state_ = ConnectabilityState::DISARMING;
  le_impl_->disarm_connectability();
  ASSERT_FALSE(le_impl_->disarmed_while_arming_);

  le_impl_->on_extended_create_connection(
      ReturnCommandStatus(OpCode::LE_EXTENDED_CREATE_CONNECTION, ErrorCode::SUCCESS));

  ASSERT_TRUE(log_capture->Rewind()->Find("Attempting to disarm le connection"));
  ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMING"));
}

}  // namespace acl_manager
}  // namespace acl_manager
}  // namespace hci
}  // namespace hci
}  // namespace bluetooth
}  // namespace bluetooth
+5 −0
Original line number Original line Diff line number Diff line
@@ -94,6 +94,11 @@ class LeAddressManager {
  void OnCommandComplete(CommandCompleteView view);
  void OnCommandComplete(CommandCompleteView view);
  std::chrono::milliseconds GetNextPrivateAddressIntervalMs();
  std::chrono::milliseconds GetNextPrivateAddressIntervalMs();


  // Unsynchronized check for testing purposes
  size_t NumberCachedCommands() const {
    return cached_commands_.size();
  }

 private:
 private:
  enum ClientState {
  enum ClientState {
    WAITING_FOR_PAUSE,
    WAITING_FOR_PAUSE,