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

Commit 897f7d55 authored by Chris Manton's avatar Chris Manton
Browse files

Add gd shim l2cap unit test

Bug: 141758481
Test: bluetooth_test_gd
Change-Id: I7ba26676a3e91f98f5d5d148422e51e737fc62f2
parent d2e1ed53
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -29,20 +29,20 @@ namespace shim {

using ConnectionClosedCallback = std::function<void(uint16_t cid, int error_code)>;
using ConnectionCompleteCallback =
    std::function<void(std::string string_address, uint16_t psm, uint16_t cid, bool connected)>;
    std::function<void(std::string string_address, uint16_t psm, uint16_t cid, bool is_connected)>;
using ReadDataReadyCallback = std::function<void(uint16_t cid, std::vector<const uint8_t> data)>;

using RegisterServicePending = std::promise<uint16_t>;
using UnregisterServicePending = std::promise<void>;
using CreateConnectionPending = std::promise<uint16_t>;
using RegisterServicePromise = std::promise<uint16_t>;
using UnregisterServicePromise = std::promise<void>;
using CreateConnectionPromise = std::promise<uint16_t>;

struct IL2cap {
  virtual void RegisterService(uint16_t psm, bool use_ertm, uint16_t mtu, ConnectionCompleteCallback on_complete,
                               RegisterServicePending register_pending) = 0;
  virtual void UnregisterService(uint16_t psm, UnregisterServicePending unregister_pending) = 0;
                               RegisterServicePromise register_promise) = 0;
  virtual void UnregisterService(uint16_t psm, UnregisterServicePromise unregister_promise) = 0;

  virtual void CreateConnection(uint16_t psm, const std::string address, ConnectionCompleteCallback on_complete,
                                CreateConnectionPending create_pending) = 0;
                                CreateConnectionPromise create_promise) = 0;
  virtual void CloseConnection(uint16_t cid) = 0;

  virtual void SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) = 0;
+209 −156

File changed.

Preview size limit exceeded, changes collapsed.

+3 −3
Original line number Diff line number Diff line
@@ -30,11 +30,11 @@ namespace shim {
class L2cap : public bluetooth::Module, public bluetooth::shim::IL2cap {
 public:
  void RegisterService(uint16_t psm, bool use_ertm, uint16_t mtu, ConnectionCompleteCallback on_complete,
                       RegisterServicePending register_pending) override;
  void UnregisterService(uint16_t psm, UnregisterServicePending unregister_pending) override;
                       RegisterServicePromise register_promise) override;
  void UnregisterService(uint16_t psm, UnregisterServicePromise unregister_promise) override;

  void CreateConnection(uint16_t psm, const std::string address_string, ConnectionCompleteCallback on_complete,
                        CreateConnectionPending create_pending) override;
                        CreateConnectionPromise create_promise) override;
  void CloseConnection(uint16_t cid) override;

  void SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) override;
+244 −63
Original line number Diff line number Diff line
@@ -16,24 +16,20 @@

#include "shim/l2cap.h"

#include <algorithm>
#include <chrono>
#include <gtest/gtest.h>
#include <future>
#include <map>
#include <memory>

#include <unistd.h>

#include <gtest/gtest.h>

#include "common/bind.h"
#include "hci/address.h"
#include "hci/address_with_type.h"
#include "l2cap/classic/dynamic_channel_configuration_option.h"
#include "l2cap/classic/dynamic_channel_manager.h"
#include "l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h"
#include "l2cap/classic/l2cap_classic_module.h"
#include "l2cap/internal/ilink.h"
#include "l2cap/psm.h"
#include "l2cap/security_policy.h"
#include "module.h"
#include "os/handler.h"

namespace bluetooth {
@@ -41,7 +37,13 @@ namespace shim {
namespace {

constexpr uint16_t kPsm = 123;
constexpr uint16_t kPsm2 = kPsm + 2;
constexpr uint16_t kCid = 456;
constexpr uint16_t kCid2 = kCid + 1;
constexpr char device_address[] = "11:22:33:44:55:66";
constexpr char device_address2[] = "aa:bb:cc:dd:ee:ff";
constexpr bool kNoUseErtm = false;
constexpr uint16_t kMtu = 1000;

class TestDynamicChannelService : public l2cap::classic::DynamicChannelService {
 public:
@@ -50,15 +52,32 @@ class TestDynamicChannelService : public l2cap::classic::DynamicChannelService {
      : DynamicChannelService(psm, manager, handler) {}
};

class TestLink : public l2cap::internal::ILink {
 public:
  hci::AddressWithType GetDevice() {
    return device_with_type_;
  }
  hci::AddressWithType device_with_type_;

  void SendLeCredit(l2cap::Cid local_cid, uint16_t credit) {}

  void SendDisconnectionRequest(l2cap::Cid cid, l2cap::Cid remote_cid) {
    connection_closed_promise_.set_value();
  }
  std::promise<void> connection_closed_promise_;
};

class TestDynamicChannelManagerImpl {
 public:
  bool ConnectChannel(hci::Address device, l2cap::classic::DynamicChannelConfigurationOption configuration_option,
                      l2cap::Psm psm,
                      l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open,
                      l2cap::Psm psm, l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback,
                      l2cap::classic::DynamicChannelManager::OnConnectionFailureCallback on_fail_callback,
                      os::Handler* handler) {
    connections_++;
    if (connected_promise_ != nullptr) connected_promise_->set_value();
    on_open_callback_ = std::move(on_open_callback);
    on_fail_callback_ = std::move(on_fail_callback);

    connected_promise_.set_value();
    return true;
  }
  int connections_{0};
@@ -66,48 +85,77 @@ class TestDynamicChannelManagerImpl {
  bool RegisterService(l2cap::Psm psm, l2cap::classic::DynamicChannelConfigurationOption configuration_option,
                       const l2cap::SecurityPolicy& security_policy,
                       l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete,
                       l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open,
                       l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback,
                       os::Handler* handler) {
    services_++;
    on_registration_complete_ = std::move(on_registration_complete);
    on_connection_open_ = std::move(on_connection_open);
    on_open_callback_ = std::move(on_open_callback);

    if (registered_promise_ != nullptr) registered_promise_->set_value();
    register_promise_.set_value();
    return true;
  }
  int services_{0};

  ~TestDynamicChannelManagerImpl() {
    if (connected_promise_ != nullptr) delete connected_promise_;
    if (registered_promise_ != nullptr) delete registered_promise_;
  void SetConnectionFuture() {
    connected_promise_ = std::promise<void>();
  }

  void WaitConnectionFuture() {
    connected_future_ = connected_promise_.get_future();
    connected_future_.wait();
  }

  void SetRegistrationFuture() {
    register_promise_ = std::promise<void>();
  }
  std::promise<void>* connected_promise_{nullptr};
  std::promise<void>* registered_promise_{nullptr};

  l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete_;
  l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open_;
  void WaitRegistrationFuture() {
    register_future_ = register_promise_.get_future();
    register_future_.wait();
  }

  void SetConnectionOnFail(l2cap::classic::DynamicChannelManager::ConnectionResult result, std::promise<void> promise) {
    std::move(on_fail_callback_).Run(result);
    promise.set_value();
  }

  void SetConnectionOnOpen(std::unique_ptr<l2cap::DynamicChannel> channel, std::promise<void> promise) {
    std::move(on_open_callback_).Run(std::move(channel));
    promise.set_value();
  }

  l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete_{};
  l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback_{};
  l2cap::classic::DynamicChannelManager::OnConnectionFailureCallback on_fail_callback_{};

  TestDynamicChannelManagerImpl() = default;
  ~TestDynamicChannelManagerImpl() = default;

 private:
  std::promise<void> connected_promise_;
  std::future<void> connected_future_;

  std::promise<void> register_promise_;
  std::future<void> register_future_;
};

class TestDynamicChannelManager : public l2cap::classic::DynamicChannelManager {
 public:
  bool ConnectChannel(hci::Address device, l2cap::classic::DynamicChannelConfigurationOption configuration_option,
                      l2cap::Psm psm,
                      l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open,
                      l2cap::Psm psm, l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback,
                      l2cap::classic::DynamicChannelManager::OnConnectionFailureCallback on_fail_callback,
                      os::Handler* handler) override {
    return impl_.ConnectChannel(device, configuration_option, psm, std::move(on_connection_open),
    return impl_.ConnectChannel(device, configuration_option, psm, std::move(on_open_callback),
                                std::move(on_fail_callback), handler);
  }

  bool RegisterService(l2cap::Psm psm, l2cap::classic::DynamicChannelConfigurationOption configuration_option,
                       const l2cap::SecurityPolicy& security_policy,
                       l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete,
                       l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open,
                       l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback,
                       os::Handler* handler) override {
    return impl_.RegisterService(psm, configuration_option, security_policy, std::move(on_registration_complete),
                                 std::move(on_connection_open), handler);
                                 std::move(on_open_callback), handler);
  }
  TestDynamicChannelManager(TestDynamicChannelManagerImpl& impl) : impl_(impl) {}
  TestDynamicChannelManagerImpl& impl_;
@@ -137,11 +185,61 @@ void TestL2capClassicModule::Stop() {

class ShimL2capTest : public ::testing::Test {
 public:
  void OnConnectionComplete(std::string string_address, uint16_t psm, uint16_t cid, bool connected) {}
  void OnConnectionComplete(std::string string_address, uint16_t psm, uint16_t cid, bool connected) {
    connection_string_address_ = string_address;
    connection_psm_ = psm;
    connection_cid_ = cid;
    connection_connected_ = connected;
    connection_complete_promise_.set_value();
  }

  uint16_t CreateConnection(uint16_t psm, std::string device_address) {
    std::promise<uint16_t> promise;
    auto future = promise.get_future();

    shim_l2cap_->CreateConnection(
        psm, device_address,
        std::bind(&bluetooth::shim::ShimL2capTest::OnConnectionComplete, this, std::placeholders::_1,
                  std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
        std::move(promise));
    return future.get();
  }

  void SetConnectionFuture() {
    test_l2cap_classic_module_->impl_->SetConnectionFuture();
  }

  void WaitConnectionFuture() {
    test_l2cap_classic_module_->impl_->WaitConnectionFuture();
  }

  void SetRegistrationFuture() {
    test_l2cap_classic_module_->impl_->SetRegistrationFuture();
  }

  void WaitRegistrationFuture() {
    test_l2cap_classic_module_->impl_->WaitRegistrationFuture();
  }

  int NumberOfConnections() const {
    return test_l2cap_classic_module_->impl_->connections_;
  }

  int NumberOfServices() const {
    return test_l2cap_classic_module_->impl_->services_;
  }

  std::string connection_string_address_;
  uint16_t connection_psm_{0};
  uint16_t connection_cid_{0};
  bool connection_connected_{false};

  shim::L2cap* shim_l2cap_ = nullptr;
  TestL2capClassicModule* test_l2cap_classic_module_{nullptr};

  TestLink test_link_;
  std::promise<void> connection_complete_promise_;

 protected:
  void SetUp() override {
    handler_ = new os::Handler(&thread_);
@@ -167,94 +265,177 @@ class ShimL2capTest : public ::testing::Test {
  os::Thread& thread_ = fake_registry_.GetTestThread();
};

TEST_F(ShimL2capTest, Module) {}
TEST_F(ShimL2capTest, CreateThenDisconnectBeforeCompletion) {
  SetConnectionFuture();

TEST_F(ShimL2capTest, ConnectThenDisconnectBeforeCompletion) {
  std::promise<uint16_t> promise;
  auto future = promise.get_future();
  ASSERT(NumberOfConnections() == 0);
  uint16_t cid = CreateConnection(kPsm, device_address);
  ASSERT(cid != 0);

  test_l2cap_classic_module_->impl_->connected_promise_ = new std::promise<void>();
  auto connection_started = test_l2cap_classic_module_->impl_->connected_promise_->get_future();
  WaitConnectionFuture();
  ASSERT(NumberOfConnections() == 1);

  shim_l2cap_->CreateConnection(
      kPsm, device_address,
      std::bind(&bluetooth::shim::ShimL2capTest::OnConnectionComplete, this, std::placeholders::_1,
                std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
      std::move(promise));
  uint16_t cid = future.get();
  shim_l2cap_->CloseConnection(cid);
}

TEST_F(ShimL2capTest, MaxCreatedConnections) {
  for (int i = 0; i < 65536 - 64; i++) {
    SetConnectionFuture();
    uint16_t cid = CreateConnection(kPsm, device_address);
    ASSERT(cid != 0);
    WaitConnectionFuture();

    ASSERT(NumberOfConnections() == i + 1);
  }
  uint16_t cid = CreateConnection(kPsm, device_address);
  ASSERT(cid == 0);

  ASSERT(NumberOfConnections() == 65536 - 64);
}

TEST_F(ShimL2capTest, TwoDifferentCreatedConnections) {
  {
    SetConnectionFuture();
    uint16_t cid = CreateConnection(kPsm, device_address);
    ASSERT(cid != 0);
    WaitConnectionFuture();

    ASSERT(NumberOfConnections() == 1);
  }

  {
    SetConnectionFuture();
    uint16_t cid = CreateConnection(kPsm2, device_address2);
    ASSERT(cid != 0);
    WaitConnectionFuture();

  connection_started.wait();
    ASSERT(NumberOfConnections() == 2);
  }
}

TEST_F(ShimL2capTest, ConnectFail) {
  SetConnectionFuture();
  uint16_t cid = CreateConnection(kPsm, device_address);
  ASSERT(cid != 0);
  WaitConnectionFuture();

  ASSERT(test_l2cap_classic_module_->impl_->connections_ == 1);
  ASSERT(NumberOfConnections() == 1);

  l2cap::classic::DynamicChannelManager::ConnectionResult result{
      .connection_result_code = TestDynamicChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED,
      .hci_error = hci::ErrorCode::SUCCESS,
      .l2cap_connection_response_result = l2cap::ConnectionResponseResult::SUCCESS,
  };

  std::promise<void> on_fail_promise;
  auto on_fail_future = on_fail_promise.get_future();
  handler_->Post(common::BindOnce(&TestDynamicChannelManagerImpl::SetConnectionOnFail,
                                  common::Unretained(test_l2cap_classic_module_->impl_.get()), result,
                                  std::move(on_fail_promise)));
  on_fail_future.wait();

  ASSERT(connection_connected_ == false);

  shim_l2cap_->CloseConnection(cid);
}

TEST_F(ShimL2capTest, RegisterService_Success) {
  std::promise<uint16_t> promise;
  auto future = promise.get_future();
TEST_F(ShimL2capTest, ConnectOpen) {
  SetConnectionFuture();
  uint16_t cid = CreateConnection(kPsm, device_address);
  ASSERT(cid != 0);
  WaitConnectionFuture();

  ASSERT(NumberOfConnections() == 1);

  hci::Address address;
  hci::Address::FromString(device_address, address);
  test_link_.device_with_type_ = hci::AddressWithType(address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);

  l2cap::Psm psm = kPsm;
  l2cap::Cid local_cid = kCid;
  l2cap::Cid remote_cid = kCid2;

  std::shared_ptr<l2cap::internal::DynamicChannelImpl> impl =
      std::make_shared<l2cap::internal::DynamicChannelImpl>(psm, local_cid, remote_cid, &test_link_, handler_);

  auto channel = std::make_unique<l2cap::DynamicChannel>(impl, handler_);

  std::promise<void> on_fail_promise;
  auto on_fail_future = on_fail_promise.get_future();

  auto connection_complete_future = connection_complete_promise_.get_future();
  handler_->Post(common::BindOnce(&TestDynamicChannelManagerImpl::SetConnectionOnOpen,
                                  common::Unretained(test_l2cap_classic_module_->impl_.get()), std::move(channel),
                                  std::move(on_fail_promise)));
  connection_complete_future.wait();

  on_fail_future.wait();

  ASSERT(connection_connected_ == true);

  auto future = test_link_.connection_closed_promise_.get_future();
  shim_l2cap_->CloseConnection(cid);
  future.wait();
}

  test_l2cap_classic_module_->impl_->registered_promise_ = new std::promise<void>();
  auto registration_started = test_l2cap_classic_module_->impl_->registered_promise_->get_future();
TEST_F(ShimL2capTest, RegisterService_Success) {
  std::promise<uint16_t> registration_promise;
  auto registration_pending = registration_promise.get_future();

  SetRegistrationFuture();
  shim_l2cap_->RegisterService(
      kPsm, false, 1000,
      kPsm, kNoUseErtm, kMtu,
      std::bind(&bluetooth::shim::ShimL2capTest::OnConnectionComplete, this, std::placeholders::_1,
                std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
      std::move(promise));
      std::move(registration_promise));
  WaitRegistrationFuture();
  ASSERT_LOG(test_l2cap_classic_module_->impl_->on_registration_complete_, "Synchronization failure");
  ASSERT(test_l2cap_classic_module_->impl_->services_ == 1);

  l2cap::classic::DynamicChannelManager::RegistrationResult result{
      l2cap::classic::DynamicChannelManager::RegistrationResult::SUCCESS,
  };
  auto service = std::make_unique<TestDynamicChannelService>(kPsm, &mock_, handler_);
  registration_started.wait();

  ASSERT_LOG(test_l2cap_classic_module_->impl_->on_registration_complete_, "Synchronization failure");
  handler_->Post(common::BindOnce(std::move(test_l2cap_classic_module_->impl_->on_registration_complete_), result,
                                  std::move(service)));
  uint16_t psm = future.get();
  uint16_t psm = registration_pending.get();
  ASSERT(psm == kPsm);
  ASSERT(test_l2cap_classic_module_->impl_->services_ == 1);
}

TEST_F(ShimL2capTest, RegisterService_Duplicate) {
  std::promise<uint16_t> promise;
  auto future = promise.get_future();

  test_l2cap_classic_module_->impl_->registered_promise_ = new std::promise<void>();
  auto registration_started = test_l2cap_classic_module_->impl_->registered_promise_->get_future();

  SetRegistrationFuture();
  shim_l2cap_->RegisterService(
      kPsm, false, 1000,
      kPsm, kNoUseErtm, kMtu,
      std::bind(&bluetooth::shim::ShimL2capTest::OnConnectionComplete, this, std::placeholders::_1,
                std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
      std::move(promise));
  WaitRegistrationFuture();
  ASSERT_LOG(test_l2cap_classic_module_->impl_->on_registration_complete_, "Synchronization failure");
  ASSERT(test_l2cap_classic_module_->impl_->services_ == 1);

  l2cap::classic::DynamicChannelManager::RegistrationResult result{
      l2cap::classic::DynamicChannelManager::RegistrationResult::FAIL_DUPLICATE_SERVICE,
  };
  auto service = std::make_unique<TestDynamicChannelService>(kPsm, &mock_, handler_);
  registration_started.wait();

  ASSERT_LOG(test_l2cap_classic_module_->impl_->on_registration_complete_, "Synchronization failure");
  handler_->Post(common::BindOnce(std::move(test_l2cap_classic_module_->impl_->on_registration_complete_), result,
                                  std::move(service)));
  uint16_t psm = future.get();
  ASSERT(psm == l2cap::kDefaultPsm);
  ASSERT(test_l2cap_classic_module_->impl_->services_ == 1);
}

TEST_F(ShimL2capTest, RegisterService_Invalid) {
  std::promise<uint16_t> promise;
  auto future = promise.get_future();

  test_l2cap_classic_module_->impl_->registered_promise_ = new std::promise<void>();
  auto registration_started = test_l2cap_classic_module_->impl_->registered_promise_->get_future();
  SetRegistrationFuture();

  shim_l2cap_->RegisterService(
      kPsm, false, 1000,
      kPsm, kNoUseErtm, kMtu,
      std::bind(&bluetooth::shim::ShimL2capTest::OnConnectionComplete, this, std::placeholders::_1,
                std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
      std::move(promise));
@@ -263,7 +444,7 @@ TEST_F(ShimL2capTest, RegisterService_Invalid) {
      l2cap::classic::DynamicChannelManager::RegistrationResult::FAIL_INVALID_SERVICE,
  };
  auto service = std::make_unique<TestDynamicChannelService>(kPsm, &mock_, handler_);
  registration_started.wait();
  WaitRegistrationFuture();

  ASSERT_LOG(test_l2cap_classic_module_->impl_->on_registration_complete_, "Synchronization failure");
  handler_->Post(common::BindOnce(std::move(test_l2cap_classic_module_->impl_->on_registration_complete_), result,
+9 −9
Original line number Diff line number Diff line
@@ -172,8 +172,8 @@ uint16_t bluetooth::shim::legacy::L2cap::RegisterService(
  }

  LOG_DEBUG(LOG_TAG, "Registering service on psm:%hd", psm);
  RegisterServicePending register_pending;
  auto service_registered = register_pending.get_future();
  RegisterServicePromise register_promise;
  auto service_registered = register_promise.get_future();
  bool use_ertm = false;
  if (p_ertm_info != nullptr &&
      p_ertm_info->preferred_mode == L2CAP_FCR_ERTM_MODE) {
@@ -186,7 +186,7 @@ uint16_t bluetooth::shim::legacy::L2cap::RegisterService(
          &bluetooth::shim::legacy::L2cap::OnRemoteInitiatedConnectionCreated,
          this, std::placeholders::_1, std::placeholders::_2,
          std::placeholders::_3),
      std::move(register_pending));
      std::move(register_promise));

  uint16_t registered_psm = service_registered.get();
  if (registered_psm != psm) {
@@ -213,10 +213,10 @@ void bluetooth::shim::legacy::L2cap::UnregisterService(uint16_t psm) {
  }

  LOG_DEBUG(LOG_TAG, "Unregistering service on psm:%hd", psm);
  UnregisterServicePending unregister_pending;
  auto service_unregistered = unregister_pending.get_future();
  UnregisterServicePromise unregister_promise;
  auto service_unregistered = unregister_promise.get_future();
  bluetooth::shim::GetL2cap()->UnregisterService(psm,
                                                 std::move(unregister_pending));
                                                 std::move(unregister_promise));
  service_unregistered.wait();
  Classic().UnregisterPsm(psm);
}
@@ -229,8 +229,8 @@ uint16_t bluetooth::shim::legacy::L2cap::CreateConnection(
    return kInvalidConnectionInterfaceDescriptor;
  }

  CreateConnectionPending create_pending;
  auto created = create_pending.get_future();
  CreateConnectionPromise create_promise;
  auto created = create_promise.get_future();
  LOG_DEBUG(LOG_TAG, "Initiating local connection to psm:%hd address:%s", psm,
            raw_address.ToString().c_str());

@@ -240,7 +240,7 @@ uint16_t bluetooth::shim::legacy::L2cap::CreateConnection(
          &bluetooth::shim::legacy::L2cap::OnLocalInitiatedConnectionCreated,
          this, std::placeholders::_1, std::placeholders::_2,
          std::placeholders::_3, std::placeholders::_4),
      std::move(create_pending));
      std::move(create_promise));

  uint16_t cid = created.get();
  if (cid == kInvalidConnectionInterfaceDescriptor) {
Loading