From c6f874451d21284fc97f068e2c882b5e852752c9 Mon Sep 17 00:00:00 2001 From: Chris Manton Date: Fri, 8 Nov 2019 15:19:33 -0800 Subject: [PATCH] gd shim layer changes Bug: 144171652 Test: bluetooth_test_gd Change-Id: If56602e1a90d692435b4366b98c959cc4a13e09f --- gd/shim/il2cap.h | 3 + gd/shim/l2cap.cc | 305 ++++++++++++++++++++++++++++++------------------ gd/shim/l2cap.h | 3 + main/shim/test_stack.cc | 4 + main/shim/test_stack.h | 2 + 5 files changed, 204 insertions(+), 113 deletions(-) diff --git a/gd/shim/il2cap.h b/gd/shim/il2cap.h index 363c28f51..c4e746359 100644 --- a/gd/shim/il2cap.h +++ b/gd/shim/il2cap.h @@ -34,7 +34,10 @@ using ReadDataReadyCallback = std::function completed) = 0; + virtual void UnregisterService(uint16_t psm) = 0; + virtual void CreateConnection(uint16_t psm, const std::string address, std::promise completed) = 0; + virtual void CloseConnection(uint16_t cid) = 0; virtual void SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) = 0; virtual void SetConnectionClosedCallback(uint16_t cid, ConnectionClosedCallback on_closed) = 0; diff --git a/gd/shim/l2cap.cc b/gd/shim/l2cap.cc index 9db5f4acc..58b10b562 100644 --- a/gd/shim/l2cap.cc +++ b/gd/shim/l2cap.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,11 @@ static const ConnectionInterfaceDescriptor kInvalidConnectionInterfaceDescriptor static const ConnectionInterfaceDescriptor kStartConnectionInterfaceDescriptor = 64; static const ConnectionInterfaceDescriptor kMaxConnections = UINT16_MAX - kStartConnectionInterfaceDescriptor - 1; +using ServiceInterfaceCallback = + std::function; +using ConnectionInterfaceCallback = + std::function)>; + std::unique_ptr MakeUniquePacket(const uint8_t* data, size_t len) { packet::RawBuilder builder; std::vector bytes(data, data + len); @@ -60,7 +66,7 @@ class ConnectionInterface { ConnectionInterface(ConnectionInterfaceDescriptor cid, std::unique_ptr channel, os::Handler* handler) : cid_(cid), channel_(std::move(channel)), handler_(handler), on_data_ready_callback_(nullptr), - on_connection_closed_callback_(nullptr) { + on_connection_closed_callback_(nullptr), address_(channel_->GetDevice()) { channel_->RegisterOnCloseCallback( handler_, common::BindOnce(&ConnectionInterface::OnConnectionClosed, common::Unretained(this))); channel_->GetQueueUpEnd()->RegisterDequeue( @@ -69,10 +75,7 @@ class ConnectionInterface { } ~ConnectionInterface() { - if (dequeue_registered_) { - channel_->GetQueueUpEnd()->UnregisterDequeue(); - dequeue_registered_ = false; - } + ASSERT(!dequeue_registered_); } void OnReadReady() { @@ -86,11 +89,10 @@ class ConnectionInterface { on_data_ready_callback_(cid_, data); } - void OnConnectionClosed(hci::ErrorCode error_code) { - LOG_DEBUG("Channel interface closed reason:%s cid:%hd device:%s", hci::ErrorCodeText(error_code).c_str(), cid_, - channel_->GetDevice().ToString().c_str()); - ASSERT(on_connection_closed_callback_ != nullptr); - on_connection_closed_callback_(cid_, static_cast(error_code)); + void SetReadDataReadyCallback(ReadDataReadyCallback on_data_ready) { + ASSERT(on_data_ready != nullptr); + ASSERT(on_data_ready_callback_ == nullptr); + on_data_ready_callback_ = on_data_ready; } std::unique_ptr WriteReady() { @@ -103,17 +105,8 @@ class ConnectionInterface { return data; } - void SetReadDataReadyCallback(ReadDataReadyCallback on_data_ready) { - ASSERT(on_data_ready_callback_ == nullptr); - on_data_ready_callback_ = on_data_ready; - } - - void SetConnectionClosedCallback(::bluetooth::shim::ConnectionClosedCallback on_connection_closed) { - ASSERT(on_connection_closed_callback_ == nullptr); - on_connection_closed_callback_ = on_connection_closed; - } - void Write(std::unique_ptr packet) { + LOG_DEBUG("Writing packet cid:%hd size:%zd", cid_, packet->size()); write_queue_.push(std::move(packet)); if (!enqueue_registered_) { enqueue_registered_ = true; @@ -123,18 +116,36 @@ class ConnectionInterface { } void Close() { + if (dequeue_registered_) { + channel_->GetQueueUpEnd()->UnregisterDequeue(); + dequeue_registered_ = false; + } ASSERT(write_queue_.empty()); - channel_->GetQueueUpEnd()->UnregisterDequeue(); channel_->Close(); } + void OnConnectionClosed(hci::ErrorCode error_code) { + LOG_DEBUG("Channel interface closed reason:%s cid:%hd device:%s", hci::ErrorCodeText(error_code).c_str(), cid_, + address_.ToString().c_str()); + ASSERT(on_connection_closed_callback_ != nullptr); + on_connection_closed_callback_(cid_, static_cast(error_code)); + } + + void SetConnectionClosedCallback(::bluetooth::shim::ConnectionClosedCallback on_connection_closed) { + ASSERT(on_connection_closed != nullptr); + ASSERT(on_connection_closed_callback_ == nullptr); + on_connection_closed_callback_ = std::move(on_connection_closed); + } + private: - ConnectionInterfaceDescriptor cid_; - std::unique_ptr channel_; + const ConnectionInterfaceDescriptor cid_; + const std::unique_ptr channel_; os::Handler* handler_; ReadDataReadyCallback on_data_ready_callback_; - ::bluetooth::shim::ConnectionClosedCallback on_connection_closed_callback_; + ConnectionClosedCallback on_connection_closed_callback_; + + const hci::Address address_; std::queue>> write_queue_; @@ -152,7 +163,6 @@ struct ConnectionInterfaceManager { bool Write(ConnectionInterfaceDescriptor cid, std::unique_ptr packet); - bool HasResources() const; void SetHandler(os::Handler* handler) { handler_ = handler; } @@ -168,38 +178,50 @@ struct ConnectionInterfaceManager { ConnectionInterfaceDescriptor current_connection_interface_descriptor_; os::Handler* handler_; + bool HasResources() const; bool Exists(ConnectionInterfaceDescriptor id) const; + ConnectionInterfaceDescriptor AllocateConnectionInterfaceDescriptor(); }; ConnectionInterfaceManager::ConnectionInterfaceManager() : current_connection_interface_descriptor_(kStartConnectionInterfaceDescriptor) {} -ConnectionInterfaceDescriptor ConnectionInterfaceManager::AddChannel( - std::unique_ptr channel) { +bool ConnectionInterfaceManager::Exists(ConnectionInterfaceDescriptor cid) const { + return cid_to_interface_map_.find(cid) != cid_to_interface_map_.end(); +} + +ConnectionInterfaceDescriptor ConnectionInterfaceManager::AllocateConnectionInterfaceDescriptor() { ASSERT(HasResources()); while (Exists(current_connection_interface_descriptor_)) { if (++current_connection_interface_descriptor_ == kInvalidConnectionInterfaceDescriptor) { current_connection_interface_descriptor_ = kStartConnectionInterfaceDescriptor; } } - auto channel_interface = - std::make_unique(current_connection_interface_descriptor_, std::move(channel), handler_); - cid_to_interface_map_[current_connection_interface_descriptor_] = std::move(channel_interface); - return current_connection_interface_descriptor_; + return current_connection_interface_descriptor_++; +} + +ConnectionInterfaceDescriptor ConnectionInterfaceManager::AddChannel( + std::unique_ptr channel) { + if (!HasResources()) { + return kInvalidConnectionInterfaceDescriptor; + } + ConnectionInterfaceDescriptor cid = AllocateConnectionInterfaceDescriptor(); + + auto channel_interface = std::make_unique(cid, std::move(channel), handler_); + cid_to_interface_map_[cid] = std::move(channel_interface); + return cid; } void ConnectionInterfaceManager::RemoveConnection(ConnectionInterfaceDescriptor cid) { - ASSERT(cid_to_interface_map_.erase(cid) == 1); + ASSERT(cid_to_interface_map_.count(cid) == 1); + cid_to_interface_map_.find(cid)->second->Close(); + cid_to_interface_map_.erase(cid); } bool ConnectionInterfaceManager::HasResources() const { return cid_to_interface_map_.size() < kMaxConnections; } -bool ConnectionInterfaceManager::Exists(ConnectionInterfaceDescriptor cid) const { - return cid_to_interface_map_.find(cid) != cid_to_interface_map_.end(); -} - void ConnectionInterfaceManager::SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready) { ASSERT(Exists(cid)); @@ -220,59 +242,75 @@ bool ConnectionInterfaceManager::Write(ConnectionInterfaceDescriptor cid, std::u return true; } -struct ServiceManager { +class ServiceInterface { public: - void AddService(l2cap::Psm psm, std::unique_ptr service); - void RemoveService(l2cap::Psm psm); - - ServiceManager() = default; + ServiceInterface(uint16_t psm, ServiceInterfaceCallback register_callback, + ConnectionInterfaceCallback connection_callback) + : psm_(psm), register_callback_(register_callback), connection_callback_(connection_callback) {} - private: - std::unordered_map> psm_to_service_map_; + void OnRegistrationComplete(l2cap::classic::DynamicChannelManager::RegistrationResult result, + std::unique_ptr service) { + ASSERT(service_ == nullptr); + ASSERT(psm_ == service->GetPsm()); + LOG_DEBUG("Registration is complete for psm:%hd", psm_); + service_ = std::move(service); + register_callback_(psm_, result); + } - bool Exists(l2cap::Psm psm) const; -}; + void OnConnectionOpen(std::unique_ptr channel) { + LOG_DEBUG("Connection is open to device:%s for psm:%hd", channel->GetDevice().ToString().c_str(), psm_); + connection_callback_(psm_, std::move(channel)); + } -void ServiceManager::AddService(l2cap::Psm psm, std::unique_ptr service) { - ASSERT(psm_to_service_map_.find(psm) == psm_to_service_map_.end()); - psm_to_service_map_[psm] = std::move(service); -} + l2cap::SecurityPolicy GetSecurityPolicy() const { + return security_policy_; + } -void ServiceManager::RemoveService(l2cap::Psm psm) { - ASSERT(psm_to_service_map_.erase(psm) == 1); -} + void RegisterService( + std::function + func) { + func(psm_, security_policy_, common::BindOnce(&ServiceInterface::OnRegistrationComplete, common::Unretained(this)), + common::Bind(&ServiceInterface::OnConnectionOpen, common::Unretained(this))); + } -bool ServiceManager::Exists(l2cap::Psm psm) const { - return psm_to_service_map_.find(psm) != psm_to_service_map_.end(); -} + private: + const l2cap::Psm psm_; + std::unique_ptr service_; + const l2cap::SecurityPolicy security_policy_; + ServiceInterfaceCallback register_callback_; + ConnectionInterfaceCallback connection_callback_; +}; struct L2cap::impl { void RegisterService(l2cap::Psm psm, ConnectionOpenCallback on_open, std::promise completed); + void UnregisterService(l2cap::Psm psm); + void CreateConnection(l2cap::Psm psm, hci::Address address, std::promise completed); + void CloseConnection(ConnectionInterfaceDescriptor cid); - void OnRegistrationComplete(l2cap::classic::DynamicChannelManager::RegistrationResult result, - std::unique_ptr service); - void OnConnectionOpen(std::unique_ptr channel); - void OnConnectionFailure(l2cap::classic::DynamicChannelManager::ConnectionResult result); + void OnConnectionOpenNever(std::unique_ptr channel); + void OnConnectionFailureNever(l2cap::classic::DynamicChannelManager::ConnectionResult result); bool Write(ConnectionInterfaceDescriptor cid, std::unique_ptr packet); impl(L2cap& module, l2cap::classic::L2capClassicModule* l2cap_module); ConnectionInterfaceManager connection_interface_manager_; - ServiceManager service_manager_; - private: - void SyncConnectionOpen(ConnectionInterfaceDescriptor cid); + void OpenConnection(l2cap::Psm psm, ConnectionInterfaceDescriptor cid); + private: L2cap& module_; l2cap::classic::L2capClassicModule* l2cap_module_{nullptr}; - - std::unordered_map psm_to_connection_open_map_; - std::unique_ptr dynamic_channel_manager_; - std::queue> register_completed_queue_; - std::queue> connect_completed_queue_; + std::unordered_map> psm_to_service_interface_map_; + std::unordered_map psm_to_on_open_map_; + + std::mutex mutex_; + std::unordered_map> psm_to_register_complete_map_; + std::unordered_map>> psm_to_connect_completed_queue_; os::Handler* handler_; }; @@ -284,40 +322,12 @@ L2cap::impl::impl(L2cap& module, l2cap::classic::L2capClassicModule* l2cap_modul connection_interface_manager_.SetHandler(handler_); } -void L2cap::impl::OnRegistrationComplete(l2cap::classic::DynamicChannelManager::RegistrationResult result, - std::unique_ptr service) { - LOG_DEBUG("Registration is complete"); - ASSERT(!register_completed_queue_.empty()); - auto completed = std::move(register_completed_queue_.front()); - register_completed_queue_.pop(); - completed.set_value(); - - service_manager_.AddService(service->GetPsm(), std::move(service)); -} - -void L2cap::impl::SyncConnectionOpen(ConnectionInterfaceDescriptor cid) { - ASSERT(!connect_completed_queue_.empty()); - auto completed = std::move(connect_completed_queue_.front()); - connect_completed_queue_.pop(); - completed.set_value(cid); +void L2cap::impl::OnConnectionOpenNever(std::unique_ptr channel) { + ASSERT(false); } -void L2cap::impl::OnConnectionOpen(std::unique_ptr channel) { - LOG_DEBUG("Connection is open to connect_queue_size:%zd device:%s", connect_completed_queue_.size(), - channel->GetDevice().ToString().c_str()); - - ConnectionInterfaceDescriptor cid = kInvalidConnectionInterfaceDescriptor; - if (connection_interface_manager_.HasResources()) { - cid = connection_interface_manager_.AddChannel(std::move(channel)); - } - if (!connect_completed_queue_.empty()) { - SyncConnectionOpen(cid); - } - // TODO(cmanton) Inform legacy psm service that a new connection is - // available -} - -void L2cap::impl::OnConnectionFailure(l2cap::classic::DynamicChannelManager::ConnectionResult result) { +void L2cap::impl::OnConnectionFailureNever(l2cap::classic::DynamicChannelManager::ConnectionResult result) { + ASSERT(false); switch (result.connection_result_code) { case l2cap::classic::DynamicChannelManager::ConnectionResultCode::SUCCESS: LOG_WARN("Connection failed result:success hci:%s", hci::ErrorCodeText(result.hci_error).c_str()); @@ -333,32 +343,91 @@ void L2cap::impl::OnConnectionFailure(l2cap::classic::DynamicChannelManager::Con l2cap::ConnectionResponseResultText(result.l2cap_connection_response_result).c_str()); break; } - auto completed = std::move(connect_completed_queue_.front()); - connect_completed_queue_.pop(); - completed.set_value(kInvalidConnectionInterfaceDescriptor); } -void L2cap::impl::RegisterService(l2cap::Psm psm, ConnectionOpenCallback on_open, std::promise completed) { - l2cap::SecurityPolicy security_policy; - register_completed_queue_.push(std::move(completed)); +void L2cap::impl::OpenConnection(l2cap::Psm psm, ConnectionInterfaceDescriptor cid) { + LOG_INFO("About to call back to client indicating open connection psm:%hd cid:%hd", psm, cid); + psm_to_on_open_map_[psm](psm, cid, [cid](std::function func) { + LOG_DEBUG("About to run postable on this thread and inform sdp that connection is open"); + func(cid); + }); +} - psm_to_connection_open_map_[psm] = std::move(on_open); +void L2cap::impl::RegisterService(l2cap::Psm psm, ConnectionOpenCallback on_open, std::promise completed) { + ASSERT(psm_to_service_interface_map_.find(psm) == psm_to_service_interface_map_.end()); + ASSERT(psm_to_register_complete_map_.find(psm) == psm_to_register_complete_map_.end()); + ASSERT(psm_to_on_open_map_.find(psm) == psm_to_on_open_map_.end()); + + psm_to_on_open_map_[psm] = on_open; + + psm_to_service_interface_map_.emplace( + psm, std::make_shared( + psm, + [this](l2cap::Psm psm, l2cap::classic::DynamicChannelManager::RegistrationResult result) { + LOG_DEBUG("Service has been registered"); + ASSERT(psm_to_register_complete_map_.find(psm) != psm_to_register_complete_map_.end()); + { + std::unique_lock lock(mutex_); + auto completed = std::move(psm_to_register_complete_map_[psm]); + psm_to_register_complete_map_.erase(psm); + completed.set_value(); + } + }, + + [this](l2cap::Psm psm, std::unique_ptr channel) { + ConnectionInterfaceDescriptor cid = connection_interface_manager_.AddChannel(std::move(channel)); + LOG_DEBUG("Connection has been opened cid:%hd psm:%hd", cid, psm); + { + // If initiated locally unblock requestor that + // we now have a connection by providing the + // cid. + std::unique_lock lock(mutex_); + if (psm_to_connect_completed_queue_.find(psm) != psm_to_connect_completed_queue_.end()) { + if (!psm_to_connect_completed_queue_[psm].empty()) { + LOG_DEBUG("Locally initiated, so inform waiting client of the cid %hd", cid); + auto completed = std::move(psm_to_connect_completed_queue_[psm].front()); + psm_to_connect_completed_queue_[psm].pop(); + completed.set_value(cid); + } + } + std::this_thread::yield(); + } + if (cid != kInvalidConnectionInterfaceDescriptor) { + handler_->Post(common::BindOnce(&L2cap::impl::OpenConnection, common::Unretained(this), psm, cid)); + } + usleep(10); + })); + + psm_to_service_interface_map_.find(psm)->second->RegisterService( + [this](l2cap::Psm psm, l2cap::SecurityPolicy security_policy, + l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete, + l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open) { + bool rc = dynamic_channel_manager_->RegisterService(psm, security_policy, std::move(on_registration_complete), + on_connection_open, handler_); + ASSERT_LOG(rc == true, "Failed to register classic service"); + }); +} - bool rc = dynamic_channel_manager_->RegisterService( - psm, security_policy, common::BindOnce(&L2cap::impl::OnRegistrationComplete, common::Unretained(this)), - common::Bind(&L2cap::impl::OnConnectionOpen, common::Unretained(this)), handler_); - ASSERT_LOG(rc == true, "Failed to register classic service"); +void L2cap::impl::UnregisterService(l2cap::Psm psm) { + psm_to_service_interface_map_.erase(psm); } void L2cap::impl::CreateConnection(l2cap::Psm psm, hci::Address address, std::promise completed) { LOG_INFO("Creating connection to psm:%hd device:%s", psm, address.ToString().c_str()); - connect_completed_queue_.push(std::move(completed)); + { + std::unique_lock lock(mutex_); + psm_to_connect_completed_queue_[psm].push(std::move(completed)); + } bool rc = dynamic_channel_manager_->ConnectChannel( - address, psm, common::Bind(&L2cap::impl::OnConnectionOpen, common::Unretained(this)), - common::Bind(&L2cap::impl::OnConnectionFailure, common::Unretained(this)), handler_); + address, psm, common::Bind(&L2cap::impl::OnConnectionOpenNever, common::Unretained(this)), + common::Bind(&L2cap::impl::OnConnectionFailureNever, common::Unretained(this)), handler_); ASSERT_LOG(rc == true, "Failed to create classic connection channel"); } +void L2cap::impl::CloseConnection(ConnectionInterfaceDescriptor cid) { + connection_interface_manager_.RemoveConnection(cid); +} + bool L2cap::impl::Write(ConnectionInterfaceDescriptor cid, std::unique_ptr packet) { return connection_interface_manager_.Write(cid, std::move(packet)); } @@ -368,6 +437,11 @@ void L2cap::RegisterService(uint16_t raw_psm, ConnectionOpenCallback on_open, st pimpl_->RegisterService(psm, on_open, std::move(completed)); } +void L2cap::UnregisterService(uint16_t raw_psm) { + l2cap::Psm psm{raw_psm}; + pimpl_->UnregisterService(psm); +} + void L2cap::CreateConnection(uint16_t raw_psm, const std::string address_string, std::promise completed) { l2cap::Psm psm{raw_psm}; hci::Address address; @@ -376,6 +450,11 @@ void L2cap::CreateConnection(uint16_t raw_psm, const std::string address_string, return pimpl_->CreateConnection(psm, address, std::move(completed)); } +void L2cap::CloseConnection(uint16_t raw_cid) { + ConnectionInterfaceDescriptor cid(raw_cid); + return pimpl_->CloseConnection(cid); +} + void L2cap::SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) { pimpl_->connection_interface_manager_.SetReadDataReadyCallback(static_cast(cid), on_data_ready); diff --git a/gd/shim/l2cap.h b/gd/shim/l2cap.h index 5918b20fd..67a75d9da 100644 --- a/gd/shim/l2cap.h +++ b/gd/shim/l2cap.h @@ -30,7 +30,10 @@ namespace shim { class L2cap : public bluetooth::Module, public bluetooth::shim::IL2cap { public: void RegisterService(uint16_t psm, ConnectionOpenCallback on_open, std::promise completed) override; + void UnregisterService(uint16_t psm) override; + void CreateConnection(uint16_t psm, const std::string address, std::promise completed) override; + void CloseConnection(uint16_t cid) override; void SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) override; void SetConnectionClosedCallback(uint16_t cid, ConnectionClosedCallback on_closed) override; diff --git a/main/shim/test_stack.cc b/main/shim/test_stack.cc index 14a7f5aa6..7769fa0b0 100644 --- a/main/shim/test_stack.cc +++ b/main/shim/test_stack.cc @@ -34,11 +34,15 @@ void TestGdShimL2cap::RegisterService( completed.set_value(); } +void TestGdShimL2cap::UnregisterService(uint16_t psm) {} + void TestGdShimL2cap::CreateConnection(uint16_t psm, const std::string address, std::promise completed) { completed.set_value(cid_); } +void TestGdShimL2cap::CloseConnection(uint16_t cid) {} + void TestGdShimL2cap::SetReadDataReadyCallback( uint16_t cid, bluetooth::shim::ReadDataReadyCallback on_data_ready) {} diff --git a/main/shim/test_stack.h b/main/shim/test_stack.h index 967e7f9f1..9f90199e1 100644 --- a/main/shim/test_stack.h +++ b/main/shim/test_stack.h @@ -30,8 +30,10 @@ class TestGdShimL2cap : public bluetooth::shim::IL2cap { void RegisterService(uint16_t psm, bluetooth::shim::ConnectionOpenCallback on_open, std::promise completed) override; + void UnregisterService(uint16_t psm); void CreateConnection(uint16_t psm, const std::string address, std::promise completed) override; + void CloseConnection(uint16_t cid); void SetReadDataReadyCallback( uint16_t cid, bluetooth::shim::ReadDataReadyCallback on_data_ready) override; -- 2.11.0