OSDN Git Service

LE ACL: Expose Connection Update API to L2CAP
authorHansong Zhang <hsz@google.com>
Fri, 6 Dec 2019 00:23:03 +0000 (16:23 -0800)
committerHansong Zhang <hsz@google.com>
Fri, 6 Dec 2019 01:53:12 +0000 (17:53 -0800)
Allow updating connection parameter from L2CAP, because L2CAP needs to
handle ConnectionParameterUpdateRequest from remote in some cases

Test: bluetooth_test_gd
Bug: 145014338
Change-Id: I85a567c5a29798aabfe2b07b598d657d43d2c307

gd/hci/acl_manager.cc
gd/hci/acl_manager.h
gd/hci/acl_manager_test.cc
gd/l2cap/le/internal/link.cc
gd/l2cap/le/internal/link.h
gd/l2cap/le/internal/signalling_manager.cc
gd/l2cap/le/internal/signalling_manager.h

index faad20b..4e337ff 100644 (file)
@@ -46,6 +46,9 @@ struct AclManager::acl_connection {
   os::Handler* disconnect_handler_ = nullptr;
   ConnectionManagementCallbacks* command_complete_callbacks_;
   common::OnceCallback<void(ErrorCode)> on_disconnect_callback_;
+  // For LE Connection parameter update from L2CAP
+  common::OnceCallback<void(ErrorCode)> on_connection_update_complete_callback_;
+  os::Handler* on_connection_update_complete_callback_handler_ = nullptr;
   // Round-robin: Track if dequeue is registered for this connection
   bool is_registered_ = false;
   // Credits: Track the number of packets which have been sent to the controller
@@ -84,6 +87,9 @@ struct AclManager::impl {
     hci_layer_->RegisterLeEventHandler(SubeventCode::ENHANCED_CONNECTION_COMPLETE,
                                        Bind(&impl::on_le_enhanced_connection_complete, common::Unretained(this)),
                                        handler_);
+    hci_layer_->RegisterLeEventHandler(SubeventCode::CONNECTION_UPDATE_COMPLETE,
+                                       Bind(&impl::on_le_connection_update_complete, common::Unretained(this)),
+                                       handler_);
     hci_layer_->RegisterEventHandler(EventCode::CONNECTION_PACKET_TYPE_CHANGED,
                                      Bind(&impl::on_connection_packet_type_changed, common::Unretained(this)),
                                      handler_);
@@ -864,6 +870,34 @@ struct AclManager::impl {
     }
   }
 
+  void on_le_connection_update_complete(LeMetaEventView view) {
+    auto complete_view = LeConnectionUpdateCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_le_connection_update_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_le_connection_update_complete with error code %s", error_code.c_str());
+      return;
+    }
+    auto handle = complete_view.GetConnectionHandle();
+    if (acl_connections_.find(handle) == acl_connections_.end()) {
+      LOG_WARN("Can't find connection");
+      return;
+    }
+    auto& connection = acl_connections_.find(handle)->second;
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return;
+    }
+    if (!connection.on_connection_update_complete_callback_.is_null()) {
+      connection.on_connection_update_complete_callback_handler_->Post(
+          common::BindOnce(std::move(connection.on_connection_update_complete_callback_), complete_view.GetStatus()));
+      connection.on_connection_update_complete_callback_handler_ = nullptr;
+    }
+  }
+
   bool is_classic_link_already_connected(Address address) {
     for (const auto& connection : acl_connections_) {
       if (connection.second.address_with_type_.GetAddress() == address) {
@@ -911,8 +945,6 @@ struct AclManager::impl {
     uint16_t conn_interval_max = 0x0C00;
     uint16_t conn_latency = 0x0C0;
     uint16_t supervision_timeout = 0x0C00;
-    uint16_t minimum_ce_length = 0x0002;
-    uint16_t maximum_ce_length = 0x0C00;
     ASSERT(le_client_callbacks_ != nullptr);
 
     connecting_le_.insert(address_with_type);
@@ -921,7 +953,7 @@ struct AclManager::impl {
         LeCreateConnectionBuilder::Create(le_scan_interval, le_scan_window, initiator_filter_policy,
                                           address_with_type.GetAddressType(), address_with_type.GetAddress(),
                                           own_address_type, conn_interval_min, conn_interval_max, conn_latency,
-                                          supervision_timeout, minimum_ce_length, maximum_ce_length),
+                                          supervision_timeout, kMinimumCeLength, kMaximumCeLength),
         common::BindOnce([](CommandStatusView status) {
           ASSERT(status.IsValid());
           ASSERT(status.GetCommandOpCode() == OpCode::LE_CREATE_CONNECTION);
@@ -1188,6 +1220,17 @@ struct AclManager::impl {
                                common::BindOnce(&impl::on_read_clock_complete, common::Unretained(this)), handler_);
   }
 
+  void handle_le_connection_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max,
+                                   uint16_t conn_latency, uint16_t supervision_timeout) {
+    auto packet = LeConnectionUpdateBuilder::Create(handle, conn_interval_min, conn_interval_max, conn_latency,
+                                                    supervision_timeout, kMinimumCeLength, kMaximumCeLength);
+    hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandStatusView status) {
+                                 ASSERT(status.IsValid());
+                                 ASSERT(status.GetCommandOpCode() == OpCode::LE_CREATE_CONNECTION);
+                               }),
+                               handler_);
+  }
+
   template <class T>
   void check_command_complete(CommandCompleteView view) {
     ASSERT(view.IsValid());
@@ -1574,6 +1617,31 @@ struct AclManager::impl {
     return true;
   }
 
+  bool LeConnectionUpdate(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max,
+                          uint16_t conn_latency, uint16_t supervision_timeout,
+                          common::OnceCallback<void(ErrorCode)> done_callback, os::Handler* handler) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    if (!connection.on_connection_update_complete_callback_.is_null()) {
+      LOG_INFO("There is another pending connection update");
+      return false;
+    }
+    connection.on_connection_update_complete_callback_ = std::move(done_callback);
+    connection.on_connection_update_complete_callback_handler_ = handler;
+    if (conn_interval_min < 0x0006 || conn_interval_min > 0x0C80 || conn_interval_max < 0x0006 ||
+        conn_interval_max > 0x0C80 || conn_latency > 0x01F3 || supervision_timeout < 0x000A ||
+        supervision_timeout > 0x0C80) {
+      LOG_ERROR("Invalid parameter");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_le_connection_update, common::Unretained(this), handle, conn_interval_min,
+                            conn_interval_max, conn_latency, supervision_timeout));
+    return true;
+  }
+
   void Finish(uint16_t handle) {
     auto& connection = check_and_get_connection(handle);
     ASSERT_LOG(connection.is_disconnected_, "Finish must be invoked after disconnection (handle 0x%04hx)", handle);
@@ -1582,6 +1650,9 @@ struct AclManager::impl {
 
   const AclManager& acl_manager_;
 
+  static constexpr uint16_t kMinimumCeLength = 0x0002;
+  static constexpr uint16_t kMaximumCeLength = 0x0C00;
+
   Controller* controller_ = nullptr;
   uint16_t max_acl_packet_credits_ = 0;
   uint16_t acl_packet_credits_ = 0;
@@ -1732,6 +1803,13 @@ bool AclConnection::ReadClock(WhichClock which_clock) {
   return manager_->pimpl_->ReadClock(handle_, which_clock);
 }
 
+bool AclConnection::LeConnectionUpdate(uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency,
+                                       uint16_t supervision_timeout,
+                                       common::OnceCallback<void(ErrorCode)> done_callback, os::Handler* handler) {
+  return manager_->pimpl_->LeConnectionUpdate(handle_, conn_interval_min, conn_interval_max, conn_latency,
+                                              supervision_timeout, std::move(done_callback), handler);
+}
+
 void AclConnection::Finish() {
   return manager_->pimpl_->Finish(handle_);
 }
index 3706aba..1402628 100644 (file)
@@ -143,6 +143,11 @@ class AclConnection {
   virtual bool ReadRssi();
   virtual bool ReadClock(WhichClock which_clock);
 
+  // LE ACL Method
+  virtual bool LeConnectionUpdate(uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency,
+                                  uint16_t supervision_timeout, common::OnceCallback<void(ErrorCode)> done_callback,
+                                  os::Handler* handler);
+
   // Ask AclManager to clean me up. Must invoke after on_disconnect is called
   virtual void Finish();
 
index 805f926..50c4e05 100644 (file)
@@ -537,6 +537,45 @@ TEST_F(AclManagerTest, invoke_registered_callback_le_connection_complete_fail) {
       0x0100, 0x0010, 0x0011, MasterClockAccuracy::PPM_30));
 }
 
+TEST_F(AclManagerTest, invoke_registered_callback_le_connection_update_success) {
+  AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
+  test_hci_layer_->SetCommandFuture();
+  acl_manager_->CreateLeConnection(remote_with_type);
+
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_CREATE_CONNECTION);
+  auto le_connection_management_command_view = LeConnectionManagementCommandView::Create(packet);
+  auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetPeerAddress(), remote);
+  EXPECT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);
+
+  test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
+
+  auto first_connection = GetLeConnectionFuture();
+
+  test_hci_layer_->IncomingLeMetaEvent(
+      LeConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, 0x123, Role::SLAVE, AddressType::PUBLIC_DEVICE_ADDRESS,
+                                          remote, 0x0100, 0x0010, 0x0011, MasterClockAccuracy::PPM_30));
+
+  auto first_connection_status = first_connection.wait_for(kTimeout);
+  ASSERT_EQ(first_connection_status, std::future_status::ready);
+
+  std::shared_ptr<AclConnection> connection = GetLastLeConnection();
+  ASSERT_EQ(connection->GetAddress(), remote);
+
+  std::promise<ErrorCode> promise;
+  auto future = promise.get_future();
+  connection->LeConnectionUpdate(
+      0x0006, 0x0C80, 0x0000, 0x000A,
+      common::BindOnce([](std::promise<ErrorCode> promise, ErrorCode code) { promise.set_value(code); },
+                       std::move(promise)),
+      client_handler_);
+  test_hci_layer_->IncomingLeMetaEvent(
+      LeConnectionUpdateCompleteBuilder::Create(ErrorCode::SUCCESS, 0x123, 0x0006, 0x0000, 0x000A));
+  EXPECT_EQ(future.wait_for(std::chrono::milliseconds(3)), std::future_status::ready);
+  EXPECT_EQ(future.get(), ErrorCode::SUCCESS);
+}
+
 TEST_F(AclManagerTest, invoke_registered_callback_disconnection_complete) {
   uint16_t handle = 0x123;
 
index 66dd580..2f147a7 100644 (file)
@@ -55,6 +55,13 @@ void Link::Disconnect() {
   acl_connection_->Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
 }
 
+void Link::UpdateConnectionParameter(SignalId signal_id, uint16_t conn_interval_min, uint16_t conn_interval_max,
+                                     uint16_t conn_latency, uint16_t supervision_timeout) {
+  acl_connection_->LeConnectionUpdate(
+      conn_interval_min, conn_interval_max, conn_latency, supervision_timeout,
+      common::BindOnce(&Link::on_connection_update_complete, common::Unretained(this), signal_id), l2cap_handler_);
+}
+
 std::shared_ptr<FixedChannelImpl> Link::AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) {
   auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy);
   data_pipeline_manager_.AttachChannel(cid, channel,
@@ -172,11 +179,17 @@ uint16_t Link::GetInitialCredit() const {
   return parameter_provider_->GetLeInitialCredit();
 }
 
-
 void Link::SendLeCredit(Cid local_cid, uint16_t credit) {
   signalling_manager_.SendCredit(local_cid, credit);
 }
 
+void Link::on_connection_update_complete(SignalId signal_id, hci::ErrorCode error_code) {
+  ConnectionParameterUpdateResponseResult result = (error_code == hci::ErrorCode::SUCCESS)
+                                                       ? ConnectionParameterUpdateResponseResult::ACCEPTED
+                                                       : ConnectionParameterUpdateResponseResult::REJECTED;
+  signalling_manager_.SendConnectionParameterUpdateResponse(SignalId(), result);
+}
+
 }  // namespace internal
 }  // namespace le
 }  // namespace l2cap
index 633aa29..1d4ed3a 100644 (file)
@@ -67,6 +67,10 @@ class Link : public l2cap::internal::ILink {
 
   virtual void Disconnect();
 
+  // Handles connection parameter update request from remote
+  virtual void UpdateConnectionParameter(SignalId signal_id, uint16_t conn_interval_min, uint16_t conn_interval_max,
+                                         uint16_t conn_latency, uint16_t supervision_timeout);
+
   // FixedChannel methods
 
   virtual std::shared_ptr<FixedChannelImpl> AllocateFixedChannel(Cid cid, SecurityPolicy security_policy);
@@ -122,6 +126,8 @@ class Link : public l2cap::internal::ILink {
   std::unordered_map<Cid, PendingDynamicChannelConnection> local_cid_to_pending_dynamic_channel_connection_map_;
   os::Alarm link_idle_disconnect_alarm_{l2cap_handler_};
   DISALLOW_COPY_AND_ASSIGN(Link);
+
+  void on_connection_update_complete(SignalId signal_id, hci::ErrorCode error_code);
 };
 
 }  // namespace internal
index 18b2e95..2922a74 100644 (file)
@@ -81,8 +81,10 @@ void LeSignallingManager::SendConnectionParameterUpdateRequest(uint16_t interval
   LOG_ERROR("Not implemented");
 }
 
-void LeSignallingManager::SendConnectionParameterUpdateResponse(ConnectionParameterUpdateResponseResult result) {
-  LOG_ERROR("Not implemented");
+void LeSignallingManager::SendConnectionParameterUpdateResponse(SignalId signal_id,
+                                                                ConnectionParameterUpdateResponseResult result) {
+  auto builder = ConnectionParameterUpdateResponseBuilder::Create(signal_id.Value(), result);
+  enqueue_buffer_->Enqueue(std::move(builder), handler_);
 }
 
 void LeSignallingManager::SendCredit(Cid local_cid, uint16_t credits) {
index c93812b..74e85ce 100644 (file)
@@ -68,7 +68,7 @@ class LeSignallingManager {
   void SendConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency,
                                             uint16_t timeout_multiplier);
 
-  void SendConnectionParameterUpdateResponse(ConnectionParameterUpdateResponseResult result);
+  void SendConnectionParameterUpdateResponse(SignalId signal_id, ConnectionParameterUpdateResponseResult result);
 
   void SendCredit(Cid local_cid, uint16_t credits);