diff options
| author | 2018-08-28 01:23:02 -0700 | |
|---|---|---|
| committer | 2018-10-08 11:23:42 -0700 | |
| commit | 2648d2026c998a1c827bceabebf659c4de50daf0 (patch) | |
| tree | e3679891839ce0a080224d00bcba63d104230aa5 | |
| parent | 7b06f592bbf9beb1239a211faa14541ad0d5176b (diff) | |
libbinder_ndk: Add C++ wrapper code.
This library wraps libbinder_ndk with types similar to those found in
libbinder. This makes implementations more familiar and reduces the
amount of auto-generated code that has to be repeated in AIDL.
In order to simplify the distribution of the this code, it is
header-only in the NDK headers. This allows NDK users to use AIDL
against the NDK with no additional dependencies.
Bug: 112664205
Test: atest android.binder.cts
Change-Id: I6e6ef646226d474d538639f740e340c4e37fa7f7
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_auto_utils.h | 234 | ||||
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_interface_utils.h | 131 | ||||
| -rw-r--r-- | libs/binder/ndk/test/main_client.cpp | 3 |
3 files changed, 368 insertions, 0 deletions
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h new file mode 100644 index 0000000000..11b1e8eaf5 --- /dev/null +++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h @@ -0,0 +1,234 @@ +/* + * Copyright (C) 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. + */ + +/** + * @addtogroup NdkBinder + * @{ + */ + +/** + * @file binder_auto_utils.h + * @brief These objects provide a more C++-like thin interface to the . + */ + +#pragma once + +#include <android/binder_ibinder.h> +#include <android/binder_parcel.h> +#include <android/binder_status.h> + +#ifdef __cplusplus + +#include <cstddef> + +namespace android { + +/** + * Represents one strong pointer to an AIBinder object. + */ +class AutoAIBinder { +public: + /** + * Takes ownership of one strong refcount of binder. + */ + explicit AutoAIBinder(AIBinder* binder = nullptr) : mBinder(binder) {} + + /** + * Convenience operator for implicitly constructing an AutoAIBinder from nullptr. This is not + * explicit because it is not taking ownership of anything. + */ + AutoAIBinder(std::nullptr_t) : AutoAIBinder() {} + + /** + * This will delete the underlying object if it exists. See operator=. + */ + AutoAIBinder(const AutoAIBinder& other) { *this = other; } + + /** + * This deletes the underlying object if it exists. See set. + */ + ~AutoAIBinder() { set(nullptr); } + + /** + * This takes ownership of a binder from another AIBinder object but it does not affect the + * ownership of that other object. + */ + AutoAIBinder& operator=(const AutoAIBinder& other) { + AIBinder_incStrong(other.mBinder); + set(other.mBinder); + return *this; + } + + /** + * Takes ownership of one strong refcount of binder + */ + void set(AIBinder* binder) { + if (mBinder != nullptr) AIBinder_decStrong(mBinder); + mBinder = binder; + } + + /** + * This returns the underlying binder object for transactions. If it is used to create another + * AutoAIBinder object, it should first be incremented. + */ + AIBinder* get() const { return mBinder; } + + /** + * This allows the value in this class to be set from beneath it. If you call this method and + * then change the value of T*, you must take ownership of the value you are replacing and add + * ownership to the object that is put in here. + * + * Recommended use is like this: + * AutoAIBinder a; // will be nullptr + * SomeInitFunction(a.getR()); // value is initialized with refcount + * + * Other usecases are discouraged. + * + */ + AIBinder** getR() { return &mBinder; } + +private: + AIBinder* mBinder = nullptr; +}; + +/** + * This baseclass owns a single object, used to make various classes RAII. + */ +template <typename T, void (*Destroy)(T*)> +class AutoA { +public: + /** + * Takes ownership of t. + */ + explicit AutoA(T* t = nullptr) : mT(t) {} + + /** + * This deletes the underlying object if it exists. See set. + */ + ~AutoA() { set(nullptr); } + + /** + * Takes ownership of t. + */ + void set(T* t) { + Destroy(mT); + mT = t; + } + + /** + * This returns the underlying object to be modified but does not affect ownership. + */ + T* get() { return mT; } + + /** + * This returns the const underlying object but does not affect ownership. + */ + const T* get() const { return mT; } + + /** + * This allows the value in this class to be set from beneath it. If you call this method and + * then change the value of T*, you must take ownership of the value you are replacing and add + * ownership to the object that is put in here. + * + * Recommended use is like this: + * AutoA<T> a; // will be nullptr + * SomeInitFunction(a.getR()); // value is initialized with refcount + * + * Other usecases are discouraged. + * + */ + T** getR() { return &mT; } + + // copy-constructing, or move/copy assignment is disallowed + AutoA(const AutoA&) = delete; + AutoA& operator=(const AutoA&) = delete; + AutoA& operator=(AutoA&&) = delete; + + // move-constructing is okay + AutoA(AutoA&&) = default; + +private: + T* mT; +}; + +/** + * Convenience wrapper. See AParcel. + */ +class AutoAParcel : public AutoA<AParcel, AParcel_delete> { +public: + /** + * Takes ownership of a. + */ + explicit AutoAParcel(AParcel* a = nullptr) : AutoA(a) {} + ~AutoAParcel() {} + AutoAParcel(AutoAParcel&&) = default; +}; + +/** + * Convenience wrapper. See AStatus. + */ +class AutoAStatus : public AutoA<AStatus, AStatus_delete> { +public: + /** + * Takes ownership of a. + */ + explicit AutoAStatus(AStatus* a = nullptr) : AutoA(a) {} + ~AutoAStatus() {} + AutoAStatus(AutoAStatus&&) = default; + + /** + * See AStatus_isOk. + */ + bool isOk() { return get() != nullptr && AStatus_isOk(get()); } +}; + +/** + * Convenience wrapper. See AIBinder_DeathRecipient. + */ +class AutoAIBinder_DeathRecipient + : public AutoA<AIBinder_DeathRecipient, AIBinder_DeathRecipient_delete> { +public: + /** + * Takes ownership of a. + */ + explicit AutoAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr) : AutoA(a) {} + ~AutoAIBinder_DeathRecipient() {} + AutoAIBinder_DeathRecipient(AutoAIBinder_DeathRecipient&&) = default; +}; + +/** + * Convenience wrapper. See AIBinder_Weak. + */ +class AutoAIBinder_Weak : public AutoA<AIBinder_Weak, AIBinder_Weak_delete> { +public: + /** + * Takes ownership of a. + */ + explicit AutoAIBinder_Weak(AIBinder_Weak* a = nullptr) : AutoA(a) {} + ~AutoAIBinder_Weak() {} + AutoAIBinder_Weak(AutoAIBinder_Weak&&) = default; + + /** + * See AIBinder_Weak_promote. + */ + AutoAIBinder promote() { return AutoAIBinder(AIBinder_Weak_promote(get())); } +}; + +} // namespace android + +#endif // __cplusplus + +/** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h new file mode 100644 index 0000000000..d7e1566010 --- /dev/null +++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 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. + */ + +/** + * @addtogroup NdkBinder + * @{ + */ + +/** + * @file binder_interface_utils.h + * @brief This provides common C++ classes for common operations and as base classes for C++ + * interfaces. + */ + +#pragma once + +#include <android/binder_auto_utils.h> +#include <android/binder_ibinder.h> + +#ifdef __cplusplus + +#include <memory> +#include <mutex> + +namespace android { + +// analog using std::shared_ptr for RefBase-like semantics +class SharedRefBase { +public: + SharedRefBase() {} + virtual ~SharedRefBase() {} + + std::shared_ptr<SharedRefBase> ref() { + std::shared_ptr<SharedRefBase> thiz = mThis.lock(); + + std::call_once(mFlagThis, [&]() { mThis = thiz = std::shared_ptr<SharedRefBase>(this); }); + + return thiz; + } + + template <typename CHILD> + std::shared_ptr<CHILD> ref() { + return std::static_pointer_cast<CHILD>(ref()); + } + +private: + std::once_flag mFlagThis; + std::weak_ptr<SharedRefBase> mThis; +}; + +// wrapper analog to IInterface +class ICInterface : public SharedRefBase { +public: + ICInterface() {} + virtual ~ICInterface() {} + + // This either returns the single existing implementation or creates a new implementation. + virtual AutoAIBinder asBinder() = 0; +}; + +// wrapper analog to BnInterface +template <typename INTERFACE> +class BnCInterface : public INTERFACE { +public: + BnCInterface() {} + virtual ~BnCInterface() {} + + AutoAIBinder asBinder() override; + +protected: + // This function should only be called by asBinder. Otherwise, there is a possibility of + // multiple AIBinder* objects being created for the same instance of an object. + virtual AutoAIBinder createBinder() = 0; + +private: + std::mutex mMutex; // for asBinder + AutoAIBinder_Weak mWeakBinder; +}; + +// wrapper analog to BpInterfae +template <typename INTERFACE> +class BpCInterface : public INTERFACE { +public: + BpCInterface(const AutoAIBinder& binder) : mBinder(binder) {} + virtual ~BpCInterface() {} + + AutoAIBinder asBinder() override; + +private: + AutoAIBinder mBinder; +}; + +template <typename INTERFACE> +AutoAIBinder BnCInterface<INTERFACE>::asBinder() { + std::lock_guard<std::mutex> l(mMutex); + + AutoAIBinder binder; + if (mWeakBinder.get() != nullptr) { + binder.set(AIBinder_Weak_promote(mWeakBinder.get())); + } + if (binder.get() == nullptr) { + binder = createBinder(); + mWeakBinder.set(AIBinder_Weak_new(binder.get())); + } + + return binder; +} + +template <typename INTERFACE> +AutoAIBinder BpCInterface<INTERFACE>::asBinder() { + return mBinder; +} + +#endif // __cplusplus + +} // namespace android + +/** @} */ diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp index 3fc096a9ed..22bf1e5be5 100644 --- a/libs/binder/ndk/test/main_client.cpp +++ b/libs/binder/ndk/test/main_client.cpp @@ -131,3 +131,6 @@ TEST(NdkBinder, AddServiceMultipleTimes) { EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName2)); EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2)); } + +#include <android/binder_auto_utils.h> +#include <android/binder_interface_utils.h> |