From be43a39ff56ca8840ccfed048f75633adc535e92 Mon Sep 17 00:00:00 2001 From: Daniel Erat Date: Tue, 8 Sep 2015 13:20:02 -0600 Subject: [PATCH] Add libbinderwrapper. Add a library that wraps libbinder to make it possible to write tests for native code that communicates via binder. Bug: 23791723 Change-Id: I3c842413e0f07dc252040c042d664031b0354353 --- include/binderwrapper/binder_test_base.h | 45 +++++++ include/binderwrapper/binder_wrapper.h | 77 ++++++++++++ include/binderwrapper/stub_binder_wrapper.h | 124 ++++++++++++++++++++ libbinderwrapper/Android.mk | 62 ++++++++++ libbinderwrapper/binder_test_base.cc | 33 ++++++ libbinderwrapper/binder_wrapper.cc | 53 +++++++++ libbinderwrapper/real_binder_wrapper.cc | 114 ++++++++++++++++++ libbinderwrapper/real_binder_wrapper.h | 54 +++++++++ libbinderwrapper/stub_binder_wrapper.cc | 76 ++++++++++++ 9 files changed, 638 insertions(+) create mode 100644 include/binderwrapper/binder_test_base.h create mode 100644 include/binderwrapper/binder_wrapper.h create mode 100644 include/binderwrapper/stub_binder_wrapper.h create mode 100644 libbinderwrapper/Android.mk create mode 100644 libbinderwrapper/binder_test_base.cc create mode 100644 libbinderwrapper/binder_wrapper.cc create mode 100644 libbinderwrapper/real_binder_wrapper.cc create mode 100644 libbinderwrapper/real_binder_wrapper.h create mode 100644 libbinderwrapper/stub_binder_wrapper.cc diff --git a/include/binderwrapper/binder_test_base.h b/include/binderwrapper/binder_test_base.h new file mode 100644 index 000000000..06543de6f --- /dev/null +++ b/include/binderwrapper/binder_test_base.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_TEST_BASE_H_ +#define SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_TEST_BASE_H_ + +#include +#include + +namespace android { + +class StubBinderWrapper; + +// Class that can be inherited from (or aliased via typedef/using) when writing +// tests that use StubBinderManager. +class BinderTestBase : public ::testing::Test { + public: + BinderTestBase(); + ~BinderTestBase() override; + + StubBinderWrapper* binder_wrapper() { return binder_wrapper_; } + + protected: + StubBinderWrapper* binder_wrapper_; // Not owned. + + private: + DISALLOW_COPY_AND_ASSIGN(BinderTestBase); +}; + +} // namespace android + +#endif // SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_TEST_BASE_H_ diff --git a/include/binderwrapper/binder_wrapper.h b/include/binderwrapper/binder_wrapper.h new file mode 100644 index 000000000..e57cf8318 --- /dev/null +++ b/include/binderwrapper/binder_wrapper.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_WRAPPER_H_ +#define SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_WRAPPER_H_ + +#include + +#include +#include + +namespace android { + +class BBinder; +class IBinder; + +// Wraps libbinder to make it testable. +class BinderWrapper { + public: + virtual ~BinderWrapper() {} + + // Creates and initializes the singleton (using a wrapper that communicates + // with the real binder system). + static void Create(); + + // Initializes |wrapper| as the singleton, taking ownership of it. Tests that + // want to inject their own wrappers should call this instead of Create(). + static void InitForTesting(BinderWrapper* wrapper); + + // Destroys the singleton. Must be called before calling Create() or + // InitForTesting() a second time. + static void Destroy(); + + // Returns the singleton instance previously created by Create() or set by + // InitForTesting(). + static BinderWrapper* Get(); + + // Gets the binder for communicating with the service identified by + // |service_name|, returning null immediately if it doesn't exist. + virtual sp GetService(const std::string& service_name) = 0; + + // Registers |binder| as |service_name| with the service manager. + virtual bool RegisterService(const std::string& service_name, + const sp& binder) = 0; + + // Creates a local binder object. + virtual sp CreateLocalBinder() = 0; + + // Registers |callback| to be invoked when |binder| dies. If another callback + // is currently registered for |binder|, it will be replaced. + virtual bool RegisterForDeathNotifications( + const sp& binder, + const base::Closure& callback) = 0; + + // Unregisters the callback, if any, for |binder|. + virtual bool UnregisterForDeathNotifications(const sp& binder) = 0; + + private: + static BinderWrapper* instance_; +}; + +} // namespace android + +#endif // SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_WRAPPER_H_ diff --git a/include/binderwrapper/stub_binder_wrapper.h b/include/binderwrapper/stub_binder_wrapper.h new file mode 100644 index 000000000..6e198aea3 --- /dev/null +++ b/include/binderwrapper/stub_binder_wrapper.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef SYSTEM_CORE_INCLUDE_BINDERWRAPPER_STUB_BINDER_WRAPPER_H_ +#define SYSTEM_CORE_INCLUDE_BINDERWRAPPER_STUB_BINDER_WRAPPER_H_ + +#include +#include +#include + +#include +#include +#include +#include + +namespace android { + +// Stub implementation of BinderWrapper for testing. +// +// Example usage: +// +// First, assuming a base IFoo binder interface, create a stub class that +// derives from BnFoo to implement the receiver side of the communication: +// +// class StubFoo : public BnFoo { +// public: +// ... +// status_t doSomething(int arg) override { +// // e.g. save passed-in value for later inspection by tests. +// return OK; +// } +// }; +// +// Next, from your test code, inject a StubBinderManager either directly or by +// inheriting from the BinderTestBase class: +// +// StubBinderWrapper* wrapper = new StubBinderWrapper(); +// BinderWrapper::InitForTesting(wrapper); // Takes ownership. +// +// Also from your test, create a StubFoo and register it with the wrapper: +// +// StubFoo* foo = new StubFoo(); +// sp binder(foo); +// wrapper->SetBinderForService("foo", binder); +// +// The code being tested can now use the wrapper to get the stub and call it: +// +// sp binder = BinderWrapper::Get()->GetService("foo"); +// CHECK(binder.get()); +// sp foo = interface_cast(binder); +// CHECK_EQ(foo->doSomething(3), OK); +// +// To create a local BBinder object, production code can call +// CreateLocalBinder(). Then, a test can get the BBinder's address via +// local_binders() to check that they're passed as expected in binder calls. +// +class StubBinderWrapper : public BinderWrapper { + public: + StubBinderWrapper(); + ~StubBinderWrapper() override; + + const std::vector>& local_binders() const { + return local_binders_; + } + void clear_local_binders() { local_binders_.clear(); } + + // Sets the binder to return when |service_name| is passed to GetService() or + // WaitForService(). + void SetBinderForService(const std::string& service_name, + const sp& binder); + + // Returns the binder previously registered for |service_name| via + // RegisterService(), or null if the service hasn't been registered. + sp GetRegisteredService(const std::string& service_name) const; + + // Run the calback in |death_callbacks_| corresponding to |binder|. + void NotifyAboutBinderDeath(const sp& binder); + + // BinderWrapper: + sp GetService(const std::string& service_name) override; + bool RegisterService(const std::string& service_name, + const sp& binder) override; + sp CreateLocalBinder() override; + bool RegisterForDeathNotifications(const sp& binder, + const base::Closure& callback) override; + bool UnregisterForDeathNotifications(const sp& binder) override; + + private: + using ServiceMap = std::map>; + + // Map from service name to associated binder handle. Used by GetService() and + // WaitForService(). + ServiceMap services_to_return_; + + // Map from service name to associated binder handle. Updated by + // RegisterService(). + ServiceMap registered_services_; + + // Local binders returned by CreateLocalBinder(). + std::vector> local_binders_; + + // Map from binder handle to the callback that should be invoked on binder + // death. + std::map, base::Closure> death_callbacks_; + + DISALLOW_COPY_AND_ASSIGN(StubBinderWrapper); +}; + +} // namespace android + +#endif // SYSTEM_CORE_INCLUDE_BINDERWRAPPER_STUB_BINDER_WRAPPER_H_ diff --git a/libbinderwrapper/Android.mk b/libbinderwrapper/Android.mk new file mode 100644 index 000000000..23c2246da --- /dev/null +++ b/libbinderwrapper/Android.mk @@ -0,0 +1,62 @@ +# +# Copyright (C) 2015 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. +# + +LOCAL_PATH := $(call my-dir) + +binderwrapperCommonCFlags := -Wall -Werror -Wno-unused-parameter +binderwrapperCommonCFlags += -Wno-sign-promo # for libchrome +binderwrapperCommonExportCIncludeDirs := $(LOCAL_PATH)/../include +binderwrapperCommonCIncludes := $(LOCAL_PATH)/../include +binderwrapperCommonSharedLibraries := \ + libbinder \ + libchrome \ + libutils \ + +# libbinderwrapper shared library +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := libbinderwrapper +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(binderwrapperCommonCFlags) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(binderwrapperCommonExportCIncludeDirs) +LOCAL_C_INCLUDES := $(binderwrapperCommonCIncludes) +LOCAL_SHARED_LIBRARIES := $(binderwrapperCommonSharedLibraries) +LOCAL_SRC_FILES := \ + binder_wrapper.cc \ + real_binder_wrapper.cc \ + +include $(BUILD_SHARED_LIBRARY) + +# libbinderwrapper_test_support shared library +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := libbinderwrapper_test_support +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(binderwrapperCommonCFlags) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(binderwrapperCommonExportCIncludeDirs) +LOCAL_C_INCLUDES := $(binderwrapperCommonCIncludes) +LOCAL_STATIC_LIBRARIES := libgtest +LOCAL_SHARED_LIBRARIES := \ + $(binderwrapperCommonSharedLibraries) \ + libbinderwrapper \ + +LOCAL_SRC_FILES := \ + binder_test_base.cc \ + stub_binder_wrapper.cc \ + +include $(BUILD_SHARED_LIBRARY) diff --git a/libbinderwrapper/binder_test_base.cc b/libbinderwrapper/binder_test_base.cc new file mode 100644 index 000000000..af93a04d9 --- /dev/null +++ b/libbinderwrapper/binder_test_base.cc @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 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 + +#include +#include + +namespace android { + +BinderTestBase::BinderTestBase() : binder_wrapper_(new StubBinderWrapper()) { + // Pass ownership. + BinderWrapper::InitForTesting(binder_wrapper_); +} + +BinderTestBase::~BinderTestBase() { + BinderWrapper::Destroy(); +} + +} // namespace android diff --git a/libbinderwrapper/binder_wrapper.cc b/libbinderwrapper/binder_wrapper.cc new file mode 100644 index 000000000..0b5ff9612 --- /dev/null +++ b/libbinderwrapper/binder_wrapper.cc @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 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 + +#include + +#include "real_binder_wrapper.h" + +namespace android { + +// Singleton instance. +BinderWrapper* BinderWrapper::instance_ = nullptr; + +// static +void BinderWrapper::Create() { + CHECK(!instance_) << "Already initialized; missing call to Destroy()?"; + instance_ = new RealBinderWrapper(); +} + +// static +void BinderWrapper::InitForTesting(BinderWrapper* wrapper) { + CHECK(!instance_) << "Already initialized; missing call to Destroy()?"; + instance_ = wrapper; +} + +// static +void BinderWrapper::Destroy() { + CHECK(instance_) << "Not initialized; missing call to Create()?"; + delete instance_; + instance_ = nullptr; +} + +// static +BinderWrapper* BinderWrapper::Get() { + CHECK(instance_) << "Not initialized; missing call to Create()?"; + return instance_; +} + +} // namespace android diff --git a/libbinderwrapper/real_binder_wrapper.cc b/libbinderwrapper/real_binder_wrapper.cc new file mode 100644 index 000000000..adff19bed --- /dev/null +++ b/libbinderwrapper/real_binder_wrapper.cc @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 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 "real_binder_wrapper.h" + +#include +#include +#include +#include + +namespace android { + +// Class that handles binder death notifications. libbinder wants the recipient +// to be wrapped in sp<>, so registering RealBinderWrapper as a recipient would +// be awkward. +class RealBinderWrapper::DeathRecipient : public IBinder::DeathRecipient { + public: + explicit DeathRecipient(const base::Closure& callback) + : callback_(callback) {} + ~DeathRecipient() = default; + + // IBinder::DeathRecipient: + void binderDied(const wp& who) override { + callback_.Run(); + } + + private: + // Callback to run in response to binder death. + base::Closure callback_; + + DISALLOW_COPY_AND_ASSIGN(DeathRecipient); +}; + +RealBinderWrapper::RealBinderWrapper() = default; + +RealBinderWrapper::~RealBinderWrapper() = default; + +sp RealBinderWrapper::GetService(const std::string& service_name) { + sp service_manager = defaultServiceManager(); + if (!service_manager.get()) { + LOG(ERROR) << "Unable to get service manager"; + return sp(); + } + sp binder = + service_manager->checkService(String16(service_name.c_str())); + if (!binder.get()) + LOG(ERROR) << "Unable to get \"" << service_name << "\" service"; + return binder; +} + +bool RealBinderWrapper::RegisterService(const std::string& service_name, + const sp& binder) { + sp service_manager = defaultServiceManager(); + if (!service_manager.get()) { + LOG(ERROR) << "Unable to get service manager"; + return false; + } + status_t status = defaultServiceManager()->addService( + String16(service_name.c_str()), binder); + if (status != OK) { + LOG(ERROR) << "Failed to register \"" << service_name << "\" with service " + << "manager"; + return false; + } + return true; +} + +sp RealBinderWrapper::CreateLocalBinder() { + return sp(new BBinder()); +} + +bool RealBinderWrapper::RegisterForDeathNotifications( + const sp& binder, + const base::Closure& callback) { + sp recipient(new DeathRecipient(callback)); + if (binder->linkToDeath(recipient) != OK) { + LOG(ERROR) << "Failed to register for death notifications on " + << binder.get(); + return false; + } + death_recipients_[binder] = recipient; + return true; +} + +bool RealBinderWrapper::UnregisterForDeathNotifications( + const sp& binder) { + auto it = death_recipients_.find(binder); + if (it == death_recipients_.end()) { + LOG(ERROR) << "Not registered for death notifications on " << binder.get(); + return false; + } + if (binder->unlinkToDeath(it->second) != OK) { + LOG(ERROR) << "Failed to unregister for death notifications on " + << binder.get(); + return false; + } + death_recipients_.erase(it); + return true; +} + +} // namespace android diff --git a/libbinderwrapper/real_binder_wrapper.h b/libbinderwrapper/real_binder_wrapper.h new file mode 100644 index 000000000..8e281f2f8 --- /dev/null +++ b/libbinderwrapper/real_binder_wrapper.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef SYSTEM_CORE_LIBBINDERWRAPPER_REAL_BINDER_WRAPPER_H_ +#define SYSTEM_CORE_LIBBINDERWRAPPER_REAL_BINDER_WRAPPER_H_ + +#include +#include + +namespace android { + +class IBinder; + +// Real implementation of BinderWrapper. +class RealBinderWrapper : public BinderWrapper { + public: + RealBinderWrapper(); + ~RealBinderWrapper() override; + + // BinderWrapper: + sp GetService(const std::string& service_name) override; + bool RegisterService(const std::string& service_name, + const sp& binder) override; + sp CreateLocalBinder() override; + bool RegisterForDeathNotifications(const sp& binder, + const base::Closure& callback) override; + bool UnregisterForDeathNotifications(const sp& binder) override; + + private: + class DeathRecipient; + + // Map from binder handle to object that should be notified of the binder's + // death. + std::map, sp> death_recipients_; + + DISALLOW_COPY_AND_ASSIGN(RealBinderWrapper); +}; + +} // namespace android + +#endif // SYSTEM_CORE_LIBBINDER_WRAPPER_REAL_BINDER_WRAPPER_H_ diff --git a/libbinderwrapper/stub_binder_wrapper.cc b/libbinderwrapper/stub_binder_wrapper.cc new file mode 100644 index 000000000..1d2468101 --- /dev/null +++ b/libbinderwrapper/stub_binder_wrapper.cc @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2015 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 + +#include +#include +#include + +namespace android { + +StubBinderWrapper::StubBinderWrapper() = default; + +StubBinderWrapper::~StubBinderWrapper() = default; + +void StubBinderWrapper::SetBinderForService(const std::string& service_name, + const sp& binder) { + services_to_return_[service_name] = binder; +} + +sp StubBinderWrapper::GetRegisteredService( + const std::string& service_name) const { + const auto it = registered_services_.find(service_name); + return it != registered_services_.end() ? it->second : sp(); +} + +void StubBinderWrapper::NotifyAboutBinderDeath(const sp& binder) { + const auto it = death_callbacks_.find(binder); + if (it != death_callbacks_.end()) + it->second.Run(); +} + +sp StubBinderWrapper::GetService(const std::string& service_name) { + const auto it = services_to_return_.find(service_name); + return it != services_to_return_.end() ? it->second : sp(); +} + +bool StubBinderWrapper::RegisterService(const std::string& service_name, + const sp& binder) { + registered_services_[service_name] = binder; + return true; +} + +sp StubBinderWrapper::CreateLocalBinder() { + sp binder(new BBinder()); + local_binders_.push_back(binder); + return binder; +} + +bool StubBinderWrapper::RegisterForDeathNotifications( + const sp& binder, + const base::Closure& callback) { + death_callbacks_[binder] = callback; + return true; +} + +bool StubBinderWrapper::UnregisterForDeathNotifications( + const sp& binder) { + death_callbacks_.erase(binder); + return true; +} + +} // namespace android