diff options
author | Steven Moreland <smoreland@google.com> | 2018-10-08 19:52:26 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2018-10-08 19:52:26 +0000 |
commit | 8cdc1d07fee24c246cefba1504261c6032e9fa2e (patch) | |
tree | 11172dd2ab574ed547b702bf28bc11a238b72a8f | |
parent | d8c1aa725daf40e4d7bc4711e98772745f461fa6 (diff) | |
parent | 2648d2026c998a1c827bceabebf659c4de50daf0 (diff) | |
download | native-8cdc1d07fee24c246cefba1504261c6032e9fa2e.tar.gz |
Merge changes from topic "libbinder_ndk_aidl"
* changes:
libbinder_ndk: Add C++ wrapper code.
libbinder_ndk: add read/write string methods.
-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/include_ndk/android/binder_parcel.h | 37 | ||||
-rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_parcel_utils.h | 71 | ||||
-rw-r--r-- | libs/binder/ndk/libbinder_ndk.map.txt | 2 | ||||
-rw-r--r-- | libs/binder/ndk/parcel.cpp | 65 | ||||
-rw-r--r-- | libs/binder/ndk/test/main_client.cpp | 3 |
7 files changed, 543 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/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h index a3800da160..0e97b507c5 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h @@ -88,6 +88,43 @@ binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) __INTRODUCED_IN(29); +/** + * Writes string value to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) + __INTRODUCED_IN(29); + +/** + * This is called to allocate a buffer + * + * The length here includes the space required to insert a '\0' for a properly formed c-str. If the + * buffer returned from this function is retStr, it will be filled by AParcel_readString with the + * data from the remote process, and it will be filled such that retStr[length] == '\0'. + * + * If allocation fails, null should be returned. + */ +typedef void* (*AParcel_string_reallocator)(void* stringData, size_t length); + +/** + * This is called to get the buffer from a stringData object. + */ +typedef char* (*AParcel_string_getter)(void* stringData); + +/** + * Reads and allocates string value from the next location in a non-null parcel. + * + * Data is passed to the string allocator once the string size is known. This data should be used to + * point to some kind of string data. For instance, it could be a char*, and the string allocator + * could be realloc. Then the getter would simply be a cast to char*. In more complicated cases, + * stringData could be a structure containing additional string data. + * + * If this function returns a success, the buffer returned by allocator when passed stringData will + * contain a null-terminated c-str read from the binder. + */ +binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator, + AParcel_string_getter getter, void** stringData) + __INTRODUCED_IN(29); + // @START /** * Writes int32_t value to the next location in a non-null parcel. diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h new file mode 100644 index 0000000000..7b261d6f98 --- /dev/null +++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h @@ -0,0 +1,71 @@ +/* + * 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_parcel_utils.h + * @brief A collection of helper wrappers for AParcel. + */ + +#pragma once + +#include <android/binder_parcel.h> + +#ifdef __cplusplus + +#include <string> + +/** + * Takes a std::string and reallocates it to the specified length. For use with AParcel_readString. + * See use below in AParcel_readString. + */ +static inline void* AParcel_std_string_reallocator(void* stringData, size_t length) { + std::string* str = static_cast<std::string*>(stringData); + str->resize(length - 1); + return stringData; +} + +/** + * Takes a std::string and returns the inner char*. + */ +static inline char* AParcel_std_string_getter(void* stringData) { + std::string* str = static_cast<std::string*>(stringData); + return &(*str)[0]; +} + +/** + * Convenience API for writing a std::string. + */ +static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) { + return AParcel_writeString(parcel, str.c_str(), str.size()); +} + +/** + * Convenience API for reading a std::string. + */ +static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) { + void* stringData = static_cast<void*>(str); + return AParcel_readString(parcel, AParcel_std_string_reallocator, AParcel_std_string_getter, + &stringData); +} + +#endif // __cplusplus + +/** @} */ diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index 4f486c99ba..2a1bff131c 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -32,6 +32,7 @@ LIBBINDER_NDK { # introduced=29 AParcel_readInt64; AParcel_readNullableStrongBinder; AParcel_readStatusHeader; + AParcel_readString; AParcel_readStrongBinder; AParcel_readUint32; AParcel_readUint64; @@ -43,6 +44,7 @@ LIBBINDER_NDK { # introduced=29 AParcel_writeInt32; AParcel_writeInt64; AParcel_writeStatusHeader; + AParcel_writeString; AParcel_writeStrongBinder; AParcel_writeUint32; AParcel_writeUint64; diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index 385e898aeb..3e03e907bb 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -20,7 +20,11 @@ #include "ibinder_internal.h" #include "status_internal.h" +#include <limits> + +#include <android-base/logging.h> #include <binder/Parcel.h> +#include <utils/Unicode.h> using ::android::IBinder; using ::android::Parcel; @@ -69,6 +73,67 @@ binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status return ret; } +binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) { + const uint8_t* str8 = (uint8_t*)string; + + const ssize_t len16 = utf8_to_utf16_length(str8, length); + + if (len16 < 0 || len16 >= std::numeric_limits<int32_t>::max()) { + LOG(WARNING) << __func__ << ": Invalid string length: " << len16; + return STATUS_BAD_VALUE; + } + + status_t err = parcel->get()->writeInt32(len16); + if (err) { + return PruneStatusT(err); + } + + void* str16 = parcel->get()->writeInplace((len16 + 1) * sizeof(char16_t)); + if (str16 == nullptr) { + return STATUS_NO_MEMORY; + } + + utf8_to_utf16(str8, length, (char16_t*)str16, (size_t)len16 + 1); + + return STATUS_OK; +} + +binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator, + AParcel_string_getter getter, void** stringData) { + size_t len16; + const char16_t* str16 = parcel->get()->readString16Inplace(&len16); + + if (str16 == nullptr) { + LOG(WARNING) << __func__ << ": Failed to read string in place."; + return STATUS_UNEXPECTED_NULL; + } + + ssize_t len8; + + if (len16 == 0) { + len8 = 1; + } else { + len8 = utf16_to_utf8_length(str16, len16) + 1; + } + + if (len8 <= 0 || len8 >= std::numeric_limits<int32_t>::max()) { + LOG(WARNING) << __func__ << ": Invalid string length: " << len8; + return STATUS_BAD_VALUE; + } + + *stringData = reallocator(*stringData, len8); + char* str8 = getter(*stringData); + + if (str8 == nullptr) { + LOG(WARNING) << __func__ << ": AParcel_string_allocator failed to allocate."; + return STATUS_NO_MEMORY; + } + + utf16_to_utf8(str16, len16, str8, len8); + + return STATUS_OK; +} + // See gen_parcel_helper.py. These auto-generated read/write methods use the same types for // libbinder and this library. // @START 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> |