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
RefType()27 RefType::RefType() {
28 }
29
typeName() const30 std::string RefType::typeName() const {
31 return "ref" + (mElementType == nullptr ? "" : (" of " + mElementType->typeName()));
32 }
33
getVtsType() const34 std::string RefType::getVtsType() const {
35 return "TYPE_REF";
36 }
37
getVtsValueName() const38 std::string RefType::getVtsValueName() const {
39 return "ref_value";
40 }
41
isCompatibleElementType(Type * elementType) const42 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) */
getCppType(StorageMode,bool specifyNamespaces) const73 std::string RefType::getCppType(StorageMode /*mode*/, bool specifyNamespaces) const {
74 return mElementType->getCppStackType(specifyNamespaces)
75 + " const*";
76 }
77
addNamedTypesToSet(std::set<const FQName> & set) const78 void RefType::addNamedTypesToSet(std::set<const FQName> &set) const {
79 mElementType->addNamedTypesToSet(set);
80 }
81
emitReaderWriter(Formatter &,const std::string &,const std::string &,bool,bool,ErrorMode) const82 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
emitResolveReferences(Formatter & out,const std::string & name,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const93 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
emitResolveReferencesEmbedded(Formatter & out,size_t,const std::string & name,const std::string & sanitizedName,bool,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode,const std::string & parentName,const std::string & offsetText) const116 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
needsResolveReferences() const232 bool RefType::needsResolveReferences() const {
233 return true;
234 }
235
needsEmbeddedReadWrite() const236 bool RefType::needsEmbeddedReadWrite() const {
237 return false;
238 }
239
resultNeedsDeref() const240 bool RefType::resultNeedsDeref() const {
241 return false;
242 }
243
isJavaCompatible() const244 bool RefType::isJavaCompatible() const {
245 return false;
246 }
247
containsPointer() const248 bool RefType::containsPointer() const {
249 return true;
250 }
251
252 } // namespace android
253
254