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