summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Moreland <smoreland@google.com>2018-10-08 19:52:26 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-10-08 19:52:26 +0000
commit8cdc1d07fee24c246cefba1504261c6032e9fa2e (patch)
tree11172dd2ab574ed547b702bf28bc11a238b72a8f
parentd8c1aa725daf40e4d7bc4711e98772745f461fa6 (diff)
parent2648d2026c998a1c827bceabebf659c4de50daf0 (diff)
downloadnative-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.h234
-rw-r--r--libs/binder/ndk/include_ndk/android/binder_interface_utils.h131
-rw-r--r--libs/binder/ndk/include_ndk/android/binder_parcel.h37
-rw-r--r--libs/binder/ndk/include_ndk/android/binder_parcel_utils.h71
-rw-r--r--libs/binder/ndk/libbinder_ndk.map.txt2
-rw-r--r--libs/binder/ndk/parcel.cpp65
-rw-r--r--libs/binder/ndk/test/main_client.cpp3
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>