From: Hansong Zhang Date: Tue, 16 Jul 2019 01:34:34 +0000 (-0700) Subject: Observer Registry X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=8d8e2068a7;p=android-x86%2Fsystem-bt.git Observer Registry Helper for client (observer) to track registration and drop callbacks if observer is unregistered Test: bluetooth_test_gd Change-Id: Icc58d812bccbcb85c8b8142c659503636f498b6a --- diff --git a/gd/common/Android.bp b/gd/common/Android.bp index e9e0b25e5..8eed81a4b 100644 --- a/gd/common/Android.bp +++ b/gd/common/Android.bp @@ -13,5 +13,6 @@ filegroup { "blocking_queue_unittest.cc", "class_of_device_unittest.cc", "bidi_queue_unittest.cc", + "observer_registry_test.cc", ], } diff --git a/gd/common/observer_registry.h b/gd/common/observer_registry.h new file mode 100644 index 000000000..99de57f98 --- /dev/null +++ b/gd/common/observer_registry.h @@ -0,0 +1,75 @@ +/* + * 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 + +#include "common/bind.h" +#include "common/callback.h" +#include "os/log.h" + +namespace bluetooth { +namespace common { + +// Tracks an observer registration on client (observer) code. Register() returns a wrapped callback object which can +// be passed to server's register API. Unregister() invalidates the wrapped callback so all callbacks that are posted +// to the client handler after the client called Unregister() call and before the server processed the Unregister() +// call on its handler, are dropped. +// Note: Register() invalidates the previous registration. +class SingleObserverRegistry { + public: + template + decltype(auto) Register(Callback callback) { + session_++; + return Bind(&SingleObserverRegistry::callback_wrapper, Unretained(this), session_, callback); + } + + void Unregister() { + session_++; + } + + private: + template + void callback_wrapper(int session, Callback callback, T... t) { + if (session == session_) { + callback.Run(std::forward(t)...); + } + } + + uint8_t session_ = 0; +}; + +// Tracks observer registration for multiple event type. Each event type is represented as an integer in [0, Capacity). +template +class MultipleObserverRegistry { + public: + template + decltype(auto) Register(int event_type, Callback callback) { + ASSERT(event_type < Capacity); + return registry_[event_type].Register(callback); + } + + void Unregister(int event_type) { + ASSERT(event_type < Capacity); + registry_[event_type].Unregister(); + } + + std::array registry_; +}; + +} // namespace common +} // namespace bluetooth diff --git a/gd/common/observer_registry_test.cc b/gd/common/observer_registry_test.cc new file mode 100644 index 000000000..f1233a89d --- /dev/null +++ b/gd/common/observer_registry_test.cc @@ -0,0 +1,120 @@ +/* + * 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 "common/observer_registry.h" + +#include "common/bind.h" +#include "gtest/gtest.h" + +namespace bluetooth { +namespace common { + +class SingleObserverRegistryTest : public ::testing::Test { + protected: + void SetUp() override { + registry_ = new SingleObserverRegistry; + } + + void TearDown() override { + delete registry_; + } + + SingleObserverRegistry* registry_; +}; + +void Increment(int* count) { + (*count)++; +} + +void IncrementBy(int* count, int n) { + (*count) += n; +} + +TEST_F(SingleObserverRegistryTest, wrapped_callback) { + int count = 0; + auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); + wrapped_callback.Run(); + EXPECT_EQ(count, 1); + wrapped_callback.Run(); + EXPECT_EQ(count, 2); + wrapped_callback.Run(); + EXPECT_EQ(count, 3); + registry_->Unregister(); +} + +TEST_F(SingleObserverRegistryTest, unregister) { + int count = 0; + auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); + registry_->Unregister(); + wrapped_callback.Run(); + EXPECT_EQ(count, 0); +} + +TEST_F(SingleObserverRegistryTest, second_register) { + int count = 0; + auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); + registry_->Unregister(); + auto wrapped_callback2 = registry_->Register(Bind(&Increment, Unretained(&count))); + wrapped_callback.Run(); + EXPECT_EQ(count, 0); + wrapped_callback2.Run(); + EXPECT_EQ(count, 1); +} + +class MultipleObserverRegistryTest : public ::testing::Test { + protected: + void SetUp() override { + registry_ = new MultipleObserverRegistry<2>; + } + + void TearDown() override { + delete registry_; + } + + MultipleObserverRegistry<2>* registry_; +}; + +TEST_F(MultipleObserverRegistryTest, single_wrapped_callback) { + int count = 0; + auto wrapped_callback = registry_->Register(0, Bind(&Increment, Unretained(&count))); + wrapped_callback.Run(); + EXPECT_EQ(count, 1); + wrapped_callback.Run(); + EXPECT_EQ(count, 2); + wrapped_callback.Run(); + EXPECT_EQ(count, 3); + registry_->Unregister(0); +} + +TEST_F(MultipleObserverRegistryTest, multiple_wrapped_callback) { + int count = 0; + auto wrapped_callback0 = registry_->Register(0, Bind(&Increment, Unretained(&count))); + auto wrapped_callback1 = registry_->Register(1, Bind(&IncrementBy, Unretained(&count), 10)); + wrapped_callback0.Run(); + EXPECT_EQ(count, 1); + wrapped_callback1.Run(); + EXPECT_EQ(count, 11); + registry_->Unregister(0); + wrapped_callback0.Run(); + EXPECT_EQ(count, 11); + wrapped_callback1.Run(); + EXPECT_EQ(count, 21); + registry_->Unregister(1); + EXPECT_EQ(count, 21); +} + +} // namespace common +} // namespace bluetooth