diff options
Diffstat (limited to 'libs/binder/include/binder/Parcel.h')
-rw-r--r-- | libs/binder/include/binder/Parcel.h | 1139 |
1 files changed, 411 insertions, 728 deletions
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 5aaaa0c3d2..c1f64fb541 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#pragma once +#ifndef ANDROID_PARCEL_H +#define ANDROID_PARCEL_H #include <map> // for legacy reasons #include <string> @@ -33,31 +34,26 @@ #include <binder/Parcelable.h> #ifdef BINDER_IPC_32BIT -//NOLINTNEXTLINE(google-runtime-int) b/173188702 typedef unsigned int binder_size_t; #else -//NOLINTNEXTLINE(google-runtime-int) b/173188702 typedef unsigned long long binder_size_t; #endif -struct flat_binder_object; // --------------------------------------------------------------------------- namespace android { template <typename T> class Flattenable; template <typename T> class LightFlattenable; +struct flat_binder_object; class IBinder; class IPCThreadState; class ProcessState; -class RpcSession; class String8; class TextOutput; class Parcel { friend class IPCThreadState; - friend class RpcState; - public: class ReadableBlob; class WritableBlob; @@ -88,30 +84,8 @@ public: bool hasFileDescriptors() const; - // Zeros data when reallocating. Other mitigations may be added - // in the future. - // - // WARNING: some read methods may make additional copies of data. - // In order to verify this, heap dumps should be used. - void markSensitive() const; - - // For a 'data' Parcel, this should mark the Parcel as being prepared for a - // transaction on this specific binder object. Based on this, the format of - // the wire binder protocol may change (data is written differently when it - // is for an RPC transaction). - void markForBinder(const sp<IBinder>& binder); - - // Whenever possible, markForBinder should be preferred. This method is - // called automatically on reply Parcels for RPC transactions. - void markForRpc(const sp<RpcSession>& session); - - // Whether this Parcel is written for RPC transactions (after calls to - // markForBinder or markForRpc). - bool isForRpc() const; - - // Writes the IPC/RPC header. + // Writes the RPC header. status_t writeInterfaceToken(const String16& interface); - status_t writeInterfaceToken(const char16_t* str, size_t len); // Parses the RPC header, returning true if the interface name // in the header matches the expected interface from the caller. @@ -147,8 +121,7 @@ public: status_t writeString8(const String8& str); status_t writeString8(const char* str, size_t len); status_t writeString16(const String16& str); - status_t writeString16(const std::optional<String16>& str); - status_t writeString16(const std::unique_ptr<String16>& str) __attribute__((deprecated("use std::optional version instead"))); + status_t writeString16(const std::unique_ptr<String16>& str); status_t writeString16(const char16_t* str, size_t len); status_t writeStrongBinder(const sp<IBinder>& val); status_t writeInt32Array(size_t len, const int32_t *val); @@ -159,95 +132,57 @@ public: // Take a UTF8 encoded string, convert to UTF16, write it to the parcel. status_t writeUtf8AsUtf16(const std::string& str); - status_t writeUtf8AsUtf16(const std::optional<std::string>& str); - status_t writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) __attribute__((deprecated("use std::optional version instead"))); + status_t writeUtf8AsUtf16(const std::unique_ptr<std::string>& str); - status_t writeByteVector(const std::optional<std::vector<int8_t>>& val); - status_t writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val) __attribute__((deprecated("use std::optional version instead"))); + status_t writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val); status_t writeByteVector(const std::vector<int8_t>& val); - status_t writeByteVector(const std::optional<std::vector<uint8_t>>& val); - status_t writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val) __attribute__((deprecated("use std::optional version instead"))); + status_t writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val); status_t writeByteVector(const std::vector<uint8_t>& val); - status_t writeInt32Vector(const std::optional<std::vector<int32_t>>& val); - status_t writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val) __attribute__((deprecated("use std::optional version instead"))); + status_t writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val); status_t writeInt32Vector(const std::vector<int32_t>& val); - status_t writeInt64Vector(const std::optional<std::vector<int64_t>>& val); - status_t writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val) __attribute__((deprecated("use std::optional version instead"))); + status_t writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val); status_t writeInt64Vector(const std::vector<int64_t>& val); - status_t writeUint64Vector(const std::optional<std::vector<uint64_t>>& val); - status_t writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val) __attribute__((deprecated("use std::optional version instead"))); + status_t writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val); status_t writeUint64Vector(const std::vector<uint64_t>& val); - status_t writeFloatVector(const std::optional<std::vector<float>>& val); - status_t writeFloatVector(const std::unique_ptr<std::vector<float>>& val) __attribute__((deprecated("use std::optional version instead"))); + status_t writeFloatVector(const std::unique_ptr<std::vector<float>>& val); status_t writeFloatVector(const std::vector<float>& val); - status_t writeDoubleVector(const std::optional<std::vector<double>>& val); - status_t writeDoubleVector(const std::unique_ptr<std::vector<double>>& val) __attribute__((deprecated("use std::optional version instead"))); + status_t writeDoubleVector(const std::unique_ptr<std::vector<double>>& val); status_t writeDoubleVector(const std::vector<double>& val); - status_t writeBoolVector(const std::optional<std::vector<bool>>& val); - status_t writeBoolVector(const std::unique_ptr<std::vector<bool>>& val) __attribute__((deprecated("use std::optional version instead"))); + status_t writeBoolVector(const std::unique_ptr<std::vector<bool>>& val); status_t writeBoolVector(const std::vector<bool>& val); - status_t writeCharVector(const std::optional<std::vector<char16_t>>& val); - status_t writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val) __attribute__((deprecated("use std::optional version instead"))); + status_t writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val); status_t writeCharVector(const std::vector<char16_t>& val); status_t writeString16Vector( - const std::optional<std::vector<std::optional<String16>>>& val); - status_t writeString16Vector( - const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val) __attribute__((deprecated("use std::optional version instead"))); + const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val); status_t writeString16Vector(const std::vector<String16>& val); status_t writeUtf8VectorAsUtf16Vector( - const std::optional<std::vector<std::optional<std::string>>>& val); - status_t writeUtf8VectorAsUtf16Vector( - const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) __attribute__((deprecated("use std::optional version instead"))); + const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val); status_t writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val); - status_t writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val); - status_t writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val) __attribute__((deprecated("use std::optional version instead"))); + status_t writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val); status_t writeStrongBinderVector(const std::vector<sp<IBinder>>& val); // 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) - { 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) - { return writeData(val); } + status_t writeEnumVector(const std::vector<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> = 0> - status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead"))) - { return writeData(val); } + status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& 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) - { return writeData(val); } + status_t writeEnumVector(const std::vector<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> = 0> - 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"))) - { return writeData(val); } + status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val); template<typename T> - 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"))) - { 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"))) - { return writeData(val); } + status_t writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val); template<typename T> - status_t writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val) - { return writeData(val); } + status_t writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val); template<typename T> - status_t writeParcelableVector(const std::vector<T>& val) - { return writeData(val); } + status_t writeParcelableVector(const std::vector<T>& val); template<typename T> - 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"))) - { return writeData(parcelable); } + status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable); status_t writeParcelable(const Parcelable& parcelable); @@ -260,9 +195,7 @@ public: template<typename T> status_t writeVectorSize(const std::vector<T>& val); template<typename T> - status_t writeVectorSize(const std::optional<std::vector<T>>& val); - template<typename T> - status_t writeVectorSize(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead"))); + status_t writeVectorSize(const std::unique_ptr<std::vector<T>>& val); // Place a native_handle into the parcel (the native_handle's file- // descriptors are dup'ed, so it is safe to delete the native_handle @@ -297,9 +230,7 @@ public: // Place a vector of file desciptors into the parcel. Each descriptor is // dup'd as in writeDupFileDescriptor status_t writeUniqueFileDescriptorVector( - const std::optional<std::vector<base::unique_fd>>& val); - status_t writeUniqueFileDescriptorVector( - const std::unique_ptr<std::vector<base::unique_fd>>& val) __attribute__((deprecated("use std::optional version instead"))); + const std::unique_ptr<std::vector<base::unique_fd>>& val); status_t writeUniqueFileDescriptorVector( const std::vector<base::unique_fd>& val); @@ -337,6 +268,8 @@ public: status_t readFloat(float *pArg) const; double readDouble() const; status_t readDouble(double *pArg) const; + intptr_t readIntPtr() const; + status_t readIntPtr(intptr_t *pArg) const; bool readBool() const; status_t readBool(bool *pArg) const; char16_t readChar() const; @@ -346,8 +279,7 @@ public: // Read a UTF16 encoded string, convert to UTF8 status_t readUtf8FromUtf16(std::string* str) const; - status_t readUtf8FromUtf16(std::optional<std::string>* str) const; - status_t readUtf8FromUtf16(std::unique_ptr<std::string>* str) const __attribute__((deprecated("use std::optional version instead"))); + status_t readUtf8FromUtf16(std::unique_ptr<std::string>* str) const; const char* readCString() const; String8 readString8() const; @@ -355,104 +287,68 @@ public: const char* readString8Inplace(size_t* outLen) const; String16 readString16() const; status_t readString16(String16* pArg) const; - status_t readString16(std::optional<String16>* pArg) const; - status_t readString16(std::unique_ptr<String16>* pArg) const __attribute__((deprecated("use std::optional version instead"))); + status_t readString16(std::unique_ptr<String16>* pArg) const; const char16_t* readString16Inplace(size_t* outLen) const; sp<IBinder> readStrongBinder() const; status_t readStrongBinder(sp<IBinder>* val) const; status_t readNullableStrongBinder(sp<IBinder>* val) const; + // 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 - { 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"))) - { return readData(val); } + status_t readEnumVector(std::vector<T>* val) const; 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 - { return readData(val); } + status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const; // 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 - { return readData(val); } + status_t readEnumVector(std::vector<T>* val) const; 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"))) - { 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 - { return readData(val); } + status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const; template<typename T> status_t readParcelableVector( - std::optional<std::vector<std::optional<T>>>* val) const - { return readData(val); } + std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const; template<typename T> - status_t readParcelableVector( - 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 - { return readData(val); } + status_t readParcelableVector(std::vector<T>* val) const; status_t readParcelable(Parcelable* parcelable) const; template<typename T> - 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"))) - { return readData(parcelable); } + status_t readParcelable(std::unique_ptr<T>* parcelable) const; - // 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; template<typename T> status_t readNullableStrongBinder(sp<T>* val) const; - status_t readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const; - status_t readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const __attribute__((deprecated("use std::optional version instead"))); + status_t readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const; status_t readStrongBinderVector(std::vector<sp<IBinder>>* val) const; - status_t readByteVector(std::optional<std::vector<int8_t>>* val) const; - status_t readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const __attribute__((deprecated("use std::optional version instead"))); + status_t readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const; status_t readByteVector(std::vector<int8_t>* val) const; - status_t readByteVector(std::optional<std::vector<uint8_t>>* val) const; - status_t readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const __attribute__((deprecated("use std::optional version instead"))); + status_t readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const; status_t readByteVector(std::vector<uint8_t>* val) const; - status_t readInt32Vector(std::optional<std::vector<int32_t>>* val) const; - status_t readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const __attribute__((deprecated("use std::optional version instead"))); + status_t readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const; status_t readInt32Vector(std::vector<int32_t>* val) const; - status_t readInt64Vector(std::optional<std::vector<int64_t>>* val) const; - status_t readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const __attribute__((deprecated("use std::optional version instead"))); + status_t readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const; status_t readInt64Vector(std::vector<int64_t>* val) const; - status_t readUint64Vector(std::optional<std::vector<uint64_t>>* val) const; - status_t readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const __attribute__((deprecated("use std::optional version instead"))); + status_t readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const; status_t readUint64Vector(std::vector<uint64_t>* val) const; - status_t readFloatVector(std::optional<std::vector<float>>* val) const; - status_t readFloatVector(std::unique_ptr<std::vector<float>>* val) const __attribute__((deprecated("use std::optional version instead"))); + status_t readFloatVector(std::unique_ptr<std::vector<float>>* val) const; status_t readFloatVector(std::vector<float>* val) const; - status_t readDoubleVector(std::optional<std::vector<double>>* val) const; - status_t readDoubleVector(std::unique_ptr<std::vector<double>>* val) const __attribute__((deprecated("use std::optional version instead"))); + status_t readDoubleVector(std::unique_ptr<std::vector<double>>* val) const; status_t readDoubleVector(std::vector<double>* val) const; - status_t readBoolVector(std::optional<std::vector<bool>>* val) const; - status_t readBoolVector(std::unique_ptr<std::vector<bool>>* val) const __attribute__((deprecated("use std::optional version instead"))); + status_t readBoolVector(std::unique_ptr<std::vector<bool>>* val) const; status_t readBoolVector(std::vector<bool>* val) const; - status_t readCharVector(std::optional<std::vector<char16_t>>* val) const; - status_t readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const __attribute__((deprecated("use std::optional version instead"))); + status_t readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const; status_t readCharVector(std::vector<char16_t>* val) const; status_t readString16Vector( - std::optional<std::vector<std::optional<String16>>>* val) const; - status_t readString16Vector( - std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const __attribute__((deprecated("use std::optional version instead"))); + std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const; status_t readString16Vector(std::vector<String16>* val) const; status_t readUtf8VectorFromUtf16Vector( - std::optional<std::vector<std::optional<std::string>>>* val) const; - status_t readUtf8VectorFromUtf16Vector( - std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const __attribute__((deprecated("use std::optional version instead"))); + std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const; status_t readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const; template<typename T> @@ -461,13 +357,15 @@ 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; + status_t resizeOutVector(std::unique_ptr<std::vector<T>>* val) const; + template<typename T> + status_t reserveOutVector(std::vector<T>* val, size_t* size) const; template<typename T> - status_t resizeOutVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead"))); + status_t reserveOutVector(std::unique_ptr<std::vector<T>>* val, + size_t* size) const; // Like Parcel.java's readExceptionCode(). Reads the first int32 // off of a Parcel's header, returning 0 or the negative error @@ -501,9 +399,7 @@ public: // Retrieve a vector of smart file descriptors from the parcel. status_t readUniqueFileDescriptorVector( - std::optional<std::vector<base::unique_fd>>* val) const; - status_t readUniqueFileDescriptorVector( - std::unique_ptr<std::vector<base::unique_fd>>* val) const __attribute__((deprecated("use std::optional version instead"))); + std::unique_ptr<std::vector<base::unique_fd>>* val) const; status_t readUniqueFileDescriptorVector( std::vector<base::unique_fd>* val) const; @@ -525,21 +421,27 @@ public: // uid. uid_t readCallingWorkSourceUid() const; - void print(TextOutput& to, uint32_t flags = 0) const; - private: typedef void (*release_func)(Parcel* parcel, const uint8_t* data, size_t dataSize, - const binder_size_t* objects, size_t objectsSize); - + const binder_size_t* objects, size_t objectsSize, + void* cookie); + uintptr_t ipcData() const; size_t ipcDataSize() const; uintptr_t ipcObjects() const; size_t ipcObjectsCount() const; void ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsCount, - release_func relFunc); + release_func relFunc, void* relCookie); + +public: + void print(TextOutput& to, uint32_t flags = 0) const; +private: + Parcel(const Parcel& o); + Parcel& operator=(const Parcel& o); + status_t finishWrite(size_t len); void releaseObjects(); void acquireObjects(); @@ -553,10 +455,10 @@ private: void initState(); void scanForFds() const; status_t validateReadData(size_t len) const; - void updateWorkSourceRequestHeaderPosition() const; - status_t finishFlattenBinder(const sp<IBinder>& binder); + status_t finishFlattenBinder(const sp<IBinder>& binder, + const flat_binder_object& flat); status_t finishUnflattenBinder(const sp<IBinder>& binder, sp<IBinder>* out) const; status_t flattenBinder(const sp<IBinder>& binder); status_t unflattenBinder(sp<IBinder>* out) const; @@ -572,544 +474,44 @@ private: status_t writeRawNullableParcelable(const Parcelable* parcelable); - //----------------------------------------------------------------------------- - // 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. - - // --- 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> - - 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 - } + 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); - 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); - } + 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; - 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; - } + status_t writeByteVectorInternal(const int8_t* data, size_t size); + template<typename T> + status_t readByteVectorInternal(std::vector<T>* val, size_t size) const; - //----------------------------------------------------------------------------- - private: + 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::unique_ptr<std::vector<T>>* val, + status_t(Parcel::*read_func)(T*) const) const; + 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::unique_ptr<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)(T)); + 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)); status_t mError; uint8_t* mData; @@ -1123,20 +525,14 @@ private: mutable bool mObjectsSorted; mutable bool mRequestHeaderPresent; - mutable size_t mWorkSourceRequestHeaderPosition; mutable bool mFdsKnown; mutable bool mHasFds; bool mAllowFds; - // if this parcelable is involved in a secure transaction, force the - // data to be overridden with zero when deallocated - mutable bool mDeallocZero; - release_func mOwner; - - sp<RpcSession> mSession; + void* mOwnerCookie; class Blob { public: @@ -1295,15 +691,6 @@ status_t Parcel::writeVectorSize(const std::vector<T>& val) { } template<typename T> -status_t Parcel::writeVectorSize(const std::optional<std::vector<T>>& val) { - if (!val) { - return writeInt32(-1); - } - - return writeVectorSize(*val); -} - -template<typename T> status_t Parcel::writeVectorSize(const std::unique_ptr<std::vector<T>>& val) { if (!val) { return writeInt32(-1); @@ -1328,7 +715,7 @@ status_t Parcel::resizeOutVector(std::vector<T>* val) const { } template<typename T> -status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const { +status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const { int32_t size; status_t err = readInt32(&size); if (err != NO_ERROR) { @@ -1337,23 +724,43 @@ status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const { val->reset(); if (size >= 0) { - val->emplace(size_t(size)); + val->reset(new std::vector<T>(size_t(size))); } return OK; } template<typename T> -status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const { - int32_t size; - status_t err = readInt32(&size); +status_t Parcel::reserveOutVector(std::vector<T>* val, size_t* size) const { + int32_t read_size; + status_t err = readInt32(&read_size); if (err != NO_ERROR) { return err; } - val->reset(); - if (size >= 0) { - val->reset(new std::vector<T>(size_t(size))); + 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::unique_ptr<std::vector<T>>* val, + size_t* size) const { + int32_t read_size; + status_t err = readInt32(&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; @@ -1391,6 +798,280 @@ 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->readInt32(&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::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 = readInt32(&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::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::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::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const { + const size_t start = dataPosition(); + int32_t size; + status_t status = readInt32(&size); + val->reset(); + + if (status != OK || size < 0) { + return status; + } + + setDataPosition(start); + val->reset(new std::vector<std::unique_ptr<T>>()); + + status = unsafeReadTypedVector(val->get(), &Parcel::readParcelable<T>); + + if (status != OK) { + val->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::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::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); + } + + return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable<T>); +} + +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::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::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::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::unique_ptr<std::vector<T>>* val) const { + return readNullableTypedVector(val, &Parcel::readEnum); +} + // --------------------------------------------------------------------------- inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel) @@ -1402,3 +1083,5 @@ inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel) } // namespace android // --------------------------------------------------------------------------- + +#endif // ANDROID_PARCEL_H |