diff options
Diffstat (limited to 'libs/binder/ndk/include_cpp/android/binder_auto_utils.h')
-rw-r--r-- | libs/binder/ndk/include_cpp/android/binder_auto_utils.h | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h new file mode 100644 index 0000000000..0ad400bffb --- /dev/null +++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h @@ -0,0 +1,378 @@ +/* + * 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 binder. + */ + +#pragma once + +#include <android/binder_ibinder.h> +#include <android/binder_internal_logging.h> +#include <android/binder_parcel.h> +#include <android/binder_status.h> + +#include <assert.h> + +#include <unistd.h> +#include <cstddef> +#include <string> + +namespace ndk { + +/** + * Represents one strong pointer to an AIBinder object. + */ +class SpAIBinder { + public: + /** + * Default constructor. + */ + SpAIBinder() : mBinder(nullptr) {} + + /** + * Takes ownership of one strong refcount of binder. + */ + explicit SpAIBinder(AIBinder* binder) : mBinder(binder) {} + + /** + * Convenience operator for implicitly constructing an SpAIBinder from nullptr. This is not + * explicit because it is not taking ownership of anything. + */ + SpAIBinder(std::nullptr_t) : SpAIBinder() {} // NOLINT(google-explicit-constructor) + + /** + * This will delete the underlying object if it exists. See operator=. + */ + SpAIBinder(const SpAIBinder& other) { *this = other; } + + /** + * This deletes the underlying object if it exists. See set. + */ + ~SpAIBinder() { set(nullptr); } + + /** + * This takes ownership of a binder from another AIBinder object but it does not affect the + * ownership of that other object. + */ + SpAIBinder& operator=(const SpAIBinder& other) { + if (this == &other) { + return *this; + } + AIBinder_incStrong(other.mBinder); + set(other.mBinder); + return *this; + } + + /** + * Takes ownership of one strong refcount of binder + */ + void set(AIBinder* binder) { + AIBinder* old = *const_cast<AIBinder* volatile*>(&mBinder); + if (old != nullptr) AIBinder_decStrong(old); + if (old != *const_cast<AIBinder* volatile*>(&mBinder)) { + __assert(__FILE__, __LINE__, "Race detected."); + } + mBinder = binder; + } + + /** + * This returns the underlying binder object for transactions. If it is used to create another + * SpAIBinder 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: + * SpAIBinder a; // will be nullptr + * SomeInitFunction(a.getR()); // value is initialized with refcount + * + * Other usecases are discouraged. + * + */ + AIBinder** getR() { return &mBinder; } + + bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); } + bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); } + bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); } + bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); } + bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); } + bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); } + + private: + AIBinder* mBinder = nullptr; +}; + +namespace impl { + +/** + * This baseclass owns a single object, used to make various classes RAII. + */ +template <typename T, void (*Destroy)(T), T DEFAULT> +class ScopedAResource { + public: + /** + * Takes ownership of t. + */ + explicit ScopedAResource(T t = DEFAULT) : mT(t) {} + + /** + * This deletes the underlying object if it exists. See set. + */ + ~ScopedAResource() { set(DEFAULT); } + + /** + * 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: + * ScopedAResource<T> a; // will be nullptr + * SomeInitFunction(a.getR()); // value is initialized with refcount + * + * Other usecases are discouraged. + * + */ + T* getR() { return &mT; } + + // copy-constructing/assignment is disallowed + ScopedAResource(const ScopedAResource&) = delete; + ScopedAResource& operator=(const ScopedAResource&) = delete; + + // move-constructing/assignment is okay + ScopedAResource(ScopedAResource&& other) noexcept : mT(std::move(other.mT)) { + other.mT = DEFAULT; + } + ScopedAResource& operator=(ScopedAResource&& other) noexcept { + set(other.mT); + other.mT = DEFAULT; + return *this; + } + + private: + T mT; +}; + +} // namespace impl + +/** + * Convenience wrapper. See AParcel. + */ +class ScopedAParcel : public impl::ScopedAResource<AParcel*, AParcel_delete, nullptr> { + public: + /** + * Takes ownership of a. + */ + explicit ScopedAParcel(AParcel* a = nullptr) : ScopedAResource(a) {} + ~ScopedAParcel() {} + ScopedAParcel(ScopedAParcel&&) = default; + ScopedAParcel& operator=(ScopedAParcel&&) = default; + + bool operator!=(const ScopedAParcel& rhs) const { return get() != rhs.get(); } + bool operator<(const ScopedAParcel& rhs) const { return get() < rhs.get(); } + bool operator<=(const ScopedAParcel& rhs) const { return get() <= rhs.get(); } + bool operator==(const ScopedAParcel& rhs) const { return get() == rhs.get(); } + bool operator>(const ScopedAParcel& rhs) const { return get() > rhs.get(); } + bool operator>=(const ScopedAParcel& rhs) const { return get() >= rhs.get(); } +}; + +/** + * Convenience wrapper. See AStatus. + */ +class ScopedAStatus : public impl::ScopedAResource<AStatus*, AStatus_delete, nullptr> { + public: + /** + * Takes ownership of a. + * + * WARNING: this constructor is only expected to be used when reading a + * status value. Use `ScopedAStatus::ok()` instead. + */ + explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {} + ~ScopedAStatus() {} + ScopedAStatus(ScopedAStatus&&) = default; + ScopedAStatus& operator=(ScopedAStatus&&) = default; + + /** + * See AStatus_isOk. + */ + bool isOk() const { return get() != nullptr && AStatus_isOk(get()); } + + /** + * See AStatus_getExceptionCode + */ + binder_exception_t getExceptionCode() const { return AStatus_getExceptionCode(get()); } + + /** + * See AStatus_getServiceSpecificError + */ + int32_t getServiceSpecificError() const { return AStatus_getServiceSpecificError(get()); } + + /** + * See AStatus_getStatus + */ + binder_status_t getStatus() const { return AStatus_getStatus(get()); } + + /** + * See AStatus_getMessage + */ + const char* getMessage() const { return AStatus_getMessage(get()); } + + std::string getDescription() const { + if (__builtin_available(android 30, *)) { + const char* cStr = AStatus_getDescription(get()); + std::string ret = cStr; + AStatus_deleteDescription(cStr); + return ret; + } + binder_exception_t exception = getExceptionCode(); + std::string desc = std::to_string(exception); + if (exception == EX_SERVICE_SPECIFIC) { + desc += " (" + std::to_string(getServiceSpecificError()) + ")"; + } else if (exception == EX_TRANSACTION_FAILED) { + desc += " (" + std::to_string(getStatus()) + ")"; + } + if (const char* msg = getMessage(); msg != nullptr) { + desc += ": "; + desc += msg; + } + return desc; + } + + /** + * Convenience methods for creating scoped statuses. + */ + static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); } + static ScopedAStatus fromExceptionCode(binder_exception_t exception) { + return ScopedAStatus(AStatus_fromExceptionCode(exception)); + } + static ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exception, + const char* message) { + return ScopedAStatus(AStatus_fromExceptionCodeWithMessage(exception, message)); + } + static ScopedAStatus fromServiceSpecificError(int32_t serviceSpecific) { + return ScopedAStatus(AStatus_fromServiceSpecificError(serviceSpecific)); + } + static ScopedAStatus fromServiceSpecificErrorWithMessage(int32_t serviceSpecific, + const char* message) { + return ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(serviceSpecific, message)); + } + static ScopedAStatus fromStatus(binder_status_t status) { + return ScopedAStatus(AStatus_fromStatus(status)); + } +}; + +/** + * Convenience wrapper. See AIBinder_DeathRecipient. + */ +class ScopedAIBinder_DeathRecipient + : public impl::ScopedAResource<AIBinder_DeathRecipient*, AIBinder_DeathRecipient_delete, + nullptr> { + public: + /** + * Takes ownership of a. + */ + explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr) + : ScopedAResource(a) {} + ~ScopedAIBinder_DeathRecipient() {} + ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default; + ScopedAIBinder_DeathRecipient& operator=(ScopedAIBinder_DeathRecipient&&) = default; +}; + +/** + * Convenience wrapper. See AIBinder_Weak. + */ +class ScopedAIBinder_Weak + : public impl::ScopedAResource<AIBinder_Weak*, AIBinder_Weak_delete, nullptr> { + public: + /** + * Takes ownership of a. + */ + explicit ScopedAIBinder_Weak(AIBinder_Weak* a = nullptr) : ScopedAResource(a) {} + ~ScopedAIBinder_Weak() {} + ScopedAIBinder_Weak(ScopedAIBinder_Weak&&) = default; + ScopedAIBinder_Weak& operator=(ScopedAIBinder_Weak&&) = default; + + /** + * See AIBinder_Weak_promote. + */ + SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); } +}; + +namespace internal { + +static void closeWithError(int fd) { + if (fd == -1) return; + int ret = close(fd); + if (ret != 0) { + syslog(LOG_ERR, "Could not close FD %d: %s", fd, strerror(errno)); + } +} + +} // namespace internal + +/** + * Convenience wrapper for a file descriptor. + */ +class ScopedFileDescriptor : public impl::ScopedAResource<int, internal::closeWithError, -1> { + public: + /** + * Takes ownership of a. + */ + ScopedFileDescriptor() : ScopedFileDescriptor(-1) {} + explicit ScopedFileDescriptor(int a) : ScopedAResource(a) {} + ~ScopedFileDescriptor() {} + ScopedFileDescriptor(ScopedFileDescriptor&&) = default; + ScopedFileDescriptor& operator=(ScopedFileDescriptor&&) = default; + + bool operator!=(const ScopedFileDescriptor& rhs) const { return get() != rhs.get(); } + bool operator<(const ScopedFileDescriptor& rhs) const { return get() < rhs.get(); } + bool operator<=(const ScopedFileDescriptor& rhs) const { return get() <= rhs.get(); } + bool operator==(const ScopedFileDescriptor& rhs) const { return get() == rhs.get(); } + bool operator>(const ScopedFileDescriptor& rhs) const { return get() > rhs.get(); } + bool operator>=(const ScopedFileDescriptor& rhs) const { return get() >= rhs.get(); } +}; + +} // namespace ndk + +/** @} */ |