/* * 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 "RefType.h" #include "ArrayType.h" #include "CompoundType.h" #include #include namespace android { RefType::RefType() { } std::string RefType::typeName() const { return "ref" + (mElementType == nullptr ? "" : (" of " + mElementType->typeName())); } std::string RefType::getVtsType() const { return "TYPE_REF"; } std::string RefType::getVtsValueName() const { return "ref_value"; } bool RefType::isCompatibleElementType(Type *elementType) const { if (elementType->isScalar()) { return true; } if (elementType->isString()) { return true; } if (elementType->isEnum()) { return true; } if (elementType->isBitField()) { return true; } if (elementType->isCompoundType() && static_cast(elementType)->style() == CompoundType::STYLE_STRUCT) { return true; } if (elementType->isTemplatedType()) { return this->isCompatibleElementType(static_cast(elementType)->getElementType()); } if (elementType->isArray()) { return this->isCompatibleElementType(static_cast(elementType)->getElementType()); } return false; } /* return something like "T const *". * The reason we don't return "const T *" is to handle cases like * ref>> t_3ptr; * in this case the const's will get stacked on the left (const const const T *** t_3ptr) * but in this implementation it would be clearer (T const* const* const* t_3ptr) */ std::string RefType::getCppType(StorageMode /*mode*/, bool specifyNamespaces) const { return mElementType->getCppStackType(specifyNamespaces) + " const*"; } void RefType::addNamedTypesToSet(std::set &set) const { mElementType->addNamedTypesToSet(set); } void RefType::emitReaderWriter( Formatter &, const std::string &, const std::string &, bool, bool, ErrorMode) const { // RefType doesn't get read / written at this stage. return; } void RefType::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, "", // parentName ""); // offsetText } void RefType::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 { std::string elementType = mElementType->getCppStackType(); std::string baseType = getCppStackType(); const std::string parcelObjDeref = parcelObjIsPointer ? ("*" + parcelObj) : parcelObj; const std::string parcelObjPointer = parcelObjIsPointer ? parcelObj : ("&" + parcelObj); // as if nameIsPointer is false. Pointers are always pass by values, // so name is always the pointer value itself. Hence nameIsPointer = false. const std::string namePointer = "&" + name; const std::string handleName = "_hidl_" + sanitizedName + "__ref_handle"; const std::string resolveBufName = "_hidl_" + sanitizedName + "__ref_resolve_buf"; bool isEmbedded = (!parentName.empty() && !offsetText.empty()); out << "size_t " << handleName << ";\n" << "bool " << resolveBufName << ";\n\n"; out << "_hidl_err = "; if (isReader) { out << "::android::hardware::read" << (isEmbedded ? "Embedded" : "") << "ReferenceFromParcel<" << elementType << ">(const_cast<" << baseType << " *>(" << namePointer << "),"; } else { out << "::android::hardware::write" << (isEmbedded ? "Embedded" : "") << "ReferenceToParcel<" << elementType << ">(" << name << ","; } out.indent(); out.indent(); out << (isReader ? parcelObjDeref : parcelObjPointer); if(isEmbedded) out << ",\n" << parentName << ",\n" << offsetText; out << ",\n&" + handleName; out << ",\n&" + resolveBufName; out << ");\n\n"; out.unindent(); out.unindent(); handleError(out, mode); if(!mElementType->needsResolveReferences() && !mElementType->needsEmbeddedReadWrite()) return; // no need to deal with element type recursively. out << "if(" << resolveBufName << ") {\n"; out.indent(); if(mElementType->needsEmbeddedReadWrite()) { mElementType->emitReaderWriterEmbedded( out, 0 /* depth */, name, sanitizedName, true /* nameIsPointer */, // for element type, name is a pointer. parcelObj, parcelObjIsPointer, isReader, mode, handleName, "0 /* parentOffset */"); } if(mElementType->needsResolveReferences()) { mElementType->emitResolveReferencesEmbedded( out, 0 /* depth */, "(*" + name + ")", sanitizedName + "_deref", false /* nameIsPointer */, // must deref it and say false here, otherwise pointer to pointers don't work parcelObj, parcelObjIsPointer, isReader, mode, handleName, "0 /* parentOffset */"); } out.unindent(); out << "}\n\n"; } bool RefType::needsResolveReferences() const { return true; } bool RefType::needsEmbeddedReadWrite() const { return false; } bool RefType::resultNeedsDeref() const { return false; } bool RefType::isJavaCompatible() const { return false; } bool RefType::containsPointer() const { return true; } } // namespace android