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