diff options
-rw-r--r-- | libs/binder/Parcel.cpp | 710 | ||||
-rw-r--r-- | libs/binder/include/binder/Parcel.h | 1140 | ||||
-rw-r--r-- | libs/binder/tests/binderParcelBenchmark.cpp | 100 |
3 files changed, 740 insertions, 1210 deletions
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index b9d00fe7ea..1a4ede1940 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -769,200 +769,116 @@ status_t Parcel::writeUtf8AsUtf16(const std::string& str) { 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::writeByteVectorInternal(const int8_t* data, size_t size) { - if (size > std::numeric_limits<int32_t>::max()) { - return BAD_VALUE; - } - - status_t status = writeInt32(size); - if (status != OK) { - return status; - } - - 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::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::writeString16(const std::optional<String16>& str) { return writeData(str); } +status_t Parcel::writeString16(const std::unique_ptr<String16>& str) { return writeData(str); } + +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); } + +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::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::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) { - return writeTypedVector(val, &Parcel::writeUtf8AsUtf16); -} +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 @@ status_t Parcel::writeString8(const char* str, size_t len) 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 @@ status_t Parcel::writeStrongBinder(const sp<IBinder>& val) 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 @@ status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) { 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 @@ status_t Parcel::writeUniqueFileDescriptor(const base::unique_fd& fd) { 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 @@ data_unsorted: 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 @@ restart_write: 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 @@ status_t Parcel::readUtf8FromUtf16(std::string* str) const { 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 @@ String16 Parcel::readString16() const 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 @@ sp<IBinder> Parcel::readStrongBinder() const 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 @@ status_t Parcel::readUniqueParcelFileDescriptor(base::unique_fd* val) const 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 54c49e4c0c..7b298f5b39 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -190,34 +190,47 @@ public: // 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 @@ public: // 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 @@ public: 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 @@ private: 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 @@ private: 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} + + // --- 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> - status_t writeByteVectorInternal(const int8_t* data, size_t size); - template<typename T> - status_t readByteVectorInternal(std::vector<T>* val, size_t size) const; + template <typename Test, template <typename...> class Ref> + struct is_specialization : std::false_type {}; - 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 <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 @@ status_t Parcel::writeVectorSize(const std::unique_ptr<std::vector<T>>& val) { 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 @@ status_t Parcel::resizeOutVector(std::vector<T>* val) const { 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 @@ status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const { 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 @@ status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const { } 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 @@ status_t Parcel::readNullableStrongBinder(sp<T>* val) const { 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 ec69c367ba..26c50ebb57 100644 --- a/libs/binder/tests/binderParcelBenchmark.cpp +++ b/libs/binder/tests/binderParcelBenchmark.cpp @@ -91,56 +91,56 @@ static void BM_ParcelVector(benchmark::State& state) { 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) { |