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() { 28 } 29 30 std::string RefType::typeName() const { 31 return "ref" + (mElementType == nullptr ? "" : (" of " + mElementType->typeName())); 32 } 33 34 std::string RefType::getVtsType() const { 35 return "TYPE_REF"; 36 } 37 38 std::string RefType::getVtsValueName() const { 39 return "ref_value"; 40 } 41 42 bool RefType::isCompatibleElementType(Type *elementType) const { 43 if (elementType->isScalar()) { 44 return true; 45 } 46 if (elementType->isString()) { 47 return true; 48 } 49 if (elementType->isEnum()) { 50 return true; 51 } 52 if (elementType->isBitField()) { 53 return true; 54 } 55 if (elementType->isCompoundType() 56 && static_cast<CompoundType *>(elementType)->style() == CompoundType::STYLE_STRUCT) { 57 return true; 58 } 59 if (elementType->isTemplatedType()) { 60 return this->isCompatibleElementType(static_cast<TemplatedType *>(elementType)->getElementType()); 61 } 62 if (elementType->isArray()) { 63 return this->isCompatibleElementType(static_cast<ArrayType *>(elementType)->getElementType()); 64 } 65 return false; 66 } 67 68 /* return something like "T const *". 69 * The reason we don't return "const T *" is to handle cases like 70 * ref<ref<ref<T>>> t_3ptr; 71 * in this case the const's will get stacked on the left (const const const T *** t_3ptr) 72 * but in this implementation it would be clearer (T const* const* const* t_3ptr) */ 73 std::string RefType::getCppType(StorageMode /*mode*/, bool specifyNamespaces) const { 74 return mElementType->getCppStackType(specifyNamespaces) 75 + " const*"; 76 } 77 78 void RefType::addNamedTypesToSet(std::set<const FQName> &set) const { 79 mElementType->addNamedTypesToSet(set); 80 } 81 82 void RefType::emitReaderWriter( 83 Formatter &, 84 const std::string &, 85 const std::string &, 86 bool, 87 bool, 88 ErrorMode) const { 89 // RefType doesn't get read / written at this stage. 90 return; 91 } 92 93 void RefType::emitResolveReferences( 94 Formatter &out, 95 const std::string &name, 96 bool nameIsPointer, 97 const std::string &parcelObj, 98 bool parcelObjIsPointer, 99 bool isReader, 100 ErrorMode mode) const { 101 102 emitResolveReferencesEmbedded( 103 out, 104 0 /* depth */, 105 name, 106 name /* sanitizedName */, 107 nameIsPointer, 108 parcelObj, 109 parcelObjIsPointer, 110 isReader, 111 mode, 112 "", // parentName 113 ""); // offsetText 114 } 115 116 void RefType::emitResolveReferencesEmbedded( 117 Formatter &out, 118 size_t /* depth */, 119 const std::string &name, 120 const std::string &sanitizedName, 121 bool /*nameIsPointer*/, 122 const std::string &parcelObj, 123 bool parcelObjIsPointer, 124 bool isReader, 125 ErrorMode mode, 126 const std::string &parentName, 127 const std::string &offsetText) const { 128 129 std::string elementType = mElementType->getCppStackType(); 130 131 std::string baseType = getCppStackType(); 132 133 const std::string parcelObjDeref = 134 parcelObjIsPointer ? ("*" + parcelObj) : parcelObj; 135 136 const std::string parcelObjPointer = 137 parcelObjIsPointer ? parcelObj : ("&" + parcelObj); 138 139 // as if nameIsPointer is false. Pointers are always pass by values, 140 // so name is always the pointer value itself. Hence nameIsPointer = false. 141 const std::string namePointer = "&" + name; 142 const std::string handleName = "_hidl_" + sanitizedName + "__ref_handle"; 143 const std::string resolveBufName = "_hidl_" + sanitizedName + "__ref_resolve_buf"; 144 145 bool isEmbedded = (!parentName.empty() && !offsetText.empty()); 146 147 out << "size_t " << handleName << ";\n" 148 << "bool " << resolveBufName << ";\n\n"; 149 150 out << "_hidl_err = "; 151 152 if (isReader) { 153 out << "::android::hardware::read" 154 << (isEmbedded ? "Embedded" : "") 155 << "ReferenceFromParcel<" 156 << elementType 157 << ">(const_cast<" 158 << baseType 159 << " *>(" 160 << namePointer 161 << "),"; 162 } else { 163 out << "::android::hardware::write" 164 << (isEmbedded ? "Embedded" : "") 165 << "ReferenceToParcel<" 166 << elementType 167 << ">(" 168 << name 169 << ","; 170 } 171 172 out.indent(); 173 out.indent(); 174 175 out << (isReader ? parcelObjDeref : parcelObjPointer); 176 if(isEmbedded) 177 out << ",\n" 178 << parentName 179 << ",\n" 180 << offsetText; 181 182 out << ",\n&" + handleName; 183 out << ",\n&" + resolveBufName; 184 out << ");\n\n"; 185 186 out.unindent(); 187 out.unindent(); 188 189 handleError(out, mode); 190 191 if(!mElementType->needsResolveReferences() && !mElementType->needsEmbeddedReadWrite()) 192 return; // no need to deal with element type recursively. 193 194 out << "if(" << resolveBufName << ") {\n"; 195 out.indent(); 196 197 if(mElementType->needsEmbeddedReadWrite()) { 198 mElementType->emitReaderWriterEmbedded( 199 out, 200 0 /* depth */, 201 name, 202 sanitizedName, 203 true /* nameIsPointer */, // for element type, name is a pointer. 204 parcelObj, 205 parcelObjIsPointer, 206 isReader, 207 mode, 208 handleName, 209 "0 /* parentOffset */"); 210 } 211 212 if(mElementType->needsResolveReferences()) { 213 mElementType->emitResolveReferencesEmbedded( 214 out, 215 0 /* depth */, 216 "(*" + name + ")", 217 sanitizedName + "_deref", 218 false /* nameIsPointer */, 219 // must deref it and say false here, otherwise pointer to pointers don't work 220 parcelObj, 221 parcelObjIsPointer, 222 isReader, 223 mode, 224 handleName, 225 "0 /* parentOffset */"); 226 } 227 228 out.unindent(); 229 out << "}\n\n"; 230 } 231 232 bool RefType::needsResolveReferences() const { 233 return true; 234 } 235 236 bool RefType::needsEmbeddedReadWrite() const { 237 return false; 238 } 239 240 bool RefType::resultNeedsDeref() const { 241 return false; 242 } 243 244 bool RefType::isJavaCompatible() const { 245 return false; 246 } 247 248 bool RefType::containsPointer() const { 249 return true; 250 } 251 252 } // namespace android 253 254