libbinder_ndk: read/write array for primitive types.
am: a884566fee

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