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