diff options
Diffstat (limited to 'libs/binder/ndk/include_cpp/android/binder_interface_utils.h')
-rw-r--r-- | libs/binder/ndk/include_cpp/android/binder_interface_utils.h | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h new file mode 100644 index 0000000000..6c4472632d --- /dev/null +++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h @@ -0,0 +1,317 @@ +/* + * 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> + +#if __has_include(<android/binder_shell.h>) +#include <android/binder_shell.h> +#define HAS_BINDER_SHELL_COMMAND +#endif //_has_include + +#include <assert.h> + +#include <memory> +#include <mutex> + +namespace ndk { + +/** + * analog using std::shared_ptr for internally held refcount + * + * ref must be called at least one time during the lifetime of this object. The recommended way to + * construct this object is with SharedRefBase::make. + */ +class SharedRefBase { + public: + SharedRefBase() {} + virtual ~SharedRefBase() { + std::call_once(mFlagThis, [&]() { + __assert(__FILE__, __LINE__, "SharedRefBase: no ref created during lifetime"); + }); + } + + /** + * A shared_ptr must be held to this object when this is called. This must be called once during + * the lifetime of this object. + */ + 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; + } + + /** + * Convenience method for a ref (see above) which automatically casts to the desired child type. + */ + template <typename CHILD> + std::shared_ptr<CHILD> ref() { + return std::static_pointer_cast<CHILD>(ref()); + } + + /** + * Convenience method for making an object directly with a reference. + */ + template <class T, class... Args> + static std::shared_ptr<T> make(Args&&... args) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + T* t = new T(std::forward<Args>(args)...); +#pragma clang diagnostic pop + // warning: Potential leak of memory pointed to by 't' [clang-analyzer-unix.Malloc] + return t->template ref<T>(); // NOLINT(clang-analyzer-unix.Malloc) + } + + static void operator delete(void* p) { std::free(p); } + + // Once minSdkVersion is 30, we are guaranteed to be building with the + // Android 11 AIDL compiler which supports the SharedRefBase::make API. + // + // Use 'SharedRefBase::make<T>(...)' to make. SharedRefBase has implicit + // ownership. Making this operator private to avoid double-ownership. +#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30 || defined(__ANDROID_APEX__) + private: +#else + [[deprecated("Prefer SharedRefBase::make<T>(...) if possible.")]] +#endif + static void* operator new(size_t s) { return std::malloc(s); } + + 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 SpAIBinder asBinder() = 0; + + /** + * Returns whether this interface is in a remote process. If it cannot be determined locally, + * this will be checked using AIBinder_isRemote. + */ + virtual bool isRemote() = 0; + + /** + * Dumps information about the interface. By default, dumps nothing. + */ + virtual inline binder_status_t dump(int fd, const char** args, uint32_t numArgs); + +#ifdef HAS_BINDER_SHELL_COMMAND + /** + * Process shell commands. By default, does nothing. + */ + virtual inline binder_status_t handleShellCommand(int in, int out, int err, const char** argv, + uint32_t argc); +#endif + + /** + * Interprets this binder as this underlying interface if this has stored an ICInterface in the + * binder's user data. + * + * This does not do type checking and should only be used when the binder is known to originate + * from ICInterface. Most likely, you want to use I*::fromBinder. + */ + static inline std::shared_ptr<ICInterface> asInterface(AIBinder* binder); + + /** + * Helper method to create a class + */ + static inline AIBinder_Class* defineClass(const char* interfaceDescriptor, + AIBinder_Class_onTransact onTransact); + + private: + class ICInterfaceData { + public: + std::shared_ptr<ICInterface> interface; + + static inline std::shared_ptr<ICInterface> getInterface(AIBinder* binder); + + static inline void* onCreate(void* args); + static inline void onDestroy(void* userData); + static inline binder_status_t onDump(AIBinder* binder, int fd, const char** args, + uint32_t numArgs); + +#ifdef HAS_BINDER_SHELL_COMMAND + static inline binder_status_t handleShellCommand(AIBinder* binder, int in, int out, int err, + const char** argv, uint32_t argc); +#endif + }; +}; + +/** + * implementation of IInterface for server (n = native) + */ +template <typename INTERFACE> +class BnCInterface : public INTERFACE { + public: + BnCInterface() {} + virtual ~BnCInterface() {} + + SpAIBinder asBinder() override; + + bool isRemote() override { return false; } + + 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 SpAIBinder createBinder() = 0; + + private: + std::mutex mMutex; // for asBinder + ScopedAIBinder_Weak mWeakBinder; +}; + +/** + * implementation of IInterface for client (p = proxy) + */ +template <typename INTERFACE> +class BpCInterface : public INTERFACE { + public: + explicit BpCInterface(const SpAIBinder& binder) : mBinder(binder) {} + virtual ~BpCInterface() {} + + SpAIBinder asBinder() override; + + bool isRemote() override { return AIBinder_isRemote(mBinder.get()); } + + binder_status_t dump(int fd, const char** args, uint32_t numArgs) override { + return AIBinder_dump(asBinder().get(), fd, args, numArgs); + } + + private: + SpAIBinder mBinder; +}; + +// END OF CLASS DECLARATIONS + +binder_status_t ICInterface::dump(int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/) { + return STATUS_OK; +} + +#ifdef HAS_BINDER_SHELL_COMMAND +binder_status_t ICInterface::handleShellCommand(int /*in*/, int /*out*/, int /*err*/, + const char** /*argv*/, uint32_t /*argc*/) { + return STATUS_OK; +} +#endif + +std::shared_ptr<ICInterface> ICInterface::asInterface(AIBinder* binder) { + return ICInterfaceData::getInterface(binder); +} + +AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor, + AIBinder_Class_onTransact onTransact) { + AIBinder_Class* clazz = AIBinder_Class_define(interfaceDescriptor, ICInterfaceData::onCreate, + ICInterfaceData::onDestroy, onTransact); + if (clazz == nullptr) { + return nullptr; + } + + // We can't know if these methods are overridden by a subclass interface, so we must register + // ourselves. The defaults are harmless. + AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump); +#ifdef HAS_BINDER_SHELL_COMMAND + if (__builtin_available(android 30, *)) { + AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand); + } +#endif + return clazz; +} + +std::shared_ptr<ICInterface> ICInterface::ICInterfaceData::getInterface(AIBinder* binder) { + if (binder == nullptr) return nullptr; + + void* userData = AIBinder_getUserData(binder); + if (userData == nullptr) return nullptr; + + return static_cast<ICInterfaceData*>(userData)->interface; +} + +void* ICInterface::ICInterfaceData::onCreate(void* args) { + std::shared_ptr<ICInterface> interface = static_cast<ICInterface*>(args)->ref<ICInterface>(); + ICInterfaceData* data = new ICInterfaceData{interface}; + return static_cast<void*>(data); +} + +void ICInterface::ICInterfaceData::onDestroy(void* userData) { + delete static_cast<ICInterfaceData*>(userData); +} + +binder_status_t ICInterface::ICInterfaceData::onDump(AIBinder* binder, int fd, const char** args, + uint32_t numArgs) { + std::shared_ptr<ICInterface> interface = getInterface(binder); + return interface->dump(fd, args, numArgs); +} + +#ifdef HAS_BINDER_SHELL_COMMAND +binder_status_t ICInterface::ICInterfaceData::handleShellCommand(AIBinder* binder, int in, int out, + int err, const char** argv, + uint32_t argc) { + std::shared_ptr<ICInterface> interface = getInterface(binder); + return interface->handleShellCommand(in, out, err, argv, argc); +} +#endif + +template <typename INTERFACE> +SpAIBinder BnCInterface<INTERFACE>::asBinder() { + std::lock_guard<std::mutex> l(mMutex); + + SpAIBinder 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> +SpAIBinder BpCInterface<INTERFACE>::asBinder() { + return mBinder; +} + +} // namespace ndk + +/** @} */ |