OSDN Git Service

L2CAP classic signalling handler, data pipeline, and cert test
authorHansong Zhang <hsz@google.com>
Fri, 20 Sep 2019 22:50:42 +0000 (15:50 -0700)
committerHansong Zhang <hsz@google.com>
Wed, 9 Oct 2019 02:00:55 +0000 (19:00 -0700)
Supports listening to an incoming L2CAP connection, open the channel and
transfer data.

Test: bluetooth_test_gd and cert/run_cert.sh
Bug: 138260719
Change-Id: I5a1b93dc30b43bb149c32e5f4ef5404f2d091cdb

29 files changed:
gd/l2cap/Android.bp
gd/l2cap/classic/cert/api.proto
gd/l2cap/classic/cert/cert.cc
gd/l2cap/classic/cert/simple_l2cap_test.py
gd/l2cap/classic/dynamic_channel_manager.cc
gd/l2cap/classic/facade.cc
gd/l2cap/classic/facade.proto
gd/l2cap/classic/internal/dynamic_channel_allocator.cc
gd/l2cap/classic/internal/dynamic_channel_allocator.h
gd/l2cap/classic/internal/dynamic_channel_allocator_test.cc
gd/l2cap/classic/internal/dynamic_channel_impl.cc
gd/l2cap/classic/internal/dynamic_channel_impl.h
gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.h
gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h [new file with mode: 0644]
gd/l2cap/classic/internal/fixed_channel_impl.cc
gd/l2cap/classic/internal/fixed_channel_service_manager_impl.cc
gd/l2cap/classic/internal/fixed_channel_service_manager_impl.h
gd/l2cap/classic/internal/link.cc
gd/l2cap/classic/internal/link.h
gd/l2cap/classic/internal/link_manager.cc
gd/l2cap/classic/internal/link_manager.h
gd/l2cap/classic/internal/link_manager_test.cc
gd/l2cap/classic/internal/link_mock.h
gd/l2cap/classic/internal/signalling_manager.cc [new file with mode: 0644]
gd/l2cap/classic/internal/signalling_manager.h [new file with mode: 0644]
gd/l2cap/classic/internal/signalling_manager_test.cc [new file with mode: 0644]
gd/l2cap/classic/l2cap_classic_module.cc
gd/l2cap/classic/l2cap_classic_module.h
gd/l2cap/psm.h

index af12aa2..f07762c 100644 (file)
@@ -15,6 +15,7 @@ filegroup {
         "classic/internal/fixed_channel_service_manager_impl.cc",
         "classic/internal/link.cc",
         "classic/internal/link_manager.cc",
+        "classic/internal/signalling_manager.cc",
         "classic/l2cap_classic_module.cc",
         "internal/scheduler_fifo.cc",
         "le/internal/fixed_channel_impl.cc",
@@ -36,6 +37,7 @@ filegroup {
         "classic/internal/fixed_channel_impl_test.cc",
         "classic/internal/fixed_channel_service_manager_test.cc",
         "classic/internal/link_manager_test.cc",
+        "classic/internal/signalling_manager_test.cc",
         "internal/fixed_channel_allocator_test.cc",
         "internal/scheduler_fifo_test.cc",
         "l2cap_packet_test.cc",
index e5ba697..e045a21 100644 (file)
@@ -11,6 +11,7 @@ service L2capModuleCert {
   rpc FetchConnectionComplete(facade.EventStreamRequest) returns (stream ConnectionCompleteEvent) {}
   rpc DisconnectLink(DisconnectLinkRequest) returns (google.protobuf.Empty) {}
   rpc SendConnectionRequest(ConnectionRequest) returns (google.protobuf.Empty) {}
+  rpc SendDisconnectionRequest(DisconnectionRequest) returns (google.protobuf.Empty) {}
 }
 
 message L2capPacket {
@@ -32,3 +33,9 @@ message ConnectionRequest {
   uint32 dcid = 2;
   uint32 scid = 3;
 }
+
+message DisconnectionRequest {
+  facade.BluetoothAddress remote = 1;
+  uint32 dcid = 2;
+  uint32 scid = 3;
+}
\ No newline at end of file
index eda0c4f..1ac0df4 100644 (file)
@@ -88,6 +88,32 @@ class L2capModuleCertService : public L2capModuleCert::Service {
     return ::grpc::Status::OK;
   }
 
+  ::grpc::Status SendConnectionRequest(::grpc::ServerContext* context, const cert::ConnectionRequest* request,
+                                       ::google::protobuf::Empty* response) override {
+    auto builder = ConnectionRequestBuilder::Create(1, 1, 101);
+    auto l2cap_builder = BasicFrameBuilder::Create(1, std::move(builder));
+    outgoing_packet_queue_.push(std::move(l2cap_builder));
+    if (outgoing_packet_queue_.size() == 1) {
+      acl_connection_->GetAclQueueEnd()->RegisterEnqueue(
+          handler_, common::Bind(&L2capModuleCertService::enqueue_packet_to_acl, common::Unretained(this)));
+    }
+
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendDisconnectionRequest(::grpc::ServerContext* context, const cert::DisconnectionRequest* request,
+                                          ::google::protobuf::Empty* response) override {
+    auto builder = DisconnectionRequestBuilder::Create(3, 0x40, 101);
+    auto l2cap_builder = BasicFrameBuilder::Create(1, std::move(builder));
+    outgoing_packet_queue_.push(std::move(l2cap_builder));
+    if (outgoing_packet_queue_.size() == 1) {
+      acl_connection_->GetAclQueueEnd()->RegisterEnqueue(
+          handler_, common::Bind(&L2capModuleCertService::enqueue_packet_to_acl, common::Unretained(this)));
+    }
+
+    return ::grpc::Status::OK;
+  }
+
   std::unique_ptr<packet::BasePacketBuilder> enqueue_packet_to_acl() {
     auto basic_frame_builder = std::move(outgoing_packet_queue_.front());
     outgoing_packet_queue_.pop();
@@ -122,7 +148,7 @@ class L2capModuleCertService : public L2capModuleCert::Service {
     l2cap_stream_.OnIncomingEvent(l2cap_packet);
   }
 
-  std::queue<std::unique_ptr<BasicFrameBuilder>> outgoing_packet_queue_;
+  std::queue<std::unique_ptr<BasePacketBuilder>> outgoing_packet_queue_;
   ::bluetooth::os::Handler* handler_;
   hci::AclManager* acl_manager_;
   std::unique_ptr<hci::AclConnection> acl_connection_;
index c1a841c..e4adcde 100644 (file)
@@ -25,6 +25,9 @@ from facade import common_pb2
 from facade import rootservice_pb2 as facade_rootservice_pb2
 from google.protobuf import empty_pb2
 from l2cap.classic import facade_pb2 as l2cap_facade_pb2
+from l2cap.classic.cert import api_pb2 as l2cap_cert_pb2
+
+import time
 
 class SimpleL2capTest(GdBaseTestClass):
     def setup_test(self):
@@ -64,6 +67,7 @@ class SimpleL2capTest(GdBaseTestClass):
 
     def test_connect_and_send_data(self):
         self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2))
+        self.device_under_test.l2cap.SetDynamicChannel(l2cap_facade_pb2.SetEnableDynamicChannelRequest(psm=0x01))
         dut_packet_stream = self.device_under_test.l2cap.packet_stream
         cert_packet_stream = self.cert_device.l2cap.packet_stream
         cert_connection_stream = self.cert_device.l2cap.connection_complete_stream
@@ -79,6 +83,10 @@ class SimpleL2capTest(GdBaseTestClass):
             lambda device: device.remote == self.cert_address
         )
         dut_connection_stream.unsubscribe()
+
+        self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest())
+        time.sleep(1)
+
         dut_packet_stream.subscribe()
         cert_packet_stream.subscribe()
         self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=2, payload=b"abc"))
@@ -89,5 +97,18 @@ class SimpleL2capTest(GdBaseTestClass):
         cert_packet_stream.assert_event_occurs(
             lambda packet: b"123" in packet.payload
         )
+
+        self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=64, payload=b"123"))
+        dut_packet_stream.assert_event_occurs(
+            lambda packet: b"123" in packet.payload
+        )
+
+        self.device_under_test.l2cap.SendDynamicChannelPacket(l2cap_facade_pb2.DynamicChannelPacket(psm=1, payload=b'abc'))
+        cert_packet_stream.assert_event_occurs(
+            lambda packet: b"abc" in packet.payload
+        )
+
+        self.cert_device.l2cap.SendDisconnectionRequest(l2cap_cert_pb2.DisconnectionRequest())
+        time.sleep(1)
         dut_packet_stream.unsubscribe()
         cert_packet_stream.unsubscribe()
index 923e06f..6aaaf5d 100644 (file)
@@ -25,8 +25,15 @@ namespace classic {
 
 bool DynamicChannelManager::ConnectChannel(hci::Address device, Psm psm, OnConnectionOpenCallback on_connection_open,
                                            OnConnectionFailureCallback on_fail_callback, os::Handler* handler) {
-  // TODO impl me when there is no link, and when there is link
-  return false;
+  internal::LinkManager::PendingDynamicChannelConnection pending_dynamic_channel_connection{
+      .on_open_callback_ = std::move(on_connection_open),
+      .on_fail_callback_ = std::move(on_fail_callback),
+      .handler_ = handler};
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::LinkManager::ConnectDynamicChannelServices,
+                                              common::Unretained(link_manager_), device,
+                                              std::move(pending_dynamic_channel_connection), psm));
+
+  return true;
 }
 
 bool DynamicChannelManager::RegisterService(Psm psm, const SecurityPolicy& security_policy,
index 9072db0..bbaa1b5 100644 (file)
@@ -58,9 +58,9 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service {
   ::bluetooth::grpc::GrpcEventStream<ConnectionCompleteEvent, ConnectionCompleteEvent> connection_complete_stream_{
       &connection_complete_callback_};
 
-  ::grpc::Status FetchConnectionComplete(
-      ::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
-      ::grpc::ServerWriter<::bluetooth::l2cap::classic::ConnectionCompleteEvent>* writer) override {
+  ::grpc::Status FetchConnectionComplete(::grpc::ServerContext* context,
+                                         const ::bluetooth::facade::EventStreamRequest* request,
+                                         ::grpc::ServerWriter<classic::ConnectionCompleteEvent>* writer) override {
     return connection_complete_stream_.HandleRequest(context, request, writer);
   }
 
@@ -74,32 +74,39 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service {
     return ::grpc::Status::OK;
   }
 
-  ::grpc::Status SendL2capPacket(::grpc::ServerContext* context,
-                                 const ::bluetooth::l2cap::classic::L2capPacket* request,
-                                 ::bluetooth::l2cap::classic::SendL2capPacketResult* response) override {
-    if (connection_less_channel_helper_map_.find(request->channel()) == connection_less_channel_helper_map_.end()) {
+  ::grpc::Status SendL2capPacket(::grpc::ServerContext* context, const classic::L2capPacket* request,
+                                 SendL2capPacketResult* response) override {
+    if (fixed_channel_helper_map_.find(request->channel()) == fixed_channel_helper_map_.end()) {
       return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Channel not registered");
     }
     std::vector<uint8_t> packet(request->payload().begin(), request->payload().end());
-    connection_less_channel_helper_map_[request->channel()]->SendPacket(packet);
-    response->set_result_type(::bluetooth::l2cap::classic::SendL2capPacketResultType::OK);
+    fixed_channel_helper_map_[request->channel()]->SendPacket(packet);
+    response->set_result_type(SendL2capPacketResultType::OK);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendDynamicChannelPacket(::grpc::ServerContext* context, const DynamicChannelPacket* request,
+                                          ::google::protobuf::Empty* response) override {
+    if (dynamic_channel_helper_map_.find(request->psm()) == dynamic_channel_helper_map_.end()) {
+      return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered");
+    }
+    std::vector<uint8_t> packet(request->payload().begin(), request->payload().end());
+    dynamic_channel_helper_map_[request->psm()]->SendPacket(packet);
     return ::grpc::Status::OK;
   }
 
   ::grpc::Status FetchL2capData(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
-                                ::grpc::ServerWriter<::bluetooth::l2cap::classic::L2capPacket>* writer) override {
+                                ::grpc::ServerWriter<classic::L2capPacket>* writer) override {
     return l2cap_stream_.HandleRequest(context, request, writer);
   }
 
-  ::grpc::Status RegisterChannel(::grpc::ServerContext* context,
-                                 const ::bluetooth::l2cap::classic::RegisterChannelRequest* request,
+  ::grpc::Status RegisterChannel(::grpc::ServerContext* context, const classic::RegisterChannelRequest* request,
                                  ::google::protobuf::Empty* response) override {
-    if (connection_less_channel_helper_map_.find(request->channel()) != connection_less_channel_helper_map_.end()) {
+    if (fixed_channel_helper_map_.find(request->channel()) != fixed_channel_helper_map_.end()) {
       return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Already registered");
     }
-    connection_less_channel_helper_map_.emplace(
-        request->channel(),
-        std::make_unique<L2capFixedChannelHelper>(this, l2cap_layer_, facade_handler_, request->channel()));
+    fixed_channel_helper_map_.emplace(request->channel(), std::make_unique<L2capFixedChannelHelper>(
+                                                              this, l2cap_layer_, facade_handler_, request->channel()));
 
     return ::grpc::Status::OK;
   }
@@ -162,39 +169,127 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service {
     Cid cid_;
   };
 
-  l2cap::classic::L2capClassicModule* l2cap_layer_;
+  ::grpc::Status SetDynamicChannel(::grpc::ServerContext* context, const SetEnableDynamicChannelRequest* request,
+                                   google::protobuf::Empty* response) override {
+    dynamic_channel_helper_map_.emplace(request->psm(), std::make_unique<L2capDynamicChannelHelper>(
+                                                            this, l2cap_layer_, facade_handler_, request->psm()));
+    return ::grpc::Status::OK;
+  }
+
+  class L2capDynamicChannelHelper {
+   public:
+    L2capDynamicChannelHelper(L2capModuleFacadeService* service, L2capClassicModule* l2cap_layer, os::Handler* handler,
+                              Psm psm)
+        : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), psm_(psm) {
+      dynamic_channel_manager_ = l2cap_layer_->GetDynamicChannelManager();
+      dynamic_channel_manager_->RegisterService(
+          psm, {},
+          common::BindOnce(&L2capDynamicChannelHelper::on_l2cap_service_registration_complete,
+                           common::Unretained(this)),
+          common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), handler_);
+    }
+
+    void on_l2cap_service_registration_complete(DynamicChannelManager::RegistrationResult registration_result,
+                                                std::unique_ptr<DynamicChannelService> service) {}
+
+    void on_connection_open(std::unique_ptr<DynamicChannel> channel) {
+      ConnectionCompleteEvent event;
+      event.mutable_remote()->set_address(channel->GetDevice().ToString());
+      facade_service_->connection_complete_stream_.OnIncomingEvent(event);
+      channel_ = std::move(channel);
+    }
+
+    void on_incoming_packet() {
+      auto packet = channel_->GetQueueUpEnd()->TryDequeue();
+      std::string data = std::string(packet->begin(), packet->end());
+      L2capPacket l2cap_data;
+      //      l2cap_data.set_channel(cid_);
+      l2cap_data.set_payload(data);
+      facade_service_->l2cap_stream_.OnIncomingEvent(l2cap_data);
+    }
+
+    void SendPacket(std::vector<uint8_t> packet) {
+      if (channel_ == nullptr) {
+        LOG_WARN("Channel is not open");
+        return;
+      }
+      channel_->GetQueueUpEnd()->RegisterEnqueue(
+          handler_, common::Bind(&L2capDynamicChannelHelper::enqueue_callback, common::Unretained(this), packet));
+    }
+
+    std::unique_ptr<packet::BasePacketBuilder> enqueue_callback(std::vector<uint8_t> packet) {
+      auto packet_one = std::make_unique<packet::RawBuilder>();
+      packet_one->AddOctets(packet);
+      channel_->GetQueueUpEnd()->UnregisterEnqueue();
+      return packet_one;
+    };
+
+    L2capModuleFacadeService* facade_service_;
+    L2capClassicModule* l2cap_layer_;
+    os::Handler* handler_;
+    std::unique_ptr<DynamicChannelManager> dynamic_channel_manager_;
+    std::unique_ptr<DynamicChannelService> service_;
+    std::unique_ptr<DynamicChannel> channel_ = nullptr;
+    Psm psm_;
+  };
+
+  L2capClassicModule* l2cap_layer_;
   ::bluetooth::os::Handler* facade_handler_;
-  std::map<Cid, std::unique_ptr<L2capFixedChannelHelper>> connection_less_channel_helper_map_;
+  std::map<Cid, std::unique_ptr<L2capFixedChannelHelper>> fixed_channel_helper_map_;
+  std::map<Psm, std::unique_ptr<L2capDynamicChannelHelper>> dynamic_channel_helper_map_;
 
   class L2capStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<L2capPacket, L2capPacket> {
    public:
     L2capStreamCallback(L2capModuleFacadeService* service) : service_(service) {}
 
     ~L2capStreamCallback() {
-      for (const auto& connection : service_->connection_less_channel_helper_map_) {
-        if (subscribed_[connection.first] && connection.second->channel_ != nullptr) {
+      for (const auto& connection : service_->fixed_channel_helper_map_) {
+        if (subscribed_fixed_channel_[connection.first] && connection.second->channel_ != nullptr) {
           connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
-          subscribed_[connection.first] = false;
+          subscribed_fixed_channel_[connection.first] = false;
+        }
+      }
+
+      for (const auto& connection : service_->dynamic_channel_helper_map_) {
+        if (subscribed_dynamic_channel_[connection.first] && connection.second->channel_ != nullptr) {
+          connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
+          subscribed_dynamic_channel_[connection.first] = false;
         }
       }
     }
 
     void OnSubscribe() override {
-      for (auto& connection : service_->connection_less_channel_helper_map_) {
-        if (!subscribed_[connection.first] && connection.second->channel_ != nullptr) {
+      for (auto& connection : service_->fixed_channel_helper_map_) {
+        if (!subscribed_fixed_channel_[connection.first] && connection.second->channel_ != nullptr) {
           connection.second->channel_->GetQueueUpEnd()->RegisterDequeue(
               service_->facade_handler_,
               common::Bind(&L2capFixedChannelHelper::on_incoming_packet, common::Unretained(connection.second.get())));
-          subscribed_[connection.first] = true;
+          subscribed_fixed_channel_[connection.first] = true;
+        }
+      }
+
+      for (auto& connection : service_->dynamic_channel_helper_map_) {
+        if (!subscribed_dynamic_channel_[connection.first] && connection.second->channel_ != nullptr) {
+          connection.second->channel_->GetQueueUpEnd()->RegisterDequeue(
+              service_->facade_handler_, common::Bind(&L2capDynamicChannelHelper::on_incoming_packet,
+                                                      common::Unretained(connection.second.get())));
+          subscribed_dynamic_channel_[connection.first] = true;
         }
       }
     }
 
     void OnUnsubscribe() override {
-      for (const auto& connection : service_->connection_less_channel_helper_map_) {
-        if (subscribed_[connection.first] && connection.second->channel_ != nullptr) {
+      for (const auto& connection : service_->fixed_channel_helper_map_) {
+        if (subscribed_fixed_channel_[connection.first] && connection.second->channel_ != nullptr) {
+          connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
+          subscribed_fixed_channel_[connection.first] = false;
+        }
+      }
+
+      for (const auto& connection : service_->dynamic_channel_helper_map_) {
+        if (subscribed_dynamic_channel_[connection.first] && connection.second->channel_ != nullptr) {
           connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
-          subscribed_[connection.first] = false;
+          subscribed_dynamic_channel_[connection.first] = false;
         }
       }
     }
@@ -204,7 +299,8 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service {
     }
 
     L2capModuleFacadeService* service_;
-    std::map<Cid, bool> subscribed_;
+    std::map<Cid, bool> subscribed_fixed_channel_;
+    std::map<Psm, bool> subscribed_dynamic_channel_;
 
   } l2cap_stream_callback_{this};
   ::bluetooth::grpc::GrpcEventStream<L2capPacket, L2capPacket> l2cap_stream_{&l2cap_stream_callback_};
index 2e3f6f3..21add63 100644 (file)
@@ -17,6 +17,9 @@ service L2capModuleFacade {
   rpc ConfigureChannel(ConfigureChannelRequest) returns (google.protobuf.Empty) {}
   rpc SendL2capPacket(L2capPacket) returns (SendL2capPacketResult) {}
   rpc FetchL2capData(facade.EventStreamRequest) returns (stream L2capPacket) {}
+  rpc RegisterDynamicChannel(RegisterDynamicChannelRequest) returns (google.protobuf.Empty) {}
+  rpc SetDynamicChannel(SetEnableDynamicChannelRequest) returns (google.protobuf.Empty) {}
+  rpc SendDynamicChannelPacket(DynamicChannelPacket) returns (google.protobuf.Empty) {}
 }
 
 message RegisterChannelRequest {
@@ -67,3 +70,18 @@ message L2capPacket {
   uint32 channel = 2;
   bytes payload = 3;
 }
+
+message RegisterDynamicChannelRequest {
+  uint32 psm = 1;
+}
+
+message SetEnableDynamicChannelRequest {
+  uint32 psm = 1;
+  bool enable = 2;
+}
+
+message DynamicChannelPacket {
+  facade.BluetoothAddress remote = 1;
+  uint32 psm = 2;
+  bytes payload = 3;
+}
index ad2f1c4..bf7e194 100644 (file)
@@ -30,51 +30,55 @@ namespace internal {
 
 std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateChannel(Psm psm, Cid remote_cid,
                                                                              SecurityPolicy security_policy) {
-  if (IsChannelAllocated((psm))) {
-    LOG_INFO("Psm 0x%x for device %s is already in use", psm, link_->GetDevice().ToString().c_str());
-    return nullptr;
-  }
-  if (!IsPsmValid(psm)) {
-    LOG_INFO("Psm 0x%x is invalid", psm);
-    return nullptr;
-  }
+  ASSERT_LOG(!IsPsmUsed((psm)), "Psm 0x%x for device %s is already in use", psm, link_->GetDevice().ToString().c_str());
+  ASSERT_LOG(IsPsmValid(psm), "Psm 0x%x is invalid", psm);
+
   if (used_remote_cid_.find(remote_cid) != used_remote_cid_.end()) {
     LOG_INFO("Remote cid 0x%x is used", remote_cid);
     return nullptr;
   }
   Cid cid = kFirstDynamicChannel;
   for (; cid <= kLastDynamicChannel; cid++) {
-    LOG_INFO();
-    if (used_cid_.count(cid) == 0) break;
+    if (channels_.find(cid) == channels_.end()) break;
   }
   if (cid > kLastDynamicChannel) {
     LOG_WARN("All cid are used");
     return nullptr;
   }
   auto elem =
-      channels_.try_emplace(psm, std::make_shared<DynamicChannelImpl>(psm, cid, remote_cid, link_, l2cap_handler_));
+      channels_.try_emplace(cid, std::make_shared<DynamicChannelImpl>(psm, cid, remote_cid, link_, l2cap_handler_));
   ASSERT_LOG(elem.second, "Failed to create channel for psm 0x%x device %s", psm,
              link_->GetDevice().ToString().c_str());
   ASSERT(elem.first->second != nullptr);
-  used_cid_.insert(cid);
   used_remote_cid_.insert(remote_cid);
   return elem.first->second;
 }
 
-void DynamicChannelAllocator::FreeChannel(Psm psm) {
-  ASSERT_LOG(IsChannelAllocated(psm), "Channel is not in use: psm %d, device %s", psm,
-             link_->GetDevice().ToString().c_str());
-  channels_.erase(psm);
+void DynamicChannelAllocator::FreeChannel(Cid cid) {
+  auto channel = FindChannelByCid(cid);
+  if (channel == nullptr) {
+    LOG_INFO("Channel is not in use: psm %d, device %s", cid, link_->GetDevice().ToString().c_str());
+    return;
+  }
+  used_remote_cid_.erase(channel->GetRemoteCid());
+  channels_.erase(cid);
 }
 
-bool DynamicChannelAllocator::IsChannelAllocated(Psm psm) const {
-  return channels_.find(psm) != channels_.end();
+bool DynamicChannelAllocator::IsPsmUsed(Psm psm) const {
+  for (const auto& channel : channels_) {
+    if (channel.second->GetPsm() == psm) {
+      return true;
+    }
+  }
+  return false;
 }
 
-std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::FindChannel(Psm psm) {
-  ASSERT_LOG(IsChannelAllocated(psm), "Channel is not in use: psm %d, device %s", psm,
-             link_->GetDevice().ToString().c_str());
-  return channels_.find(psm)->second;
+std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::FindChannelByCid(Cid cid) {
+  if (channels_.find(cid) == channels_.end()) {
+    LOG_WARN("Can't find cid %d", cid);
+    return nullptr;
+  }
+  return channels_.find(cid)->second;
 }
 
 size_t DynamicChannelAllocator::NumberOfChannels() const {
index 68ce9bb..40c94b1 100644 (file)
@@ -16,8 +16,8 @@
 
 #pragma once
 
-#include <set>
 #include <unordered_map>
+#include <unordered_set>
 
 #include "l2cap/cid.h"
 #include "l2cap/classic/internal/dynamic_channel_impl.h"
@@ -47,11 +47,11 @@ class DynamicChannelAllocator {
   std::shared_ptr<DynamicChannelImpl> AllocateChannel(Psm psm, Cid remote_cid, SecurityPolicy security_policy);
 
   // Frees a channel. If psm doesn't exist, it will crash
-  void FreeChannel(Psm psm);
+  void FreeChannel(Cid cid);
 
-  bool IsChannelAllocated(Psm psm) const;
+  bool IsPsmUsed(Psm psm) const;
 
-  std::shared_ptr<DynamicChannelImpl> FindChannel(Psm psm);
+  std::shared_ptr<DynamicChannelImpl> FindChannelByCid(Cid cid);
 
   size_t NumberOfChannels() const;
 
@@ -60,9 +60,8 @@ class DynamicChannelAllocator {
  private:
   Link* link_;
   os::Handler* l2cap_handler_;
-  std::unordered_map<Psm, std::shared_ptr<DynamicChannelImpl>> channels_;
-  std::set<Cid> used_cid_;
-  std::set<Cid> used_remote_cid_;
+  std::unordered_map<Cid, std::shared_ptr<DynamicChannelImpl>> channels_;
+  std::unordered_set<Cid> used_remote_cid_;
 };
 
 }  // namespace internal
index 03d5fcc..1e36555 100644 (file)
@@ -61,17 +61,18 @@ class L2capClassicDynamicChannelAllocatorTest : public ::testing::Test {
 
 TEST_F(L2capClassicDynamicChannelAllocatorTest, precondition) {
   Psm psm = 0x03;
-  EXPECT_FALSE(channel_allocator_->IsChannelAllocated(psm));
+  EXPECT_FALSE(channel_allocator_->IsPsmUsed(psm));
 }
 
 TEST_F(L2capClassicDynamicChannelAllocatorTest, allocate_and_free_channel) {
   Psm psm = 0x03;
   Cid remote_cid = kFirstDynamicChannel;
   auto channel = channel_allocator_->AllocateChannel(psm, remote_cid, {});
-  EXPECT_TRUE(channel_allocator_->IsChannelAllocated(psm));
-  EXPECT_EQ(channel, channel_allocator_->FindChannel(psm));
-  ASSERT_NO_FATAL_FAILURE(channel_allocator_->FreeChannel(psm));
-  EXPECT_FALSE(channel_allocator_->IsChannelAllocated(psm));
+  Cid local_cid = channel->GetCid();
+  EXPECT_TRUE(channel_allocator_->IsPsmUsed(psm));
+  EXPECT_EQ(channel, channel_allocator_->FindChannelByCid(local_cid));
+  ASSERT_NO_FATAL_FAILURE(channel_allocator_->FreeChannel(local_cid));
+  EXPECT_FALSE(channel_allocator_->IsPsmUsed(psm));
 }
 
 }  // namespace internal
index a0625d5..47bfd5e 100644 (file)
@@ -56,7 +56,7 @@ void DynamicChannelImpl::RegisterOnCloseCallback(os::Handler* user_handler,
 }
 
 void DynamicChannelImpl::Close() {
-  // TODO: Implement it by sending signalling packet
+  link_->SendDisconnectionRequest(cid_, remote_cid_);
 }
 
 void DynamicChannelImpl::OnClosed(hci::ErrorCode status) {
@@ -77,7 +77,7 @@ void DynamicChannelImpl::OnClosed(hci::ErrorCode status) {
 
 std::string DynamicChannelImpl::ToString() {
   std::ostringstream ss;
-  ss << "Device " << device_.ToString() << "Psm 0x" << std::hex << psm_ << " Cid 0x" << std::hex << cid_;
+  ss << "Device " << device_ << "Psm 0x" << std::hex << psm_ << " Cid 0x" << std::hex << cid_;
   return ss.str();
 }
 
index 4efe113..8a6270a 100644 (file)
@@ -57,6 +57,14 @@ class DynamicChannelImpl {
     return cid_;
   }
 
+  virtual Cid GetRemoteCid() const {
+    return remote_cid_;
+  }
+
+  virtual Psm GetPsm() const {
+    return psm_;
+  }
+
  private:
   const Psm psm_;
   const Cid cid_;
index 409b78a..c980639 100644 (file)
@@ -44,7 +44,6 @@ class DynamicChannelServiceManagerImpl {
   virtual DynamicChannelServiceImpl* GetService(Psm psm);
 
   virtual std::vector<std::pair<Psm, DynamicChannelServiceImpl*>> GetRegisteredServices();
-  //
  private:
   os::Handler* l2cap_layer_handler_ = nullptr;
   std::unordered_map<Psm, DynamicChannelServiceImpl> service_map_;
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h
new file mode 100644 (file)
index 0000000..34363f1
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace testing {
+
+class MockDynamicChannelServiceManagerImpl : public DynamicChannelServiceManagerImpl {
+ public:
+  MockDynamicChannelServiceManagerImpl() : DynamicChannelServiceManagerImpl(nullptr) {}
+  MOCK_METHOD(void, Register, (Psm psm, DynamicChannelServiceImpl::PendingRegistration pending_registration),
+              (override));
+  MOCK_METHOD(void, Unregister, (Psm psm, DynamicChannelService::OnUnregisteredCallback callback, os::Handler* handler),
+              (override));
+  MOCK_METHOD(bool, IsServiceRegistered, (Psm psm), (const, override));
+  MOCK_METHOD(DynamicChannelServiceImpl*, GetService, (Psm psm), (override));
+  MOCK_METHOD((std::vector<std::pair<Psm, DynamicChannelServiceImpl*>>), GetRegisteredServices, (), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
index 9c54f6e..9bfaef8 100644 (file)
@@ -31,7 +31,6 @@ namespace internal {
 FixedChannelImpl::FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler)
     : cid_(cid), device_(link->GetDevice()), link_(link), l2cap_handler_(l2cap_handler) {
   ASSERT_LOG(cid_ >= kFirstFixedChannel && cid_ <= kLastFixedChannel, "Invalid cid: %d", cid_);
-  ASSERT(!device_.IsEmpty());
   ASSERT(link_ != nullptr);
   ASSERT(l2cap_handler_ != nullptr);
 }
index 206c0e4..b557970 100644 (file)
@@ -76,6 +76,31 @@ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> FixedChannelServiceManager
   return results;
 }
 
+namespace {
+constexpr uint64_t kSignallingChannelMask = 0x02;
+constexpr uint64_t kConnectionlessReceptionMask = 0x04;
+constexpr uint64_t kBrEdrSecurityManager = 0x80;
+}  // namespace
+
+uint64_t FixedChannelServiceManagerImpl::GetSupportedFixedChannelMask() {
+  uint64_t result = 0;
+  result |= kSignallingChannelMask;  // Signalling channel is mandatory
+  for (const auto& elem : service_map_) {
+    Cid cid = elem.first;
+    switch (cid) {
+      case kConnectionlessCid:
+        result |= kConnectionlessReceptionMask;
+        continue;
+      case kSmpBrCid:
+        result |= kBrEdrSecurityManager;
+        continue;
+      default:
+        LOG_WARN("Unknown fixed channel is registered: 0x%x", cid);
+        continue;
+    }
+  }
+  return result;
+}
 }  // namespace internal
 }  // namespace classic
 }  // namespace l2cap
index 7cff4ee..1e1d21d 100644 (file)
@@ -41,6 +41,7 @@ class FixedChannelServiceManagerImpl {
   virtual bool IsServiceRegistered(Cid cid) const;
   virtual FixedChannelServiceImpl* GetService(Cid cid);
   virtual std::vector<std::pair<Cid, FixedChannelServiceImpl*>> GetRegisteredServices();
+  virtual uint64_t GetSupportedFixedChannelMask();
 
  private:
   os::Handler* l2cap_layer_handler_ = nullptr;
index 692a3fc..2e6dd42 100644 (file)
@@ -31,9 +31,14 @@ namespace internal {
 
 Link::Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_connection,
            std::unique_ptr<l2cap::internal::Scheduler> scheduler,
-           l2cap::internal::ParameterProvider* parameter_provider)
+           l2cap::internal::ParameterProvider* parameter_provider,
+           DynamicChannelServiceManagerImpl* dynamic_service_manager,
+           FixedChannelServiceManagerImpl* fixed_service_manager)
     : l2cap_handler_(l2cap_handler), acl_connection_(std::move(acl_connection)), scheduler_(std::move(scheduler)),
-      parameter_provider_(parameter_provider) {
+      parameter_provider_(parameter_provider), dynamic_service_manager_(dynamic_service_manager),
+      fixed_service_manager_(fixed_service_manager),
+      signalling_manager_(l2cap_handler_, this, dynamic_service_manager_, &dynamic_channel_allocator_,
+                          fixed_service_manager_) {
   ASSERT(l2cap_handler_ != nullptr);
   ASSERT(acl_connection_ != nullptr);
   ASSERT(scheduler_ != nullptr);
@@ -46,7 +51,7 @@ Link::Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_c
 
 void Link::OnAclDisconnected(hci::ErrorCode status) {
   fixed_channel_allocator_.OnAclDisconnected(status);
-  // TODO hsz: add dynamic channel part
+  dynamic_channel_allocator_.OnAclDisconnected(status);
 }
 
 void Link::Disconnect() {
@@ -63,14 +68,30 @@ bool Link::IsFixedChannelAllocated(Cid cid) {
   return fixed_channel_allocator_.IsChannelAllocated(cid);
 }
 
+void Link::SendConnectionRequest(Psm psm, Cid local_cid) {
+  signalling_manager_.SendConnectionRequest(psm, local_cid);
+}
+
+void Link::SendDisconnectionRequest(Cid local_cid, Cid remote_cid) {
+  signalling_manager_.SendDisconnectionRequest(local_cid, remote_cid);
+}
+
 std::shared_ptr<DynamicChannelImpl> Link::AllocateDynamicChannel(Psm psm, Cid remote_cid,
                                                                  SecurityPolicy security_policy) {
   auto channel = dynamic_channel_allocator_.AllocateChannel(psm, remote_cid, security_policy);
-  scheduler_->AttachChannel(channel->GetCid(), channel->GetQueueDownEnd());
+  if (channel != nullptr) {
+    scheduler_->AttachChannel(channel->GetCid(), channel->GetQueueDownEnd());
+  }
   return channel;
 }
 
-void Link::FreeDynamicChannel(Cid cid) {}
+void Link::FreeDynamicChannel(Cid cid) {
+  if (dynamic_channel_allocator_.FindChannelByCid(cid) == nullptr) {
+    return;
+  }
+  scheduler_->DetachChannel(cid);
+  dynamic_channel_allocator_.FreeChannel(cid);
+}
 
 void Link::RefreshRefCount() {
   int ref_count = 0;
index bb5ef85..eacb1f9 100644 (file)
 #include "hci/acl_manager.h"
 #include "l2cap/classic/internal/dynamic_channel_allocator.h"
 #include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
 #include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
 #include "l2cap/internal/fixed_channel_allocator.h"
 #include "l2cap/internal/parameter_provider.h"
 #include "l2cap/internal/scheduler.h"
 #include "os/alarm.h"
+#include "os/handler.h"
+#include "signalling_manager.h"
 
 namespace bluetooth {
 namespace l2cap {
@@ -35,7 +39,9 @@ namespace internal {
 class Link {
  public:
   Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_connection,
-       std::unique_ptr<l2cap::internal::Scheduler> scheduler, l2cap::internal::ParameterProvider* parameter_provider);
+       std::unique_ptr<l2cap::internal::Scheduler> scheduler, l2cap::internal::ParameterProvider* parameter_provider,
+       DynamicChannelServiceManagerImpl* dynamic_service_manager,
+       FixedChannelServiceManagerImpl* fixed_service_manager);
 
   virtual ~Link() = default;
 
@@ -55,7 +61,11 @@ class Link {
 
   virtual bool IsFixedChannelAllocated(Cid cid);
 
-  // ClassicDynamicChannel methods
+  // DynamicChannel methods
+
+  virtual void SendConnectionRequest(Psm psm, Cid local_cid);
+
+  virtual void SendDisconnectionRequest(Cid local_cid, Cid remote_cid);
 
   virtual std::shared_ptr<DynamicChannelImpl> AllocateDynamicChannel(Psm psm, Cid remote_cid,
                                                                      SecurityPolicy security_policy);
@@ -72,6 +82,9 @@ class Link {
   std::unique_ptr<hci::AclConnection> acl_connection_;
   std::unique_ptr<l2cap::internal::Scheduler> scheduler_;
   l2cap::internal::ParameterProvider* parameter_provider_;
+  DynamicChannelServiceManagerImpl* dynamic_service_manager_;
+  FixedChannelServiceManagerImpl* fixed_service_manager_;
+  ClassicSignallingManager signalling_manager_;
   os::Alarm link_idle_disconnect_alarm_{l2cap_handler_};
   DISALLOW_COPY_AND_ASSIGN(Link);
 };
index 5cc06bb..a808fbb 100644 (file)
@@ -33,7 +33,7 @@ namespace internal {
 void LinkManager::ConnectFixedChannelServices(hci::Address device,
                                               PendingFixedChannelConnection pending_fixed_channel_connection) {
   // Check if there is any service registered
-  auto fixed_channel_services = service_manager_->GetRegisteredServices();
+  auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices();
   if (fixed_channel_services.empty()) {
     // If so, return error
     pending_fixed_channel_connection.handler_->Post(common::BindOnce(
@@ -82,6 +82,16 @@ void LinkManager::ConnectFixedChannelServices(hci::Address device,
   acl_manager_->CreateConnection(device);
 }
 
+void LinkManager::ConnectDynamicChannelServices(hci::Address device,
+                                                PendingDynamicChannelConnection pending_dynamic_channel_connection,
+                                                Psm psm) {
+  // TODO: if there is no link, establish link. Otherwise send command.
+  auto* link = GetLink(device);
+  if (link != nullptr) {
+    return;
+  }
+}
+
 Link* LinkManager::GetLink(const hci::Address device) {
   if (links_.find(device) == links_.end()) {
     return nullptr;
@@ -96,10 +106,11 @@ void LinkManager::OnConnectSuccess(std::unique_ptr<hci::AclConnection> acl_conne
              acl_connection->GetAddress().ToString().c_str());
   auto* link_queue_up_end = acl_connection->GetAclQueueEnd();
   links_.try_emplace(device, l2cap_handler_, std::move(acl_connection),
-                     std::make_unique<l2cap::internal::Fifo>(link_queue_up_end, l2cap_handler_), parameter_provider_);
+                     std::make_unique<l2cap::internal::Fifo>(link_queue_up_end, l2cap_handler_), parameter_provider_,
+                     dynamic_channel_service_manager_, fixed_channel_service_manager_);
   auto* link = GetLink(device);
   // Allocate and distribute channels for all registered fixed channel services
-  auto fixed_channel_services = service_manager_->GetRegisteredServices();
+  auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices();
   for (auto& fixed_channel_service : fixed_channel_services) {
     auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy());
     fixed_channel_service.second->NotifyChannelCreation(
index e190a27..92c0c3e 100644 (file)
@@ -23,6 +23,7 @@
 #include "hci/address.h"
 #include "l2cap/classic/dynamic_channel_manager.h"
 #include "l2cap/classic/fixed_channel_manager.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
 #include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
 #include "l2cap/classic/internal/link.h"
 #include "l2cap/internal/parameter_provider.h"
@@ -36,10 +37,13 @@ namespace internal {
 
 class LinkManager : public hci::ConnectionCallbacks {
  public:
-  LinkManager(os::Handler* l2cap_handler, hci::AclManager* acl_manager, FixedChannelServiceManagerImpl* service_manager,
+  LinkManager(os::Handler* l2cap_handler, hci::AclManager* acl_manager,
+              FixedChannelServiceManagerImpl* fixed_channel_service_manager,
+              DynamicChannelServiceManagerImpl* dynamic_channel_service_manager,
               l2cap::internal::ParameterProvider* parameter_provider)
-      : l2cap_handler_(l2cap_handler), acl_manager_(acl_manager), service_manager_(service_manager),
-        parameter_provider_(parameter_provider) {
+      : l2cap_handler_(l2cap_handler), acl_manager_(acl_manager),
+        fixed_channel_service_manager_(fixed_channel_service_manager),
+        dynamic_channel_service_manager_(dynamic_channel_service_manager), parameter_provider_(parameter_provider) {
     acl_manager_->RegisterCallbacks(this, l2cap_handler_);
   }
 
@@ -69,11 +73,17 @@ class LinkManager : public hci::ConnectionCallbacks {
 
   void ConnectFixedChannelServices(hci::Address device, PendingFixedChannelConnection pending_fixed_channel_connection);
 
+  // DynamicChannelManager methods
+
+  void ConnectDynamicChannelServices(hci::Address device,
+                                     PendingDynamicChannelConnection pending_dynamic_channel_connection, Psm psm);
+
  private:
   // Dependencies
   os::Handler* l2cap_handler_;
   hci::AclManager* acl_manager_;
-  FixedChannelServiceManagerImpl* service_manager_;
+  FixedChannelServiceManagerImpl* fixed_channel_service_manager_;
+  DynamicChannelServiceManagerImpl* dynamic_channel_service_manager_;
   l2cap::internal::ParameterProvider* parameter_provider_;
 
   // Internal states
index 0ec2c70..e49f058 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "common/bind.h"
 #include "common/testing/bind_test_util.h"
+#include "dynamic_channel_service_manager_impl_mock.h"
 #include "hci/acl_manager_mock.h"
 #include "hci/address.h"
 #include "l2cap/cid.h"
@@ -45,6 +46,7 @@ using l2cap::internal::testing::MockParameterProvider;
 using ::testing::_;  // Matcher to any value
 using ::testing::ByMove;
 using ::testing::DoAll;
+using testing::MockDynamicChannelServiceManagerImpl;
 using testing::MockFixedChannelServiceImpl;
 using testing::MockFixedChannelServiceManagerImpl;
 using ::testing::Return;
@@ -85,6 +87,7 @@ class L2capClassicLinkManagerTest : public ::testing::Test {
 
 TEST_F(L2capClassicLinkManagerTest, connect_fixed_channel_service_without_acl) {
   MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+  MockDynamicChannelServiceManagerImpl mock_classic_dynamic_channel_service_manager;
   MockAclManager mock_acl_manager;
   hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
   auto user_handler = std::make_unique<os::Handler>(thread_);
@@ -95,7 +98,7 @@ TEST_F(L2capClassicLinkManagerTest, connect_fixed_channel_service_without_acl) {
   EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
       .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
   LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
-                                   mock_parameter_provider_);
+                                   &mock_classic_dynamic_channel_service_manager, mock_parameter_provider_);
   EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
   EXPECT_EQ(hci_callback_handler, l2cap_handler_);
 
@@ -174,7 +177,7 @@ TEST_F(L2capClassicLinkManagerTest, connect_fixed_channel_service_without_acl_wi
   EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
       .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
   LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
-                                   mock_parameter_provider_);
+                                   nullptr, mock_parameter_provider_);
   EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
   EXPECT_EQ(hci_callback_handler, l2cap_handler_);
 
@@ -208,7 +211,7 @@ TEST_F(L2capClassicLinkManagerTest, connect_fixed_channel_service_without_acl_wi
   EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
       .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
   LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
-                                   mock_parameter_provider_);
+                                   nullptr, mock_parameter_provider_);
   EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
   EXPECT_EQ(hci_callback_handler, l2cap_handler_);
 
@@ -254,7 +257,7 @@ TEST_F(L2capClassicLinkManagerTest, not_acquiring_channels_should_disconnect_acl
   EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
       .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
   LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
-                                   mock_parameter_provider_);
+                                   nullptr, mock_parameter_provider_);
   EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
   EXPECT_EQ(hci_callback_handler, l2cap_handler_);
 
@@ -324,7 +327,7 @@ TEST_F(L2capClassicLinkManagerTest, acquiring_channels_should_not_disconnect_acl
   EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
       .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
   LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
-                                   mock_parameter_provider_);
+                                   nullptr, mock_parameter_provider_);
   EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
   EXPECT_EQ(hci_callback_handler, l2cap_handler_);
 
@@ -396,7 +399,7 @@ TEST_F(L2capClassicLinkManagerTest, acquiring_and_releasing_channels_should_even
   EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
       .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
   LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
-                                   mock_parameter_provider_);
+                                   nullptr, mock_parameter_provider_);
   EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
   EXPECT_EQ(hci_callback_handler, l2cap_handler_);
 
index 0f7f1be..710cc44 100644 (file)
@@ -35,12 +35,14 @@ class MockLink : public Link {
  public:
   explicit MockLink(os::Handler* handler, l2cap::internal::ParameterProvider* parameter_provider)
       : Link(handler, std::make_unique<MockAclConnection>(),
-             std::make_unique<l2cap::internal::testing::MockScheduler>(), parameter_provider){};
+             std::make_unique<l2cap::internal::testing::MockScheduler>(), parameter_provider, nullptr, nullptr){};
   MOCK_METHOD(hci::Address, GetDevice, (), (override));
   MOCK_METHOD(void, OnAclDisconnected, (hci::ErrorCode status), (override));
   MOCK_METHOD(void, Disconnect, (), (override));
   MOCK_METHOD(std::shared_ptr<FixedChannelImpl>, AllocateFixedChannel, (Cid cid, SecurityPolicy security_policy),
               (override));
+  MOCK_METHOD(std::shared_ptr<DynamicChannelImpl>, AllocateDynamicChannel,
+              (Psm psm, Cid cid, SecurityPolicy security_policy), (override));
   MOCK_METHOD(bool, IsFixedChannelAllocated, (Cid cid), (override));
   MOCK_METHOD(void, RefreshRefCount, (), (override));
 };
diff --git a/gd/l2cap/classic/internal/signalling_manager.cc b/gd/l2cap/classic/internal/signalling_manager.cc
new file mode 100644 (file)
index 0000000..93f166b
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "l2cap/classic/internal/signalling_manager.h"
+
+#include <chrono>
+
+#include "common/bind.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/log.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+static constexpr auto kTimeout = std::chrono::seconds(3);
+
+ClassicSignallingManager::ClassicSignallingManager(os::Handler* handler, Link* link,
+                                                   DynamicChannelServiceManagerImpl* dynamic_service_manager,
+                                                   DynamicChannelAllocator* channel_allocator,
+                                                   FixedChannelServiceManagerImpl* fixed_service_manager)
+    : handler_(handler), link_(link), dynamic_service_manager_(dynamic_service_manager),
+      channel_allocator_(channel_allocator), fixed_service_manager_(fixed_service_manager), alarm_(handler) {
+  ASSERT(handler_ != nullptr);
+  ASSERT(link_ != nullptr);
+  signalling_channel_ = link_->AllocateFixedChannel(kClassicSignallingCid, {});
+  signalling_channel_->GetQueueUpEnd()->RegisterDequeue(
+      handler_, common::Bind(&ClassicSignallingManager::on_incoming_packet, common::Unretained(this)));
+  enqueue_buffer_ =
+      std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(signalling_channel_->GetQueueUpEnd());
+}
+
+ClassicSignallingManager::~ClassicSignallingManager() {
+  enqueue_buffer_.reset();
+  signalling_channel_->GetQueueUpEnd()->UnregisterDequeue();
+  signalling_channel_ = nullptr;
+}
+
+void ClassicSignallingManager::OnCommandReject(CommandRejectView command_reject_view) {
+  SignalId signal_id = command_reject_view.GetIdentifier();
+  if (pending_command_.signal_id_ != signal_id) {
+    LOG_WARN("Unknown command reject");
+    return;
+  }
+  pending_command_ = {};
+
+  LOG_INFO("Command rejected");
+}
+
+void ClassicSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid) {
+  PendingCommand pending_command = {next_signal_id_, CommandCode::CONNECTION_REQUEST, psm, local_cid, {}, {}};
+  next_signal_id_++;
+  pending_commands_.push(pending_command);
+  if (pending_commands_.size() == 1) {
+    handle_send_next_command();
+  }
+}
+
+void ClassicSignallingManager::SendConfigurationRequest() {}
+
+void ClassicSignallingManager::SendDisconnectionRequest(Cid local_cid, Cid remote_cid) {
+  PendingCommand pending_command = {next_signal_id_, CommandCode::DISCONNECTION_REQUEST, {}, local_cid, remote_cid, {}};
+  next_signal_id_++;
+  pending_commands_.push(pending_command);
+  if (pending_commands_.size() == 1) {
+    handle_send_next_command();
+  }
+}
+
+void ClassicSignallingManager::SendInformationRequest(InformationRequestInfoType type) {
+  PendingCommand pending_command = {next_signal_id_, CommandCode::INFORMATION_REQUEST, {}, {}, {}, type};
+  next_signal_id_++;
+  pending_commands_.push(pending_command);
+  if (pending_commands_.size() == 1) {
+    handle_send_next_command();
+  }
+}
+
+void ClassicSignallingManager::SendEchoRequest(std::unique_ptr<packet::RawBuilder> payload) {
+  LOG_WARN("Not supported");
+}
+
+void ClassicSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid) {
+  if (!IsPsmValid(psm)) {
+    LOG_WARN("Invalid psm received from remote psm:%d remote_cid:%d", psm, remote_cid);
+    send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
+                             ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+    return;
+  }
+
+  if (remote_cid == kInvalidCid) {
+    LOG_WARN("Invalid remote cid received from remote psm:%d remote_cid:%d", psm, remote_cid);
+    send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::INVALID_CID,
+                             ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+    return;
+  }
+  if (channel_allocator_->IsPsmUsed(psm)) {
+    LOG_WARN("Psm already exists");
+    send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
+                             ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+    return;
+  }
+
+  if (!dynamic_service_manager_->IsServiceRegistered(psm)) {
+    LOG_INFO("Service for this psm (%d) is not registered", psm);
+    send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
+                             ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+    return;
+  }
+
+  auto new_channel = link_->AllocateDynamicChannel(psm, remote_cid, {});
+  if (new_channel == nullptr) {
+    LOG_WARN("Can't allocate dynamic channel");
+    return;
+  }
+  send_connection_response(signal_id, remote_cid, new_channel->GetCid(), ConnectionResponseResult::SUCCESS,
+                           ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+  std::unique_ptr<DynamicChannel> channel = std::make_unique<DynamicChannel>(new_channel, handler_);
+  dynamic_service_manager_->GetService(psm)->NotifyChannelCreation(std::move(channel));
+}
+
+void ClassicSignallingManager::OnConnectionResponse(SignalId signal_id, Cid cid, Cid remote_cid,
+                                                    ConnectionResponseResult result, ConnectionResponseStatus status) {
+  if (pending_command_.signal_id_ != signal_id || pending_command_.command_code_ != CommandCode::CONNECTION_REQUEST) {
+    LOG_WARN("Received unexpected connection response");
+    return;
+  }
+  if (pending_command_.source_cid_ != cid) {
+    LOG_WARN("SCID doesn't match");
+    return;
+  }
+  if (result != ConnectionResponseResult::SUCCESS) {
+    return;
+  }
+  Psm pending_psm = pending_command_.psm_;
+  pending_command_ = {};
+  auto new_channel = link_->AllocateDynamicChannel(pending_psm, remote_cid, {});
+  if (new_channel == nullptr) {
+    LOG_WARN("Can't allocate dynamic channel");
+    return;
+  }
+  send_connection_response(signal_id, remote_cid, new_channel->GetCid(), ConnectionResponseResult::SUCCESS,
+                           ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+  std::unique_ptr<DynamicChannel> channel = std::make_unique<DynamicChannel>(new_channel, handler_);
+  dynamic_service_manager_->GetService(pending_psm)->NotifyChannelCreation(std::move(channel));
+  alarm_.Cancel();
+}
+
+void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid cid, Continuation is_continuation,
+                                                      std::vector<std::unique_ptr<ConfigurationOption>> option) {}
+
+void ClassicSignallingManager::OnConfigurationResponse(SignalId signal_id, Cid cid, Continuation is_continuation,
+                                                       ConfigurationResponseResult result,
+                                                       std::vector<std::unique_ptr<ConfigurationOption>> option) {}
+
+void ClassicSignallingManager::OnDisconnectionRequest(SignalId signal_id, Cid cid, Cid remote_cid) {
+  // TODO: check cid match
+  auto channel = channel_allocator_->FindChannelByCid(cid);
+  if (channel == nullptr) {
+    LOG_WARN("Disconnect request for an unknown channel");
+    return;
+  }
+  auto builder = DisconnectionResponseBuilder::Create(signal_id.Value(), remote_cid, cid);
+  enqueue_buffer_->Enqueue(std::move(builder), handler_);
+  channel->OnClosed(hci::ErrorCode::SUCCESS);
+  link_->FreeDynamicChannel(cid);
+}
+
+void ClassicSignallingManager::OnDisconnectionResponse(SignalId signal_id, Cid cid, Cid remote_cid) {
+  if (pending_command_.signal_id_ != signal_id ||
+      pending_command_.command_code_ != CommandCode::DISCONNECTION_REQUEST) {
+    return;
+  }
+
+  auto channel = channel_allocator_->FindChannelByCid(cid);
+  if (channel == nullptr) {
+    LOG_WARN("Disconnect response for an unknown channel");
+    return;
+  }
+
+  channel->OnClosed(hci::ErrorCode::SUCCESS);
+  link_->FreeDynamicChannel(cid);
+}
+
+void ClassicSignallingManager::OnEchoRequest(SignalId signal_id, const PacketView<kLittleEndian>& packet) {
+  std::vector<uint8_t> packet_vector{packet.begin(), packet.end()};
+  auto raw_builder = std::make_unique<packet::RawBuilder>();
+  raw_builder->AddOctets(packet_vector);
+  auto builder = EchoRequestBuilder::Create(signal_id.Value(), std::move(raw_builder));
+  enqueue_buffer_->Enqueue(std::move(builder), handler_);
+}
+
+void ClassicSignallingManager::OnEchoResponse(SignalId signal_id, const PacketView<kLittleEndian>& packet) {
+  if (pending_command_.signal_id_ != signal_id || pending_command_.command_code_ != CommandCode::ECHO_REQUEST) {
+    return;
+  }
+  LOG_INFO("Echo response received");
+}
+
+void ClassicSignallingManager::OnInformationRequest(SignalId signal_id, InformationRequestInfoType type) {
+  switch (type) {
+    case InformationRequestInfoType::CONNECTIONLESS_MTU: {
+      auto response = InformationResponseConnectionlessMtuBuilder::Create(signal_id.Value(),
+                                                                          InformationRequestResult::NOT_SUPPORTED, 0);
+      enqueue_buffer_->Enqueue(std::move(response), handler_);
+      return;
+    }
+    case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
+      // TODO: implement this response
+      auto response = InformationResponseExtendedFeaturesBuilder::Create(
+          signal_id.Value(), InformationRequestResult::NOT_SUPPORTED, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+      enqueue_buffer_->Enqueue(std::move(response), handler_);
+      return;
+    }
+    case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
+      auto response = InformationResponseFixedChannelsBuilder::Create(
+          signal_id.Value(), InformationRequestResult::SUCCESS, fixed_service_manager_->GetSupportedFixedChannelMask());
+      enqueue_buffer_->Enqueue(std::move(response), handler_);
+      return;
+    }
+  }
+}
+
+void ClassicSignallingManager::OnInformationResponse(SignalId signal_id, const InformationResponseView& view) {
+  if (pending_command_.signal_id_ != signal_id || pending_command_.command_code_ != CommandCode::INFORMATION_REQUEST) {
+    return;
+  }
+  if (view.GetResult() != InformationRequestResult::SUCCESS) {
+    return;
+  }
+}
+
+void ClassicSignallingManager::on_incoming_packet() {
+  auto packet = signalling_channel_->GetQueueUpEnd()->TryDequeue();
+  ControlView control_packet_view = ControlView::Create(*packet);
+  if (!control_packet_view.IsValid()) {
+    LOG_WARN("Invalid signalling packet received");
+    return;
+  }
+  auto code = control_packet_view.GetCode();
+  switch (code) {
+    case CommandCode::COMMAND_REJECT: {
+      CommandRejectView command_reject_view = CommandRejectView::Create(control_packet_view);
+      if (!command_reject_view.IsValid()) {
+        return;
+      }
+      OnCommandReject(command_reject_view);
+      return;
+    }
+    case CommandCode::CONNECTION_REQUEST: {
+      ConnectionRequestView connection_request_view = ConnectionRequestView::Create(control_packet_view);
+      if (!connection_request_view.IsValid()) {
+        return;
+      }
+      OnConnectionRequest(control_packet_view.GetIdentifier(), connection_request_view.GetPsm(),
+                          connection_request_view.GetSourceCid());
+      return;
+    }
+    case CommandCode::CONNECTION_RESPONSE: {
+      ConnectionResponseView connection_response_view = ConnectionResponseView::Create(control_packet_view);
+      if (!connection_response_view.IsValid()) {
+        return;
+      }
+      OnConnectionResponse(connection_response_view.GetIdentifier(), connection_response_view.GetDestinationCid(),
+                           connection_response_view.GetSourceCid(), connection_response_view.GetResult(),
+                           connection_response_view.GetStatus());
+      return;
+    }
+    case CommandCode::CONFIGURATION_REQUEST: {
+      ConfigurationRequestView configuration_request_view = ConfigurationRequestView::Create(control_packet_view);
+      if (!configuration_request_view.IsValid()) {
+        return;
+      }
+      OnConfigurationRequest(configuration_request_view.GetIdentifier(), configuration_request_view.GetDestinationCid(),
+                             configuration_request_view.GetContinuation(), configuration_request_view.GetConfig());
+      return;
+    }
+    case CommandCode::CONFIGURATION_RESPONSE: {
+      ConfigurationResponseView configuration_response_view = ConfigurationResponseView::Create(control_packet_view);
+      if (!configuration_response_view.IsValid()) {
+        return;
+      }
+      OnConfigurationResponse(configuration_response_view.GetIdentifier(), configuration_response_view.GetSourceCid(),
+                              configuration_response_view.GetContinuation(), configuration_response_view.GetResult(),
+                              configuration_response_view.GetConfig());
+    }
+    case CommandCode::DISCONNECTION_REQUEST: {
+      DisconnectionRequestView disconnection_request_view = DisconnectionRequestView::Create(control_packet_view);
+      if (!disconnection_request_view.IsValid()) {
+        return;
+      }
+      OnDisconnectionRequest(disconnection_request_view.GetIdentifier(), disconnection_request_view.GetDestinationCid(),
+                             disconnection_request_view.GetSourceCid());
+      return;
+    }
+    case CommandCode::DISCONNECTION_RESPONSE: {
+      DisconnectionResponseView disconnection_response_view = DisconnectionResponseView::Create(control_packet_view);
+      if (!disconnection_response_view.IsValid()) {
+        return;
+      }
+      OnDisconnectionResponse(disconnection_response_view.GetIdentifier(),
+                              disconnection_response_view.GetDestinationCid(),
+                              disconnection_response_view.GetSourceCid());
+      return;
+    }
+    case CommandCode::ECHO_REQUEST: {
+      EchoRequestView echo_request_view = EchoRequestView::Create(control_packet_view);
+      if (!echo_request_view.IsValid()) {
+        return;
+      }
+      OnEchoRequest(echo_request_view.GetIdentifier(), echo_request_view.GetPayload());
+      return;
+    }
+    case CommandCode::ECHO_RESPONSE: {
+      EchoResponseView echo_response_view = EchoResponseView::Create(control_packet_view);
+      if (!echo_response_view.IsValid()) {
+        return;
+      }
+      OnEchoResponse(echo_response_view.GetIdentifier(), echo_response_view.GetPayload());
+      return;
+    }
+    case CommandCode::INFORMATION_REQUEST: {
+      InformationRequestView information_request_view = InformationRequestView::Create(control_packet_view);
+      if (!information_request_view.IsValid()) {
+        return;
+      }
+      OnInformationRequest(information_request_view.GetIdentifier(), information_request_view.GetInfoType());
+      return;
+    }
+    case CommandCode::INFORMATION_RESPONSE: {
+      InformationResponseView information_response_view = InformationResponseView::Create(control_packet_view);
+      if (!information_response_view.IsValid()) {
+        return;
+      }
+      OnInformationResponse(information_response_view.GetIdentifier(), information_response_view);
+      return;
+    }
+    default:
+      LOG_WARN("Unhandled event 0x%x", static_cast<int>(code));
+      return;
+  }
+}
+
+void ClassicSignallingManager::send_connection_response(SignalId signal_id, Cid remote_cid, Cid local_cid,
+                                                        ConnectionResponseResult result,
+                                                        ConnectionResponseStatus status) {
+  auto builder = ConnectionResponseBuilder::Create(signal_id.Value(), remote_cid, local_cid, result, status);
+  enqueue_buffer_->Enqueue(std::move(builder), handler_);
+}
+
+void ClassicSignallingManager::on_command_timeout() {
+  LOG_WARN("Response time out");
+  // TODO: drop the link?
+}
+
+void ClassicSignallingManager::handle_send_next_command() {
+  if (pending_commands_.empty()) {
+    return;
+  }
+  pending_command_ = pending_commands_.front();
+  pending_commands_.pop();
+
+  auto signal_id = pending_command_.signal_id_;
+  auto psm = pending_command_.psm_;
+  auto source_cid = pending_command_.source_cid_;
+  auto destination_cid = pending_command_.destination_cid_;
+  auto info_type = pending_command_.info_type_;
+  switch (pending_command_.command_code_) {
+    case CommandCode::CONNECTION_REQUEST: {
+      auto builder = ConnectionRequestBuilder::Create(signal_id.Value(), psm, source_cid);
+      enqueue_buffer_->Enqueue(std::move(builder), handler_);
+      alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
+                      kTimeout);
+      break;
+    }
+    case CommandCode::CONFIGURATION_REQUEST:
+      break;
+    case CommandCode::DISCONNECTION_REQUEST: {
+      auto builder = DisconnectionRequestBuilder::Create(signal_id.Value(), destination_cid, source_cid);
+      enqueue_buffer_->Enqueue(std::move(builder), handler_);
+      alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
+                      kTimeout);
+      break;
+    }
+    case CommandCode::INFORMATION_REQUEST: {
+      auto builder = InformationRequestBuilder::Create(signal_id.Value(), info_type);
+      enqueue_buffer_->Enqueue(std::move(builder), handler_);
+      alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
+                      kTimeout);
+      break;
+    }
+    default:
+      LOG_WARN("Unsupported command code 0x%x", static_cast<int>(pending_command_.command_code_));
+  }
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/signalling_manager.h b/gd/l2cap/classic/internal/signalling_manager.h
new file mode 100644 (file)
index 0000000..d63d169
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <queue>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/psm.h"
+#include "l2cap/signal_id.h"
+#include "os/alarm.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+struct PendingCommand {
+  SignalId signal_id_;
+  CommandCode command_code_;
+  Psm psm_;
+  Cid source_cid_;
+  Cid destination_cid_;
+  InformationRequestInfoType info_type_;
+};
+
+class Link;
+
+class ClassicSignallingManager {
+ public:
+  ClassicSignallingManager(os::Handler* handler, Link* link,
+                           classic::internal::DynamicChannelServiceManagerImpl* dynamic_service_manager,
+                           classic::internal::DynamicChannelAllocator* channel_allocator,
+                           classic::internal::FixedChannelServiceManagerImpl* fixed_service_manager);
+
+  virtual ~ClassicSignallingManager();
+
+  void OnCommandReject(CommandRejectView command_reject_view);
+
+  void SendConnectionRequest(Psm psm, Cid local_cid);
+
+  void SendConfigurationRequest();
+
+  void SendDisconnectionRequest(Cid local_cid, Cid remote_cid);
+
+  void SendInformationRequest(InformationRequestInfoType type);
+
+  void SendEchoRequest(std::unique_ptr<packet::RawBuilder> payload);
+
+  void OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid);
+
+  void OnConnectionResponse(SignalId signal_id, Cid cid, Cid remote_cid, ConnectionResponseResult result,
+                            ConnectionResponseStatus status);
+
+  void OnDisconnectionRequest(SignalId signal_id, Cid cid, Cid remote_cid);
+
+  void OnDisconnectionResponse(SignalId signal_id, Cid cid, Cid remote_cid);
+
+  void OnConfigurationRequest(SignalId signal_id, Cid cid, Continuation is_continuation,
+                              std::vector<std::unique_ptr<ConfigurationOption>>);
+
+  void OnConfigurationResponse(SignalId signal_id, Cid cid, Continuation is_continuation,
+                               ConfigurationResponseResult result, std::vector<std::unique_ptr<ConfigurationOption>>);
+
+  void OnEchoRequest(SignalId signal_id, const PacketView<kLittleEndian>& packet);
+
+  void OnEchoResponse(SignalId signal_id, const PacketView<kLittleEndian>& packet);
+
+  void OnInformationRequest(SignalId signal_id, InformationRequestInfoType type);
+
+  void OnInformationResponse(SignalId signal_id, const InformationResponseView& view);
+
+ private:
+  void on_incoming_packet();
+  void send_connection_response(SignalId signal_id, Cid remote_cid, Cid local_cid, ConnectionResponseResult result,
+                                ConnectionResponseStatus status);
+  void on_command_timeout();
+  void handle_send_next_command();
+
+  os::Handler* handler_;
+  Link* link_;
+  std::shared_ptr<classic::internal::FixedChannelImpl> signalling_channel_;
+  DynamicChannelServiceManagerImpl* dynamic_service_manager_;
+  DynamicChannelAllocator* channel_allocator_;
+  FixedChannelServiceManagerImpl* fixed_service_manager_;
+  std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> enqueue_buffer_;
+  PendingCommand pending_command_;
+  std::queue<std::unique_ptr<ControlBuilder>> pending_requests_;
+  std::queue<PendingCommand> pending_commands_;
+  os::Alarm alarm_;
+  SignalId next_signal_id_ = kInvalidSignalId;
+};
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/signalling_manager_test.cc b/gd/l2cap/classic/internal/signalling_manager_test.cc
new file mode 100644 (file)
index 0000000..82aeca8
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "l2cap/classic/internal/signalling_manager.h"
+
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace {
+
+class L2capClassicSignallingManagerTest : public ::testing::Test {
+ public:
+  static void SyncHandler(os::Handler* handler) {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    future.wait_for(std::chrono::milliseconds(3));
+  }
+
+ protected:
+  void SetUp() override {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    l2cap_handler_ = new os::Handler(thread_);
+  }
+
+  void TearDown() override {
+    l2cap_handler_->Clear();
+    delete l2cap_handler_;
+    delete thread_;
+  }
+
+  os::Thread* thread_ = nullptr;
+  os::Handler* l2cap_handler_ = nullptr;
+};
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter i(*bytes);
+  bytes->reserve(packet->size());
+  packet->Serialize(i);
+  return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+TEST_F(L2capClassicSignallingManagerTest, handle_connection_request) {
+  l2cap::internal::testing::MockParameterProvider parameter_provider;
+  testing::MockDynamicChannelServiceManagerImpl dynamic_service_manager_;
+  testing::MockFixedChannelServiceManagerImpl fixed_service_manager_;
+  testing::MockLink link{l2cap_handler_, &parameter_provider};
+  std::shared_ptr<FixedChannelImpl> signalling_channel = std::make_shared<FixedChannelImpl>(1, &link, l2cap_handler_);
+  EXPECT_CALL(link, AllocateFixedChannel(_, _)).WillRepeatedly(Return(signalling_channel));
+  auto service_psm = 0x1;
+  EXPECT_CALL(dynamic_service_manager_, IsServiceRegistered(service_psm)).WillRepeatedly(Return(true));
+  DynamicChannelAllocator channel_allocator{&link, l2cap_handler_};
+  ClassicSignallingManager signalling_manager{l2cap_handler_, &link, &dynamic_service_manager_, &channel_allocator,
+                                              &fixed_service_manager_};
+  auto* down_end = signalling_channel->GetQueueDownEnd();
+  os::EnqueueBuffer<packet::PacketView<kLittleEndian>> enqueue_buffer{down_end};
+  auto dcid = 0x101;
+  auto builder = ConnectionRequestBuilder::Create(1, service_psm, dcid);
+  enqueue_buffer.Enqueue(std::make_unique<PacketView<kLittleEndian>>(GetPacketView(std::move(builder))),
+                         l2cap_handler_);
+  SyncHandler(l2cap_handler_);
+  EXPECT_CALL(link, AllocateDynamicChannel(_, dcid, _));
+  SyncHandler(l2cap_handler_);
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
index 3dc892b..f248ebe 100644 (file)
@@ -22,6 +22,7 @@
 #include "hci/address.h"
 #include "hci/hci_layer.h"
 #include "hci/hci_packets.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
 #include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
 #include "l2cap/classic/internal/link_manager.h"
 #include "l2cap/internal/parameter_provider.h"
@@ -44,8 +45,9 @@ struct L2capClassicModule::impl {
   hci::AclManager* acl_manager_;
   l2cap::internal::ParameterProvider parameter_provider_;
   internal::FixedChannelServiceManagerImpl fixed_channel_service_manager_impl_{l2cap_handler_};
+  internal::DynamicChannelServiceManagerImpl dynamic_channel_service_manager_impl_{l2cap_handler_};
   internal::LinkManager link_manager_{l2cap_handler_, acl_manager_, &fixed_channel_service_manager_impl_,
-                                      &parameter_provider_};
+                                      &dynamic_channel_service_manager_impl_, &parameter_provider_};
 };
 
 void L2capClassicModule::ListDependencies(ModuleList* list) {
@@ -65,6 +67,11 @@ std::unique_ptr<FixedChannelManager> L2capClassicModule::GetFixedChannelManager(
                                                                       &pimpl_->link_manager_, pimpl_->l2cap_handler_));
 }
 
+std::unique_ptr<DynamicChannelManager> L2capClassicModule::GetDynamicChannelManager() {
+  return std::unique_ptr<DynamicChannelManager>(new DynamicChannelManager(
+      &pimpl_->dynamic_channel_service_manager_impl_, &pimpl_->link_manager_, pimpl_->l2cap_handler_));
+}
+
 }  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
\ No newline at end of file
index 398a920..ef4b771 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <memory>
 
+#include "l2cap/classic/dynamic_channel_manager.h"
 #include "l2cap/classic/fixed_channel_manager.h"
 #include "module.h"
 
@@ -34,6 +35,11 @@ class L2capClassicModule : public bluetooth::Module {
    */
   std::unique_ptr<FixedChannelManager> GetFixedChannelManager();
 
+  /**
+   * Get the api to the classic dynamic channel l2cap module
+   */
+  std::unique_ptr<DynamicChannelManager> GetDynamicChannelManager();
+
   static const ModuleFactory Factory;
 
  protected:
index 31cae13..0e89e62 100644 (file)
@@ -25,6 +25,7 @@ using Psm = uint16_t;
 constexpr Psm kDefaultPsm = 0;  // Invalid Psm as a default value
 
 constexpr bool IsPsmValid(Psm psm) {
+  // See Core spec 5.1 Vol 3 Part A 4.2 for definition
   return (psm & 0x0101u) == 0x0001u;
 }