diff options
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_parcel.h | 130 | ||||
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_parcel_utils.h | 214 | ||||
| -rw-r--r-- | libs/binder/ndk/parcel.cpp | 111 | ||||
| -rwxr-xr-x | libs/binder/ndk/scripts/gen_parcel_helper.py | 50 |
4 files changed, 377 insertions, 128 deletions
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h index ed18deeed8..b021c23610 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h @@ -132,109 +132,127 @@ typedef const char* (*AParcel_stringArrayElementGetter)(const void* arrayData, s * * The implementation of this function should allocate a contiguous array of size 'length' and * return that underlying buffer to be filled out. If there is an error or length is 0, null may be - * returned. + * returned. If length is -1, this should allocate some representation of a null array. * * See also AParcel_readInt32Array * * \param arrayData some external representation of an array of int32_t. * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of int32_t of size 'length' (if length is >= 0, if length is 0, this + * may be nullptr). * - * \return a buffer of int32_t of size 'length'. + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef int32_t* (*AParcel_int32ArrayAllocator)(void* arrayData, size_t length); +typedef bool (*AParcel_int32ArrayAllocator)(void* arrayData, int32_t length, int32_t** outBuffer); /** * This is called to get the underlying data from an arrayData object. * * The implementation of this function should allocate a contiguous array of size 'length' and * return that underlying buffer to be filled out. If there is an error or length is 0, null may be - * returned. + * returned. If length is -1, this should allocate some representation of a null array. * * See also AParcel_readUint32Array * * \param arrayData some external representation of an array of uint32_t. * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of uint32_t of size 'length' (if length is >= 0, if length is 0, this + * may be nullptr). * - * \return a buffer of uint32_t of size 'length'. + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef uint32_t* (*AParcel_uint32ArrayAllocator)(void* arrayData, size_t length); +typedef bool (*AParcel_uint32ArrayAllocator)(void* arrayData, int32_t length, uint32_t** outBuffer); /** * This is called to get the underlying data from an arrayData object. * * The implementation of this function should allocate a contiguous array of size 'length' and * return that underlying buffer to be filled out. If there is an error or length is 0, null may be - * returned. + * returned. If length is -1, this should allocate some representation of a null array. * * See also AParcel_readInt64Array * * \param arrayData some external representation of an array of int64_t. * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of int64_t of size 'length' (if length is >= 0, if length is 0, this + * may be nullptr). * - * \return a buffer of int64_t of size 'length'. + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef int64_t* (*AParcel_int64ArrayAllocator)(void* arrayData, size_t length); +typedef bool (*AParcel_int64ArrayAllocator)(void* arrayData, int32_t length, int64_t** outBuffer); /** * This is called to get the underlying data from an arrayData object. * * The implementation of this function should allocate a contiguous array of size 'length' and * return that underlying buffer to be filled out. If there is an error or length is 0, null may be - * returned. + * returned. If length is -1, this should allocate some representation of a null array. * * See also AParcel_readUint64Array * * \param arrayData some external representation of an array of uint64_t. * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of uint64_t of size 'length' (if length is >= 0, if length is 0, this + * may be nullptr). * - * \return a buffer of uint64_t of size 'length'. + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef uint64_t* (*AParcel_uint64ArrayAllocator)(void* arrayData, size_t length); +typedef bool (*AParcel_uint64ArrayAllocator)(void* arrayData, int32_t length, uint64_t** outBuffer); /** * This is called to get the underlying data from an arrayData object. * * The implementation of this function should allocate a contiguous array of size 'length' and * return that underlying buffer to be filled out. If there is an error or length is 0, null may be - * returned. + * returned. If length is -1, this should allocate some representation of a null array. * * See also AParcel_readFloatArray * * \param arrayData some external representation of an array of float. * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of float of size 'length' (if length is >= 0, if length is 0, this may + * be nullptr). * - * \return a buffer of float of size 'length'. + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef float* (*AParcel_floatArrayAllocator)(void* arrayData, size_t length); +typedef bool (*AParcel_floatArrayAllocator)(void* arrayData, int32_t length, float** outBuffer); /** * This is called to get the underlying data from an arrayData object. * * The implementation of this function should allocate a contiguous array of size 'length' and * return that underlying buffer to be filled out. If there is an error or length is 0, null may be - * returned. + * returned. If length is -1, this should allocate some representation of a null array. * * See also AParcel_readDoubleArray * * \param arrayData some external representation of an array of double. * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of double of size 'length' (if length is >= 0, if length is 0, this may + * be nullptr). * - * \return a buffer of double of size 'length'. + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef double* (*AParcel_doubleArrayAllocator)(void* arrayData, size_t length); +typedef bool (*AParcel_doubleArrayAllocator)(void* arrayData, int32_t length, double** outBuffer); /** * This allocates an array of size 'length' inside of arrayData and returns whether or not there was - * a success. + * a success. If length is -1, then this should allocate some representation of a null array. * * See also AParcel_readBoolArray * * \param arrayData some external representation of an array of bool. - * \param length the length to allocate arrayData to. + * \param length the length to allocate arrayData to (or -1 if this represents a null array). * * \return whether the allocation succeeded. */ -typedef bool (*AParcel_boolArrayAllocator)(void* arrayData, size_t length); +typedef bool (*AParcel_boolArrayAllocator)(void* arrayData, int32_t length); /** * This is called to get the underlying data from an arrayData object at index. @@ -264,32 +282,38 @@ typedef void (*AParcel_boolArraySetter)(void* arrayData, size_t index, bool valu * * The implementation of this function should allocate a contiguous array of size 'length' and * return that underlying buffer to be filled out. If there is an error or length is 0, null may be - * returned. + * returned. If length is -1, this should allocate some representation of a null array. * * See also AParcel_readCharArray * * \param arrayData some external representation of an array of char16_t. * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of char16_t of size 'length' (if length is >= 0, if length is 0, this + * may be nullptr). * - * \return a buffer of char16_t of size 'length'. + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef char16_t* (*AParcel_charArrayAllocator)(void* arrayData, size_t length); +typedef bool (*AParcel_charArrayAllocator)(void* arrayData, int32_t length, char16_t** outBuffer); /** * This is called to get the underlying data from an arrayData object. * * The implementation of this function should allocate a contiguous array of size 'length' and * return that underlying buffer to be filled out. If there is an error or length is 0, null may be - * returned. + * returned. If length is -1, this should allocate some representation of a null array. * * See also AParcel_readByteArray * * \param arrayData some external representation of an array of int8_t. * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of int8_t of size 'length' (if length is >= 0, if length is 0, this may + * be nullptr). * - * \return a buffer of int8_t of size 'length'. + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef int8_t* (*AParcel_byteArrayAllocator)(void* arrayData, size_t length); +typedef bool (*AParcel_byteArrayAllocator)(void* arrayData, int32_t length, int8_t** outBuffer); // @END-PRIMITIVE-VECTOR-GETTERS @@ -632,72 +656,72 @@ binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODU * Writes an array of int32_t to the next location in a non-null parcel. * * \param parcel the parcel to write to. - * \param arrayData an array of size 'length'. - * \param length the length of arrayData. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, size_t length) +binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of uint32_t to the next location in a non-null parcel. * * \param parcel the parcel to write to. - * \param arrayData an array of size 'length'. - * \param length the length of arrayData. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData, size_t length) +binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of int64_t to the next location in a non-null parcel. * * \param parcel the parcel to write to. - * \param arrayData an array of size 'length'. - * \param length the length of arrayData. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, size_t length) +binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of uint64_t to the next location in a non-null parcel. * * \param parcel the parcel to write to. - * \param arrayData an array of size 'length'. - * \param length the length of arrayData. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData, size_t length) +binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of float to the next location in a non-null parcel. * * \param parcel the parcel to write to. - * \param arrayData an array of size 'length'. - * \param length the length of arrayData. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, size_t length) +binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of double to the next location in a non-null parcel. * * \param parcel the parcel to write to. - * \param arrayData an array of size 'length'. - * \param length the length of arrayData. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, size_t length) +binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, int32_t length) __INTRODUCED_IN(29); /** @@ -708,36 +732,36 @@ binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayDat * * \param parcel the parcel to write to. * \param arrayData some external representation of an array. - * \param length the length of arrayData. + * \param length the length of arrayData (or -1 if this represents a null array). * \param getter the callback to retrieve data at specific locations in the array. * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, size_t length, +binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, int32_t length, AParcel_boolArrayGetter getter) __INTRODUCED_IN(29); /** * Writes an array of char16_t to the next location in a non-null parcel. * * \param parcel the parcel to write to. - * \param arrayData an array of size 'length'. - * \param length the length of arrayData. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, size_t length) +binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of int8_t to the next location in a non-null parcel. * * \param parcel the parcel to write to. - * \param arrayData an array of size 'length'. - * \param length the length of arrayData. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, size_t length) +binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** 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 25cc6835fc..a478ee0f0c 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h @@ -38,31 +38,36 @@ namespace ndk { * This retrieves and allocates a vector to size 'length' and returns the underlying buffer. */ template <typename T> -static inline T* AParcel_stdVectorAllocator(void* vectorData, size_t length) { +static inline bool AParcel_stdVectorAllocator(void* vectorData, int32_t length, T** outBuffer) { + if (length < 0) return false; + std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData); - if (length > vec->max_size()) return nullptr; + if (length > vec->max_size()) return false; vec->resize(length); - return vec->data(); + *outBuffer = vec->data(); + return true; } /** - * TODO(b/111445392): delete this function - * - * This allocates a vector to size 'length' and returns whether the allocation is successful. - * - * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined - * externally with respect to the NDK, and that size information is not passed into the NDK. - * Instead, it is used in cases where callbacks are used. - * - * See AParcel_readVector(const AParcel* parcel, std::vector<bool>) + * This retrieves and allocates a vector to size 'length' and returns the underlying buffer. */ template <typename T> -static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, size_t length) { - std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData); - if (length > vec->max_size()) return false; +static inline bool AParcel_nullableStdVectorAllocator(void* vectorData, int32_t length, + T** outBuffer) { + std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData); - vec->resize(length); + if (length < 0) { + *vec = std::nullopt; + return true; + } + + *vec = std::optional<std::vector<T>>(std::vector<T>{}); + + if (length > (*vec)->max_size()) return false; + (*vec)->resize(length); + + *outBuffer = (*vec)->data(); return true; } @@ -74,6 +79,7 @@ static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, size_t l * Instead, it is used in cases where callbacks are used. Note that when this allocator is used, * null arrays are not supported. * + * See AParcel_readVector(const AParcel* parcel, std::vector<bool>) * See AParcel_readVector(const AParcel* parcel, std::vector<std::string>) */ template <typename T> @@ -136,6 +142,16 @@ static inline void AParcel_stdVectorSetter(void* vectorData, size_t index, T val } /** + * This sets the underlying value in a corresponding vectorData which may not be contiguous at + * index. + */ +template <typename T> +static inline void AParcel_nullableStdVectorSetter(void* vectorData, size_t index, T value) { + std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData); + vec->value()[index] = value; +} + +/** * Convenience method to write a strong binder but return an error if it is null. */ static inline binder_status_t AParcel_writeRequiredStrongBinder(AParcel* parcel, AIBinder* binder) { @@ -337,6 +353,15 @@ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<in } /** + * Writes an optional vector of int32_t to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<int32_t>>& vec) { + if (!vec) return AParcel_writeInt32Array(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of int32_t from the next location in a non-null parcel. */ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int32_t>* vec) { @@ -345,6 +370,15 @@ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int } /** + * Reads an optional vector of int32_t from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<int32_t>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readInt32Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int32_t>); +} + +/** * Writes a vector of uint32_t to the next location in a non-null parcel. */ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) { @@ -352,6 +386,15 @@ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<ui } /** + * Writes an optional vector of uint32_t to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<uint32_t>>& vec) { + if (!vec) return AParcel_writeUint32Array(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of uint32_t from the next location in a non-null parcel. */ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint32_t>* vec) { @@ -360,6 +403,16 @@ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uin } /** + * Reads an optional vector of uint32_t from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<uint32_t>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readUint32Array(parcel, vectorData, + AParcel_nullableStdVectorAllocator<uint32_t>); +} + +/** * Writes a vector of int64_t to the next location in a non-null parcel. */ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) { @@ -367,6 +420,15 @@ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<in } /** + * Writes an optional vector of int64_t to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<int64_t>>& vec) { + if (!vec) return AParcel_writeInt64Array(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of int64_t from the next location in a non-null parcel. */ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int64_t>* vec) { @@ -375,6 +437,15 @@ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int } /** + * Reads an optional vector of int64_t from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<int64_t>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readInt64Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int64_t>); +} + +/** * Writes a vector of uint64_t to the next location in a non-null parcel. */ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) { @@ -382,6 +453,15 @@ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<ui } /** + * Writes an optional vector of uint64_t to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<uint64_t>>& vec) { + if (!vec) return AParcel_writeUint64Array(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of uint64_t from the next location in a non-null parcel. */ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint64_t>* vec) { @@ -390,6 +470,16 @@ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uin } /** + * Reads an optional vector of uint64_t from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<uint64_t>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readUint64Array(parcel, vectorData, + AParcel_nullableStdVectorAllocator<uint64_t>); +} + +/** * Writes a vector of float to the next location in a non-null parcel. */ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) { @@ -397,6 +487,15 @@ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<fl } /** + * Writes an optional vector of float to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<float>>& vec) { + if (!vec) return AParcel_writeFloatArray(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of float from the next location in a non-null parcel. */ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<float>* vec) { @@ -405,6 +504,15 @@ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<flo } /** + * Reads an optional vector of float from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<float>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readFloatArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<float>); +} + +/** * Writes a vector of double to the next location in a non-null parcel. */ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) { @@ -412,6 +520,15 @@ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<do } /** + * Writes an optional vector of double to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<double>>& vec) { + if (!vec) return AParcel_writeDoubleArray(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of double from the next location in a non-null parcel. */ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<double>* vec) { @@ -420,6 +537,15 @@ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<dou } /** + * Reads an optional vector of double from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<double>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readDoubleArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<double>); +} + +/** * Writes a vector of bool to the next location in a non-null parcel. */ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) { @@ -428,6 +554,15 @@ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bo } /** + * Writes an optional vector of bool to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<bool>>& vec) { + if (!vec) return AParcel_writeBoolArray(parcel, nullptr, -1, AParcel_stdVectorGetter<bool>); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of bool from the next location in a non-null parcel. */ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<bool>* vec) { @@ -437,6 +572,17 @@ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<boo } /** + * Reads an optional vector of bool from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<bool>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readBoolArray(parcel, vectorData, + AParcel_nullableStdVectorExternalAllocator<bool>, + AParcel_nullableStdVectorSetter<bool>); +} + +/** * Writes a vector of char16_t to the next location in a non-null parcel. */ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) { @@ -444,6 +590,15 @@ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<ch } /** + * Writes an optional vector of char16_t to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<char16_t>>& vec) { + if (!vec) return AParcel_writeCharArray(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of char16_t from the next location in a non-null parcel. */ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<char16_t>* vec) { @@ -452,6 +607,15 @@ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<cha } /** + * Reads an optional vector of char16_t from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<char16_t>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readCharArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<char16_t>); +} + +/** * Writes a vector of int8_t to the next location in a non-null parcel. */ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) { @@ -459,6 +623,15 @@ inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<in } /** + * Writes an optional vector of int8_t to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<int8_t>>& vec) { + if (!vec) return AParcel_writeByteArray(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of int8_t from the next location in a non-null parcel. */ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int8_t>* vec) { @@ -466,6 +639,15 @@ inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>); } +/** + * Reads an optional vector of int8_t from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<int8_t>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readByteArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<int8_t>); +} + // @END /** diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index 4136698abe..b1a295584a 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -36,28 +36,46 @@ using ::android::base::unique_fd; using ::android::os::ParcelFileDescriptor; template <typename T> -using ContiguousArrayAllocator = T* (*)(void* arrayData, size_t length); +using ContiguousArrayAllocator = bool (*)(void* arrayData, int32_t length, T** outBuffer); template <typename T> -using ArrayAllocator = bool (*)(void* arrayData, size_t length); +using ArrayAllocator = bool (*)(void* arrayData, int32_t length); 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; +binder_status_t WriteAndValidateArraySize(AParcel* parcel, bool isNullArray, int32_t length) { + // only -1 can be used to represent a null array + if (length < -1) return STATUS_BAD_VALUE; + + if (!isNullArray && length < 0) { + LOG(ERROR) << __func__ << ": null array must be used with length == -1."; + return STATUS_BAD_VALUE; + } + if (isNullArray && length > 0) { + LOG(ERROR) << __func__ << ": null buffer cannot be for size " << length << " array."; + 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); + return STATUS_OK; +} + +template <typename T> +binder_status_t WriteArray(AParcel* parcel, const T* array, int32_t length) { + binder_status_t status = WriteAndValidateArraySize(parcel, array == nullptr, length); + if (status != STATUS_OK) return status; + if (length <= 0) return STATUS_OK; + int32_t size = 0; if (__builtin_smul_overflow(sizeof(T), length, &size)) return STATUS_NO_MEMORY; - void* const data = rawParcel->writeInplace(size); + void* const data = parcel->get()->writeInplace(size); if (data == nullptr) return STATUS_NO_MEMORY; memcpy(data, array, size); @@ -67,17 +85,16 @@ binder_status_t WriteArray(AParcel* parcel, const T* array, size_t length) { // 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); +binder_status_t WriteArray<char16_t>(AParcel* parcel, const char16_t* array, int32_t length) { + binder_status_t status = WriteAndValidateArraySize(parcel, array == nullptr, length); + if (status != STATUS_OK) return status; + if (length <= 0) return STATUS_OK; int32_t size = 0; if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY; + Parcel* rawParcel = parcel->get(); + for (int32_t i = 0; i < length; i++) { status = rawParcel->writeChar(array[i]); @@ -96,10 +113,12 @@ binder_status_t ReadArray(const AParcel* parcel, void* arrayData, status_t status = rawParcel->readInt32(&length); if (status != STATUS_OK) return PruneStatusT(status); - if (length < 0) return STATUS_UNEXPECTED_NULL; + if (length < -1) return STATUS_BAD_VALUE; - T* array = allocator(arrayData, length); - if (length == 0) return STATUS_OK; + T* array; + if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY; + + if (length <= 0) return STATUS_OK; if (array == nullptr) return STATUS_NO_MEMORY; int32_t size = 0; @@ -123,10 +142,12 @@ binder_status_t ReadArray<char16_t>(const AParcel* parcel, void* arrayData, status_t status = rawParcel->readInt32(&length); if (status != STATUS_OK) return PruneStatusT(status); - if (length < 0) return STATUS_UNEXPECTED_NULL; + if (length < -1) return STATUS_BAD_VALUE; + + char16_t* array; + if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY; - char16_t* array = allocator(arrayData, length); - if (length == 0) return STATUS_OK; + if (length <= 0) return STATUS_OK; if (array == nullptr) return STATUS_NO_MEMORY; int32_t size = 0; @@ -142,15 +163,16 @@ binder_status_t ReadArray<char16_t>(const AParcel* parcel, void* arrayData, } template <typename T> -binder_status_t WriteArray(AParcel* parcel, const void* arrayData, size_t length, +binder_status_t WriteArray(AParcel* parcel, const void* arrayData, int32_t length, ArrayGetter<T> getter, status_t (Parcel::*write)(T)) { - if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE; + // we have no clue if arrayData represents a null object or not, we can only infer from length + bool arrayIsNull = length < 0; + binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length); + if (status != STATUS_OK) return status; + if (length <= 0) return STATUS_OK; 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)); @@ -169,10 +191,12 @@ binder_status_t ReadArray(const AParcel* parcel, void* arrayData, ArrayAllocator status_t status = rawParcel->readInt32(&length); if (status != STATUS_OK) return PruneStatusT(status); - if (length < 0) return STATUS_UNEXPECTED_NULL; + if (length < -1) return STATUS_BAD_VALUE; if (!allocator(arrayData, length)) return STATUS_NO_MEMORY; + if (length <= 0) return STATUS_OK; + for (size_t i = 0; i < length; i++) { T readTarget; status = (rawParcel->*read)(&readTarget); @@ -317,20 +341,11 @@ binder_status_t AParcel_readString(const AParcel* parcel, void* stringData, binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length, AParcel_stringArrayElementGetter getter) { - Parcel* rawParcel = parcel->get(); - - if (length < 0) { - if (length != -1) { - LOG(WARNING) << __func__ << ": null array must be used with length == -1."; - return STATUS_BAD_VALUE; - } - - status_t status = rawParcel->writeInt32(-1); - return PruneStatusT(status); - } - - status_t status = rawParcel->writeInt32(static_cast<int32_t>(length)); - if (status != STATUS_OK) return PruneStatusT(status); + // we have no clue if arrayData represents a null object or not, we can only infer from length + bool arrayIsNull = length < 0; + binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length); + if (status != STATUS_OK) return status; + if (length <= 0) return STATUS_OK; for (size_t i = 0; i < length; i++) { size_t length = 0; @@ -482,42 +497,42 @@ binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) { return PruneStatusT(status); } -binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, size_t length) { +binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, int32_t length) { return WriteArray<int32_t>(parcel, arrayData, length); } binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData, - size_t length) { + int32_t length) { return WriteArray<uint32_t>(parcel, arrayData, length); } -binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, size_t length) { +binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, int32_t length) { return WriteArray<int64_t>(parcel, arrayData, length); } binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData, - size_t length) { + int32_t length) { return WriteArray<uint64_t>(parcel, arrayData, length); } -binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, size_t length) { +binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, int32_t length) { return WriteArray<float>(parcel, arrayData, length); } -binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, size_t length) { +binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, int32_t length) { return WriteArray<double>(parcel, arrayData, length); } -binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, size_t length, +binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, int32_t length, AParcel_boolArrayGetter getter) { return WriteArray<bool>(parcel, arrayData, length, getter, &Parcel::writeBool); } -binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, size_t length) { +binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, int32_t length) { return WriteArray<char16_t>(parcel, arrayData, length); } -binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, size_t length) { +binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length) { return WriteArray<int8_t>(parcel, arrayData, length); } diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py index bb762540e4..8f587d2ccf 100755 --- a/libs/binder/ndk/scripts/gen_parcel_helper.py +++ b/libs/binder/ndk/scripts/gen_parcel_helper.py @@ -99,8 +99,8 @@ def main(): for pretty, cpp in data_types: nca = pretty in non_contiguously_addressable - arg_types = "const " + cpp + "* arrayData, size_t length" - if nca: arg_types = "const void* arrayData, size_t length, AParcel_" + pretty.lower() + "ArrayGetter getter" + arg_types = "const " + cpp + "* arrayData, int32_t length" + if nca: arg_types = "const void* arrayData, int32_t length, AParcel_" + pretty.lower() + "ArrayGetter getter" args = "arrayData, length" if nca: args = "arrayData, length, getter, &Parcel::write" + pretty @@ -114,11 +114,11 @@ def main(): header += " * \\param parcel the parcel to write to.\n" if nca: header += " * \\param arrayData some external representation of an array.\n" - header += " * \\param length the length of arrayData.\n" + header += " * \\param length the length of arrayData (or -1 if this represents a null array).\n" header += " * \\param getter the callback to retrieve data at specific locations in the array.\n" else: - header += " * \\param arrayData an array of size 'length'.\n" - header += " * \\param length the length of arrayData.\n" + header += " * \\param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).\n" + header += " * \\param length the length of arrayData or -1 if this represents a null array.\n" header += " *\n" header += " * \\return STATUS_OK on successful write.\n" header += " */\n" @@ -139,16 +139,16 @@ def main(): if nca: pre_header += "/**\n" pre_header += " * This allocates an array of size 'length' inside of arrayData and returns whether or not there was " - pre_header += "a success.\n" + pre_header += "a success. If length is -1, then this should allocate some representation of a null array.\n" pre_header += " *\n" pre_header += " * See also " + read_func + "\n" pre_header += " *\n" pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n" - pre_header += " * \\param length the length to allocate arrayData to.\n" + pre_header += " * \\param length the length to allocate arrayData to (or -1 if this represents a null array).\n" pre_header += " *\n" pre_header += " * \\return whether the allocation succeeded.\n" pre_header += " */\n" - pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, size_t length);\n\n" + pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, int32_t length);\n\n" pre_header += "/**\n" pre_header += " * This is called to get the underlying data from an arrayData object at index.\n" @@ -178,16 +178,18 @@ def main(): pre_header += " *\n" pre_header += " * The implementation of this function should allocate a contiguous array of size 'length' and " pre_header += "return that underlying buffer to be filled out. If there is an error or length is 0, null may be " - pre_header += "returned.\n" + pre_header += "returned. If length is -1, this should allocate some representation of a null array.\n" pre_header += " *\n" pre_header += " * See also " + read_func + "\n" pre_header += " *\n" pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n" pre_header += " * \\param length the length to allocate arrayData to.\n" + pre_header += " * \\param outBuffer a buffer of " + cpp + " of size 'length' (if length is >= 0, if length is 0, " + pre_header += "this may be nullptr).\n" pre_header += " *\n" - pre_header += " * \\return a buffer of " + cpp + " of size 'length'.\n" + pre_header += " * \\return whether or not the allocation was successful (or whether a null array is represented when length is -1).\n" pre_header += " */\n" - pre_header += "typedef " + cpp + "* (*" + allocator_type + ")(void* arrayData, size_t length);\n\n" + pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, int32_t length, " + cpp + "** outBuffer);\n\n" read_array_args = [("const AParcel*", "parcel")] read_array_args += [("void*", "arrayData")] @@ -232,6 +234,16 @@ def main(): cpp_helper += "}\n\n" cpp_helper += "/**\n" + cpp_helper += " * Writes an optional vector of " + cpp + " to the next location in a non-null parcel.\n" + cpp_helper += " */\n" + cpp_helper += "inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::optional<std::vector<" + cpp + ">>& vec) {\n" + extra_args = "" + if nca: extra_args = ", AParcel_stdVectorGetter<" + cpp + ">" + cpp_helper += " if (!vec) return AParcel_write" + pretty + "Array(parcel, nullptr, -1" + extra_args + ");\n" + cpp_helper += " return AParcel_writeVector(parcel, *vec);\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 += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n" @@ -247,6 +259,22 @@ def main(): cpp_helper += " return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n" cpp_helper += "}\n\n" + cpp_helper += "/**\n" + cpp_helper += " * Reads an optional vector of " + cpp + " from the next location in a non-null parcel.\n" + cpp_helper += " */\n" + cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::optional<std::vector<" + cpp + ">>* vec) {\n" + cpp_helper += " void* vectorData = static_cast<void*>(vec);\n" + read_args = [] + read_args += ["parcel"] + read_args += ["vectorData"] + if nca: + read_args += ["AParcel_nullableStdVectorExternalAllocator<bool>"] + read_args += ["AParcel_nullableStdVectorSetter<" + cpp + ">"] + else: + read_args += ["AParcel_nullableStdVectorAllocator<" + 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") |