Merge "Parcel: add generic readData and writeData methods." am: d098c22c14 am: 6acd539f0d am: c599dff21f

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1577869

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Iedf1143cf0736df0966768eb0005b740f1a24f0a
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b9d00fe..1a4ede1 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -769,200 +769,116 @@
     return NO_ERROR;
 }
 
-status_t Parcel::writeUtf8AsUtf16(const std::optional<std::string>& str) {
-  if (!str) {
-    return writeInt32(-1);
-  }
-  return writeUtf8AsUtf16(*str);
-}
 
-status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) {
-  if (!str) {
-    return writeInt32(-1);
-  }
-  return writeUtf8AsUtf16(*str);
-}
+status_t Parcel::writeUtf8AsUtf16(const std::optional<std::string>& str) { return writeData(str); }
+status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) { return writeData(str); }
 
-status_t Parcel::writeByteVectorInternal(const int8_t* data, size_t size) {
-    if (size > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
+status_t Parcel::writeString16(const std::optional<String16>& str) { return writeData(str); }
+status_t Parcel::writeString16(const std::unique_ptr<String16>& str) { return writeData(str); }
 
-    status_t status = writeInt32(size);
-    if (status != OK) {
-        return status;
-    }
+status_t Parcel::writeByteVector(const std::vector<int8_t>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::optional<std::vector<int8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::vector<uint8_t>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::optional<std::vector<uint8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val){ return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val) { return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::optional<std::vector<int32_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::optional<std::vector<int64_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::vector<uint64_t>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::optional<std::vector<uint64_t>>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::vector<float>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::optional<std::vector<float>>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::unique_ptr<std::vector<float>>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::vector<double>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::optional<std::vector<double>>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::unique_ptr<std::vector<double>>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::vector<bool>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::optional<std::vector<bool>>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::unique_ptr<std::vector<bool>>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::vector<char16_t>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::optional<std::vector<char16_t>>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val) { return writeData(val); }
 
-    return write(data, size);
-}
-
-status_t Parcel::writeByteVector(const std::vector<int8_t>& val) {
-    return writeByteVectorInternal(val.data(), val.size());
-}
-
-status_t Parcel::writeByteVector(const std::optional<std::vector<int8_t>>& val)
-{
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(val->data(), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val)
-{
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(val->data(), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::vector<uint8_t>& val) {
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
-}
-
-status_t Parcel::writeByteVector(const std::optional<std::vector<uint8_t>>& val)
-{
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val)
-{
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-
-status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val)
-{
-    return writeTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt32Vector(const std::optional<std::vector<int32_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val)
-{
-    return writeTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeInt64Vector(const std::optional<std::vector<int64_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeUint64Vector(const std::vector<uint64_t>& val)
-{
-    return writeTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeUint64Vector(const std::optional<std::vector<uint64_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeFloatVector(const std::vector<float>& val)
-{
-    return writeTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeFloatVector(const std::optional<std::vector<float>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeFloatVector(const std::unique_ptr<std::vector<float>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeDoubleVector(const std::vector<double>& val)
-{
-    return writeTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeDoubleVector(const std::optional<std::vector<double>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeDoubleVector(const std::unique_ptr<std::vector<double>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeBoolVector(const std::vector<bool>& val)
-{
-    return writeTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeBoolVector(const std::optional<std::vector<bool>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeBoolVector(const std::unique_ptr<std::vector<bool>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeCharVector(const std::vector<char16_t>& val)
-{
-    return writeTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeCharVector(const std::optional<std::vector<char16_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeString16Vector(const std::vector<String16>& val)
-{
-    return writeTypedVector(val, &Parcel::writeString16);
-}
-
+status_t Parcel::writeString16Vector(const std::vector<String16>& val) { return writeData(val); }
 status_t Parcel::writeString16Vector(
-        const std::optional<std::vector<std::optional<String16>>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeString16);
-}
-
+        const std::optional<std::vector<std::optional<String16>>>& val) { return writeData(val); }
 status_t Parcel::writeString16Vector(
-        const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeString16);
-}
-
+        const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val) { return writeData(val); }
 status_t Parcel::writeUtf8VectorAsUtf16Vector(
-                        const std::optional<std::vector<std::optional<std::string>>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
-
+                        const std::optional<std::vector<std::optional<std::string>>>& val) { return writeData(val); }
 status_t Parcel::writeUtf8VectorAsUtf16Vector(
-                        const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
+                        const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) { return writeData(val); }
+status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) { return writeData(val); }
 
-status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) {
-    return writeTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
+status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<base::unique_fd>& val) { return writeData(val); }
+status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<base::unique_fd>>& val) { return writeData(val); }
+status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) { return writeData(val); }
+
+status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val) { return writeData(val); }
+status_t Parcel::writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val) { return writeData(val); }
+status_t Parcel::writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val) { return writeData(val); }
+
+status_t Parcel::writeParcelable(const Parcelable& parcelable) { return writeData(parcelable); }
+
+status_t Parcel::readUtf8FromUtf16(std::optional<std::string>* str) const { return readData(str); }
+status_t Parcel::readUtf8FromUtf16(std::unique_ptr<std::string>* str) const { return readData(str); }
+
+status_t Parcel::readString16(std::optional<String16>* pArg) const { return readData(pArg); }
+status_t Parcel::readString16(std::unique_ptr<String16>* pArg) const { return readData(pArg); }
+
+status_t Parcel::readByteVector(std::vector<int8_t>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::vector<uint8_t>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::optional<std::vector<int8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::optional<std::vector<uint8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::optional<std::vector<int32_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::optional<std::vector<int64_t>>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::optional<std::vector<uint64_t>>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::vector<uint64_t>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::optional<std::vector<float>>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::unique_ptr<std::vector<float>>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::vector<float>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::optional<std::vector<double>>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::unique_ptr<std::vector<double>>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::vector<double>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::optional<std::vector<bool>>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::unique_ptr<std::vector<bool>>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::vector<bool>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::optional<std::vector<char16_t>>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::vector<char16_t>* val) const { return readData(val); }
+
+status_t Parcel::readString16Vector(
+        std::optional<std::vector<std::optional<String16>>>* val) const { return readData(val); }
+status_t Parcel::readString16Vector(
+        std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const { return readData(val); }
+status_t Parcel::readString16Vector(std::vector<String16>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(
+        std::optional<std::vector<std::optional<std::string>>>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(
+        std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const { return readData(val); }
+
+status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<base::unique_fd>>* val) const { return readData(val); }
+status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const { return readData(val); }
+status_t Parcel::readUniqueFileDescriptorVector(std::vector<base::unique_fd>* val) const { return readData(val); }
+
+status_t Parcel::readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const { return readData(val); }
+status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const { return readData(val); }
+status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const { return readData(val); }
+
+status_t Parcel::readParcelable(Parcelable* parcelable) const { return readData(parcelable); }
 
 status_t Parcel::writeInt32(int32_t val)
 {
@@ -1091,24 +1007,6 @@
     return err;
 }
 
-status_t Parcel::writeString16(const std::optional<String16>& str)
-{
-    if (!str) {
-        return writeInt32(-1);
-    }
-
-    return writeString16(*str);
-}
-
-status_t Parcel::writeString16(const std::unique_ptr<String16>& str)
-{
-    if (!str) {
-        return writeInt32(-1);
-    }
-
-    return writeString16(*str);
-}
-
 status_t Parcel::writeString16(const String16& str)
 {
     return writeString16(str.string(), str.size());
@@ -1138,32 +1036,6 @@
     return flattenBinder(val);
 }
 
-status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
-{
-    return writeTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const {
-    return readTypedVector(val, &Parcel::readStrongBinder);
-}
 
 status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) {
     if (!parcelable) {
@@ -1173,14 +1045,6 @@
     return writeParcelable(*parcelable);
 }
 
-status_t Parcel::writeParcelable(const Parcelable& parcelable) {
-    status_t status = writeInt32(1);  // parcelable is not null.
-    if (status != OK) {
-        return status;
-    }
-    return parcelable.writeToParcel(this);
-}
-
 status_t Parcel::writeNativeHandle(const native_handle* handle)
 {
     if (!handle || handle->version != sizeof(native_handle))
@@ -1251,18 +1115,6 @@
     return writeDupFileDescriptor(fd.get());
 }
 
-status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<base::unique_fd>& val) {
-    return writeTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
-status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<base::unique_fd>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
-status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
 status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob)
 {
     if (len > INT32_MAX) {
@@ -1477,31 +1329,6 @@
     goto data_sorted;
 }
 
-status_t Parcel::readVectorSizeWithCoarseBoundCheck(int32_t *size) const {
-    int32_t requestedSize;
-    const status_t status = readInt32(&requestedSize);
-    if (status != NO_ERROR) return status;
-
-    // We permit negative sizes, which indicate presence of a nullable vector,
-    // i.e. a vector embedded in std::optional, std::unique_ptr, or std::shared_ptr.
-    if (requestedSize > 0) {
-        // Check if there are fewer bytes than vector elements.
-        // A lower bound is 1 byte per element, satisfied by some enum and int8_t and uint8_t.
-        const size_t availableBytes = dataAvail();
-        if (static_cast<size_t>(requestedSize) > availableBytes) {
-            // We have a size that is greater than the number of bytes available.
-            // On bounds failure we do not 'rewind' position by 4 bytes of the size already read.
-            ALOGW("%s: rejecting out of bounds vector size (requestedSize):%d "
-                    "Parcel{dataAvail:%zu mDataSize:%zu mDataPos:%zu mDataCapacity:%zu}",
-                    __func__, requestedSize, availableBytes, mDataSize, mDataPos, mDataCapacity);
-            return BAD_VALUE;
-        }
-    }
-
-    *size = requestedSize;
-    return NO_ERROR;
-}
-
 status_t Parcel::read(void* outData, size_t len) const
 {
     if (len > INT32_MAX) {
@@ -1605,236 +1432,6 @@
     return err;
 }
 
-status_t Parcel::readByteVector(std::vector<int8_t>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    return readByteVectorInternal(val, size);
-}
-
-status_t Parcel::readByteVector(std::vector<uint8_t>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    return readByteVectorInternal(val, size);
-}
-
-status_t Parcel::readByteVector(std::optional<std::vector<int8_t>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (!*val) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null byte vector.
-        return OK;
-    }
-    return readByteVectorInternal(&**val, size);
-}
-
-status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (val->get() == nullptr) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null byte vector.
-        return OK;
-    }
-    return readByteVectorInternal(val->get(), size);
-}
-
-status_t Parcel::readByteVector(std::optional<std::vector<uint8_t>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (!*val) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null byte vector.
-        return OK;
-    }
-    return readByteVectorInternal(&**val, size);
-}
-
-status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (val->get() == nullptr) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null byte vector.
-        return OK;
-    }
-    return readByteVectorInternal(val->get(), size);
-}
-
-status_t Parcel::readInt32Vector(std::optional<std::vector<int32_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const {
-    return readTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt64Vector(std::optional<std::vector<int64_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const {
-    return readTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readUint64Vector(std::optional<std::vector<uint64_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readUint64Vector(std::vector<uint64_t>* val) const {
-    return readTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readFloatVector(std::optional<std::vector<float>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readFloatVector(std::unique_ptr<std::vector<float>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readFloatVector(std::vector<float>* val) const {
-    return readTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readDoubleVector(std::optional<std::vector<double>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readDoubleVector(std::unique_ptr<std::vector<double>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readDoubleVector(std::vector<double>* val) const {
-    return readTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readBoolVector(std::optional<std::vector<bool>>* val) const {
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->emplace();
-
-    status = readBoolVector(&**val);
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-status_t Parcel::readBoolVector(std::unique_ptr<std::vector<bool>>* val) const {
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->reset(new (std::nothrow) std::vector<bool>());
-
-    status = readBoolVector(val->get());
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-status_t Parcel::readBoolVector(std::vector<bool>* val) const {
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return UNEXPECTED_NULL;
-    }
-
-    val->resize(size);
-
-    /* C++ bool handling means a vector of bools isn't necessarily addressable
-     * (we might use individual bits)
-     */
-    bool data;
-    for (int32_t i = 0; i < size; ++i) {
-        status = readBool(&data);
-        (*val)[i] = data;
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
-}
-
-status_t Parcel::readCharVector(std::optional<std::vector<char16_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readCharVector(std::vector<char16_t>* val) const {
-    return readTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readString16Vector(
-        std::optional<std::vector<std::optional<String16>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readString16Vector(
-        std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readString16Vector(std::vector<String16>* val) const {
-    return readTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(
-        std::optional<std::vector<std::optional<std::string>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(
-        std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const {
-    return readTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
 status_t Parcel::readInt32(int32_t *pArg) const
 {
     return readAligned(pArg);
@@ -2007,36 +1604,6 @@
     return NO_ERROR;
 }
 
-status_t Parcel::readUtf8FromUtf16(std::optional<std::string>* str) const {
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readInt32(&size);
-    str->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    str->emplace();
-    return readUtf8FromUtf16(&**str);
-}
-
-status_t Parcel::readUtf8FromUtf16(std::unique_ptr<std::string>* str) const {
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readInt32(&size);
-    str->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    str->reset(new (std::nothrow) std::string());
-    return readUtf8FromUtf16(str->get());
-}
-
 const char* Parcel::readCString() const
 {
     if (mDataPos < mDataSize) {
@@ -2103,51 +1670,6 @@
     return String16();
 }
 
-status_t Parcel::readString16(std::optional<String16>* pArg) const
-{
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readInt32(&size);
-    pArg->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    pArg->emplace();
-
-    status = readString16(&**pArg);
-
-    if (status != OK) {
-        pArg->reset();
-    }
-
-    return status;
-}
-
-status_t Parcel::readString16(std::unique_ptr<String16>* pArg) const
-{
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readInt32(&size);
-    pArg->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    pArg->reset(new (std::nothrow) String16());
-
-    status = readString16(pArg->get());
-
-    if (status != OK) {
-        pArg->reset();
-    }
-
-    return status;
-}
 
 status_t Parcel::readString16(String16* pArg) const
 {
@@ -2204,18 +1726,6 @@
     return val;
 }
 
-status_t Parcel::readParcelable(Parcelable* parcelable) const {
-    int32_t have_parcelable = 0;
-    status_t status = readInt32(&have_parcelable);
-    if (status != OK) {
-        return status;
-    }
-    if (!have_parcelable) {
-        return UNEXPECTED_NULL;
-    }
-    return parcelable->readFromParcel(this);
-}
-
 int32_t Parcel::readExceptionCode() const
 {
     binder::Status status;
@@ -2334,18 +1844,6 @@
     return OK;
 }
 
-status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<base::unique_fd>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
-status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
-status_t Parcel::readUniqueFileDescriptorVector(std::vector<base::unique_fd>* val) const {
-    return readTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
 status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const
 {
     int32_t blobType;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 54c49e4..7b298f5 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -190,34 +190,47 @@
     // Write an Enum vector with underlying type int8_t.
     // Does not use padding; each byte is contiguous.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::vector<T>& val);
+    status_t            writeEnumVector(const std::vector<T>& val)
+            { return writeData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::optional<std::vector<T>>& val);
+    status_t            writeEnumVector(const std::optional<std::vector<T>>& val)
+            { return writeData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")))
+            { return writeData(val); }
     // Write an Enum vector with underlying type != int8_t.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::vector<T>& val);
+    status_t            writeEnumVector(const std::vector<T>& val)
+            { return writeData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::optional<std::vector<T>>& val);
+    status_t            writeEnumVector(const std::optional<std::vector<T>>& val)
+            { return writeData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")))
+            { return writeData(val); }
 
     template<typename T>
-    status_t            writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val);
+    status_t            writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val)
+            { return writeData(val); }
     template<typename T>
-    status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
+    status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")))
+            { return writeData(val); }
     template<typename T>
-    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
+    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")))
+            { return writeData(val); }
     template<typename T>
-    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val);
+    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val)
+            { return writeData(val); }
     template<typename T>
-    status_t            writeParcelableVector(const std::vector<T>& val);
+    status_t            writeParcelableVector(const std::vector<T>& val)
+            { return writeData(val); }
 
     template<typename T>
-    status_t            writeNullableParcelable(const std::optional<T>& parcelable);
+    status_t            writeNullableParcelable(const std::optional<T>& parcelable)
+            { return writeData(parcelable); }
     template<typename T>
-    status_t            writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")));
+    status_t            writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")))
+            { return writeData(parcelable); }
 
     status_t            writeParcelable(const Parcelable& parcelable);
 
@@ -335,35 +348,48 @@
     // Read an Enum vector with underlying type int8_t.
     // Does not use padding; each byte is contiguous.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::vector<T>* val) const;
+    status_t            readEnumVector(std::vector<T>* val) const
+            { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")))
+            { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::optional<std::vector<T>>* val) const;
+    status_t            readEnumVector(std::optional<std::vector<T>>* val) const
+            { return readData(val); }
     // Read an Enum vector with underlying type != int8_t.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::vector<T>* val) const;
+    status_t            readEnumVector(std::vector<T>* val) const
+            { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")))
+            { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::optional<std::vector<T>>* val) const;
+    status_t            readEnumVector(std::optional<std::vector<T>>* val) const
+            { return readData(val); }
 
     template<typename T>
     status_t            readParcelableVector(
-                            std::optional<std::vector<std::optional<T>>>* val) const;
+                            std::optional<std::vector<std::optional<T>>>* val) const
+            { return readData(val); }
     template<typename T>
     status_t            readParcelableVector(
-                            std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const __attribute__((deprecated("use std::optional version instead")));
+                            std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const __attribute__((deprecated("use std::optional version instead")))
+            { return readData(val); }
     template<typename T>
-    status_t            readParcelableVector(std::vector<T>* val) const;
+    status_t            readParcelableVector(std::vector<T>* val) const
+            { return readData(val); }
 
     status_t            readParcelable(Parcelable* parcelable) const;
 
     template<typename T>
-    status_t            readParcelable(std::optional<T>* parcelable) const;
+    status_t            readParcelable(std::optional<T>* parcelable) const
+            { return readData(parcelable); }
     template<typename T>
-    status_t            readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")));
+    status_t            readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")))
+            { return readData(parcelable); }
 
+    // If strong binder would be nullptr, readStrongBinder() returns an error.
+    // TODO: T must be derived from IInterface, fix for clarity.
     template<typename T>
     status_t            readStrongBinder(sp<T>* val) const;
 
@@ -418,20 +444,13 @@
     template<typename T>
     status_t            read(LightFlattenable<T>& val) const;
 
+    // resizeOutVector is used to resize AIDL out vector parameters.
     template<typename T>
     status_t            resizeOutVector(std::vector<T>* val) const;
     template<typename T>
     status_t            resizeOutVector(std::optional<std::vector<T>>* val) const;
     template<typename T>
     status_t            resizeOutVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
-    template<typename T>
-    status_t            reserveOutVector(std::vector<T>* val, size_t* size) const;
-    template<typename T>
-    status_t            reserveOutVector(std::optional<std::vector<T>>* val,
-                                         size_t* size) const;
-    template<typename T>
-    status_t            reserveOutVector(std::unique_ptr<std::vector<T>>* val,
-                                         size_t* size) const __attribute__((deprecated("use std::optional version instead")));
 
     // Like Parcel.java's readExceptionCode().  Reads the first int32
     // off of a Parcel's header, returning 0 or the negative error
@@ -518,10 +537,6 @@
     void                scanForFds() const;
     status_t            validateReadData(size_t len) const;
 
-    // Reads an int32 size and does a coarse bounds check against the number
-    // of available bytes in the Parcel.
-    status_t            readVectorSizeWithCoarseBoundCheck(int32_t *size) const;
-
     void                updateWorkSourceRequestHeaderPosition() const;
 
     status_t            finishFlattenBinder(const sp<IBinder>& binder);
@@ -540,53 +555,544 @@
     status_t            writeRawNullableParcelable(const Parcelable*
                                                    parcelable);
 
-    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
-    status_t            writeEnum(const T& val);
-    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
-    status_t            writeEnum(const T& val);
+    //-----------------------------------------------------------------------------
+    // Generic type read and write methods for Parcel:
+    //
+    // readData(T *value) will read a value from the Parcel.
+    // writeData(const T& value) will write a value to the Parcel.
+    //
+    // Our approach to parceling is based on two overloaded functions
+    // readData() and writeData() that generate parceling code for an
+    // object automatically based on its type. The code from templates are generated at
+    // compile time (if constexpr), and decomposes an object through a call graph matching
+    // recursive descent of the template typename.
+    //
+    // This approach unifies handling of complex objects,
+    // resulting in fewer lines of code, greater consistency,
+    // extensibility to nested types, efficiency (decisions made at compile time),
+    // and better code maintainability and optimization.
+    //
+    // Design decision: Incorporate the read and write code into Parcel rather than
+    // as a non-intrusive serializer that emits a byte stream, as we have
+    // active objects, alignment, legacy code, and historical idiosyncrasies.
+    //
+    // --- Overview
+    //
+    // Parceling is a way of serializing objects into a sequence of bytes for communication
+    // between processes, as part of marshaling data for remote procedure calls.
+    //
+    // The Parcel instance contains objects serialized as bytes, such as the following:
+    //
+    // 1) Ordinary primitive data such as int, float.
+    // 2) Established structured data such as String16, std::string.
+    // 3) Parcelables, which are C++ objects that derive from Parcelable (and thus have a
+    //    readFromParcel and writeToParcel method).  (Similar for Java)
+    // 4) A std::vector<> of such data.
+    // 5) Nullable objects contained in std::optional, std::unique_ptr, or std::shared_ptr.
+    //
+    // And active objects from the Android ecosystem such as:
+    // 6) File descriptors, base::unique_fd (kernel object handles)
+    // 7) Binder objects, sp<IBinder> (active Android RPC handles)
+    //
+    // Objects from (1) through (5) serialize into the mData buffer.
+    // Active objects (6) and (7) serialize into both mData and mObjects buffers.
+    //
+    // --- Data layout details
+    //
+    // Data is read or written to the parcel by recursively decomposing the type of the parameter
+    // type T through readData() and writeData() methods.
+    //
+    // We focus on writeData() here in our explanation of the data layout.
+    //
+    // 1) Alignment
+    // Implementation detail: Regardless of the parameter type, writeData() calls are designed
+    // to finish at a multiple of 4 bytes, the default alignment of the Parcel.
+    //
+    // Writes of single uint8_t, int8_t, enums based on types of size 1, char16_t, etc
+    // will result in 4 bytes being written.  The data is widened to int32 and then written;
+    // hence the position of the nonzero bytes depend on the native endianness of the CPU.
+    //
+    // Writes of primitive values with 8 byte size, double, int64_t, uint64_t,
+    // are stored with 4 byte alignment.  The ARM and x86/x64 permit unaligned reads
+    // and writes (albeit with potential latency/throughput penalty) which may or may
+    // not be observable unless the process is IO bound.
+    //
+    // 2) Parcelables
+    // Parcelables are detected by the type's base class, and implemented through calling
+    // into the Parcelable type's readFromParcel() or writeToParcel() methods.
+    // Historically, due to null object detection, a (int32_t) 1 is prepended to the data written.
+    // Parcelables must have a default constructor (i.e. one that takes no arguments).
+    //
+    // 3) Arrays
+    // Arrays of uint8_t and int8_t, and enums based on size 1 are written as
+    // a contiguous packed byte stream.  Hidden zero padding is applied at the end of the byte
+    // stream to make a multiple of 4 bytes (and prevent info leakage when writing).
+    //
+    // All other array writes can be conceptually thought of as recursively calling
+    // writeData on the individual elements (though may be implemented differently for speed).
+    // As discussed in (1), alignment rules are therefore applied for each element
+    // write (not as an aggregate whole), so the wire representation of data can be
+    // substantially larger.
+    //
+    // Historical Note:
+    // Because of element-wise alignment, CharVector and BoolVector are expanded
+    // element-wise into integers even though they could have been optimized to be packed
+    // just like uint8_t, int8_t (size 1 data).
+    //
+    // 3.1) Arrays accessed by the std::vector type.  This is the default for AIDL.
+    //
+    // 4) Nullables
+    // std::optional, std::unique_ptr, std::shared_ptr are all parceled identically
+    // (i.e. result in identical byte layout).
+    // The target of the std::optional, std::unique_ptr, or std::shared_ptr
+    // can either be a std::vector, String16, std::string, or a Parcelable.
+    //
+    // Detection of null relies on peeking the first int32 data and checking if the
+    // the peeked value is considered invalid for the object:
+    // (-1 for vectors, String16, std::string) (0 for Parcelables).  If the peeked value
+    // is invalid, then a null is returned.
+    //
+    // Application Note: When to use each nullable type:
+    //
+    // std::optional: Embeds the object T by value rather than creating a new instance
+    // by managed pointer as std::unique_ptr or std::shared_ptr.  This will save a malloc
+    // when creating an optional instance.
+    //
+    // Use of std::optionals by value can result in copies of the underlying value stored in it,
+    // so a std::move may be used to move in and move out (for example) a vector value into
+    // the std::optional or for the std::optional itself.
+    //
+    // std::unique_ptr, std::shared_ptr: These are preferred when the lifetime of the object is
+    // already managed by the application.  This reduces unnecessary copying of data
+    // especially when the calls are local in-proc (rather than via binder rpc).
+    //
+    // 5) StrongBinder (sp<IBinder>)
+    // StrongBinder objects are written regardless of null. When read, null StrongBinder values
+    // will be interpreted as UNKNOWN_ERROR if the type is a single argument <sp<T>>
+    // or in a vector argument <std::vector<sp<T>>. However, they will be read without an error
+    // if present in a std::optional, std::unique_ptr, or std::shared_ptr vector, e.g.
+    // <std::optional<std::vector<sp<T>>>.
+    //
+    // See AIDL annotation @Nullable, readStrongBinder(), and readNullableStrongBinder().
+    //
+    // Historical Note: writing a vector of StrongBinder objects <std::vector<sp<T>>
+    // containing a null will not cause an error. However reading such a vector will cause
+    // an error _and_ early termination of the read.
 
-    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
-    status_t            readEnum(T* pArg) const;
-    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
-    status_t            readEnum(T* pArg) const;
+    //  --- Examples
+    //
+    // Using recursive parceling, we can parcel complex data types so long
+    // as they obey the rules described above.
+    //
+    // Example #1
+    // Parceling of a 3D vector
+    //
+    // std::vector<std::vector<std::vector<int32_t>>> v1 {
+    //     { {1}, {2, 3}, {4} },
+    //     {},
+    //     { {10}, {20}, {30, 40} },
+    // };
+    // Parcel p1;
+    // p1.writeData(v1);
+    // decltype(v1) v2;
+    // p1.setDataPosition(0);
+    // p1.readData(&v2);
+    // ASSERT_EQ(v1, v2);
+    //
+    // Example #2
+    // Parceling of mixed shared pointers
+    //
+    // Parcel p1;
+    // auto sp1 = std::make_shared<std::vector<std::shared_ptr<std::vector<int>>>>(3);
+    // (*sp1)[2] = std::make_shared<std::vector<int>>(3);
+    // (*(*sp1)[2])[2] = 2;
+    // p1.writeData(sp1);
+    // decltype(sp1) sp2;
+    // p1.setDataPosition(0);
+    // p1.readData(&sp2);
+    // ASSERT_EQ((*sp1)[0], (*sp2)[0]); // nullptr
+    // ASSERT_EQ((*sp1)[1], (*sp2)[1]); // nullptr
+    // ASSERT_EQ(*(*sp1)[2], *(*sp2)[2]); // { 0, 0, 2}
 
-    status_t writeByteVectorInternal(const int8_t* data, size_t size);
-    template<typename T>
-    status_t readByteVectorInternal(std::vector<T>* val, size_t size) const;
+    //  --- Helper Methods
+    // TODO: move this to a utils header.
+    //
+    // Determine if a type is a specialization of a templated type
+    // Example: is_specialization_v<T, std::vector>
 
-    template<typename T, typename U>
-    status_t            unsafeReadTypedVector(std::vector<T>* val,
-                                              status_t(Parcel::*read_func)(U*) const) const;
-    template<typename T>
-    status_t            readNullableTypedVector(std::optional<std::vector<T>>* val,
-                                                status_t(Parcel::*read_func)(T*) const) const;
-    template<typename T>
-    status_t            readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
-                                                status_t(Parcel::*read_func)(T*) const) const __attribute__((deprecated("use std::optional version instead")));
-    template<typename T>
-    status_t            readTypedVector(std::vector<T>* val,
-                                        status_t(Parcel::*read_func)(T*) const) const;
-    template<typename T, typename U>
-    status_t            unsafeWriteTypedVector(const std::vector<T>& val,
-                                               status_t(Parcel::*write_func)(U));
-    template<typename T>
-    status_t            writeNullableTypedVector(const std::optional<std::vector<T>>& val,
-                                                 status_t(Parcel::*write_func)(const T&));
-    template<typename T>
-    status_t            writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                                 status_t(Parcel::*write_func)(const T&)) __attribute__((deprecated("use std::optional version instead")));
-    template<typename T>
-    status_t            writeNullableTypedVector(const std::optional<std::vector<T>>& val,
-                                                 status_t(Parcel::*write_func)(T));
-    template<typename T>
-    status_t            writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                                 status_t(Parcel::*write_func)(T)) __attribute__((deprecated("use std::optional version instead")));
-    template<typename T>
-    status_t            writeTypedVector(const std::vector<T>& val,
-                                         status_t(Parcel::*write_func)(const T&));
-    template<typename T>
-    status_t            writeTypedVector(const std::vector<T>& val,
-                                         status_t(Parcel::*write_func)(T));
+    template <typename Test, template <typename...> class Ref>
+    struct is_specialization : std::false_type {};
+
+    template <template <typename...> class Ref, typename... Args>
+    struct is_specialization<Ref<Args...>, Ref>: std::true_type {};
+
+    template <typename Test, template <typename...> class Ref>
+    static inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value;
+
+    // Get the first template type from a container, the T from MyClass<T, ...>.
+    template<typename T> struct first_template_type;
+
+    template <template <typename ...> class V, typename T, typename... Args>
+    struct first_template_type<V<T, Args...>> {
+        using type_t = T;
+    };
+
+    template <typename T>
+    using first_template_type_t = typename first_template_type<T>::type_t;
+
+    // For static assert(false) we need a template version to avoid early failure.
+    template <typename T>
+    static inline constexpr bool dependent_false_v = false;
+
+    // primitive types that we consider packed and trivially copyable as an array
+    template <typename T>
+    static inline constexpr bool is_pointer_equivalent_array_v =
+            std::is_same_v<T, int8_t>
+            || std::is_same_v<T, uint8_t>
+            // We could support int16_t and uint16_t, but those aren't currently AIDL types.
+            || std::is_same_v<T, int32_t>
+            || std::is_same_v<T, uint32_t>
+            || std::is_same_v<T, float>
+            // are unaligned reads and write support is assumed.
+            || std::is_same_v<T, uint64_t>
+            || std::is_same_v<T, int64_t>
+            || std::is_same_v<T, double>
+            || (std::is_enum_v<T> && (sizeof(T) == 1 || sizeof(T) == 4)); // size check not type
+
+    // allowed "nullable" types
+    // These are nonintrusive containers std::optional, std::unique_ptr, std::shared_ptr.
+    template <typename T>
+    static inline constexpr bool is_parcel_nullable_type_v =
+            is_specialization_v<T, std::optional>
+            || is_specialization_v<T, std::unique_ptr>
+            || is_specialization_v<T, std::shared_ptr>;
+
+    // special int32 value to indicate NonNull or Null parcelables
+    // This is fixed to be only 0 or 1 by contract, do not change.
+    static constexpr int32_t kNonNullParcelableFlag = 1;
+    static constexpr int32_t kNullParcelableFlag = 0;
+
+    // special int32 size representing a null vector, when applicable in Nullable data.
+    // This fixed as -1 by contract, do not change.
+    static constexpr int32_t kNullVectorSize = -1;
+
+    // --- readData and writeData methods.
+    // We choose a mixture of function and template overloads to improve code readability.
+    // TODO: Consider C++20 concepts when they become available.
+
+    // writeData function overloads.
+    // Implementation detail: Function overloading improves code readability over
+    // template overloading, but prevents writeData<T> from being used for those types.
+
+    status_t writeData(bool t) {
+        return writeBool(t);  // this writes as int32_t
+    }
+
+    status_t writeData(int8_t t) {
+        return writeByte(t);  // this writes as int32_t
+    }
+
+    status_t writeData(uint8_t t) {
+        return writeByte(static_cast<int8_t>(t));  // this writes as int32_t
+    }
+
+    status_t writeData(char16_t t) {
+        return writeChar(t);  // this writes as int32_t
+    }
+
+    status_t writeData(int32_t t) {
+        return writeInt32(t);
+    }
+
+    status_t writeData(uint32_t t) {
+        return writeUint32(t);
+    }
+
+    status_t writeData(int64_t t) {
+        return writeInt64(t);
+    }
+
+    status_t writeData(uint64_t t) {
+        return writeUint64(t);
+    }
+
+    status_t writeData(float t) {
+        return writeFloat(t);
+    }
+
+    status_t writeData(double t) {
+        return writeDouble(t);
+    }
+
+    status_t writeData(const String16& t) {
+        return writeString16(t);
+    }
+
+    status_t writeData(const std::string& t) {
+        return writeUtf8AsUtf16(t);
+    }
+
+    status_t writeData(const base::unique_fd& t) {
+        return writeUniqueFileDescriptor(t);
+    }
+
+    status_t writeData(const Parcelable& t) {  // std::is_base_of_v<Parcelable, T>
+        // implemented here. writeParcelable() calls this.
+        status_t status = writeData(static_cast<int32_t>(kNonNullParcelableFlag));
+        if (status != OK) return status;
+        return t.writeToParcel(this);
+    }
+
+    // writeData<T> template overloads.
+    // Written such that the first template type parameter is the complete type
+    // of the first function parameter.
+    template <typename T,
+            typename std::enable_if_t<std::is_enum_v<T>, bool> = true>
+    status_t writeData(const T& t) {
+        // implemented here. writeEnum() calls this.
+        using UT = std::underlying_type_t<T>;
+        return writeData(static_cast<UT>(t)); // recurse
+    }
+
+    template <typename T,
+            typename std::enable_if_t<is_specialization_v<T, sp>, bool> = true>
+    status_t writeData(const T& t) {
+        return writeStrongBinder(t);
+    }
+
+    // std::optional, std::unique_ptr, std::shared_ptr special case.
+    template <typename CT,
+            typename std::enable_if_t<is_parcel_nullable_type_v<CT>, bool> = true>
+    status_t writeData(const CT& c) {
+        using T = first_template_type_t<CT>;  // The T in CT == C<T, ...>
+        if constexpr (is_specialization_v<T, std::vector>
+                || std::is_same_v<T, String16>
+                || std::is_same_v<T, std::string>) {
+            if (!c) return writeData(static_cast<int32_t>(kNullVectorSize));
+        } else if constexpr (std::is_base_of_v<Parcelable, T>) {
+            if (!c) return writeData(static_cast<int32_t>(kNullParcelableFlag));
+        } else /* constexpr */ {  // could define this, but raise as error.
+            static_assert(dependent_false_v<CT>);
+        }
+        return writeData(*c);
+    }
+
+    template <typename CT,
+            typename std::enable_if_t<is_specialization_v<CT, std::vector>, bool> = true>
+    status_t writeData(const CT& c) {
+        using T = first_template_type_t<CT>;  // The T in CT == C<T, ...>
+        if (c.size() >  std::numeric_limits<int32_t>::max()) return BAD_VALUE;
+        const auto size = static_cast<int32_t>(c.size());
+        writeData(size);
+        if constexpr (is_pointer_equivalent_array_v<T>) {
+            constexpr size_t limit = std::numeric_limits<size_t>::max() / sizeof(T);
+            if (c.size() > limit) return BAD_VALUE;
+            // is_pointer_equivalent types do not have gaps which could leak info,
+            // which is only a concern when writing through binder.
+
+            // TODO: Padding of the write is suboptimal when the length of the
+            // data is not a multiple of 4.  Consider improving the write() method.
+            return write(c.data(), c.size() * sizeof(T));
+        } else if constexpr (std::is_same_v<T, bool>
+                || std::is_same_v<T, char16_t>) {
+            // reserve data space to write to
+            auto data = reinterpret_cast<int32_t*>(writeInplace(c.size() * sizeof(int32_t)));
+            if (data == nullptr) return BAD_VALUE;
+            for (const auto t: c) {
+                *data++ = static_cast<int32_t>(t);
+            }
+        } else /* constexpr */ {
+            for (const auto &t : c) {
+                const status_t status = writeData(t);
+                if (status != OK) return status;
+            }
+        }
+        return OK;
+    }
+
+    // readData function overloads.
+    // Implementation detail: Function overloading improves code readability over
+    // template overloading, but prevents readData<T> from being used for those types.
+
+    status_t readData(bool* t) const {
+        return readBool(t);  // this reads as int32_t
+    }
+
+    status_t readData(int8_t* t) const {
+        return readByte(t);  // this reads as int32_t
+    }
+
+    status_t readData(uint8_t* t) const {
+        return readByte(reinterpret_cast<int8_t*>(t));  // NOTE: this reads as int32_t
+    }
+
+    status_t readData(char16_t* t) const {
+        return readChar(t);  // this reads as int32_t
+    }
+
+    status_t readData(int32_t* t) const {
+        return readInt32(t);
+    }
+
+    status_t readData(uint32_t* t) const {
+        return readUint32(t);
+    }
+
+    status_t readData(int64_t* t) const {
+        return readInt64(t);
+    }
+
+    status_t readData(uint64_t* t) const {
+        return readUint64(t);
+    }
+
+    status_t readData(float* t) const {
+        return readFloat(t);
+    }
+
+    status_t readData(double* t) const {
+        return readDouble(t);
+    }
+
+    status_t readData(String16* t) const {
+        return readString16(t);
+    }
+
+    status_t readData(std::string* t) const {
+        return readUtf8FromUtf16(t);
+    }
+
+    status_t readData(base::unique_fd* t) const {
+        return readUniqueFileDescriptor(t);
+    }
+
+    status_t readData(Parcelable* t) const { // std::is_base_of_v<Parcelable, T>
+        // implemented here. readParcelable() calls this.
+        int32_t present;
+        status_t status = readData(&present);
+        if (status != OK) return status;
+        if (present != kNonNullParcelableFlag) return UNEXPECTED_NULL;
+        return t->readFromParcel(this);
+    }
+
+    // readData<T> template overloads.
+    // Written such that the first template type parameter is the complete type
+    // of the first function parameter.
+
+    template <typename T,
+            typename std::enable_if_t<std::is_enum_v<T>, bool> = true>
+    status_t readData(T* t) const {
+        // implemented here. readEnum() calls this.
+        using UT = std::underlying_type_t<T>;
+        return readData(reinterpret_cast<UT*>(t));
+    }
+
+    template <typename T,
+            typename std::enable_if_t<is_specialization_v<T, sp>, bool> = true>
+    status_t readData(T* t) const {
+        return readStrongBinder(t);  // Note: on null, returns failure
+    }
+
+
+    template <typename CT,
+            typename std::enable_if_t<is_parcel_nullable_type_v<CT>, bool> = true>
+    status_t readData(CT* c) const {
+        using T = first_template_type_t<CT>;  // The T in CT == C<T, ...>
+        const size_t startPos = dataPosition();
+        int32_t peek;
+        status_t status = readData(&peek);
+        if (status != OK) return status;
+        if constexpr (is_specialization_v<T, std::vector>
+                || std::is_same_v<T, String16>
+                || std::is_same_v<T, std::string>) {
+            if (peek == kNullVectorSize) {
+                c->reset();
+                return OK;
+            }
+        } else if constexpr (std::is_base_of_v<Parcelable, T>) {
+            if (peek == kNullParcelableFlag) {
+                c->reset();
+                return OK;
+            }
+        } else /* constexpr */ {  // could define this, but raise as error.
+            static_assert(dependent_false_v<CT>);
+        }
+        // create a new object.
+        if constexpr (is_specialization_v<CT, std::optional>) {
+            c->emplace();
+        } else /* constexpr */ {
+            T* const t = new (std::nothrow) T;  // contents read from Parcel below.
+            if (t == nullptr) return NO_MEMORY;
+            c->reset(t);
+        }
+        // rewind data ptr to reread (this is pretty quick), otherwise we could
+        // pass an optional argument to readData to indicate a peeked value.
+        setDataPosition(startPos);
+        if constexpr (is_specialization_v<T, std::vector>) {
+            return readData(&**c, READ_FLAG_SP_NULLABLE);  // nullable sp<> allowed now
+        } else {
+            return readData(&**c);
+        }
+    }
+
+    // std::vector special case, incorporating flags whether the vector
+    // accepts nullable sp<> to be read.
+    enum ReadFlags {
+        READ_FLAG_NONE = 0,
+        READ_FLAG_SP_NULLABLE = 1 << 0,
+    };
+
+    template <typename CT,
+            typename std::enable_if_t<is_specialization_v<CT, std::vector>, bool> = true>
+    status_t readData(CT* c, ReadFlags readFlags = READ_FLAG_NONE) const {
+        using T = first_template_type_t<CT>;  // The T in CT == C<T, ...>
+        int32_t size;
+        status_t status = readInt32(&size);
+        if (status != OK) return status;
+        if (size < 0) return UNEXPECTED_NULL;
+        const size_t availableBytes = dataAvail();  // coarse bound on vector size.
+        if (static_cast<size_t>(size) > availableBytes) return BAD_VALUE;
+        c->clear(); // must clear before resizing/reserving otherwise move ctors may be called.
+        if constexpr (is_pointer_equivalent_array_v<T>) {
+            // could consider POD without gaps and alignment of 4.
+            auto data = reinterpret_cast<const T*>(
+                    readInplace(static_cast<size_t>(size) * sizeof(T)));
+            if (data == nullptr) return BAD_VALUE;
+            c->insert(c->begin(), data, data + size); // insert should do a reserve().
+        } else if constexpr (std::is_same_v<T, bool>
+                || std::is_same_v<T, char16_t>) {
+            c->reserve(size); // avoids default initialization
+            auto data = reinterpret_cast<const int32_t*>(
+                    readInplace(static_cast<size_t>(size) * sizeof(int32_t)));
+            if (data == nullptr) return BAD_VALUE;
+            for (int32_t i = 0; i < size; ++i) {
+                c->emplace_back(static_cast<T>(*data++));
+            }
+        } else if constexpr (is_specialization_v<T, sp>) {
+            c->resize(size); // calls ctor
+            if (readFlags & READ_FLAG_SP_NULLABLE) {
+                for (auto &t : *c) {
+                    status = readNullableStrongBinder(&t);  // allow nullable
+                    if (status != OK) return status;
+                }
+            } else {
+                for (auto &t : *c) {
+                    status = readStrongBinder(&t);
+                    if (status != OK) return status;
+                }
+            }
+        } else /* constexpr */ {
+            c->resize(size); // calls ctor
+            for (auto &t : *c) {
+                status = readData(&t);
+                if (status != OK) return status;
+            }
+        }
+        return OK;
+    }
+
+    //-----------------------------------------------------------------------------
+    private:
 
     status_t            mError;
     uint8_t*            mData;
@@ -792,7 +1298,6 @@
 template<typename T>
 status_t Parcel::resizeOutVector(std::vector<T>* val) const {
     int32_t size;
-    // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
     status_t err = readInt32(&size);
     if (err != NO_ERROR) {
         return err;
@@ -808,7 +1313,6 @@
 template<typename T>
 status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const {
     int32_t size;
-    // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
     status_t err = readInt32(&size);
     if (err != NO_ERROR) {
         return err;
@@ -825,7 +1329,6 @@
 template<typename T>
 status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const {
     int32_t size;
-    // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
     status_t err = readInt32(&size);
     if (err != NO_ERROR) {
         return err;
@@ -840,61 +1343,6 @@
 }
 
 template<typename T>
-status_t Parcel::reserveOutVector(std::vector<T>* val, size_t* size) const {
-    int32_t read_size;
-    status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    if (read_size < 0) {
-        return UNEXPECTED_NULL;
-    }
-    *size = static_cast<size_t>(read_size);
-    val->reserve(*size);
-    return OK;
-}
-
-template<typename T>
-status_t Parcel::reserveOutVector(std::optional<std::vector<T>>* val, size_t* size) const {
-    int32_t read_size;
-    status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    if (read_size >= 0) {
-        *size = static_cast<size_t>(read_size);
-        val->emplace();
-        (*val)->reserve(*size);
-    } else {
-        val->reset();
-    }
-
-    return OK;
-}
-
-template<typename T>
-status_t Parcel::reserveOutVector(std::unique_ptr<std::vector<T>>* val,
-                                  size_t* size) const {
-    int32_t read_size;
-    status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    if (read_size >= 0) {
-        *size = static_cast<size_t>(read_size);
-        val->reset(new std::vector<T>());
-        (*val)->reserve(*size);
-    } else {
-        val->reset();
-    }
-
-    return OK;
-}
-
-template<typename T>
 status_t Parcel::readStrongBinder(sp<T>* val) const {
     sp<IBinder> tmp;
     status_t ret = readStrongBinder(&tmp);
@@ -926,422 +1374,6 @@
     return ret;
 }
 
-template<typename T, typename U>
-status_t Parcel::unsafeReadTypedVector(
-        std::vector<T>* val,
-        status_t(Parcel::*read_func)(U*) const) const {
-    int32_t size;
-    status_t status = this->readVectorSizeWithCoarseBoundCheck(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return UNEXPECTED_NULL;
-    }
-
-    if (val->max_size() < static_cast<size_t>(size)) {
-        return NO_MEMORY;
-    }
-
-    val->resize(static_cast<size_t>(size));
-
-    if (val->size() < static_cast<size_t>(size)) {
-        return NO_MEMORY;
-    }
-
-    for (auto& v: *val) {
-        status = (this->*read_func)(&v);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
-}
-
-template<typename T>
-status_t Parcel::readTypedVector(std::vector<T>* val,
-                                 status_t(Parcel::*read_func)(T*) const) const {
-    return unsafeReadTypedVector(val, read_func);
-}
-
-template<typename T>
-status_t Parcel::readNullableTypedVector(std::optional<std::vector<T>>* val,
-                                         status_t(Parcel::*read_func)(T*) const) const {
-    const size_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->emplace();
-
-    status = unsafeReadTypedVector(&**val, read_func);
-
-    if (status != OK) {
-       val->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
-                                         status_t(Parcel::*read_func)(T*) const) const {
-    const size_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->reset(new std::vector<T>());
-
-    status = unsafeReadTypedVector(val->get(), read_func);
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-template<typename T, typename U>
-status_t Parcel::unsafeWriteTypedVector(const std::vector<T>& val,
-                                        status_t(Parcel::*write_func)(U)) {
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
-
-    status_t status = this->writeInt32(static_cast<int32_t>(val.size()));
-
-    if (status != OK) {
-        return status;
-    }
-
-    for (const auto& item : val) {
-        status = (this->*write_func)(item);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
-}
-
-template<typename T>
-status_t Parcel::writeTypedVector(const std::vector<T>& val,
-                                  status_t(Parcel::*write_func)(const T&)) {
-    return unsafeWriteTypedVector(val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeTypedVector(const std::vector<T>& val,
-                                  status_t(Parcel::*write_func)(T)) {
-    return unsafeWriteTypedVector(val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::optional<std::vector<T>>& val,
-                                          status_t(Parcel::*write_func)(const T&)) {
-    if (!val) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                          status_t(Parcel::*write_func)(const T&)) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::optional<std::vector<T>>& val,
-                                          status_t(Parcel::*write_func)(T)) {
-    if (!val) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                          status_t(Parcel::*write_func)(T)) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::vector<T>* val) const {
-    return unsafeReadTypedVector<T, Parcelable>(val, &Parcel::readParcelable);
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::optional<std::vector<std::optional<T>>>* val) const {
-    const size_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->emplace();
-
-    using NullableT = std::optional<T>;
-    status = unsafeReadTypedVector<NullableT, NullableT>(&**val, &Parcel::readParcelable);
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const {
-    const size_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->reset(new std::vector<std::unique_ptr<T>>());
-
-    using NullableT = std::unique_ptr<T>;
-    status = unsafeReadTypedVector<NullableT, NullableT>(val->get(), &Parcel::readParcelable);
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelable(std::optional<T>* parcelable) const {
-    const size_t start = dataPosition();
-    int32_t present;
-    status_t status = readInt32(&present);
-    parcelable->reset();
-
-    if (status != OK || !present) {
-        return status;
-    }
-
-    setDataPosition(start);
-    parcelable->emplace();
-
-    status = readParcelable(&**parcelable);
-
-    if (status != OK) {
-        parcelable->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelable(std::unique_ptr<T>* parcelable) const {
-    const size_t start = dataPosition();
-    int32_t present;
-    status_t status = readInt32(&present);
-    parcelable->reset();
-
-    if (status != OK || !present) {
-        return status;
-    }
-
-    setDataPosition(start);
-    parcelable->reset(new T());
-
-    status = readParcelable(parcelable->get());
-
-    if (status != OK) {
-        parcelable->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::writeNullableParcelable(const std::optional<T>& parcelable) {
-    return writeRawNullableParcelable(parcelable ? &*parcelable : nullptr);
-}
-
-template<typename T>
-status_t Parcel::writeNullableParcelable(const std::unique_ptr<T>& parcelable) {
-    return writeRawNullableParcelable(parcelable.get());
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::vector<T>& val) {
-    return unsafeWriteTypedVector<T,const Parcelable&>(val, &Parcel::writeParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val) {
-    if (!val) {
-        return this->writeInt32(-1);
-    }
-
-    using NullableT = std::optional<T>;
-    return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable<T>);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    using NullableT = std::unique_ptr<T>;
-    return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    using NullableT = std::optional<T>;
-    return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
-status_t Parcel::writeEnum(const T& val) {
-    return writeInt32(static_cast<int32_t>(val));
-}
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
-status_t Parcel::writeEnum(const T& val) {
-    return writeInt64(static_cast<int64_t>(val));
-}
-
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::vector<T>& val) {
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::optional<std::vector<T>>& val) {
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::vector<T>& val) {
-    return writeTypedVector(val, &Parcel::writeEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::optional<std::vector<T>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeEnum);
-}
-
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
-status_t Parcel::readEnum(T* pArg) const {
-    return readInt32(reinterpret_cast<int32_t *>(pArg));
-}
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
-status_t Parcel::readEnum(T* pArg) const {
-    return readInt64(reinterpret_cast<int64_t *>(pArg));
-}
-
-template<typename T>
-inline status_t Parcel::readByteVectorInternal(std::vector<T>* val, size_t size) const {
-  // readByteVectorInternal expects a vector that has been reserved (but not
-  // resized) to have the provided size.
-  const T* data = reinterpret_cast<const T*>(readInplace(size));
-  if (!data) return BAD_VALUE;
-  val->clear();
-  val->insert(val->begin(), data, data+size);
-  return NO_ERROR;
-}
-
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::vector<T>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    return readByteVectorInternal(val, size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::optional<std::vector<T>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (!*val) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null Enum vector.
-        return OK;
-    }
-    return readByteVectorInternal(&**val, size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (val->get() == nullptr) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null Enum vector.
-        return OK;
-    }
-    return readByteVectorInternal(val->get(), size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::vector<T>* val) const {
-    return readTypedVector(val, &Parcel::readEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::optional<std::vector<T>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readEnum);
-}
-
 // ---------------------------------------------------------------------------
 
 inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
diff --git a/libs/binder/tests/binderParcelBenchmark.cpp b/libs/binder/tests/binderParcelBenchmark.cpp
index ec69c36..26c50eb 100644
--- a/libs/binder/tests/binderParcelBenchmark.cpp
+++ b/libs/binder/tests/binderParcelBenchmark.cpp
@@ -91,56 +91,56 @@
 
   Results on Crosshatch Pixel 3XL
 
-  #BM_BoolVector/1         40 ns      40 ns     17261011
-  #BM_BoolVector/2         46 ns      46 ns     15029619
-  #BM_BoolVector/4         65 ns      64 ns     10888021
-  #BM_BoolVector/8        114 ns     114 ns      6130937
-  #BM_BoolVector/16       179 ns     179 ns      3902462
-  #BM_BoolVector/32       328 ns     327 ns      2138812
-  #BM_BoolVector/64       600 ns     598 ns      1169414
-  #BM_BoolVector/128     1168 ns    1165 ns       601281
-  #BM_BoolVector/256     2288 ns    2281 ns       305737
-  #BM_BoolVector/512     4535 ns    4521 ns       154668
-  #BM_ByteVector/1         53 ns      52 ns     13212196
-  #BM_ByteVector/2         53 ns      53 ns     13194050
-  #BM_ByteVector/4         50 ns      50 ns     13768037
-  #BM_ByteVector/8         50 ns      50 ns     13890210
-  #BM_ByteVector/16        50 ns      50 ns     13897305
-  #BM_ByteVector/32        51 ns      51 ns     13679862
-  #BM_ByteVector/64        54 ns      53 ns     12988544
-  #BM_ByteVector/128       64 ns      64 ns     10921227
-  #BM_ByteVector/256       82 ns      81 ns      8542549
-  #BM_ByteVector/512      118 ns     118 ns      5862931
-  #BM_CharVector/1         32 ns      32 ns     21783579
-  #BM_CharVector/2         38 ns      38 ns     18200971
-  #BM_CharVector/4         53 ns      53 ns     13111785
-  #BM_CharVector/8         80 ns      80 ns      8698331
-  #BM_CharVector/16       159 ns     159 ns      4390738
-  #BM_CharVector/32       263 ns     262 ns      2667310
-  #BM_CharVector/64       486 ns     485 ns      1441118
-  #BM_CharVector/128      937 ns     934 ns       749006
-  #BM_CharVector/256     1848 ns    1843 ns       379537
-  #BM_CharVector/512     3650 ns    3639 ns       191713
-  #BM_Int32Vector/1        31 ns      31 ns     22104147
-  #BM_Int32Vector/2        38 ns      38 ns     18075471
-  #BM_Int32Vector/4        53 ns      52 ns     13249969
-  #BM_Int32Vector/8        80 ns      80 ns      8719798
-  #BM_Int32Vector/16      161 ns     160 ns      4350096
-  #BM_Int32Vector/32      271 ns     270 ns      2591896
-  #BM_Int32Vector/64      499 ns     498 ns      1406201
-  #BM_Int32Vector/128     948 ns     945 ns       740052
-  #BM_Int32Vector/256    1855 ns    1849 ns       379127
-  #BM_Int32Vector/512    3665 ns    3653 ns       191533
-  #BM_Int64Vector/1        31 ns      31 ns     22388370
-  #BM_Int64Vector/2        38 ns      38 ns     18300347
-  #BM_Int64Vector/4        53 ns      53 ns     13137818
-  #BM_Int64Vector/8        81 ns      81 ns      8599613
-  #BM_Int64Vector/16      167 ns     166 ns      4195953
-  #BM_Int64Vector/32      280 ns     280 ns      2499271
-  #BM_Int64Vector/64      523 ns     522 ns      1341380
-  #BM_Int64Vector/128     991 ns     988 ns       707437
-  #BM_Int64Vector/256    1940 ns    1934 ns       361704
-  #BM_Int64Vector/512    3843 ns    3831 ns       183204
+  #BM_BoolVector/1         44 ns      44 ns     15630626
+  #BM_BoolVector/2         54 ns      54 ns     12900340
+  #BM_BoolVector/4         73 ns      72 ns      9749841
+  #BM_BoolVector/8        107 ns     107 ns      6503326
+  #BM_BoolVector/16       186 ns     185 ns      3773627
+  #BM_BoolVector/32       337 ns     336 ns      2083877
+  #BM_BoolVector/64       607 ns     605 ns      1154113
+  #BM_BoolVector/128     1155 ns    1151 ns       608128
+  #BM_BoolVector/256     2259 ns    2253 ns       310973
+  #BM_BoolVector/512     4469 ns    4455 ns       157277
+  #BM_ByteVector/1         41 ns      41 ns     16837425
+  #BM_ByteVector/2         41 ns      41 ns     16820726
+  #BM_ByteVector/4         38 ns      38 ns     18217813
+  #BM_ByteVector/8         38 ns      38 ns     18290298
+  #BM_ByteVector/16        38 ns      38 ns     18117817
+  #BM_ByteVector/32        38 ns      38 ns     18172385
+  #BM_ByteVector/64        41 ns      41 ns     16950055
+  #BM_ByteVector/128       53 ns      53 ns     13170749
+  #BM_ByteVector/256       69 ns      69 ns     10113626
+  #BM_ByteVector/512      106 ns     106 ns      6561936
+  #BM_CharVector/1         38 ns      38 ns     18074831
+  #BM_CharVector/2         40 ns      40 ns     17206266
+  #BM_CharVector/4         50 ns      50 ns     13785944
+  #BM_CharVector/8         67 ns      67 ns     10223316
+  #BM_CharVector/16        96 ns      96 ns      7297285
+  #BM_CharVector/32       156 ns     155 ns      4484845
+  #BM_CharVector/64       277 ns     276 ns      2536003
+  #BM_CharVector/128      520 ns     518 ns      1347070
+  #BM_CharVector/256     1006 ns    1003 ns       695952
+  #BM_CharVector/512     1976 ns    1970 ns       354673
+  #BM_Int32Vector/1        41 ns      41 ns     16951262
+  #BM_Int32Vector/2        41 ns      41 ns     16916883
+  #BM_Int32Vector/4        41 ns      41 ns     16761373
+  #BM_Int32Vector/8        42 ns      42 ns     16553179
+  #BM_Int32Vector/16       43 ns      43 ns     16200362
+  #BM_Int32Vector/32       55 ns      54 ns     12724454
+  #BM_Int32Vector/64       70 ns      69 ns     10049223
+  #BM_Int32Vector/128     107 ns     107 ns      6525796
+  #BM_Int32Vector/256     179 ns     178 ns      3922563
+  #BM_Int32Vector/512     324 ns     323 ns      2160653
+  #BM_Int64Vector/1        41 ns      41 ns     16909470
+  #BM_Int64Vector/2        41 ns      41 ns     16740788
+  #BM_Int64Vector/4        42 ns      42 ns     16564197
+  #BM_Int64Vector/8        43 ns      42 ns     16284082
+  #BM_Int64Vector/16       54 ns      54 ns     12839474
+  #BM_Int64Vector/32       69 ns      69 ns     10011010
+  #BM_Int64Vector/64      107 ns     106 ns      6557956
+  #BM_Int64Vector/128     177 ns     177 ns      3925618
+  #BM_Int64Vector/256     324 ns     323 ns      2163321
+  #BM_Int64Vector/512     613 ns     611 ns      1140418
 */
 
 static void BM_BoolVector(benchmark::State& state) {