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

Commit 92caecf5 authored by Myles Watson's avatar Myles Watson Committed by Automerger Merge Worker
Browse files

LeAclManagerFacade: Allow multiple connections am: b2af0bd5

parents 043f523b b2af0bd5
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -7,8 +7,6 @@ import "blueberry/facade/common.proto";

service LeAclManagerFacade {
  rpc CreateConnection(CreateConnectionMsg) returns (stream LeConnectionEvent) {}
  rpc CreateBackgroundAndDirectConnection(blueberry.facade.BluetoothAddressWithType)
      returns (stream LeConnectionEvent) {}
  rpc CancelConnection(blueberry.facade.BluetoothAddressWithType) returns (google.protobuf.Empty) {}
  rpc Disconnect(LeHandleMsg) returns (google.protobuf.Empty) {}
  rpc ConnectionCommand(LeConnectionCommandMsg) returns (google.protobuf.Empty) {}
+1 −12
Original line number Diff line number Diff line
@@ -115,24 +115,13 @@ class PyLeAclManager(Closable):

    def initiate_connection(self, remote_addr, is_direct=True):
        assertThat(self.next_token in self.outgoing_connection_event_streams).isFalse()
        create_connection_msg = le_acl_manager_facade.CreateConnectionMsg(
            peer_address=remote_addr,
            is_direct=is_direct
        )
        create_connection_msg = le_acl_manager_facade.CreateConnectionMsg(peer_address=remote_addr, is_direct=is_direct)
        self.outgoing_connection_event_streams[self.next_token] = EventStream(
            self.le_acl_manager.CreateConnection(create_connection_msg)), remote_addr
        token = self.next_token
        self.next_token += 1
        return token

    def initiate_background_and_direct_connection(self, remote_addr):
        assertThat(self.next_token in self.outgoing_connection_event_streams).isFalse()
        self.outgoing_connection_event_streams[self.next_token] = EventStream(
            self.le_acl_manager.CreateBackgroundAndDirectConnection(remote_addr)), remote_addr
        token = self.next_token
        self.next_token += 1
        return token

    def complete_connection(self, event_stream):
        connection_complete = HciCaptures.LeConnectionCompleteCapture()
        assertThat(event_stream).emits(connection_complete)
+54 −4
Original line number Diff line number Diff line
@@ -200,13 +200,19 @@ class LeAclManagerTest(gd_base_test.GdBaseTestClass):
        self.set_privacy_policy_static()

        # Start background and direct connection
        token = self.dut_le_acl_manager.initiate_background_and_direct_connection(
        token_direct = self.dut_le_acl_manager.initiate_connection(
            remote_addr=common.BluetoothAddressWithType(
                address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:01', 'utf8')),
                address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:02', 'utf8')),
                type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)))

        token_background = self.dut_le_acl_manager.initiate_connection(
            remote_addr=common.BluetoothAddressWithType(
                address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:01', 'utf8')),
                type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)),
            is_direct=False)

        # Wait for direct connection timeout
        self.dut_le_acl_manager.wait_for_connection_fail(token)
        self.dut_le_acl_manager.wait_for_connection_fail(token_direct)

        # Cert Advertises
        advertising_handle = 0
@@ -219,7 +225,51 @@ class LeAclManagerTest(gd_base_test.GdBaseTestClass):
        py_hci_adv.start()

        # Check background connection complete
        self.dut_le_acl_manager.complete_outgoing_connection(token)
        self.dut_le_acl_manager.complete_outgoing_connection(token_background)

    def test_multiple_background_connections(self):
        self.set_privacy_policy_static()

        # Start two background connections
        token_1 = self.dut_le_acl_manager.initiate_connection(
            remote_addr=common.BluetoothAddressWithType(
                address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:01', 'utf8')),
                type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)),
            is_direct=False)

        token_2 = self.dut_le_acl_manager.initiate_connection(
            remote_addr=common.BluetoothAddressWithType(
                address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:02', 'utf8')),
                type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)),
            is_direct=False)

        # Cert Advertises
        advertising_handle = 0

        py_hci_adv = self.cert_hci.create_advertisement(advertising_handle, '0C:05:04:03:02:01',
                                                        hci_packets.LegacyAdvertisingProperties.ADV_IND, 155, 165)

        py_hci_adv.set_data(b'Im_A_Cert')
        py_hci_adv.set_scan_response(b'Im_A_C')
        py_hci_adv.start()

        # First background connection completes
        connection = self.dut_le_acl_manager.complete_outgoing_connection(token_1)
        connection.close()

        # Cert Advertises again
        advertising_handle = 0

        py_hci_adv = self.cert_hci.create_advertisement(advertising_handle, '0C:05:04:03:02:02',
                                                        hci_packets.LegacyAdvertisingProperties.ADV_IND, 155, 165)

        py_hci_adv.set_data(b'Im_A_Cert')
        py_hci_adv.set_scan_response(b'Im_A_C')
        py_hci_adv.start()

        # Second background connection completes
        connection = self.dut_le_acl_manager.complete_outgoing_connection(token_2)
        connection.close()

    def test_direct_connection(self):
        self.set_privacy_policy_static()
+52 −54
Original line number Diff line number Diff line
@@ -71,31 +71,21 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC
    bool is_direct = request->is_direct();
    acl_manager_->CreateLeConnection(peer, is_direct);

    if (per_connection_events_.size() > current_connection_request_) {
      return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding request is supported");
    if (is_direct) {
      if (direct_connection_events_ != nullptr) {
        return ::grpc::Status(
            ::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding direct request is supported");
      }
    per_connection_events_.emplace_back(std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
        std::string("connection attempt ") + std::to_string(current_connection_request_)));
    return per_connection_events_[current_connection_request_]->RunLoop(context, writer);
      direct_connection_events_ = std::make_shared<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
          std::string("direct connection attempt ") + peer.ToString());
      direct_connection_address_ = peer;
      return direct_connection_events_->RunLoop(context, writer);
    }

  ::grpc::Status CreateBackgroundAndDirectConnection(
      ::grpc::ServerContext* context,
      const ::blueberry::facade::BluetoothAddressWithType* request,
      ::grpc::ServerWriter<LeConnectionEvent>* writer) override {
    Address peer_address;
    ASSERT(Address::FromString(request->address().address(), peer_address));
    AddressWithType peer(peer_address, static_cast<AddressType>(request->type()));
    // Create background connection first
    acl_manager_->CreateLeConnection(peer, /* is_direct */ false);
    acl_manager_->CreateLeConnection(peer, /* is_direct */ true);
    wait_for_background_connection_complete = true;
    if (per_connection_events_.size() > current_connection_request_) {
      return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding request is supported");
    }
    per_connection_events_.emplace_back(std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
        std::string("connection attempt ") + std::to_string(current_connection_request_)));
    return per_connection_events_[current_connection_request_]->RunLoop(context, writer);
    per_connection_events_.emplace(
        peer,
        std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
            std::string("connection attempt ") + peer.ToString()));
    return per_connection_events_[peer]->RunLoop(context, writer);
  }

  ::grpc::Status CancelConnection(
@@ -105,10 +95,14 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC
    Address peer_address;
    ASSERT(Address::FromString(request->address().address(), peer_address));
    AddressWithType peer(peer_address, static_cast<AddressType>(request->type()));
    if (per_connection_events_.size() == current_connection_request_) {
      // Todo: Check that the address matches an outstanding connection request
    if (peer == direct_connection_address_) {
      direct_connection_address_ = AddressWithType();
      direct_connection_events_.reset();
    } else {
      if (per_connection_events_.count(peer) == 0) {
        return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "No matching outstanding connection");
      }
    }
    acl_manager_->CancelLeConnect(peer);
    return ::grpc::Status::OK;
  }
@@ -166,12 +160,13 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC
      ::grpc::ServerContext* context,
      const google::protobuf::Empty* request,
      ::grpc::ServerWriter<LeConnectionEvent>* writer) override {
    if (per_connection_events_.size() > current_connection_request_) {
      return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding connection is supported");
    if (incoming_connection_events_ != nullptr) {
      return ::grpc::Status(
          ::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding incoming connection is supported");
    }
    per_connection_events_.emplace_back(std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
        std::string("incoming connection ") + std::to_string(current_connection_request_)));
    return per_connection_events_[current_connection_request_]->RunLoop(context, writer);
    incoming_connection_events_ =
        std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(std::string("incoming connection "));
    return incoming_connection_events_->RunLoop(context, writer);
  }

  ::grpc::Status SendAclData(
@@ -235,17 +230,26 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC
    connection_tracker->second.pending_acl_data_.OnIncomingEvent(acl_data);
  }

  void OnLeConnectSuccess(AddressWithType address_with_type, std::unique_ptr<LeAclConnection> connection) override {
    LOG_INFO("%s", address_with_type.ToString().c_str());
  void OnLeConnectSuccess(AddressWithType peer, std::unique_ptr<LeAclConnection> connection) override {
    LOG_INFO("%s", peer.ToString().c_str());

    std::unique_lock<std::mutex> lock(acl_connections_mutex_);
    auto addr = address_with_type.GetAddress();
    std::shared_ptr<LeAclConnection> shared_connection = std::move(connection);
    uint16_t handle = shared_connection->GetHandle();
    auto role = shared_connection->GetRole();
    if (role == Role::PERIPHERAL) {
      ASSERT(incoming_connection_events_ != nullptr);
      per_connection_events_.emplace(peer, incoming_connection_events_);
      incoming_connection_events_.reset();
    } else if (direct_connection_address_ == peer) {
      direct_connection_address_ = AddressWithType();
      per_connection_events_.emplace(peer, direct_connection_events_);
      direct_connection_events_.reset();
    }
    acl_connections_.emplace(
        std::piecewise_construct,
        std::forward_as_tuple(handle),
        std::forward_as_tuple(handle, shared_connection, per_connection_events_[current_connection_request_]));
        std::forward_as_tuple(handle, shared_connection, per_connection_events_[peer]));
    shared_connection->GetAclQueueEnd()->RegisterDequeue(
        facade_handler_,
        common::Bind(&LeAclManagerFacadeService::on_incoming_acl, common::Unretained(this), shared_connection, handle));
@@ -253,21 +257,11 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC
    shared_connection->RegisterCallbacks(callbacks, facade_handler_);
    {
      std::unique_ptr<BasePacketBuilder> builder = LeConnectionCompleteBuilder::Create(
          ErrorCode::SUCCESS,
          handle,
          Role::CENTRAL,
          address_with_type.GetAddressType(),
          addr,
          1,
          2,
          3,
          ClockAccuracy::PPM_20);
          ErrorCode::SUCCESS, handle, role, peer.GetAddressType(), peer.GetAddress(), 1, 2, 3, ClockAccuracy::PPM_20);
      LeConnectionEvent success;
      success.set_payload(builder_to_string(std::move(builder)));
      per_connection_events_[current_connection_request_]->OnIncomingEvent(success);
      per_connection_events_[peer]->OnIncomingEvent(success);
    }
    wait_for_background_connection_complete = false;
    current_connection_request_++;
  }

  void OnLeConnectFail(AddressWithType address, ErrorCode reason) override {
@@ -275,9 +269,11 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC
        reason, 0, Role::CENTRAL, address.GetAddressType(), address.GetAddress(), 0, 0, 0, ClockAccuracy::PPM_20);
    LeConnectionEvent fail;
    fail.set_payload(builder_to_string(std::move(builder)));
    per_connection_events_[current_connection_request_]->OnIncomingEvent(fail);
    if (!wait_for_background_connection_complete) {
      current_connection_request_++;
    if (address == direct_connection_address_) {
      direct_connection_address_ = AddressWithType();
      direct_connection_events_->OnIncomingEvent(fail);
    } else {
      per_connection_events_[address]->OnIncomingEvent(fail);
    }
  }

@@ -334,10 +330,12 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC
  AclManager* acl_manager_;
  ::bluetooth::os::Handler* facade_handler_;
  mutable std::mutex acl_connections_mutex_;
  std::vector<std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>> per_connection_events_;
  std::map<bluetooth::hci::AddressWithType, std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>>
      per_connection_events_;
  std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>> direct_connection_events_;
  bluetooth::hci::AddressWithType direct_connection_address_;
  std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>> incoming_connection_events_;
  std::map<uint16_t, Connection> acl_connections_;
  uint32_t current_connection_request_{0};
  bool wait_for_background_connection_complete = false;
};

void LeAclManagerFacadeModule::ListDependencies(ModuleList* list) const {