/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ArrayType.h" #include <hidl-util/Formatter.h> #include <android-base/logging.h> #include "ConstantExpression.h" namespace android { ArrayType::ArrayType(ArrayType *srcArray, ConstantExpression *size) : mElementType(srcArray->mElementType), mSizes(srcArray->mSizes) { prependDimension(size); } ArrayType::ArrayType(Type *elementType, ConstantExpression *size) : mElementType(elementType) { prependDimension(size); } void ArrayType::prependDimension(ConstantExpression *size) { mSizes.insert(mSizes.begin(), size); } void ArrayType::appendDimension(ConstantExpression *size) { mSizes.push_back(size); } size_t ArrayType::countDimensions() const { return mSizes.size(); } void ArrayType::addNamedTypesToSet(std::set<const FQName> &set) const { mElementType->addNamedTypesToSet(set); } bool ArrayType::isArray() const { return true; } bool ArrayType::canCheckEquality() const { return mElementType->canCheckEquality(); } Type *ArrayType::getElementType() const { return mElementType; } std::string ArrayType::getCppType(StorageMode mode, bool specifyNamespaces) const { const std::string base = mElementType->getCppStackType(specifyNamespaces); std::string space = specifyNamespaces ? "::android::hardware::" : ""; std::string arrayType = space + "hidl_array<" + base; for (size_t i = 0; i < mSizes.size(); ++i) { arrayType += ", "; arrayType += mSizes[i]->cppValue(); if (!mSizes[i]->descriptionIsTrivial()) { arrayType += " /* "; arrayType += mSizes[i]->description(); arrayType += " */"; } } arrayType += ">"; switch (mode) { case StorageMode_Stack: return arrayType; case StorageMode_Argument: return "const " + arrayType + "&"; case StorageMode_Result: return "const " + arrayType + "*"; } CHECK(!"Should not be here"); } std::string ArrayType::getInternalDataCppType() const { std::string result = mElementType->getCppStackType(); for (size_t i = 0; i < mSizes.size(); ++i) { result += "["; result += mSizes[i]->cppValue(); result += "]"; } return result; } std::string ArrayType::getJavaType(bool forInitializer) const { std::string base = mElementType->getJavaType(forInitializer); for (size_t i = 0; i < mSizes.size(); ++i) { base += "["; if (forInitializer) { base += mSizes[i]->javaValue(); } if (!forInitializer || !mSizes[i]->descriptionIsTrivial()) { if (forInitializer) base += " "; base += "/* " + mSizes[i]->description() + " */"; } base += "]"; } return base; } std::string ArrayType::getJavaWrapperType() const { return mElementType->getJavaWrapperType(); } std::string ArrayType::getVtsType() const { return "TYPE_ARRAY"; } void ArrayType::emitReaderWriter( Formatter &out, const std::string &name, const std::string &parcelObj, bool parcelObjIsPointer, bool isReader, ErrorMode mode) const { std::string baseType = mElementType->getCppStackType(); const std::string parentName = "_hidl_" + name + "_parent"; out << "size_t " << parentName << ";\n\n"; const std::string parcelObjDeref = parcelObj + (parcelObjIsPointer ? "->" : "."); size_t numArrayElements = 1; for (auto size : mSizes) { numArrayElements *= size->castSizeT(); } if (isReader) { out << "_hidl_err = " << parcelObjDeref << "readBuffer(" << numArrayElements << " * sizeof(" << baseType << "), &" << parentName << ", " << " reinterpret_cast<const void **>(" << "&" << name << "));\n\n"; handleError(out, mode); } else { out << "_hidl_err = " << parcelObjDeref << "writeBuffer(" << name << ".data(), " << numArrayElements << " * sizeof(" << baseType << "), &" << parentName << ");\n"; handleError(out, mode); } emitReaderWriterEmbedded( out, 0 /* depth */, name, name /* sanitizedName */, isReader /* nameIsPointer */, parcelObj, parcelObjIsPointer, isReader, mode, parentName, "0 /* parentOffset */"); } void ArrayType::emitReaderWriterEmbedded( Formatter &out, size_t depth, const std::string &name, const std::string &sanitizedName, bool nameIsPointer, const std::string &parcelObj, bool parcelObjIsPointer, bool isReader, ErrorMode mode, const std::string &parentName, const std::string &offsetText) const { if (!mElementType->needsEmbeddedReadWrite()) { return; } const std::string nameDeref = name + (nameIsPointer ? "->" : "."); std::string baseType = mElementType->getCppStackType(); std::string iteratorName = "_hidl_index_" + std::to_string(depth); out << "for (size_t " << iteratorName << " = 0; " << iteratorName << " < " << dimension() << "; ++" << iteratorName << ") {\n"; out.indent(); mElementType->emitReaderWriterEmbedded( out, depth + 1, nameDeref + "data()[" + iteratorName + "]", sanitizedName + "_indexed", false /* nameIsPointer */, parcelObj, parcelObjIsPointer, isReader, mode, parentName, offsetText + " + " + iteratorName + " * sizeof(" + baseType + ")"); out.unindent(); out << "}\n\n"; } void ArrayType::emitResolveReferences( Formatter &out, const std::string &name, bool nameIsPointer, const std::string &parcelObj, bool parcelObjIsPointer, bool isReader, ErrorMode mode) const { emitResolveReferencesEmbedded( out, 0 /* depth */, name, name /* sanitizedName */, nameIsPointer, parcelObj, parcelObjIsPointer, isReader, mode, "_hidl_" + name + "_parent", "0 /* parentOffset */"); } void ArrayType::emitResolveReferencesEmbedded( Formatter &out, size_t depth, const std::string &name, const std::string &sanitizedName, bool nameIsPointer, const std::string &parcelObj, bool parcelObjIsPointer, bool isReader, ErrorMode mode, const std::string &parentName, const std::string &offsetText) const { CHECK(needsResolveReferences() && mElementType->needsResolveReferences()); const std::string nameDeref = name + (nameIsPointer ? "->" : "."); std::string baseType = mElementType->getCppStackType(); std::string iteratorName = "_hidl_index_" + std::to_string(depth); out << "for (size_t " << iteratorName << " = 0; " << iteratorName << " < " << dimension() << "; ++" << iteratorName << ") {\n"; out.indent(); mElementType->emitResolveReferencesEmbedded( out, depth + 1, nameDeref + "data()[" + iteratorName + "]", sanitizedName + "_indexed", false /* nameIsPointer */, parcelObj, parcelObjIsPointer, isReader, mode, parentName, offsetText + " + " + iteratorName + " * sizeof(" + baseType + ")"); out.unindent(); out << "}\n\n"; } void ArrayType::emitJavaDump( Formatter &out, const std::string &streamName, const std::string &name) const { out << streamName << ".append(java.util.Arrays." << (countDimensions() > 1 ? "deepToString" : "toString") << "(" << name << "));\n"; } bool ArrayType::needsEmbeddedReadWrite() const { return mElementType->needsEmbeddedReadWrite(); } bool ArrayType::needsResolveReferences() const { return mElementType->needsResolveReferences(); } bool ArrayType::resultNeedsDeref() const { return true; } void ArrayType::emitJavaReaderWriter( Formatter &out, const std::string &parcelObj, const std::string &argName, bool isReader) const { size_t align, size; getAlignmentAndSize(&align, &size); if (isReader) { out << "new " << getJavaType(true /* forInitializer */) << ";\n"; } out << "{\n"; out.indent(); out << "android.os.HwBlob _hidl_blob = "; if (isReader) { out << parcelObj << ".readBuffer(" << size << " /* size */);\n"; } else { out << "new android.os.HwBlob(" << size << " /* size */);\n"; } emitJavaFieldReaderWriter( out, 0 /* depth */, parcelObj, "_hidl_blob", argName, "0 /* offset */", isReader); if (!isReader) { out << parcelObj << ".writeBuffer(_hidl_blob);\n"; } out.unindent(); out << "}\n"; } void ArrayType::emitJavaFieldInitializer( Formatter &out, const std::string &fieldName) const { std::string typeName = getJavaType(false /* forInitializer */); std::string initName = getJavaType(true /* forInitializer */); out << "final " << typeName << " " << fieldName << " = new " << initName << ";\n"; } void ArrayType::emitJavaFieldReaderWriter( Formatter &out, size_t depth, const std::string &parcelName, const std::string &blobName, const std::string &fieldName, const std::string &offset, bool isReader) const { out << "{\n"; out.indent(); std::string offsetName = "_hidl_array_offset_" + std::to_string(depth); out << "long " << offsetName << " = " << offset << ";\n"; std::string indexString; for (size_t dim = 0; dim < mSizes.size(); ++dim) { std::string iteratorName = "_hidl_index_" + std::to_string(depth) + "_" + std::to_string(dim); out << "for (int " << iteratorName << " = 0; " << iteratorName << " < " << mSizes[dim]->javaValue() << "; ++" << iteratorName << ") {\n"; out.indent(); indexString += "[" + iteratorName + "]"; } if (isReader && mElementType->isCompoundType()) { std::string typeName = mElementType->getJavaType(false /* forInitializer */); out << fieldName << indexString << " = new " << typeName << "();\n"; } mElementType->emitJavaFieldReaderWriter( out, depth + 1, parcelName, blobName, fieldName + indexString, offsetName, isReader); size_t elementAlign, elementSize; mElementType->getAlignmentAndSize(&elementAlign, &elementSize); out << offsetName << " += " << std::to_string(elementSize) << ";\n"; for (size_t dim = 0; dim < mSizes.size(); ++dim) { out.unindent(); out << "}\n"; } out.unindent(); out << "}\n"; } status_t ArrayType::emitVtsTypeDeclarations(Formatter &out) const { out << "type: " << getVtsType() << "\n"; out << "vector_size: " << mSizes[0]->value() << "\n"; out << "vector_value: {\n"; out.indent(); // Simple array case. if (mSizes.size() == 1) { status_t err = mElementType->emitVtsTypeDeclarations(out); if (err != OK) { return err; } } else { // Multi-dimension array case. for (size_t index = 1; index < mSizes.size(); index++) { out << "type: " << getVtsType() << "\n"; out << "vector_size: " << mSizes[index]->value() << "\n"; out << "vector_value: {\n"; out.indent(); if (index == mSizes.size() - 1) { status_t err = mElementType->emitVtsTypeDeclarations(out); if (err != OK) { return err; } } } } for (size_t index = 0; index < mSizes.size(); index++) { out.unindent(); out << "}\n"; } return OK; } bool ArrayType::isJavaCompatible() const { return mElementType->isJavaCompatible(); } bool ArrayType::containsPointer() const { return mElementType->containsPointer(); } void ArrayType::getAlignmentAndSize(size_t *align, size_t *size) const { mElementType->getAlignmentAndSize(align, size); for (auto sizeInDimension : mSizes) { (*size) *= sizeInDimension->castSizeT(); } } size_t ArrayType::dimension() const { size_t numArrayElements = 1; for (auto size : mSizes) { numArrayElements *= size->castSizeT(); } return numArrayElements; } } // namespace android