diff options
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_parcel.h | 231 | ||||
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_parcel_utils.h | 253 | ||||
| -rw-r--r-- | libs/binder/ndk/libbinder_ndk.map.txt | 18 | ||||
| -rw-r--r-- | libs/binder/ndk/parcel.cpp | 253 | ||||
| -rwxr-xr-x | libs/binder/ndk/scripts/gen_parcel_helper.py | 103 | ||||
| -rw-r--r-- | libs/binder/ndk/test/main_client.cpp | 1 | ||||
| -rwxr-xr-x | libs/binder/ndk/update.sh | 2 |
7 files changed, 837 insertions, 24 deletions
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h index 0e97b507c5..73df69c0e3 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h @@ -51,6 +51,99 @@ typedef struct AParcel AParcel; void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29); /** + * This is called to allocate an array with a given length. If allocation fails, null should be + * returned. + */ +typedef void* (*AParcel_arrayReallocator)(void* vectorData, size_t length); + +// @START-PRIMITIVE-VECTOR-GETTERS +/** + * This is called to get the underlying data from an arrayData object. + * + * This will never be called for an empty array. + */ +typedef int32_t* (*AParcel_int32ArrayGetter)(void* arrayData); + +/** + * This is called to get the underlying data from an arrayData object. + * + * This will never be called for an empty array. + */ +typedef uint32_t* (*AParcel_uint32ArrayGetter)(void* arrayData); + +/** + * This is called to get the underlying data from an arrayData object. + * + * This will never be called for an empty array. + */ +typedef int64_t* (*AParcel_int64ArrayGetter)(void* arrayData); + +/** + * This is called to get the underlying data from an arrayData object. + * + * This will never be called for an empty array. + */ +typedef uint64_t* (*AParcel_uint64ArrayGetter)(void* arrayData); + +/** + * This is called to get the underlying data from an arrayData object. + * + * This will never be called for an empty array. + */ +typedef float* (*AParcel_floatArrayGetter)(void* arrayData); + +/** + * This is called to get the underlying data from an arrayData object. + * + * This will never be called for an empty array. + */ +typedef double* (*AParcel_doubleArrayGetter)(void* arrayData); + +/** + * This is called to get the underlying data from an arrayData object. + * + * This will never be called for an empty array. + */ +typedef bool (*AParcel_boolArrayGetter)(const void* arrayData, size_t index); + +/** + * This is called to set an underlying value in an arrayData object at index. + */ +typedef void (*AParcel_boolArraySetter)(void* arrayData, size_t index, bool value); + +/** + * This is called to get the underlying data from an arrayData object. + * + * This will never be called for an empty array. + */ +typedef char16_t* (*AParcel_charArrayGetter)(void* arrayData); + +/** + * This is called to get the underlying data from an arrayData object. + * + * This will never be called for an empty array. + */ +typedef int8_t* (*AParcel_byteArrayGetter)(void* arrayData); + +// @END-PRIMITIVE-VECTOR-GETTERS + +/** + * 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); + +/** * Writes an AIBinder to the next location in a non-null parcel. Can be null. */ binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __INTRODUCED_IN(29); @@ -95,22 +188,6 @@ binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t __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 @@ -125,7 +202,7 @@ binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_realloc AParcel_string_getter getter, void** stringData) __INTRODUCED_IN(29); -// @START +// @START-PRIMITIVE-READ-WRITE /** * Writes int32_t value to the next location in a non-null parcel. */ @@ -216,7 +293,125 @@ binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) __INTRO */ binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODUCED_IN(29); -// @END +/** + * Writes an array of int32_t to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length) + __INTRODUCED_IN(29); + +/** + * Writes an array of uint32_t to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length) + __INTRODUCED_IN(29); + +/** + * Writes an array of int64_t to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length) + __INTRODUCED_IN(29); + +/** + * Writes an array of uint64_t to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length) + __INTRODUCED_IN(29); + +/** + * Writes an array of float to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length) + __INTRODUCED_IN(29); + +/** + * Writes an array of double to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length) + __INTRODUCED_IN(29); + +/** + * Writes an array of bool to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, + AParcel_boolArrayGetter getter, size_t length) + __INTRODUCED_IN(29); + +/** + * Writes an array of char16_t to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length) + __INTRODUCED_IN(29); + +/** + * Writes an array of int8_t to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length) + __INTRODUCED_IN(29); + +/** + * Reads an array of int32_t from the next location in a non-null parcel. + */ +binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_int32ArrayGetter getter) __INTRODUCED_IN(29); + +/** + * Reads an array of uint32_t from the next location in a non-null parcel. + */ +binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_uint32ArrayGetter getter) __INTRODUCED_IN(29); + +/** + * Reads an array of int64_t from the next location in a non-null parcel. + */ +binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_int64ArrayGetter getter) __INTRODUCED_IN(29); + +/** + * Reads an array of uint64_t from the next location in a non-null parcel. + */ +binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_uint64ArrayGetter getter) __INTRODUCED_IN(29); + +/** + * Reads an array of float from the next location in a non-null parcel. + */ +binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_floatArrayGetter getter) __INTRODUCED_IN(29); + +/** + * Reads an array of double from the next location in a non-null parcel. + */ +binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_doubleArrayGetter getter) __INTRODUCED_IN(29); + +/** + * Reads an array of bool from the next location in a non-null parcel. + */ +binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_boolArraySetter setter) __INTRODUCED_IN(29); + +/** + * Reads an array of char16_t from the next location in a non-null parcel. + */ +binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_charArrayGetter getter) __INTRODUCED_IN(29); + +/** + * Reads an array of int8_t from the next location in a non-null parcel. + */ +binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_byteArrayGetter getter) __INTRODUCED_IN(29); + +// @END-PRIMITIVE-READ-WRITE #endif //__ANDROID_API__ >= __ANDROID_API_Q__ __END_DECLS diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h index d3e6caecd7..6341b46d21 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h @@ -31,10 +31,242 @@ #ifdef __cplusplus #include <string> +#include <vector> namespace ndk { /** + * This resizes a std::vector of some underlying type to the given length. + */ +template <typename T> +static inline void* AParcel_stdVectorReallocator(void* vectorData, size_t length) { + std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData); + if (length > vec->max_size()) return nullptr; + + vec->resize(length); + return vec; +} + +/** + * This retrieves the underlying contiguous vector from a corresponding vectorData. + */ +template <typename T> +static inline T* AParcel_stdVectorGetter(void* vectorData) { + std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData); + return vec->data(); +} + +/** + * This retrieves the underlying value in a vector which may not be contiguous at index from a + * corresponding vectorData. + */ +template <typename T> +static inline T AParcel_stdVectorGetter(const void* vectorData, size_t index) { + const std::vector<T>* vec = static_cast<const std::vector<T>*>(vectorData); + return (*vec)[index]; +} + +/** + * This sets the underlying value in a corresponding vectorData which may not be contiguous at + * index. + */ +template <typename T> +static inline void AParcel_stdVectorSetter(void* vectorData, size_t index, T value) { + std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData); + (*vec)[index] = value; +} + +/** + * Writes a vector to the next location in a non-null parcel. + */ +template <typename T> +static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<T>& vec); + +/** + * Reads a vector to the next location in a non-null parcel. + */ +template <typename T> +static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<T>* vec); + +// @START +/** + * Writes a vector of int32_t to the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_writeVector<int32_t>(AParcel* parcel, + const std::vector<int32_t>& vec) { + return AParcel_writeInt32Array(parcel, vec.data(), vec.size()); +} + +/** + * Reads a vector of int32_t from the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_readVector<int32_t>(const AParcel* parcel, + std::vector<int32_t>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readInt32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int32_t>, + AParcel_stdVectorGetter<int32_t>); +} + +/** + * Writes a vector of uint32_t to the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_writeVector<uint32_t>(AParcel* parcel, + const std::vector<uint32_t>& vec) { + return AParcel_writeUint32Array(parcel, vec.data(), vec.size()); +} + +/** + * Reads a vector of uint32_t from the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_readVector<uint32_t>(const AParcel* parcel, + std::vector<uint32_t>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readUint32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint32_t>, + AParcel_stdVectorGetter<uint32_t>); +} + +/** + * Writes a vector of int64_t to the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_writeVector<int64_t>(AParcel* parcel, + const std::vector<int64_t>& vec) { + return AParcel_writeInt64Array(parcel, vec.data(), vec.size()); +} + +/** + * Reads a vector of int64_t from the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_readVector<int64_t>(const AParcel* parcel, + std::vector<int64_t>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readInt64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int64_t>, + AParcel_stdVectorGetter<int64_t>); +} + +/** + * Writes a vector of uint64_t to the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_writeVector<uint64_t>(AParcel* parcel, + const std::vector<uint64_t>& vec) { + return AParcel_writeUint64Array(parcel, vec.data(), vec.size()); +} + +/** + * Reads a vector of uint64_t from the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_readVector<uint64_t>(const AParcel* parcel, + std::vector<uint64_t>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readUint64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint64_t>, + AParcel_stdVectorGetter<uint64_t>); +} + +/** + * Writes a vector of float to the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_writeVector<float>(AParcel* parcel, const std::vector<float>& vec) { + return AParcel_writeFloatArray(parcel, vec.data(), vec.size()); +} + +/** + * Reads a vector of float from the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_readVector<float>(const AParcel* parcel, std::vector<float>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readFloatArray(parcel, &vectorData, &AParcel_stdVectorReallocator<float>, + AParcel_stdVectorGetter<float>); +} + +/** + * Writes a vector of double to the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_writeVector<double>(AParcel* parcel, + const std::vector<double>& vec) { + return AParcel_writeDoubleArray(parcel, vec.data(), vec.size()); +} + +/** + * Reads a vector of double from the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_readVector<double>(const AParcel* parcel, std::vector<double>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readDoubleArray(parcel, &vectorData, &AParcel_stdVectorReallocator<double>, + AParcel_stdVectorGetter<double>); +} + +/** + * Writes a vector of bool to the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_writeVector<bool>(AParcel* parcel, const std::vector<bool>& vec) { + return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), + AParcel_stdVectorGetter<bool>, vec.size()); +} + +/** + * Reads a vector of bool from the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_readVector<bool>(const AParcel* parcel, std::vector<bool>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readBoolArray(parcel, &vectorData, &AParcel_stdVectorReallocator<bool>, + AParcel_stdVectorSetter<bool>); +} + +/** + * Writes a vector of char16_t to the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_writeVector<char16_t>(AParcel* parcel, + const std::vector<char16_t>& vec) { + return AParcel_writeCharArray(parcel, vec.data(), vec.size()); +} + +/** + * Reads a vector of char16_t from the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_readVector<char16_t>(const AParcel* parcel, + std::vector<char16_t>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readCharArray(parcel, &vectorData, &AParcel_stdVectorReallocator<char16_t>, + AParcel_stdVectorGetter<char16_t>); +} + +/** + * Writes a vector of int8_t to the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_writeVector<int8_t>(AParcel* parcel, + const std::vector<int8_t>& vec) { + return AParcel_writeByteArray(parcel, vec.data(), vec.size()); +} + +/** + * Reads a vector of int8_t from the next location in a non-null parcel. + */ +template <> +inline binder_status_t AParcel_readVector<int8_t>(const AParcel* parcel, std::vector<int8_t>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readByteArray(parcel, &vectorData, &AParcel_stdVectorReallocator<int8_t>, + AParcel_stdVectorGetter<int8_t>); +} + +// @END + +/** * Takes a std::string and reallocates it to the specified length. For use with AParcel_readString. * See use below in AParcel_readString. */ @@ -68,6 +300,27 @@ static inline binder_status_t AParcel_readString(const AParcel* parcel, std::str &stringData); } +template <typename T> +static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std::vector<T>& vec) { + if (vec.size() > INT32_MAX) { + return STATUS_BAD_VALUE; + } + + return AParcel_writeInt32(parcel, static_cast<int32_t>(vec.size())); +} + +template <typename T> +static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::vector<T>* vec) { + int32_t size; + binder_status_t err = AParcel_readInt32(parcel, &size); + + if (err != STATUS_OK) return err; + if (size < 0) return STATUS_UNEXPECTED_NULL; + + vec->resize(static_cast<size_t>(size)); + return STATUS_OK; +} + } // namespace ndk #endif // __cplusplus diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index 2a1bff131c..f84814fa3c 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -24,30 +24,48 @@ LIBBINDER_NDK { # introduced=29 AIBinder_Weak_promote; AParcel_delete; AParcel_readBool; + AParcel_readBoolArray; AParcel_readByte; + AParcel_readByteArray; AParcel_readChar; + AParcel_readCharArray; AParcel_readDouble; + AParcel_readDoubleArray; AParcel_readFloat; + AParcel_readFloatArray; AParcel_readInt32; + AParcel_readInt32Array; AParcel_readInt64; + AParcel_readInt64Array; AParcel_readNullableStrongBinder; AParcel_readStatusHeader; AParcel_readString; AParcel_readStrongBinder; AParcel_readUint32; + AParcel_readUint32Array; AParcel_readUint64; + AParcel_readUint64Array; AParcel_writeBool; + AParcel_writeBoolArray; AParcel_writeByte; + AParcel_writeByteArray; AParcel_writeChar; + AParcel_writeCharArray; AParcel_writeDouble; + AParcel_writeDoubleArray; AParcel_writeFloat; + AParcel_writeFloatArray; AParcel_writeInt32; + AParcel_writeInt32Array; AParcel_writeInt64; + AParcel_writeInt64Array; AParcel_writeStatusHeader; AParcel_writeString; AParcel_writeStrongBinder; AParcel_writeUint32; + AParcel_writeUint32Array; AParcel_writeUint64; + AParcel_writeUint64Array; AStatus_delete; AStatus_fromExceptionCode; AStatus_fromExceptionCodeWithMessage; diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index 3e03e907bb..5279b549ce 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -31,6 +31,163 @@ using ::android::Parcel; using ::android::sp; using ::android::status_t; +template <typename T> +using ContiguousArrayGetter = T* (*)(void* arrayData); +template <typename T> +using ArrayGetter = T (*)(const void* arrayData, size_t index); +template <typename T> +using ArraySetter = void (*)(void* arrayData, size_t index, T value); + +template <typename T> +binder_status_t WriteArray(AParcel* parcel, const T* array, size_t length) { + if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE; + + Parcel* rawParcel = parcel->get(); + + status_t status = rawParcel->writeInt32(static_cast<int32_t>(length)); + if (status != STATUS_OK) return PruneStatusT(status); + + int32_t size = 0; + if (__builtin_smul_overflow(sizeof(T), length, &size)) return STATUS_NO_MEMORY; + + void* const data = rawParcel->writeInplace(size); + if (data == nullptr) return STATUS_NO_MEMORY; + + memcpy(data, array, size); + + return STATUS_OK; +} + +// Each element in a char16_t array is converted to an int32_t (not packed). +template <> +binder_status_t WriteArray<char16_t>(AParcel* parcel, const char16_t* array, size_t length) { + if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE; + + Parcel* rawParcel = parcel->get(); + + status_t status = rawParcel->writeInt32(static_cast<int32_t>(length)); + if (status != STATUS_OK) return PruneStatusT(status); + + int32_t size = 0; + if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY; + + for (int32_t i = 0; i < length; i++) { + status = rawParcel->writeChar(array[i]); + + if (status != STATUS_OK) return PruneStatusT(status); + } + + return STATUS_OK; +} + +template <typename T> +binder_status_t ReadArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, ContiguousArrayGetter<T> getter) { + const Parcel* rawParcel = parcel->get(); + + int32_t length; + status_t status = rawParcel->readInt32(&length); + + if (status != STATUS_OK) return PruneStatusT(status); + if (length < 0) return STATUS_UNEXPECTED_NULL; + + *arrayData = reallocator(*arrayData, length); + if (*arrayData == nullptr) return STATUS_NO_MEMORY; + + if (length == 0) return STATUS_OK; + + T* array = getter(*arrayData); + if (array == nullptr) return STATUS_NO_MEMORY; + + int32_t size = 0; + if (__builtin_smul_overflow(sizeof(T), length, &size)) return STATUS_NO_MEMORY; + + const void* data = rawParcel->readInplace(size); + if (data == nullptr) return STATUS_NO_MEMORY; + + memcpy(array, data, size); + + return STATUS_OK; +} + +// Each element in a char16_t array is converted to an int32_t (not packed) +template <> +binder_status_t ReadArray<char16_t>(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + ContiguousArrayGetter<char16_t> getter) { + const Parcel* rawParcel = parcel->get(); + + int32_t length; + status_t status = rawParcel->readInt32(&length); + + if (status != STATUS_OK) return PruneStatusT(status); + if (length < 0) return STATUS_UNEXPECTED_NULL; + + *arrayData = reallocator(*arrayData, length); + if (*arrayData == nullptr) return STATUS_NO_MEMORY; + + if (length == 0) return STATUS_OK; + + char16_t* array = getter(*arrayData); + if (array == nullptr) return STATUS_NO_MEMORY; + + int32_t size = 0; + if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY; + + for (int32_t i = 0; i < length; i++) { + status = rawParcel->readChar(array + i); + + if (status != STATUS_OK) return PruneStatusT(status); + } + + return STATUS_OK; +} + +template <typename T> +binder_status_t WriteArray(AParcel* parcel, const void* arrayData, ArrayGetter<T> getter, + size_t length, status_t (Parcel::*write)(T)) { + if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE; + + Parcel* rawParcel = parcel->get(); + + status_t status = rawParcel->writeInt32(static_cast<int32_t>(length)); + if (status != STATUS_OK) return PruneStatusT(status); + + for (size_t i = 0; i < length; i++) { + status = (rawParcel->*write)(getter(arrayData, i)); + + if (status != STATUS_OK) return PruneStatusT(status); + } + + return STATUS_OK; +} + +template <typename T> +binder_status_t ReadArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, ArraySetter<T> setter, + status_t (Parcel::*read)(T*) const) { + const Parcel* rawParcel = parcel->get(); + + int32_t length; + status_t status = rawParcel->readInt32(&length); + + if (status != STATUS_OK) return PruneStatusT(status); + if (length < 0) return STATUS_UNEXPECTED_NULL; + + *arrayData = reallocator(*arrayData, length); + if (*arrayData == nullptr) return STATUS_NO_MEMORY; + + for (size_t i = 0; i < length; i++) { + T readTarget; + status = (rawParcel->*read)(&readTarget); + if (status != STATUS_OK) return PruneStatusT(status); + + setter(*arrayData, i, readTarget); + } + + return STATUS_OK; +} + void AParcel_delete(AParcel* parcel) { delete parcel; } @@ -122,6 +279,11 @@ binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_realloc } *stringData = reallocator(*stringData, len8); + + if (*stringData == nullptr) { + return STATUS_NO_MEMORY; + } + char* str8 = getter(*stringData); if (str8 == nullptr) { @@ -227,4 +389,95 @@ binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) { return PruneStatusT(status); } +binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length) { + return WriteArray<int32_t>(parcel, value, length); +} + +binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length) { + return WriteArray<uint32_t>(parcel, value, length); +} + +binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length) { + return WriteArray<int64_t>(parcel, value, length); +} + +binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length) { + return WriteArray<uint64_t>(parcel, value, length); +} + +binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length) { + return WriteArray<float>(parcel, value, length); +} + +binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length) { + return WriteArray<double>(parcel, value, length); +} + +binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, + AParcel_boolArrayGetter getter, size_t length) { + return WriteArray<bool>(parcel, arrayData, getter, length, &Parcel::writeBool); +} + +binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length) { + return WriteArray<char16_t>(parcel, value, length); +} + +binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length) { + return WriteArray<int8_t>(parcel, value, length); +} + +binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_int32ArrayGetter getter) { + return ReadArray<int32_t>(parcel, arrayData, reallocator, getter); +} + +binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_uint32ArrayGetter getter) { + return ReadArray<uint32_t>(parcel, arrayData, reallocator, getter); +} + +binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_int64ArrayGetter getter) { + return ReadArray<int64_t>(parcel, arrayData, reallocator, getter); +} + +binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_uint64ArrayGetter getter) { + return ReadArray<uint64_t>(parcel, arrayData, reallocator, getter); +} + +binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_floatArrayGetter getter) { + return ReadArray<float>(parcel, arrayData, reallocator, getter); +} + +binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_doubleArrayGetter getter) { + return ReadArray<double>(parcel, arrayData, reallocator, getter); +} + +binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_boolArraySetter setter) { + return ReadArray<bool>(parcel, arrayData, reallocator, setter, &Parcel::readBool); +} + +binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_charArrayGetter getter) { + return ReadArray<char16_t>(parcel, arrayData, reallocator, getter); +} + +binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData, + AParcel_arrayReallocator reallocator, + AParcel_byteArrayGetter getter) { + return ReadArray<int8_t>(parcel, arrayData, reallocator, getter); +} + // @END diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py index bbd3e5de07..45f8d06883 100755 --- a/libs/binder/ndk/scripts/gen_parcel_helper.py +++ b/libs/binder/ndk/scripts/gen_parcel_helper.py @@ -30,13 +30,15 @@ data_types = [ ("Byte", "int8_t"), ] -def replaceFileTags(path, content): +non_contiguously_addressable = {"Bool"} + +def replaceFileTags(path, content, start_tag, end_tag): print("Updating", path) with open(path, "r+") as f: lines = f.readlines() - start = lines.index("// @START\n") - end = lines.index("// @END\n") + start = lines.index("// @" + start_tag + "\n") + end = lines.index("// @" + end_tag + "\n") if end <= start or start < 0 or end < 0: print("Failed to find tags in", path) @@ -59,8 +61,10 @@ def main(): print("Updating auto-generated code") + pre_header = "" header = "" source = "" + cpp_helper = "" for pretty, cpp in data_types: header += "/**\n" @@ -82,8 +86,97 @@ def main(): source += " return PruneStatusT(status);\n" source += "}\n\n" - replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header) - replaceFileTags(ROOT + "parcel.cpp", source) + for pretty, cpp in data_types: + nca = pretty in non_contiguously_addressable + + arg_type = "const " + cpp + "* value" + if nca: arg_type = "const void* arrayData, AParcel_" + pretty.lower() + "ArrayGetter getter" + args = "value, length" + if nca: args = "arrayData, getter, length, &Parcel::write" + pretty + + header += "/**\n" + header += " * Writes an array of " + cpp + " to the next location in a non-null parcel.\n" + header += " */\n" + header += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) __INTRODUCED_IN(29);\n\n" + source += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) {\n" + source += " return WriteArray<" + cpp + ">(parcel, " + args + ");\n"; + source += "}\n\n" + + for pretty, cpp in data_types: + nca = pretty in non_contiguously_addressable + + extra_getter_args = "" + if nca: extra_getter_args = ", size_t index" + getter_return = cpp + "*" + if nca: getter_return = cpp + getter_array_data = "void* arrayData" + if nca: getter_array_data = "const void* arrayData" + + getter_type = "AParcel_" + pretty.lower() + "ArrayGetter" + setter_type = "AParcel_" + pretty.lower() + "ArraySetter" + + pre_header += "/**\n" + pre_header += " * This is called to get the underlying data from an arrayData object.\n" + pre_header += " *\n" + pre_header += " * This will never be called for an empty array.\n" + pre_header += " */\n" + pre_header += "typedef " + getter_return + " (*" + getter_type + ")(" + getter_array_data + extra_getter_args + ");\n\n" + + if nca: + pre_header += "/**\n" + pre_header += " * This is called to set an underlying value in an arrayData object at index.\n" + pre_header += " */\n" + pre_header += "typedef void (*" + setter_type + ")(void* arrayData, size_t index, " + cpp + " value);\n\n" + + read_using = "getter" + if nca: read_using = "setter" + read_type = getter_type + if nca: read_type = setter_type + + arguments = ["const AParcel* parcel"] + arguments += ["void** arrayData"] + arguments += ["AParcel_arrayReallocator reallocator"] + arguments += [read_type + " " + read_using] + arguments = ", ".join(arguments) + + header += "/**\n" + header += " * Reads an array of " + cpp + " from the next location in a non-null parcel.\n" + header += " */\n" + header += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") __INTRODUCED_IN(29);\n\n" + source += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") {\n" + additional_args = "" + if nca: additional_args = ", &Parcel::read" + pretty + source += " return ReadArray<" + cpp + ">(parcel, arrayData, reallocator, " + read_using + additional_args + ");\n"; + source += "}\n\n" + + cpp_helper += "/**\n" + cpp_helper += " * Writes a vector of " + cpp + " to the next location in a non-null parcel.\n" + cpp_helper += " */\n" + cpp_helper += "template<>\n" + cpp_helper += "inline binder_status_t AParcel_writeVector<" + cpp + ">(AParcel* parcel, const std::vector<" + cpp + ">& vec) {\n" + write_args = "vec.data()" + if nca: write_args = "static_cast<const void*>(&vec), AParcel_stdVectorGetter<" + cpp + ">" + cpp_helper += " return AParcel_write" + pretty + "Array(parcel, " + write_args + ", vec.size());\n" + cpp_helper += "}\n\n" + + cpp_helper += "/**\n" + cpp_helper += " * Reads a vector of " + cpp + " from the next location in a non-null parcel.\n" + cpp_helper += " */\n" + cpp_helper += "template<>\n" + cpp_helper += "inline binder_status_t AParcel_readVector<" + cpp + ">(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n" + cpp_helper += " void* vectorData = static_cast<void*>(vec);\n" + read_args = [] + read_args += ["parcel"] + read_args += ["&vectorData"] + read_args += ["&AParcel_stdVectorReallocator<" + cpp + ">"] + read_args += ["AParcel_stdVector" + read_using.capitalize() + "<" + cpp + ">"] + cpp_helper += " return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n" + cpp_helper += "}\n\n" + + replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", pre_header, "START-PRIMITIVE-VECTOR-GETTERS", "END-PRIMITIVE-VECTOR-GETTERS") + replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header, "START-PRIMITIVE-READ-WRITE", "END-PRIMITIVE-READ-WRITE") + replaceFileTags(ROOT + "parcel.cpp", source, "START", "END") + replaceFileTags(ROOT + "include_ndk/android/binder_parcel_utils.h", cpp_helper, "START", "END") print("Updating DONE.") diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp index 22bf1e5be5..6945cac015 100644 --- a/libs/binder/ndk/test/main_client.cpp +++ b/libs/binder/ndk/test/main_client.cpp @@ -134,3 +134,4 @@ TEST(NdkBinder, AddServiceMultipleTimes) { #include <android/binder_auto_utils.h> #include <android/binder_interface_utils.h> +#include <android/binder_parcel_utils.h> diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh index 49b47305b7..9a4577ffff 100755 --- a/libs/binder/ndk/update.sh +++ b/libs/binder/ndk/update.sh @@ -18,6 +18,6 @@ set -ex # This script makes sure that the source code is in sync with the various scripts -./scripts/init_map.sh > libbinder_ndk.map.txt ./scripts/gen_parcel_helper.py ./scripts/format.sh +./scripts/init_map.sh > libbinder_ndk.map.txt |