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 "ArrayType.h"
18
19 #include <hidl-util/Formatter.h>
20 #include <android-base/logging.h>
21
22 #include "ConstantExpression.h"
23
24 namespace android {
25
ArrayType(ArrayType * srcArray,ConstantExpression * size)26 ArrayType::ArrayType(ArrayType *srcArray, ConstantExpression *size)
27 : mElementType(srcArray->mElementType),
28 mSizes(srcArray->mSizes) {
29 prependDimension(size);
30 }
31
ArrayType(Type * elementType,ConstantExpression * size)32 ArrayType::ArrayType(Type *elementType, ConstantExpression *size)
33 : mElementType(elementType) {
34 prependDimension(size);
35 }
36
prependDimension(ConstantExpression * size)37 void ArrayType::prependDimension(ConstantExpression *size) {
38 mSizes.insert(mSizes.begin(), size);
39 }
40
appendDimension(ConstantExpression * size)41 void ArrayType::appendDimension(ConstantExpression *size) {
42 mSizes.push_back(size);
43 }
44
countDimensions() const45 size_t ArrayType::countDimensions() const {
46 return mSizes.size();
47 }
48
addNamedTypesToSet(std::set<const FQName> & set) const49 void ArrayType::addNamedTypesToSet(std::set<const FQName> &set) const {
50 mElementType->addNamedTypesToSet(set);
51 }
52
isArray() const53 bool ArrayType::isArray() const {
54 return true;
55 }
56
canCheckEquality() const57 bool ArrayType::canCheckEquality() const {
58 return mElementType->canCheckEquality();
59 }
60
getElementType() const61 Type *ArrayType::getElementType() const {
62 return mElementType;
63 }
64
getCppType(StorageMode mode,bool specifyNamespaces) const65 std::string ArrayType::getCppType(StorageMode mode,
66 bool specifyNamespaces) const {
67 const std::string base = mElementType->getCppStackType(specifyNamespaces);
68
69 std::string space = specifyNamespaces ? "::android::hardware::" : "";
70 std::string arrayType = space + "hidl_array<" + base;
71
72 for (size_t i = 0; i < mSizes.size(); ++i) {
73 arrayType += ", ";
74 arrayType += mSizes[i]->cppValue();
75
76 if (!mSizes[i]->descriptionIsTrivial()) {
77 arrayType += " /* ";
78 arrayType += mSizes[i]->description();
79 arrayType += " */";
80 }
81 }
82
83 arrayType += ">";
84
85 switch (mode) {
86 case StorageMode_Stack:
87 return arrayType;
88
89 case StorageMode_Argument:
90 return "const " + arrayType + "&";
91
92 case StorageMode_Result:
93 return "const " + arrayType + "*";
94 }
95
96 CHECK(!"Should not be here");
97 }
98
getInternalDataCppType() const99 std::string ArrayType::getInternalDataCppType() const {
100 std::string result = mElementType->getCppStackType();
101 for (size_t i = 0; i < mSizes.size(); ++i) {
102 result += "[";
103 result += mSizes[i]->cppValue();
104 result += "]";
105 }
106 return result;
107 }
108
getJavaType(bool forInitializer) const109 std::string ArrayType::getJavaType(bool forInitializer) const {
110 std::string base =
111 mElementType->getJavaType(forInitializer);
112
113 for (size_t i = 0; i < mSizes.size(); ++i) {
114 base += "[";
115
116 if (forInitializer) {
117 base += mSizes[i]->javaValue();
118 }
119
120 if (!forInitializer || !mSizes[i]->descriptionIsTrivial()) {
121 if (forInitializer)
122 base += " ";
123 base += "/* " + mSizes[i]->description() + " */";
124 }
125
126 base += "]";
127 }
128
129 return base;
130 }
131
getJavaWrapperType() const132 std::string ArrayType::getJavaWrapperType() const {
133 return mElementType->getJavaWrapperType();
134 }
135
getVtsType() const136 std::string ArrayType::getVtsType() const {
137 return "TYPE_ARRAY";
138 }
139
emitReaderWriter(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const140 void ArrayType::emitReaderWriter(
141 Formatter &out,
142 const std::string &name,
143 const std::string &parcelObj,
144 bool parcelObjIsPointer,
145 bool isReader,
146 ErrorMode mode) const {
147 std::string baseType = mElementType->getCppStackType();
148
149 const std::string parentName = "_hidl_" + name + "_parent";
150
151 out << "size_t " << parentName << ";\n\n";
152
153 const std::string parcelObjDeref =
154 parcelObj + (parcelObjIsPointer ? "->" : ".");
155
156 size_t numArrayElements = 1;
157 for (auto size : mSizes) {
158 numArrayElements *= size->castSizeT();
159 }
160 if (isReader) {
161 out << "_hidl_err = "
162 << parcelObjDeref
163 << "readBuffer("
164 << numArrayElements
165 << " * sizeof("
166 << baseType
167 << "), &"
168 << parentName
169 << ", "
170 << " reinterpret_cast<const void **>("
171 << "&" << name
172 << "));\n\n";
173
174 handleError(out, mode);
175 } else {
176
177 out << "_hidl_err = "
178 << parcelObjDeref
179 << "writeBuffer("
180 << name
181 << ".data(), "
182 << numArrayElements
183 << " * sizeof("
184 << baseType
185 << "), &"
186 << parentName
187 << ");\n";
188
189 handleError(out, mode);
190 }
191
192 emitReaderWriterEmbedded(
193 out,
194 0 /* depth */,
195 name,
196 name /* sanitizedName */,
197 isReader /* nameIsPointer */,
198 parcelObj,
199 parcelObjIsPointer,
200 isReader,
201 mode,
202 parentName,
203 "0 /* parentOffset */");
204 }
205
emitReaderWriterEmbedded(Formatter & out,size_t depth,const std::string & name,const std::string & sanitizedName,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode,const std::string & parentName,const std::string & offsetText) const206 void ArrayType::emitReaderWriterEmbedded(
207 Formatter &out,
208 size_t depth,
209 const std::string &name,
210 const std::string &sanitizedName,
211 bool nameIsPointer,
212 const std::string &parcelObj,
213 bool parcelObjIsPointer,
214 bool isReader,
215 ErrorMode mode,
216 const std::string &parentName,
217 const std::string &offsetText) const {
218 if (!mElementType->needsEmbeddedReadWrite()) {
219 return;
220 }
221
222 const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
223
224 std::string baseType = mElementType->getCppStackType();
225
226 std::string iteratorName = "_hidl_index_" + std::to_string(depth);
227
228 out << "for (size_t "
229 << iteratorName
230 << " = 0; "
231 << iteratorName
232 << " < "
233 << dimension()
234 << "; ++"
235 << iteratorName
236 << ") {\n";
237
238 out.indent();
239
240 mElementType->emitReaderWriterEmbedded(
241 out,
242 depth + 1,
243 nameDeref + "data()[" + iteratorName + "]",
244 sanitizedName + "_indexed",
245 false /* nameIsPointer */,
246 parcelObj,
247 parcelObjIsPointer,
248 isReader,
249 mode,
250 parentName,
251 offsetText
252 + " + " + iteratorName + " * sizeof("
253 + baseType
254 + ")");
255
256 out.unindent();
257
258 out << "}\n\n";
259 }
260
emitResolveReferences(Formatter & out,const std::string & name,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const261 void ArrayType::emitResolveReferences(
262 Formatter &out,
263 const std::string &name,
264 bool nameIsPointer,
265 const std::string &parcelObj,
266 bool parcelObjIsPointer,
267 bool isReader,
268 ErrorMode mode) const {
269 emitResolveReferencesEmbedded(
270 out,
271 0 /* depth */,
272 name,
273 name /* sanitizedName */,
274 nameIsPointer,
275 parcelObj,
276 parcelObjIsPointer,
277 isReader,
278 mode,
279 "_hidl_" + name + "_parent",
280 "0 /* parentOffset */");
281 }
282
emitResolveReferencesEmbedded(Formatter & out,size_t depth,const std::string & name,const std::string & sanitizedName,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode,const std::string & parentName,const std::string & offsetText) const283 void ArrayType::emitResolveReferencesEmbedded(
284 Formatter &out,
285 size_t depth,
286 const std::string &name,
287 const std::string &sanitizedName,
288 bool nameIsPointer,
289 const std::string &parcelObj,
290 bool parcelObjIsPointer,
291 bool isReader,
292 ErrorMode mode,
293 const std::string &parentName,
294 const std::string &offsetText) const {
295 CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
296
297 const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
298
299 std::string baseType = mElementType->getCppStackType();
300
301 std::string iteratorName = "_hidl_index_" + std::to_string(depth);
302
303 out << "for (size_t "
304 << iteratorName
305 << " = 0; "
306 << iteratorName
307 << " < "
308 << dimension()
309 << "; ++"
310 << iteratorName
311 << ") {\n";
312
313 out.indent();
314
315 mElementType->emitResolveReferencesEmbedded(
316 out,
317 depth + 1,
318 nameDeref + "data()[" + iteratorName + "]",
319 sanitizedName + "_indexed",
320 false /* nameIsPointer */,
321 parcelObj,
322 parcelObjIsPointer,
323 isReader,
324 mode,
325 parentName,
326 offsetText + " + " + iteratorName + " * sizeof("
327 + baseType
328 + ")");
329
330 out.unindent();
331
332 out << "}\n\n";
333 }
334
emitJavaDump(Formatter & out,const std::string & streamName,const std::string & name) const335 void ArrayType::emitJavaDump(
336 Formatter &out,
337 const std::string &streamName,
338 const std::string &name) const {
339 out << streamName << ".append(java.util.Arrays."
340 << (countDimensions() > 1 ? "deepToString" : "toString")
341 << "("
342 << name << "));\n";
343 }
344
345
needsEmbeddedReadWrite() const346 bool ArrayType::needsEmbeddedReadWrite() const {
347 return mElementType->needsEmbeddedReadWrite();
348 }
349
needsResolveReferences() const350 bool ArrayType::needsResolveReferences() const {
351 return mElementType->needsResolveReferences();
352 }
353
resultNeedsDeref() const354 bool ArrayType::resultNeedsDeref() const {
355 return true;
356 }
357
emitJavaReaderWriter(Formatter & out,const std::string & parcelObj,const std::string & argName,bool isReader) const358 void ArrayType::emitJavaReaderWriter(
359 Formatter &out,
360 const std::string &parcelObj,
361 const std::string &argName,
362 bool isReader) const {
363 size_t align, size;
364 getAlignmentAndSize(&align, &size);
365
366 if (isReader) {
367 out << "new "
368 << getJavaType(true /* forInitializer */)
369 << ";\n";
370 }
371
372 out << "{\n";
373 out.indent();
374
375 out << "android.os.HwBlob _hidl_blob = ";
376
377 if (isReader) {
378 out << parcelObj
379 << ".readBuffer("
380 << size
381 << " /* size */);\n";
382 } else {
383 out << "new android.os.HwBlob("
384 << size
385 << " /* size */);\n";
386 }
387
388 emitJavaFieldReaderWriter(
389 out,
390 0 /* depth */,
391 parcelObj,
392 "_hidl_blob",
393 argName,
394 "0 /* offset */",
395 isReader);
396
397 if (!isReader) {
398 out << parcelObj << ".writeBuffer(_hidl_blob);\n";
399 }
400
401 out.unindent();
402 out << "}\n";
403 }
404
emitJavaFieldInitializer(Formatter & out,const std::string & fieldName) const405 void ArrayType::emitJavaFieldInitializer(
406 Formatter &out, const std::string &fieldName) const {
407 std::string typeName = getJavaType(false /* forInitializer */);
408 std::string initName = getJavaType(true /* forInitializer */);
409
410 out << "final "
411 << typeName
412 << " "
413 << fieldName
414 << " = new "
415 << initName
416 << ";\n";
417 }
418
emitJavaFieldReaderWriter(Formatter & out,size_t depth,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader) const419 void ArrayType::emitJavaFieldReaderWriter(
420 Formatter &out,
421 size_t depth,
422 const std::string &parcelName,
423 const std::string &blobName,
424 const std::string &fieldName,
425 const std::string &offset,
426 bool isReader) const {
427 out << "{\n";
428 out.indent();
429
430 std::string offsetName = "_hidl_array_offset_" + std::to_string(depth);
431 out << "long " << offsetName << " = " << offset << ";\n";
432
433 std::string indexString;
434 for (size_t dim = 0; dim < mSizes.size(); ++dim) {
435 std::string iteratorName =
436 "_hidl_index_" + std::to_string(depth) + "_" + std::to_string(dim);
437
438 out << "for (int "
439 << iteratorName
440 << " = 0; "
441 << iteratorName
442 << " < "
443 << mSizes[dim]->javaValue()
444 << "; ++"
445 << iteratorName
446 << ") {\n";
447
448 out.indent();
449
450 indexString += "[" + iteratorName + "]";
451 }
452
453 if (isReader && mElementType->isCompoundType()) {
454 std::string typeName =
455 mElementType->getJavaType(false /* forInitializer */);
456
457 out << fieldName
458 << indexString
459 << " = new "
460 << typeName
461 << "();\n";
462 }
463
464 mElementType->emitJavaFieldReaderWriter(
465 out,
466 depth + 1,
467 parcelName,
468 blobName,
469 fieldName + indexString,
470 offsetName,
471 isReader);
472
473 size_t elementAlign, elementSize;
474 mElementType->getAlignmentAndSize(&elementAlign, &elementSize);
475
476 out << offsetName << " += " << std::to_string(elementSize) << ";\n";
477
478 for (size_t dim = 0; dim < mSizes.size(); ++dim) {
479 out.unindent();
480 out << "}\n";
481 }
482
483 out.unindent();
484 out << "}\n";
485 }
486
emitVtsTypeDeclarations(Formatter & out) const487 status_t ArrayType::emitVtsTypeDeclarations(Formatter &out) const {
488 out << "type: " << getVtsType() << "\n";
489 out << "vector_size: " << mSizes[0]->value() << "\n";
490 out << "vector_value: {\n";
491 out.indent();
492 // Simple array case.
493 if (mSizes.size() == 1) {
494 status_t err = mElementType->emitVtsTypeDeclarations(out);
495 if (err != OK) {
496 return err;
497 }
498 } else { // Multi-dimension array case.
499 for (size_t index = 1; index < mSizes.size(); index++) {
500 out << "type: " << getVtsType() << "\n";
501 out << "vector_size: " << mSizes[index]->value() << "\n";
502 out << "vector_value: {\n";
503 out.indent();
504 if (index == mSizes.size() - 1) {
505 status_t err = mElementType->emitVtsTypeDeclarations(out);
506 if (err != OK) {
507 return err;
508 }
509 }
510 }
511 }
512 for (size_t index = 0; index < mSizes.size(); index++) {
513 out.unindent();
514 out << "}\n";
515 }
516 return OK;
517 }
518
isJavaCompatible() const519 bool ArrayType::isJavaCompatible() const {
520 return mElementType->isJavaCompatible();
521 }
522
containsPointer() const523 bool ArrayType::containsPointer() const {
524 return mElementType->containsPointer();
525 }
526
getAlignmentAndSize(size_t * align,size_t * size) const527 void ArrayType::getAlignmentAndSize(size_t *align, size_t *size) const {
528 mElementType->getAlignmentAndSize(align, size);
529
530 for (auto sizeInDimension : mSizes) {
531 (*size) *= sizeInDimension->castSizeT();
532 }
533 }
534
dimension() const535 size_t ArrayType::dimension() const {
536 size_t numArrayElements = 1;
537 for (auto size : mSizes) {
538 numArrayElements *= size->castSizeT();
539 }
540 return numArrayElements;
541 }
542
543 } // namespace android
544
545