libbinder_ndk: nullable primitive arrays
Now consistent w/ String[].
Bug: 111445392
Test: atest android.binder.cts
Change-Id: Ie671e5b08a41d4b49d9afa83d2836b6ca35847a3
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index ed18dee..b021c23 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 @@
*
* 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 @@
*
* 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 @@
* 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 @@
*
* \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 25cc683..a478ee0 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 @@
* 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) {
- std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
- if (length > vec->max_size()) return nullptr;
+static inline bool AParcel_stdVectorAllocator(void* vectorData, int32_t length, T** outBuffer) {
+ if (length < 0) return false;
- vec->resize(length);
- return vec->data();
-}
-
-/**
- * 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>)
- */
-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;
vec->resize(length);
+ *outBuffer = vec->data();
+ return true;
+}
+
+/**
+ * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
+ */
+template <typename T>
+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);
+
+ 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 @@
* 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
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 4136698..b1a2955 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -36,28 +36,46 @@
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 @@
// 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 @@
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 @@
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 = allocator(arrayData, length);
- if (length == 0) return STATUS_OK;
+ char16_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;
@@ -142,15 +163,16 @@
}
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 @@
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_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 @@
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 bb76254..8f587d2 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -99,8 +99,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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")