/* * 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 <hidl-util/Formatter.h> #include <android-base/logging.h> namespace android { RefType::RefType(Scope* parent) : TemplatedType(parent) {} std::string RefType::templatedTypeName() const { return "ref"; } std::vector<const Reference<Type>*> RefType::getStrongReferences() const { return {}; } std::string RefType::getVtsType() const { return "TYPE_REF"; } std::string RefType::getVtsValueName() const { return "ref_value"; } bool RefType::isCompatibleElementType(const 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<const CompoundType*>(elementType)->style() == CompoundType::STYLE_STRUCT) { return true; } if (elementType->isTemplatedType()) { return this->isCompatibleElementType( static_cast<const TemplatedType*>(elementType)->getElementType()); } if (elementType->isArray()) { return this->isCompatibleElementType( static_cast<const ArrayType*>(elementType)->getElementType()); } return false; } /* return something like "T const *". * The reason we don't return "const T *" is to handle cases like * ref<ref<ref<T>>> 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::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::deepNeedsResolveReferences(std::unordered_set<const Type*>* /* visited */) const { return true; } bool RefType::needsEmbeddedReadWrite() const { return false; } bool RefType::resultNeedsDeref() const { return false; } bool RefType::deepIsJavaCompatible(std::unordered_set<const Type*>* /* visited */) const { return false; } bool RefType::deepContainsPointer(std::unordered_set<const Type*>* /* visited */) const { return true; } } // namespace android