1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "RefType.h" 18 19 #include "ArrayType.h" 20 #include "CompoundType.h" 21 22 #include <hidl-util/Formatter.h> 23 #include <android-base/logging.h> 24 25 namespace android { 26 27 RefType::RefType(Scope* parent) : TemplatedType(parent) {} 28 29 std::string RefType::templatedTypeName() const { 30 return "ref"; 31 } 32 33 std::vector<const Reference<Type>*> RefType::getStrongReferences() const { 34 return {}; 35 } 36 37 std::string RefType::getVtsType() const { 38 return "TYPE_REF"; 39 } 40 41 std::string RefType::getVtsValueName() const { 42 return "ref_value"; 43 } 44 45 bool RefType::isCompatibleElementType(const Type* elementType) const { 46 if (elementType->isScalar()) { 47 return true; 48 } 49 if (elementType->isString()) { 50 return true; 51 } 52 if (elementType->isEnum()) { 53 return true; 54 } 55 if (elementType->isBitField()) { 56 return true; 57 } 58 if (elementType->isCompoundType() && 59 static_cast<const CompoundType*>(elementType)->style() == CompoundType::STYLE_STRUCT) { 60 return true; 61 } 62 if (elementType->isTemplatedType()) { 63 return this->isCompatibleElementType( 64 static_cast<const TemplatedType*>(elementType)->getElementType()); 65 } 66 if (elementType->isArray()) { 67 return this->isCompatibleElementType( 68 static_cast<const ArrayType*>(elementType)->getElementType()); 69 } 70 return false; 71 } 72 73 /* return something like "T const *". 74 * The reason we don't return "const T *" is to handle cases like 75 * ref<ref<ref<T>>> t_3ptr; 76 * in this case the const's will get stacked on the left (const const const T *** t_3ptr) 77 * but in this implementation it would be clearer (T const* const* const* t_3ptr) */ 78 std::string RefType::getCppType(StorageMode /*mode*/, bool specifyNamespaces) const { 79 return mElementType->getCppStackType(specifyNamespaces) 80 + " const*"; 81 } 82 83 void RefType::emitReaderWriter( 84 Formatter &, 85 const std::string &, 86 const std::string &, 87 bool, 88 bool, 89 ErrorMode) const { 90 // RefType doesn't get read / written at this stage. 91 return; 92 } 93 94 void RefType::emitResolveReferences( 95 Formatter &out, 96 const std::string &name, 97 bool nameIsPointer, 98 const std::string &parcelObj, 99 bool parcelObjIsPointer, 100 bool isReader, 101 ErrorMode mode) const { 102 103 emitResolveReferencesEmbedded( 104 out, 105 0 /* depth */, 106 name, 107 name /* sanitizedName */, 108 nameIsPointer, 109 parcelObj, 110 parcelObjIsPointer, 111 isReader, 112 mode, 113 "", // parentName 114 ""); // offsetText 115 } 116 117 void RefType::emitResolveReferencesEmbedded( 118 Formatter &out, 119 size_t /* depth */, 120 const std::string &name, 121 const std::string &sanitizedName, 122 bool /*nameIsPointer*/, 123 const std::string &parcelObj, 124 bool parcelObjIsPointer, 125 bool isReader, 126 ErrorMode mode, 127 const std::string &parentName, 128 const std::string &offsetText) const { 129 130 std::string elementType = mElementType->getCppStackType(); 131 132 std::string baseType = getCppStackType(); 133 134 const std::string parcelObjDeref = 135 parcelObjIsPointer ? ("*" + parcelObj) : parcelObj; 136 137 const std::string parcelObjPointer = 138 parcelObjIsPointer ? parcelObj : ("&" + parcelObj); 139 140 // as if nameIsPointer is false. Pointers are always pass by values, 141 // so name is always the pointer value itself. Hence nameIsPointer = false. 142 const std::string namePointer = "&" + name; 143 const std::string handleName = "_hidl_" + sanitizedName + "__ref_handle"; 144 const std::string resolveBufName = "_hidl_" + sanitizedName + "__ref_resolve_buf"; 145 146 bool isEmbedded = (!parentName.empty() && !offsetText.empty()); 147 148 out << "size_t " << handleName << ";\n" 149 << "bool " << resolveBufName << ";\n\n"; 150 151 out << "_hidl_err = "; 152 153 if (isReader) { 154 out << "::android::hardware::read" 155 << (isEmbedded ? "Embedded" : "") 156 << "ReferenceFromParcel<" 157 << elementType 158 << ">(const_cast<" 159 << baseType 160 << " *>(" 161 << namePointer 162 << "),"; 163 } else { 164 out << "::android::hardware::write" 165 << (isEmbedded ? "Embedded" : "") 166 << "ReferenceToParcel<" 167 << elementType 168 << ">(" 169 << name 170 << ","; 171 } 172 173 out.indent(); 174 out.indent(); 175 176 out << (isReader ? parcelObjDeref : parcelObjPointer); 177 if(isEmbedded) 178 out << ",\n" 179 << parentName 180 << ",\n" 181 << offsetText; 182 183 out << ",\n&" + handleName; 184 out << ",\n&" + resolveBufName; 185 out << ");\n\n"; 186 187 out.unindent(); 188 out.unindent(); 189 190 handleError(out, mode); 191 192 if(!mElementType->needsResolveReferences() && !mElementType->needsEmbeddedReadWrite()) 193 return; // no need to deal with element type recursively. 194 195 out << "if(" << resolveBufName << ") {\n"; 196 out.indent(); 197 198 if(mElementType->needsEmbeddedReadWrite()) { 199 mElementType->emitReaderWriterEmbedded( 200 out, 201 0 /* depth */, 202 name, 203 sanitizedName, 204 true /* nameIsPointer */, // for element type, name is a pointer. 205 parcelObj, 206 parcelObjIsPointer, 207 isReader, 208 mode, 209 handleName, 210 "0 /* parentOffset */"); 211 } 212 213 if(mElementType->needsResolveReferences()) { 214 mElementType->emitResolveReferencesEmbedded( 215 out, 216 0 /* depth */, 217 "(*" + name + ")", 218 sanitizedName + "_deref", 219 false /* nameIsPointer */, 220 // must deref it and say false here, otherwise pointer to pointers don't work 221 parcelObj, 222 parcelObjIsPointer, 223 isReader, 224 mode, 225 handleName, 226 "0 /* parentOffset */"); 227 } 228 229 out.unindent(); 230 out << "}\n\n"; 231 } 232 233 bool RefType::deepNeedsResolveReferences(std::unordered_set<const Type*>* /* visited */) const { 234 return true; 235 } 236 237 bool RefType::needsEmbeddedReadWrite() const { 238 return false; 239 } 240 241 bool RefType::resultNeedsDeref() const { 242 return false; 243 } 244 245 bool RefType::deepIsJavaCompatible(std::unordered_set<const Type*>* /* visited */) const { 246 return false; 247 } 248 249 bool RefType::deepContainsPointer(std::unordered_set<const Type*>* /* visited */) const { 250 return true; 251 } 252 253 } // namespace android 254 255