diff options
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_parcel.h | 76 | ||||
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_parcel_utils.h | 40 | ||||
| -rw-r--r-- | libs/binder/ndk/libbinder_ndk.map.txt | 2 | ||||
| -rw-r--r-- | libs/binder/ndk/parcel.cpp | 47 |
4 files changed, 161 insertions, 4 deletions
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h index 866af70157..7296d87588 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h @@ -151,6 +151,48 @@ typedef bool (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t inde typedef const char* (*AParcel_stringArrayElementGetter)(const void* arrayData, size_t index, size_t* outLength); +/** + * 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_readParcelableArray + * + * \param arrayData some external representation of an array + * \param length the length to allocate this array to + * + * \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_parcelableArrayAllocator)(void* arrayData, int32_t length); + +/** + * This is called to parcel the underlying data from an arrayData object at index. + * + * See also AParcel_writeParcelableArray + * + * \param parcel parcel to write the parcelable to + * \param arrayData some external representation of an array of parcelables (a user-defined type). + * \param index the index of the value to be retrieved. + * + * \return status (usually returned from other parceling functions). STATUS_OK for success. + */ +typedef binder_status_t (*AParcel_writeParcelableElement)(AParcel* parcel, const void* arrayData, + size_t index); + +/** + * This is called to set an underlying value in an arrayData object at index. + * + * See also AParcel_readParcelableArray + * + * \param parcel parcel to read the parcelable from + * \param arrayData some external representation of an array of parcelables (a user-defined type). + * \param index the index of the value to be set. + * + * \return status (usually returned from other parceling functions). STATUS_OK for success. + */ +typedef binder_status_t (*AParcel_readParcelableElement)(const AParcel* parcel, void* arrayData, + size_t index); + // @START-PRIMITIVE-VECTOR-GETTERS /** * This is called to get the underlying data from an arrayData object. @@ -497,6 +539,40 @@ binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData, AParcel_stringArrayElementAllocator elementAllocator) __INTRODUCED_IN(29); +/** + * Writes an array of parcelables (user-defined types) to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \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. + * \param elementWriter function to be called for every array index to write the user-defined type + * at that location. + * + * \return STATUS_OK on successful write. + */ +binder_status_t AParcel_writeParcelableArray(AParcel* parcel, const void* arrayData, int32_t length, + AParcel_writeParcelableElement elementWriter) + __INTRODUCED_IN(29); + +/** + * Reads an array of parcelables (user-defined types) from the next location in a non-null parcel. + * + * First, allocator will be called with the length of the array. If the allocation succeeds and the + * length is greater than zero, elementReader will be called for every index to read the + * corresponding parcelable. + * + * \param parcel the parcel to read from. + * \param arrayData some external representation of an array. + * \param allocator the callback that will be called to allocate the array. + * \param elementReader the callback that will be called to fill out individual elements. + * + * \return STATUS_OK on successful read. + */ +binder_status_t AParcel_readParcelableArray(const AParcel* parcel, void* arrayData, + AParcel_parcelableArrayAllocator allocator, + AParcel_readParcelableElement elementReader) + __INTRODUCED_IN(29); + // @START-PRIMITIVE-READ-WRITE /** * Writes int32_t value to the next location in a non-null parcel. diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h index f99c3a92e2..53d6e9566a 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h @@ -420,6 +420,46 @@ static inline binder_status_t AParcel_readVector( AParcel_nullableStdVectorStringElementAllocator); } +/** + * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'. + */ +template <typename P> +binder_status_t AParcel_writeStdVectorParcelableElement(AParcel* parcel, const void* vectorData, + size_t index) { + const std::vector<P>* vector = static_cast<const std::vector<P>*>(vectorData); + return vector->at(index).writeToParcel(parcel); +} + +/** + * Reads a parcelable object of type P inside a std::vector<P> at index 'index' from 'parcel'. + */ +template <typename P> +binder_status_t AParcel_readStdVectorParcelableElement(const AParcel* parcel, void* vectorData, + size_t index) { + std::vector<P>* vector = static_cast<std::vector<P>*>(vectorData); + return vector->at(index).readFromParcel(parcel); +} + +/** + * Convenience API for writing a std::vector<P> + */ +template <typename P> +static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<P>& vec) { + const void* vectorData = static_cast<const void*>(&vec); + return AParcel_writeParcelableArray(parcel, vectorData, vec.size(), + AParcel_writeStdVectorParcelableElement<P>); +} + +/** + * Convenience API for reading a std::vector<P> + */ +template <typename P> +static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<P>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readParcelableArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<P>, + AParcel_readStdVectorParcelableElement<P>); +} + // @START /** * Writes a vector of int32_t to the next location in a non-null parcel. diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index 4328b6ea6d..ee7132f87f 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -40,6 +40,7 @@ LIBBINDER_NDK { # introduced=29 AParcel_readInt32Array; AParcel_readInt64; AParcel_readInt64Array; + AParcel_readParcelableArray; AParcel_readParcelFileDescriptor; AParcel_readStatusHeader; AParcel_readString; @@ -64,6 +65,7 @@ LIBBINDER_NDK { # introduced=29 AParcel_writeInt32Array; AParcel_writeInt64; AParcel_writeInt64Array; + AParcel_writeParcelableArray; AParcel_writeParcelFileDescriptor; AParcel_writeStatusHeader; AParcel_writeString; diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index 2d68559395..39768557d4 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -377,11 +377,11 @@ binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, if (length <= 0) return STATUS_OK; for (size_t i = 0; i < length; i++) { - size_t length = 0; - const char* str = getter(arrayData, i, &length); - if (str == nullptr && length != -1) return STATUS_BAD_VALUE; + size_t elementLength = 0; + const char* str = getter(arrayData, i, &elementLength); + if (str == nullptr && elementLength != -1) return STATUS_BAD_VALUE; - binder_status_t status = AParcel_writeString(parcel, str, length); + binder_status_t status = AParcel_writeString(parcel, str, elementLength); if (status != STATUS_OK) return status; } @@ -433,6 +433,45 @@ binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData, return STATUS_OK; } +binder_status_t AParcel_writeParcelableArray(AParcel* parcel, const void* arrayData, int32_t length, + AParcel_writeParcelableElement elementWriter) { + // 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++) { + binder_status_t status = elementWriter(parcel, arrayData, i); + if (status != STATUS_OK) return status; + } + + return STATUS_OK; +} + +binder_status_t AParcel_readParcelableArray(const AParcel* parcel, void* arrayData, + AParcel_parcelableArrayAllocator allocator, + AParcel_readParcelableElement elementReader) { + const Parcel* rawParcel = parcel->get(); + + int32_t length; + status_t status = rawParcel->readInt32(&length); + + if (status != STATUS_OK) return PruneStatusT(status); + if (length < -1) return STATUS_BAD_VALUE; + + if (!allocator(arrayData, length)) return STATUS_NO_MEMORY; + + if (length == -1) return STATUS_OK; // null array + + for (size_t i = 0; i < length; i++) { + binder_status_t status = elementReader(parcel, arrayData, i); + if (status != STATUS_OK) return status; + } + + return STATUS_OK; +} + // See gen_parcel_helper.py. These auto-generated read/write methods use the same types for // libbinder and this library. // @START |