/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2020, Google Inc. * * ipa_data_serializer.cpp - Image Processing Algorithm data serializer */ #include "libcamera/internal/ipa_data_serializer.h" #include "libcamera/internal/log.h" /** * \file ipa_data_serializer.h * \brief IPA Data Serializer */ namespace libcamera { LOG_DEFINE_CATEGORY(IPADataSerializer) /** * \class IPADataSerializer * \brief IPA Data Serializer * * Static template class that provides functions for serializing and * deserializing IPA data. * * \todo Switch to Span instead of byte and fd vector * * \todo Harden the vector and map deserializer * * \todo For FileDescriptors, instead of storing a validity flag, store an * index into the fd array. This will allow us to use views instead of copying. */ namespace { /** * \fn template void appendPOD(std::vector &vec, T val) * \brief Append POD to end of byte vector, in little-endian order * \tparam T Type of POD to append * \param[in] vec Byte vector to append to * \param[in] val Value to append * * This function is meant to be used by the IPA data serializer, and the * generated IPA proxies. */ /** * \fn template T readPOD(std::vector::iterator it, size_t pos, * std::vector::iterator end) * \brief Read POD from byte vector, in little-endian order * \tparam T Type of POD to read * \param[in] it Iterator of byte vector to read from * \param[in] pos Index in byte vector to read from * \param[in] end Iterator marking end of byte vector * * This function is meant to be used by the IPA data serializer, and the * generated IPA proxies. * * If the \a pos plus the byte-width of the desired POD is past \a end, it is * a fata error will occur, as it means there is insufficient data for * deserialization, which should never happen. * * \return The POD read from \a it at index \a pos */ /** * \fn template T readPOD(std::vector &vec, size_t pos) * \brief Read POD from byte vector, in little-endian order * \tparam T Type of POD to read * \param[in] vec Byte vector to read from * \param[in] pos Index in vec to start reading from * * This function is meant to be used by the IPA data serializer, and the * generated IPA proxies. * * If the \a pos plus the byte-width of the desired POD is past the end of * \a vec, a fatal error will occur, as it means there is insufficient data * for deserialization, which should never happen. * * \return The POD read from \a vec at index \a pos */ } /* namespace */ /** * \fn template IPADataSerializer::serialize( * T data, * ControlSerializer *cs = nullptr) * \brief Serialize an object into byte vector and fd vector * \tparam T Type of object to serialize * \param[in] data Object to serialize * \param[in] cs ControlSerializer * * \a cs is only necessary if the object type \a T or its members contain * ControlList or ControlInfoMap. * * \return Tuple of byte vector and fd vector, that is the serialized form * of \a data */ /** * \fn template IPADataSerializer::deserialize( * const std::vector &data, * ControlSerializer *cs = nullptr) * \brief Deserialize byte vector into an object * \tparam T Type of object to deserialize to * \param[in] data Byte vector to deserialize from * \param[in] cs ControlSerializer * * This version of deserialize() can be used if the object type \a T and its * members don't have any FileDescriptor. * * \a cs is only necessary if the object type \a T or its members contain * ControlList or ControlInfoMap. * * \return The deserialized object */ /** * \fn template IPADataSerializer::deserialize( * std::vector::const_iterator dataBegin, * std::vector::const_iterator dataEnd, * ControlSerializer *cs = nullptr) * \brief Deserialize byte vector into an object * \tparam T Type of object to deserialize to * \param[in] dataBegin Begin iterator of byte vector to deserialize from * \param[in] dataEnd End iterator of byte vector to deserialize from * \param[in] cs ControlSerializer * * This version of deserialize() can be used if the object type \a T and its * members don't have any FileDescriptor. * * \a cs is only necessary if the object type \a T or its members contain * ControlList or ControlInfoMap. * * \return The deserialized object */ /** * \fn template IPADataSerializer::deserialize( * const std::vector &data, * const std::vector &fds, * ControlSerializer *cs = nullptr) * \brief Deserialize byte vector and fd vector into an object * \tparam T Type of object to deserialize to * \param[in] data Byte vector to deserialize from * \param[in] fds Fd vector to deserialize from * \param[in] cs ControlSerializer * * This version of deserialize() (or the iterator version) must be used if * the object type \a T or its members contain FileDescriptor. * * \a cs is only necessary if the object type \a T or its members contain * ControlList or ControlInfoMap. * * \return The deserialized object */ /** * \fn template IPADataSerializer::deserialize( * std::vector::const_iterator dataBegin, * std::vector::const_iterator dataEnd, * std::vector::const_iterator fdsBegin, * std::vector::const_iterator fdsEnd, * ControlSerializer *cs = nullptr) * \brief Deserialize byte vector and fd vector into an object * \tparam T Type of object to deserialize to * \param[in] dataBegin Begin iterator of byte vector to deserialize from * \param[in] dataEnd End iterator of byte vector to deserialize from * \param[in] fdsBegin Begin iterator of fd vector to deserialize from * \param[in] fdsEnd End iterator of fd vector to deserialize from * \param[in] cs ControlSerializer * * This version of deserialize() (or the vector version) must be used if * the object type \a T or its members contain FileDescriptor. * * \a cs is only necessary if the object type \a T or its members contain * ControlList or ControlInfoMap. * * \return The deserialized object */ #ifndef __DOXYGEN__ #define DEFINE_POD_SERIALIZER(type) \ \ template<> \ std::tuple, std::vector> \ IPADataSerializer::serialize(const type &data, \ [[maybe_unused]] ControlSerializer *cs) \ { \ std::vector dataVec; \ dataVec.reserve(sizeof(type)); \ appendPOD(dataVec, data); \ \ return { dataVec, {} }; \ } \ \ template<> \ type IPADataSerializer::deserialize(std::vector::const_iterator dataBegin, \ std::vector::const_iterator dataEnd, \ [[maybe_unused]] ControlSerializer *cs) \ { \ return readPOD(dataBegin, 0, dataEnd); \ } \ \ template<> \ type IPADataSerializer::deserialize(const std::vector &data, \ ControlSerializer *cs) \ { \ return deserialize(data.cbegin(), data.end(), cs); \ } \ \ template<> \ type IPADataSerializer::deserialize(const std::vector &data, \ [[maybe_unused]] const std::vector &fds, \ ControlSerializer *cs) \ { \ return deserialize(data.cbegin(), data.end(), cs); \ } \ \ template<> \ type IPADataSerializer::deserialize(std::vector::const_iterator dataBegin, \ std::vector::const_iterator dataEnd, \ [[maybe_unused]] std::vector::const_iterator fdsBegin, \ [[maybe_unused]] std::vector::const_iterator fdsEnd, \ ControlSerializer *cs) \ { \ return deserialize(dataBegin, dataEnd, cs); \ } DEFINE_POD_SERIALIZER(bool) DEFINE_POD_SERIALIZER(uint8_t) DEFINE_POD_SERIALIZER(uint16_t) DEFINE_POD_SERIALIZER(uint32_t) DEFINE_POD_SERIALIZER(uint64_t) DEFINE_POD_SERIALIZER(int8_t) DEFINE_POD_SERIALIZER(int16_t) DEFINE_POD_SERIALIZER(int32_t) DEFINE_POD_SERIALIZER(int64_t) DEFINE_POD_SERIALIZER(float) DEFINE_POD_SERIALIZER(double) /* * Strings are serialized simply by converting by {string.cbegin(), string.end()}. * The size of the string is recorded by the container (struct, vector, map, or * function parameter serdes). */ template<> std::tuple, std::vector> IPADataSerializer::serialize(const std::string &data, [[maybe_unused]] ControlSerializer *cs) { return { { data.cbegin(), data.end() }, {} }; } template<> std::string IPADataSerializer::deserialize(const std::vector &data, [[maybe_unused]] ControlSerializer *cs) { return { data.cbegin(), data.cend() }; } template<> std::string IPADataSerializer::deserialize(std::vector::const_iterator dataBegin, std::vector::const_iterator dataEnd, [[maybe_unused]] ControlSerializer *cs) { return { dataBegin, dataEnd }; } template<> std::string IPADataSerializer::deserialize(const std::vector &data, [[maybe_unused]] const std::vector &fds, [[maybe_unused]] ControlSerializer *cs) { return { data.cbegin(), data.cend() }; } template<> std::string IPADataSerializer::deserialize(std::vector::const_iterator dataBegin, std::vector::const_iterator dataEnd, [[maybe_unused]] std::vector::const_iterator fdsBegin, [[maybe_unused]] std::vector::const_iterator fdsEnd, [[maybe_unused]] ControlSerializer *cs) { return { dataBegin, dataEnd }; } /* * ControlList is serialized as: * * 4 bytes - uint32_t Size of serialized ControlInfoMap, in bytes * 4 bytes - uint32_t Size of serialized ControlList, in bytes * X bytes - Serialized ControlInfoMap (using ControlSerializer) * X bytes - Serialized ControlList (using ControlSerializer) * * If data.infoMap() is nullptr, then the default controls::controls will * be used. The serialized ControlInfoMap will have zero length. */ template<> std::tuple, std::vector> IPADataSerializer::serialize(const ControlList &data, ControlSerializer *cs) { if (!cs) LOG(IPADataSerializer, Fatal) << "ControlSerializer not provided for serialization of ControlList"; size_t size; std::vector infoData; int ret; /* * \todo Revisit this opportunistic serialization of the * ControlInfoMap, as it could be fragile */ if (data.infoMap() && !cs->isCached(*data.infoMap())) { size = cs->binarySize(*data.infoMap()); infoData.resize(size); ByteStreamBuffer buffer(infoData.data(), infoData.size()); ret = cs->serialize(*data.infoMap(), buffer); if (ret < 0 || buffer.overflow()) { LOG(IPADataSerializer, Error) << "Failed to serialize ControlList's ControlInfoMap"; return { {}, {} }; } } size = cs->binarySize(data); std::vector listData(size); ByteStreamBuffer buffer(listData.data(), listData.size()); ret = cs->serialize(data, buffer); if (ret < 0 || buffer.overflow()) { LOG(IPADataSerializer, Error) << "Failed to serialize ControlList"; return { {}, {} }; } std::vector dataVec; dataVec.reserve(8 + infoData.size() + listData.size()); appendPOD(dataVec, infoData.size()); appendPOD(dataVec, listData.size()); dataVec.insert(dataVec.end(), infoData.begin(), infoData.end()); dataVec.insert(dataVec.end(), listData.begin(), listData.end()); return { dataVec, {} }; } template<> ControlList IPADataSerializer::deserialize(std::vector::const_iterator dataBegin, std::vector::const_iterator dataEnd, ControlSerializer *cs) { if (!cs) LOG(IPADataSerializer, Fatal) << "ControlSerializer not provided for deserialization of ControlList"; if (std::distance(dataBegin, dataEnd) < 8) return {}; uint32_t infoDataSize = readPOD(dataBegin, 0, dataEnd); uint32_t listDataSize = readPOD(dataBegin, 4, dataEnd); std::vector::const_iterator it = dataBegin + 8; if (infoDataSize + listDataSize < infoDataSize || static_cast(std::distance(it, dataEnd)) < infoDataSize + listDataSize) return {}; if (infoDataSize > 0) { ByteStreamBuffer buffer(&*it, infoDataSize); ControlInfoMap map = cs->deserialize(buffer); /* It's fine if map is empty. */ if (buffer.overflow()) { LOG(IPADataSerializer, Error) << "Failed to deserialize ControlLists's ControlInfoMap: buffer overflow"; return ControlList(); } } it += infoDataSize; ByteStreamBuffer buffer(&*it, listDataSize); ControlList list = cs->deserialize(buffer); if (buffer.overflow()) LOG(IPADataSerializer, Error) << "Failed to deserialize ControlList: buffer overflow"; return list; } template<> ControlList IPADataSerializer::deserialize(const std::vector &data, ControlSerializer *cs) { return deserialize(data.cbegin(), data.end(), cs); } template<> ControlList IPADataSerializer::deserialize(const std::vector &data, [[maybe_unused]] const std::vector &fds, ControlSerializer *cs) { return deserialize(data.cbegin(), data.end(), cs); } template<> ControlList IPADataSerializer::deserialize(std::vector::const_iterator dataBegin, std::vector::const_iterator dataEnd, [[maybe_unused]] std::vector::const_iterator fdsBegin, [[maybe_unused]] std::vector::const_iterator fdsEnd, ControlSerializer *cs) { return deserialize(dataBegin, dataEnd, cs); } /* * const ControlInfoMap is serialized as: * * 4 bytes - uint32_t Size of serialized ControlInfoMap, in bytes * X bytes - Serialized ControlInfoMap (using ControlSerializer) */ template<> std::tuple, std::vector> IPADataSerializer::serialize(const ControlInfoMap &map, ControlSerializer *cs) { if (!cs) LOG(IPADataSerializer, Fatal) << "ControlSerializer not provided for serialization of ControlInfoMap"; size_t size = cs->binarySize(map); std::vector infoData(size); ByteStreamBuffer buffer(infoData.data(), infoData.size()); int ret = cs->serialize(map, buffer); if (ret < 0 || buffer.overflow()) { LOG(IPADataSerializer, Error) << "Failed to serialize ControlInfoMap"; return { {}, {} }; } std::vector dataVec; appendPOD(dataVec, infoData.size()); dataVec.insert(dataVec.end(), infoData.begin(), infoData.end()); return { dataVec, {} }; } template<> ControlInfoMap IPADataSerializer::deserialize(std::vector::const_iterator dataBegin, std::vector::const_iterator dataEnd, ControlSerializer *cs) { if (!cs) LOG(IPADataSerializer, Fatal) << "ControlSerializer not provided for deserialization of ControlInfoMap"; if (std::distance(dataBegin, dataEnd) < 4) return {}; uint32_t infoDataSize = readPOD(dataBegin, 0, dataEnd); std::vector::const_iterator it = dataBegin + 4; if (static_cast(std::distance(it, dataEnd)) < infoDataSize) return {}; ByteStreamBuffer buffer(&*it, infoDataSize); ControlInfoMap map = cs->deserialize(buffer); return map; } template<> ControlInfoMap IPADataSerializer::deserialize(const std::vector &data, ControlSerializer *cs) { return deserialize(data.cbegin(), data.end(), cs); } template<> ControlInfoMap IPADataSerializer::deserialize(const std::vector &data, [[maybe_unused]] const std::vector &fds, ControlSerializer *cs) { return deserialize(data.cbegin(), data.end(), cs); } template<> ControlInfoMap IPADataSerializer::deserialize(std::vector::const_iterator dataBegin, std::vector::const_iterator dataEnd, [[maybe_unused]] std::vector::const_iterator fdsBegin, [[maybe_unused]] std::vector::const_iterator fdsEnd, ControlSerializer *cs) { return deserialize(dataBegin, dataEnd, cs); } /* * FileDescriptors are serialized into a single byte that tells if the * FileDescriptor is valid or not. If it is valid, then for serialization * the fd will be written to the fd vector, or for deserialization the * fd vector const_iterator will be valid. * * This validity is necessary so that we don't send -1 fd over sendmsg(). It * also allows us to simply send the entire fd vector into the deserializer * and it will be recursively consumed as necessary. * * \todo Consider serializing the FileDescriptor in 4 bytes to ensure * 32-bit alignment of all serialized data */ template<> std::tuple, std::vector> IPADataSerializer::serialize(const FileDescriptor &data, [[maybe_unused]] ControlSerializer *cs) { std::vector dataVec = { data.isValid() }; std::vector fdVec; if (data.isValid()) fdVec.push_back(data.fd()); return { dataVec, fdVec }; } template<> FileDescriptor IPADataSerializer::deserialize(std::vector::const_iterator dataBegin, std::vector::const_iterator dataEnd, std::vector::const_iterator fdsBegin, std::vector::const_iterator fdsEnd, [[maybe_unused]] ControlSerializer *cs) { ASSERT(std::distance(dataBegin, dataEnd) >= 1); bool valid = !!(*dataBegin); ASSERT(!(valid && std::distance(fdsBegin, fdsEnd) < 1)); return valid ? FileDescriptor(*fdsBegin) : FileDescriptor(); } template<> FileDescriptor IPADataSerializer::deserialize(const std::vector &data, const std::vector &fds, [[maybe_unused]] ControlSerializer *cs) { return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end()); } /* * FrameBuffer::Plane is serialized as: * * 1 byte - FileDescriptor * 4 bytes - uint32_t Length */ template<> std::tuple, std::vector> IPADataSerializer::serialize(const FrameBuffer::Plane &data, [[maybe_unused]] ControlSerializer *cs) { std::vector dataVec; std::vector fdsVec; std::vector fdBuf; std::vector fdFds; std::tie(fdBuf, fdFds) = IPADataSerializer::serialize(data.fd); dataVec.insert(dataVec.end(), fdBuf.begin(), fdBuf.end()); fdsVec.insert(fdsVec.end(), fdFds.begin(), fdFds.end()); appendPOD(dataVec, data.length); return { dataVec, fdsVec }; } template<> FrameBuffer::Plane IPADataSerializer::deserialize(std::vector::const_iterator dataBegin, std::vector::const_iterator dataEnd, std::vector::const_iterator fdsBegin, [[maybe_unused]] std::vector::const_iterator fdsEnd, [[maybe_unused]] ControlSerializer *cs) { FrameBuffer::Plane ret; ret.fd = IPADataSerializer::deserialize(dataBegin, dataBegin + 1, fdsBegin, fdsBegin + 1); ret.length = readPOD(dataBegin, 1, dataEnd); return ret; } template<> FrameBuffer::Plane IPADataSerializer::deserialize(const std::vector &data, const std::vector &fds, ControlSerializer *cs) { return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end(), cs); } #endif /* __DOXYGEN__ */ } /* namespace libcamera */