diff options
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_parcel.h | 53 | ||||
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_parcel_utils.h | 209 | ||||
| -rw-r--r-- | libs/binder/ndk/parcel.cpp | 58 |
3 files changed, 276 insertions, 44 deletions
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h index c6178984bc..ed18deeed8 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h @@ -55,9 +55,9 @@ void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29); /** * This is called to allocate a buffer for a C-style string (null-terminated). The returned buffer - * should be at least length bytes. This includes space for a null terminator. length will always be - * strictly less than or equal to the maximum size that can be held in a size_t and will always be - * greater than 0. + * should be at least length bytes. This includes space for a null terminator. For a string, length + * will always be strictly less than or equal to the maximum size that can be held in a size_t and + * will always be greater than 0. However, if a 'null' string is being read, length will be -1. * * See also AParcel_readString. * @@ -65,31 +65,35 @@ void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29); * * \param stringData some external representation of a string * \param length the length of the buffer needed to fill (including the null-terminator) + * \param buffer a buffer of size 'length' or null if allocation failed. * - * \return a buffer of size 'length' or null if allocation failed. + * \return true if the allocation succeeded, false otherwise. If length is -1, a true return here + * means that a 'null' value (or equivalent) was successfully stored. */ -typedef char* (*AParcel_stringAllocator)(void* stringData, size_t length); +typedef bool (*AParcel_stringAllocator)(void* stringData, int32_t length, char** buffer); /** - * This is called to allocate an array of size 'length'. + * This is called to allocate an array of size 'length'. If length is -1, then a 'null' array (or + * equivalent) should be created. * * See also AParcel_readStringArray * * \param arrayData some external representation of an array * \param length the length to allocate this array to * - * \return true if allocation succeeded + * \return true if allocation succeeded. If length is -1, a true return here means that a 'null' + * value (or equivalent) was successfully stored. */ -typedef bool (*AParcel_stringArrayAllocator)(void* arrayData, size_t length); +typedef bool (*AParcel_stringArrayAllocator)(void* arrayData, int32_t length); /** * This is called to allocate a string inside of an array that was allocated by an * AParcel_stringArrayAllocator. * * The index returned will always be within the range [0, length of arrayData). The returned buffer - * should be at least length bytes. This includes space for a null-terminator. length will always be - * strictly less than or equal to the maximum size that can be held in a size_t and will always be - * greater than 0. + * should be at least length bytes. This includes space for a null-terminator. For a string, length + * will always be strictly less than or equal to the maximum size that can be held in a size_t and + * will always be greater than 0. However, if a 'null' string is being read, length will be -1. * * See also AParcel_readStringArray * @@ -97,10 +101,13 @@ typedef bool (*AParcel_stringArrayAllocator)(void* arrayData, size_t length); * \param index the index at which a string should be allocated. * \param length the length of the string to be allocated at this index. See also * AParcel_stringAllocator. This includes the length required for a null-terminator. + * \param buffer a buffer of size 'length' or null if allocation failed. * - * \return a buffer of size 'length' or null if allocation failed. + * \return true if the allocation succeeded, false otherwise. If length is -1, a true return here + * means that a 'null' value (or equivalent) was successfully stored. */ -typedef char* (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t index, size_t length); +typedef bool (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t index, int32_t length, + char** buffer); /** * This returns the length and buffer of an array at a specific index in an arrayData object. @@ -110,10 +117,11 @@ typedef char* (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t ind * \param arrayData some external representation of an array. * \param index the index at which a string should be allocated. * \param outLength an out parameter for the length of the string at the specified index. This - * should not include the length for a null-terminator if there is one. + * should not include the length for a null-terminator if there is one. If the object at this index + * is 'null', then this should be set to -1. * * \param a buffer of size outLength or more representing the string at the provided index. This is - * not required to be null-terminated. + * not required to be null-terminated. If the object at index is null, then this should be null. */ typedef const char* (*AParcel_stringArrayElementGetter)(const void* arrayData, size_t index, size_t* outLength); @@ -367,13 +375,15 @@ binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status /** * Writes utf-8 string value to the next location in a non-null parcel. * + * If length is -1, and string is nullptr, this will write a 'null' string to the parcel. + * * \param parcel the parcel to write to. * \param string the null-terminated string to write to the parcel, at least of size 'length'. * \param length the length of the string to be written. * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) +binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t length) __INTRODUCED_IN(29); /** @@ -381,7 +391,8 @@ binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t * * Data is passed to the string allocator once the string size is known. This size includes the * space for the null-terminator of this string. This allocator returns a buffer which is used as - * the output buffer from this read. + * the output buffer from this read. If there is a 'null' string on the binder buffer, the allocator + * will be called with length -1. * * \param parcel the parcel to read from. * \param stringData some external representation of a string. @@ -397,7 +408,8 @@ binder_status_t AParcel_readString(const AParcel* parcel, void* stringData, * * length is the length of the array. AParcel_stringArrayElementGetter will be called for all * indices in range [0, length) with the arrayData provided here. The string length and buffer - * returned from this function will be used to fill out the data from the parcel. + * returned from this function will be used to fill out the data from the parcel. If length is -1, + * this will write a 'null' string array to the binder buffer. * * \param parcel the parcel to write to. * \param arrayData some external representation of an array. @@ -407,7 +419,7 @@ binder_status_t AParcel_readString(const AParcel* parcel, void* stringData, * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, size_t length, +binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length, AParcel_stringArrayElementGetter getter) __INTRODUCED_IN(29); @@ -418,7 +430,8 @@ binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, * length is the length of the array to be read from the parcel. Then, for each index i in [0, * length), AParcel_stringArrayElementAllocator will be called with the length of the string to be * read from the parcel. The resultant buffer from each of these calls will be filled according to - * the contents of the string that is read. + * the contents of the string that is read. If the string array being read is 'null', this will + * instead just pass -1 to AParcel_stringArrayAllocator. * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. 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 657577ecbd..25cc6835fc 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h @@ -28,6 +28,7 @@ #include <android/binder_parcel.h> +#include <optional> #include <string> #include <vector> @@ -46,6 +47,8 @@ static inline T* AParcel_stdVectorAllocator(void* vectorData, size_t length) { } /** + * 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 @@ -53,7 +56,6 @@ static inline T* AParcel_stdVectorAllocator(void* vectorData, size_t length) { * Instead, it is used in cases where callbacks are used. * * See AParcel_readVector(const AParcel* parcel, std::vector<bool>) - * See AParcel_readVector(const AParcel* parcel, std::vector<std::string>) */ template <typename T> static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, size_t length) { @@ -65,6 +67,55 @@ static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, size_t l } /** + * 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. Note that when this allocator is used, + * null arrays are not supported. + * + * See AParcel_readVector(const AParcel* parcel, std::vector<std::string>) + */ +template <typename T> +static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, int32_t length) { + if (length < 0) return false; + + std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData); + if (length > vec->max_size()) return false; + + vec->resize(length); + return true; +} + +/** + * 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. Note, when this allocator is used, + * the vector itself can be nullable. + * + * See AParcel_readVector(const AParcel* parcel, + * std::optional<std::vector<std::optional<std::string>>>) + */ +template <typename T> +static inline bool AParcel_nullableStdVectorExternalAllocator(void* vectorData, int32_t length) { + std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData); + + 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); + + return true; +} + +/** * This retrieves the underlying value in a vector which may not be contiguous at index from a * corresponding vectorData. */ @@ -110,22 +161,45 @@ static inline binder_status_t AParcel_readRequiredStrongBinder(const AParcel* pa * Allocates a std::string to length and returns the underlying buffer. For use with * AParcel_readString. See use below in AParcel_readString(const AParcel*, std::string*). */ -static inline char* AParcel_stdStringAllocator(void* stringData, size_t length) { +static inline bool AParcel_stdStringAllocator(void* stringData, int32_t length, char** buffer) { + if (length <= 0) return false; + std::string* str = static_cast<std::string*>(stringData); str->resize(length - 1); - return &(*str)[0]; + *buffer = &(*str)[0]; + return true; } /** - * Allocates a std::string inside of a std::vector<std::string> at index index to size 'length'. + * Allocates a string in a std::optional<std::string> to size 'length' (or to std::nullopt when + * length is -1) and returns the underlying buffer. For use with AParcel_readString. See use below + * in AParcel_readString(const AParcel*, std::optional<std::string>*). */ -static inline char* AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index, - size_t length) { - std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData); +static inline bool AParcel_nullableStdStringAllocator(void* stringData, int32_t length, + char** buffer) { + if (length == 0) return false; + + std::optional<std::string>* str = static_cast<std::optional<std::string>*>(stringData); + + if (length < 0) { + *str = std::nullopt; + return true; + } + + *str = std::optional<std::string>(std::string{}); + (*str)->resize(length - 1); + *buffer = &(**str)[0]; + return true; +} +/** + * Allocates a std::string inside of a std::vector<std::string> at index 'index' to size 'length'. + */ +static inline bool AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index, + int32_t length, char** buffer) { + std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData); std::string& element = vec->at(index); - element.resize(length - 1); - return &element[0]; + return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer); } /** @@ -135,7 +209,6 @@ static inline char* AParcel_stdVectorStringElementAllocator(void* vectorData, si static inline const char* AParcel_stdVectorStringElementGetter(const void* vectorData, size_t index, size_t* outLength) { const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData); - const std::string& element = vec->at(index); *outLength = element.size(); @@ -143,6 +216,40 @@ static inline const char* AParcel_stdVectorStringElementGetter(const void* vecto } /** + * Allocates a string in a std::optional<std::string> inside of a + * std::optional<std::vector<std::optional<std::string>>> at index 'index' to size 'length' (or to + * std::nullopt when length is -1). + */ +static inline bool AParcel_nullableStdVectorStringElementAllocator(void* vectorData, size_t index, + int32_t length, char** buffer) { + std::optional<std::vector<std::optional<std::string>>>* vec = + static_cast<std::optional<std::vector<std::optional<std::string>>>*>(vectorData); + std::optional<std::string>& element = vec->value().at(index); + return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer); +} + +/** + * This gets the length and buffer of a std::optional<std::string> inside of a + * std::vector<std::string> at index index. If the string is null, then it returns null and a length + * of -1. + */ +static inline const char* AParcel_nullableStdVectorStringElementGetter(const void* vectorData, + size_t index, + size_t* outLength) { + const std::optional<std::vector<std::optional<std::string>>>* vec = + static_cast<const std::optional<std::vector<std::optional<std::string>>>*>(vectorData); + const std::optional<std::string>& element = vec->value().at(index); + + if (!element) { + *outLength = -1; + return nullptr; + } + + *outLength = element->size(); + return element->c_str(); +} + +/** * Convenience API for writing a std::string. */ static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) { @@ -158,6 +265,27 @@ static inline binder_status_t AParcel_readString(const AParcel* parcel, std::str } /** + * Convenience API for writing a std::optional<std::string>. + */ +static inline binder_status_t AParcel_writeString(AParcel* parcel, + const std::optional<std::string>& str) { + if (!str) { + return AParcel_writeString(parcel, nullptr, -1); + } + + return AParcel_writeString(parcel, str->c_str(), str->size()); +} + +/** + * Convenience API for reading a std::optional<std::string>. + */ +static inline binder_status_t AParcel_readString(const AParcel* parcel, + std::optional<std::string>* str) { + void* stringData = static_cast<void*>(str); + return AParcel_readString(parcel, stringData, AParcel_nullableStdStringAllocator); +} + +/** * Convenience API for writing a std::vector<std::string> */ static inline binder_status_t AParcel_writeVector(AParcel* parcel, @@ -178,6 +306,28 @@ static inline binder_status_t AParcel_readVector(const AParcel* parcel, AParcel_stdVectorStringElementAllocator); } +/** + * Convenience API for writing a std::optional<std::vector<std::optional<std::string>>> + */ +static inline binder_status_t AParcel_writeVector( + AParcel* parcel, const std::optional<std::vector<std::optional<std::string>>>& vec) { + const void* vectorData = static_cast<const void*>(&vec); + return AParcel_writeStringArray(parcel, vectorData, (vec ? vec->size() : -1), + AParcel_nullableStdVectorStringElementGetter); +} + +/** + * Convenience API for reading a std::optional<std::vector<std::optional<std::string>>> + */ +static inline binder_status_t AParcel_readVector( + const AParcel* parcel, std::optional<std::vector<std::optional<std::string>>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readStringArray( + parcel, vectorData, + AParcel_nullableStdVectorExternalAllocator<std::optional<std::string>>, + AParcel_nullableStdVectorStringElementAllocator); +} + // @START /** * Writes a vector of int32_t to the next location in a non-null parcel. @@ -331,6 +481,23 @@ static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std } /** + * Convenience API for writing the size of a vector. + */ +template <typename T> +static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, + const std::optional<std::vector<T>>& vec) { + if (!vec) { + return AParcel_writeInt32(parcel, -1); + } + + if (vec->size() > INT32_MAX) { + return STATUS_BAD_VALUE; + } + + return AParcel_writeInt32(parcel, static_cast<int32_t>(vec->size())); +} + +/** * Convenience API for resizing a vector. */ template <typename T> @@ -345,6 +512,28 @@ static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::v return STATUS_OK; } +/** + * Convenience API for resizing a vector. + */ +template <typename T> +static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, + std::optional<std::vector<T>>* vec) { + int32_t size; + binder_status_t err = AParcel_readInt32(parcel, &size); + + if (err != STATUS_OK) return err; + if (size < -1) return STATUS_UNEXPECTED_NULL; + + if (size == -1) { + *vec = std::nullopt; + return STATUS_OK; + } + + *vec = std::optional<std::vector<T>>(std::vector<T>{}); + (*vec)->resize(static_cast<size_t>(size)); + return STATUS_OK; +} + } // namespace ndk /** @} */ diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index 53e50100a3..4136698abe 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -237,9 +237,23 @@ binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status return PruneStatusT(ret); } -binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) { - const uint8_t* str8 = (uint8_t*)string; +binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t length) { + if (string == nullptr) { + if (length != -1) { + LOG(WARNING) << __func__ << ": null string must be used with length == -1."; + return STATUS_BAD_VALUE; + } + + status_t err = parcel->get()->writeInt32(-1); + return PruneStatusT(err); + } + if (length < 0) { + LOG(WARNING) << __func__ << ": Negative string length: " << length; + return STATUS_BAD_VALUE; + } + + 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()) { @@ -268,7 +282,10 @@ binder_status_t AParcel_readString(const AParcel* parcel, void* stringData, const char16_t* str16 = parcel->get()->readString16Inplace(&len16); if (str16 == nullptr) { - LOG(WARNING) << __func__ << ": Failed to read string in place."; + if (allocator(stringData, -1, nullptr)) { + return STATUS_OK; + } + return STATUS_UNEXPECTED_NULL; } @@ -285,9 +302,10 @@ binder_status_t AParcel_readString(const AParcel* parcel, void* stringData, return STATUS_BAD_VALUE; } - char* str8 = allocator(stringData, len8); + char* str8; + bool success = allocator(stringData, len8, &str8); - if (str8 == nullptr) { + if (!success || str8 == nullptr) { LOG(WARNING) << __func__ << ": AParcel_stringAllocator failed to allocate."; return STATUS_NO_MEMORY; } @@ -297,19 +315,27 @@ binder_status_t AParcel_readString(const AParcel* parcel, void* stringData, return STATUS_OK; } -binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, size_t length, +binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length, AParcel_stringArrayElementGetter getter) { - if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE; - 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); for (size_t i = 0; i < length; i++) { size_t length = 0; const char* str = getter(arrayData, i, &length); - if (str == nullptr) return STATUS_BAD_VALUE; + if (str == nullptr && length != -1) return STATUS_BAD_VALUE; binder_status_t status = AParcel_writeString(parcel, str, length); if (status != STATUS_OK) return status; @@ -325,10 +351,10 @@ struct StringArrayElementAllocationAdapter { size_t index; // index into the string array AParcel_stringArrayElementAllocator elementAllocator; - static char* Allocator(void* stringData, size_t length) { + static bool Allocator(void* stringData, int32_t length, char** buffer) { StringArrayElementAllocationAdapter* adapter = static_cast<StringArrayElementAllocationAdapter*>(stringData); - return adapter->elementAllocator(adapter->arrayData, adapter->index, length); + return adapter->elementAllocator(adapter->arrayData, adapter->index, length, buffer); } }; @@ -341,10 +367,12 @@ binder_status_t AParcel_readStringArray(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; if (!allocator(arrayData, length)) return STATUS_NO_MEMORY; + if (length == -1) return STATUS_OK; // null string array + StringArrayElementAllocationAdapter adapter{ .arrayData = arrayData, .index = 0, @@ -352,8 +380,10 @@ binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData, }; for (; adapter.index < length; adapter.index++) { - AParcel_readString(parcel, static_cast<void*>(&adapter), - StringArrayElementAllocationAdapter::Allocator); + binder_status_t status = AParcel_readString(parcel, static_cast<void*>(&adapter), + StringArrayElementAllocationAdapter::Allocator); + + if (status != STATUS_OK) return status; } return STATUS_OK; |