L2CAP classic fixed service manager

Implement classic fixed channel service registration

Test: bluetooth_test_gd
Change-Id: Ic5d5b4543e88a0e4b9918f4583c5d115ef021cf0
diff --git a/gd/l2cap/Android.bp b/gd/l2cap/Android.bp
index d061305..a4d419c 100644
--- a/gd/l2cap/Android.bp
+++ b/gd/l2cap/Android.bp
@@ -1,10 +1,12 @@
 filegroup {
     name: "BluetoothL2capSources",
     srcs: [
+        "fcs.cc",
         "l2cap_layer.cc",
         "classic_fixed_channel.cc",
         "classic_fixed_channel_manager.cc",
         "classic_fixed_channel_service.cc",
+        "internal/classic_fixed_channel_service_manager_impl.cc",
     ],
 }
 
@@ -12,7 +14,7 @@
     name: "BluetoothL2capTestSources",
     srcs: [
         "l2cap_packet_test.cc",
-        "fcs.cc",
+        "internal/classic_fixed_channel_service_manager_test.cc",
         "signal_id_test.cc",
     ],
 }
diff --git a/gd/l2cap/classic_fixed_channel_manager.cc b/gd/l2cap/classic_fixed_channel_manager.cc
index 928bedb..8922dc9 100644
--- a/gd/l2cap/classic_fixed_channel_manager.cc
+++ b/gd/l2cap/classic_fixed_channel_manager.cc
@@ -15,6 +15,8 @@
  */
 
 #include "l2cap/classic_fixed_channel_manager.h"
+#include "l2cap/internal/classic_fixed_channel_service.h"
+#include "l2cap/internal/classic_fixed_channel_service_manager_impl.h"
 
 namespace bluetooth {
 namespace l2cap {
@@ -28,6 +30,13 @@
 bool ClassicFixedChannelManager::RegisterService(Cid cid, const SecurityPolicy& security_policy,
                                                  OnRegistrationCompleteCallback on_registration_complete,
                                                  OnConnectionOpenCallback on_connection_open, os::Handler* handler) {
+  internal::ClassicFixedChannelServiceImpl::Builder builder;
+  builder.SetUserHandler(handler)
+      .SetOnRegister(std::move(on_registration_complete))
+      .SetOnChannelOpen(std::move(on_connection_open));
+
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::ClassicFixedChannelServiceManagerImpl::Register,
+                                              common::Unretained(manager_), cid, std::move(builder)));
   return true;
 }
 
diff --git a/gd/l2cap/classic_fixed_channel_manager.h b/gd/l2cap/classic_fixed_channel_manager.h
index cacc368..f5f5717 100644
--- a/gd/l2cap/classic_fixed_channel_manager.h
+++ b/gd/l2cap/classic_fixed_channel_manager.h
@@ -27,18 +27,23 @@
 namespace bluetooth {
 namespace l2cap {
 
+namespace internal {
+class ClassicFixedChannelServiceManagerImpl;
+}
+
 class ClassicFixedChannelManager {
+ public:
   /**
    * OnConnectionFailureCallback(std::string failure_reason);
    */
-  using OnConnectionFailureCallback = common::OnceCallback<void(std::string)>;
+  using OnConnectionFailureCallback = common::Callback<void(std::string)>;
 
   /**
    * OnConnectionOpenCallback(ClassicFixedChannel channel);
    */
-  using OnConnectionOpenCallback = common::OnceCallback<void(ClassicFixedChannel)>;
+  using OnConnectionOpenCallback = common::Callback<void(ClassicFixedChannel)>;
 
-  enum RegistrationResult { SUCCESS, FAIL };
+  enum class RegistrationResult { SUCCESS, FAIL };
 
   /**
    * OnRegistrationFailureCallback(RegistrationResult result, ClassicFixedChannelService service);
@@ -97,6 +102,14 @@
   bool RegisterService(Cid cid, const SecurityPolicy& security_policy,
                        OnRegistrationCompleteCallback on_registration_complete,
                        OnConnectionOpenCallback on_connection_open, os::Handler* handler);
+
+  // The constructor is not to be used by user code
+  ClassicFixedChannelManager(internal::ClassicFixedChannelServiceManagerImpl* manager, os::Handler* l2cap_layer_handler)
+      : manager_(manager), l2cap_layer_handler_(l2cap_layer_handler) {}
+
+ private:
+  internal::ClassicFixedChannelServiceManagerImpl* manager_ = nullptr;
+  os::Handler* l2cap_layer_handler_ = nullptr;
 };
 
 }  // namespace l2cap
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/gd/l2cap/classic_fixed_channel_service.cc
index 8a08509..b118f72 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/gd/l2cap/classic_fixed_channel_service.cc
@@ -15,11 +15,18 @@
  */
 
 #include "l2cap/classic_fixed_channel_service.h"
+#include "l2cap/internal/classic_fixed_channel_service_manager_impl.h"
 
 namespace bluetooth {
 namespace l2cap {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered,
+                                            os::Handler* on_unregistered_handler) {
+  ASSERT_LOG(manager_ != nullptr, "this service is invalid");
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::ClassicFixedChannelServiceManagerImpl::Unregister,
+                                              common::Unretained(manager_), cid_, std::move(on_unregistered),
+                                              on_unregistered_handler));
+}
 
 }  // namespace l2cap
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic_fixed_channel_service.h b/gd/l2cap/classic_fixed_channel_service.h
index 9fddeb6..355bdfd 100644
--- a/gd/l2cap/classic_fixed_channel_service.h
+++ b/gd/l2cap/classic_fixed_channel_service.h
@@ -18,12 +18,20 @@
 
 #include "common/address.h"
 #include "common/callback.h"
+#include "l2cap/cid.h"
+#include "os/handler.h"
 
 namespace bluetooth {
 namespace l2cap {
 
+namespace internal {
+class ClassicFixedChannelServiceManagerImpl;
+}
+
 class ClassicFixedChannelService {
  public:
+  ClassicFixedChannelService() = default;
+
   using OnUnregisteredCallback = common::OnceCallback<void()>;
 
   /**
@@ -32,7 +40,16 @@
    *
    * @param on_unregistered will be triggered when unregistration is complete
    */
-  void Unregister(OnUnregisteredCallback on_unregistered);
+  void Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler);
+
+  friend internal::ClassicFixedChannelServiceManagerImpl;
+
+ private:
+  ClassicFixedChannelService(Cid cid, internal::ClassicFixedChannelServiceManagerImpl* manager, os::Handler* handler)
+      : cid_(cid), manager_(manager), l2cap_layer_handler_(handler) {}
+  Cid cid_ = kInvalidCid;
+  internal::ClassicFixedChannelServiceManagerImpl* manager_ = nullptr;
+  os::Handler* l2cap_layer_handler_;
 };
 
 }  // namespace l2cap
diff --git a/gd/l2cap/internal/classic_fixed_channel_service.h b/gd/l2cap/internal/classic_fixed_channel_service.h
new file mode 100644
index 0000000..da84aa2
--- /dev/null
+++ b/gd/l2cap/internal/classic_fixed_channel_service.h
@@ -0,0 +1,83 @@
+/*
+ * 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_fixed_channel.h"
+#include "l2cap/classic_fixed_channel_manager.h"
+#include "l2cap/classic_fixed_channel_service.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class ClassicFixedChannelServiceImpl {
+ public:
+  struct Builder {
+    Builder& SetUserHandler(os::Handler* handler) {
+      user_handler_ = handler;
+      return *this;
+    }
+
+    Builder& SetOnChannelOpen(ClassicFixedChannelManager::OnConnectionOpenCallback on_connection_open_callback) {
+      on_connection_open_callback_ = on_connection_open_callback;
+      return *this;
+    }
+
+    Builder& SetOnChannelClose(ClassicFixedChannel::OnCloseCallback on_close_callback) {
+      on_close_callback_ = on_close_callback;
+      return *this;
+    }
+
+    Builder& SetOnChannelFail(ClassicFixedChannelManager::OnConnectionFailureCallback on_connection_failure_callback) {
+      on_connection_failure_callback_ = on_connection_failure_callback;
+      return *this;
+    }
+
+    Builder& SetOnRegister(
+        ClassicFixedChannelManager::OnRegistrationCompleteCallback on_registration_complete_callback) {
+      on_registration_complete_callback_ = std::move(on_registration_complete_callback);
+      return *this;
+    }
+
+    ClassicFixedChannelServiceImpl Build() {
+      ASSERT(user_handler_ != nullptr);
+      ASSERT(!on_registration_complete_callback_.is_null());
+      ClassicFixedChannelServiceImpl service;
+      service.user_handler_ = user_handler_;
+      service.on_connection_failure_callback_ = on_connection_failure_callback_;
+      service.on_connection_open_callback_ = on_connection_open_callback_;
+      service.on_close_callback_ = on_close_callback_;
+      return service;
+    }
+
+    os::Handler* user_handler_ = nullptr;
+    ClassicFixedChannelManager::OnConnectionFailureCallback on_connection_failure_callback_;
+    ClassicFixedChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+    ClassicFixedChannel::OnCloseCallback on_close_callback_;
+    ClassicFixedChannelManager::OnRegistrationCompleteCallback on_registration_complete_callback_;
+  };
+
+ private:
+  os::Handler* user_handler_ = nullptr;
+  ClassicFixedChannelManager::OnConnectionFailureCallback on_connection_failure_callback_;
+  ClassicFixedChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+  ClassicFixedChannel::OnCloseCallback on_close_callback_;
+};
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/classic_fixed_channel_service_manager_impl.cc b/gd/l2cap/internal/classic_fixed_channel_service_manager_impl.cc
new file mode 100644
index 0000000..1d7c562
--- /dev/null
+++ b/gd/l2cap/internal/classic_fixed_channel_service_manager_impl.cc
@@ -0,0 +1,66 @@
+/*
+ * 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/internal/classic_fixed_channel_service_manager_impl.h"
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/classic_fixed_channel_service.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+void ClassicFixedChannelServiceManagerImpl::Register(Cid cid, ClassicFixedChannelServiceImpl::Builder builder) {
+  if (cid < kFirstFixedChannel || cid > kLastFixedChannel || cid == kClassicSignallingCid || IsServiceRegistered(cid)) {
+    ClassicFixedChannelService invalid_service;
+    builder.user_handler_->Post(common::BindOnce(std::move(builder.on_registration_complete_callback_),
+                                                 ClassicFixedChannelManager::RegistrationResult::FAIL,
+                                                 invalid_service));
+  } else {
+    auto service = builder.Build();
+    service_map_.emplace(cid, std::move(service));
+    ClassicFixedChannelService user_service{cid, this, l2cap_layer_handler_};
+    builder.user_handler_->Post(common::BindOnce(std::move(builder.on_registration_complete_callback_),
+                                                 ClassicFixedChannelManager::RegistrationResult::SUCCESS,
+                                                 user_service));
+  }
+}
+
+void ClassicFixedChannelServiceManagerImpl::Unregister(Cid cid,
+                                                       ClassicFixedChannelService::OnUnregisteredCallback callback,
+                                                       os::Handler* handler) {
+  if (IsServiceRegistered(cid)) {
+    service_map_.erase(cid);
+    handler->Post(std::move(callback));
+  } else {
+    LOG_ERROR("service not registered cid:%d", cid);
+  }
+}
+
+bool ClassicFixedChannelServiceManagerImpl::IsServiceRegistered(Cid cid) const {
+  return service_map_.find(cid) != service_map_.end();
+}
+
+ClassicFixedChannelServiceImpl* ClassicFixedChannelServiceManagerImpl::GetService(Cid cid) {
+  ASSERT(IsServiceRegistered(cid));
+  return &service_map_.find(cid)->second;
+}
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/classic_fixed_channel_service_manager_impl.h b/gd/l2cap/internal/classic_fixed_channel_service_manager_impl.h
new file mode 100644
index 0000000..28ac10a
--- /dev/null
+++ b/gd/l2cap/internal/classic_fixed_channel_service_manager_impl.h
@@ -0,0 +1,47 @@
+/*
+ * 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 <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic_fixed_channel_service.h"
+#include "l2cap/internal/classic_fixed_channel_service.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class ClassicFixedChannelServiceManagerImpl {
+ public:
+  ClassicFixedChannelServiceManagerImpl(os::Handler* l2cap_layer_handler) : l2cap_layer_handler_(l2cap_layer_handler) {}
+
+  // All APIs must be invoked in L2CAP layer handler
+
+  void Register(Cid cid, ClassicFixedChannelServiceImpl::Builder builder);
+  void Unregister(Cid cid, ClassicFixedChannelService::OnUnregisteredCallback callback, os::Handler* handler);
+  bool IsServiceRegistered(Cid cid) const;
+  ClassicFixedChannelServiceImpl* GetService(Cid cid);
+
+ private:
+  os::Handler* l2cap_layer_handler_ = nullptr;
+  std::unordered_map<Cid, ClassicFixedChannelServiceImpl> service_map_;
+};
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/classic_fixed_channel_service_manager_test.cc b/gd/l2cap/internal/classic_fixed_channel_service_manager_test.cc
new file mode 100644
index 0000000..2e9b7c0
--- /dev/null
+++ b/gd/l2cap/internal/classic_fixed_channel_service_manager_test.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2018 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/internal/classic_fixed_channel_service_manager_impl.h"
+
+#include <future>
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic_fixed_channel_manager.h"
+#include "l2cap/classic_fixed_channel_service.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class L2capServiceManagerTest : public ::testing::Test {
+ public:
+  ~L2capServiceManagerTest() = default;
+
+  void OnServiceRegistered(bool expect_success, ClassicFixedChannelManager::RegistrationResult result,
+                           ClassicFixedChannelService user_service) {
+    EXPECT_EQ(result == ClassicFixedChannelManager::RegistrationResult::SUCCESS, expect_success);
+    service_registered_ = expect_success;
+  }
+
+ protected:
+  void SetUp() override {
+    manager_ = new ClassicFixedChannelServiceManagerImpl{nullptr};
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    user_handler_ = new os::Handler(thread_);
+  }
+
+  void TearDown() override {
+    user_handler_->Clear();
+    delete user_handler_;
+    delete thread_;
+    delete manager_;
+  }
+
+  void sync_user_handler() {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    user_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    future.wait_for(std::chrono::milliseconds(3));
+  }
+
+  ClassicFixedChannelServiceManagerImpl* manager_ = nullptr;
+  os::Thread* thread_ = nullptr;
+  os::Handler* user_handler_ = nullptr;
+
+  bool service_registered_ = false;
+};
+
+TEST_F(L2capServiceManagerTest, register_and_unregister_classic_fixed_channel) {
+  ClassicFixedChannelServiceImpl::Builder builder;
+  builder.SetUserHandler(user_handler_);
+  builder.SetOnRegister(
+      common::BindOnce(&L2capServiceManagerTest::OnServiceRegistered, common::Unretained(this), true));
+  Cid cid = kSmpBrCid;
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  manager_->Register(cid, std::move(builder));
+  EXPECT_TRUE(manager_->IsServiceRegistered(cid));
+  sync_user_handler();
+  EXPECT_TRUE(service_registered_);
+  manager_->Unregister(cid, common::BindOnce([] {}), user_handler_);
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+}
+
+TEST_F(L2capServiceManagerTest, register_classic_fixed_channel_bad_cid) {
+  ClassicFixedChannelServiceImpl::Builder builder;
+  builder.SetUserHandler(user_handler_);
+  builder.SetOnRegister(
+      common::BindOnce(&L2capServiceManagerTest::OnServiceRegistered, common::Unretained(this), false));
+  Cid cid = 0x1000;
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  manager_->Register(cid, std::move(builder));
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  sync_user_handler();
+  EXPECT_FALSE(service_registered_);
+}
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/l2cap_layer.cc b/gd/l2cap/l2cap_layer.cc
index a637998..a7448a3 100644
--- a/gd/l2cap/l2cap_layer.cc
+++ b/gd/l2cap/l2cap_layer.cc
@@ -21,6 +21,7 @@
 #include "common/bidi_queue.h"
 #include "hci/acl_manager.h"
 #include "hci/hci_packets.h"
+#include "l2cap/internal/classic_fixed_channel_service_manager_impl.h"
 #include "l2cap/l2cap_layer.h"
 #include "module.h"
 #include "os/handler.h"
@@ -31,19 +32,32 @@
 
 const ModuleFactory L2capLayer::Factory = ModuleFactory([]() { return new L2capLayer(); });
 
+struct L2capLayer::impl {
+  impl(os::Handler* handler, hci::AclManager* acl_manager) : handler_(handler), acl_manager_(acl_manager) {}
+  os::Handler* handler_;
+  hci::AclManager* acl_manager_;
+  internal::ClassicFixedChannelServiceManagerImpl fixed_channel_service_manager_{handler_};
+
+  std::unique_ptr<ClassicFixedChannelManager> GetClassicFixedChannelManager() {
+    return std::make_unique<ClassicFixedChannelManager>(&fixed_channel_service_manager_, handler_);
+  }
+};
+
 void L2capLayer::ListDependencies(ModuleList* list) {
   list->add<hci::AclManager>();
 }
 
-void L2capLayer::Start() {}
-
-void L2capLayer::Stop() {}
-
-std::unique_ptr<ClassicFixedChannelManager> L2capLayer::GetClassicFixedChannelManager() {
-  return std::make_unique<ClassicFixedChannelManager>();
+void L2capLayer::Start() {
+  impl_ = std::make_unique<impl>(GetHandler(), GetDependency<hci::AclManager>());
 }
 
-struct L2capLayer::impl {};
+void L2capLayer::Stop() {
+  impl_.reset();
+}
+
+std::unique_ptr<ClassicFixedChannelManager> L2capLayer::GetClassicFixedChannelManager() {
+  return impl_->GetClassicFixedChannelManager();
+}
 
 }  // namespace l2cap
 }  // namespace bluetooth
\ No newline at end of file