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 "VectorType.h"
18
19 #include "ArrayType.h"
20 #include "CompoundType.h"
21 #include "HidlTypeAssertion.h"
22
23 #include <hidl-util/Formatter.h>
24 #include <android-base/logging.h>
25
26 namespace android {
27
VectorType(Scope * parent)28 VectorType::VectorType(Scope* parent) : TemplatedType(parent) {}
29
templatedTypeName() const30 std::string VectorType::templatedTypeName() const {
31 return "vector";
32 }
33
isCompatibleElementType(const Type * elementType) const34 bool VectorType::isCompatibleElementType(const Type* elementType) const {
35 if (elementType->isScalar()) {
36 return true;
37 }
38 if (elementType->isString()) {
39 return true;
40 }
41 if (elementType->isEnum()) {
42 return true;
43 }
44 if (elementType->isBitField()) {
45 return true;
46 }
47 if (elementType->isCompoundType()) {
48 return true;
49 }
50 if (elementType->isInterface()) {
51 return true;
52 }
53 if (elementType->isHandle()) {
54 return true;
55 }
56 if (elementType->isMemory()) {
57 return true;
58 }
59 if (elementType->isTemplatedType()) {
60 const Type* inner = static_cast<const TemplatedType*>(elementType)->getElementType();
61 return this->isCompatibleElementType(inner) && !inner->isInterface();
62 }
63 if (elementType->isArray()) {
64 const Type* inner = static_cast<const ArrayType*>(elementType)->getElementType();
65 return this->isCompatibleElementType(inner) && !inner->isInterface();
66 }
67 return false;
68 }
69
isVector() const70 bool VectorType::isVector() const {
71 return true;
72 }
73
isVectorOfBinders() const74 bool VectorType::isVectorOfBinders() const {
75 return mElementType->isBinder();
76 }
77
deepCanCheckEquality(std::unordered_set<const Type * > * visited) const78 bool VectorType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const {
79 return mElementType->canCheckEquality(visited);
80 }
81
getStrongReferences() const82 std::vector<const Reference<Type>*> VectorType::getStrongReferences() const {
83 return {};
84 }
85
getCppType(StorageMode mode,bool specifyNamespaces) const86 std::string VectorType::getCppType(StorageMode mode,
87 bool specifyNamespaces) const {
88 const std::string base =
89 std::string(specifyNamespaces ? "::android::hardware::" : "")
90 + "hidl_vec<"
91 + mElementType->getCppStackType( specifyNamespaces)
92 + ">";
93
94 switch (mode) {
95 case StorageMode_Stack:
96 return base;
97
98 case StorageMode_Argument:
99 return "const " + base + "&";
100
101 case StorageMode_Result:
102 {
103 if (isVectorOfBinders()) {
104 return base;
105 }
106
107 return "const " + base + "*";
108 }
109 }
110 }
111
getJavaType(bool) const112 std::string VectorType::getJavaType(bool /* forInitializer */) const {
113
114 std::string elementJavaType;
115 if (mElementType->isArray()) {
116 elementJavaType = mElementType->getJavaType();
117 } else {
118 elementJavaType = mElementType->getJavaWrapperType();
119 }
120
121 return "java.util.ArrayList<"
122 + elementJavaType
123 + ">";
124 }
125
getVtsType() const126 std::string VectorType::getVtsType() const {
127 return "TYPE_VECTOR";
128 }
129
getVtsValueName() const130 std::string VectorType::getVtsValueName() const {
131 return "vector_value";
132 }
133
emitReaderWriter(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const134 void VectorType::emitReaderWriter(
135 Formatter &out,
136 const std::string &name,
137 const std::string &parcelObj,
138 bool parcelObjIsPointer,
139 bool isReader,
140 ErrorMode mode) const {
141 if (isVectorOfBinders()) {
142 emitReaderWriterForVectorOfBinders(
143 out, name, parcelObj, parcelObjIsPointer, isReader, mode);
144
145 return;
146 }
147
148 std::string baseType = mElementType->getCppStackType();
149
150 const std::string parentName = "_hidl_" + name + "_parent";
151
152 out << "size_t " << parentName << ";\n\n";
153
154 const std::string parcelObjDeref =
155 parcelObj + (parcelObjIsPointer ? "->" : ".");
156
157 if (isReader) {
158 out << "_hidl_err = "
159 << parcelObjDeref
160 << "readBuffer("
161 << "sizeof(*"
162 << name
163 << "), &"
164 << parentName
165 << ", "
166 << " reinterpret_cast<const void **>("
167 << "&" << name
168 << "));\n\n";
169
170 handleError(out, mode);
171 } else {
172 out << "_hidl_err = "
173 << parcelObjDeref
174 << "writeBuffer(&"
175 << name
176 << ", sizeof("
177 << name
178 << "), &"
179 << parentName
180 << ");\n";
181
182 handleError(out, mode);
183 }
184
185 emitReaderWriterEmbedded(
186 out,
187 0 /* depth */,
188 name,
189 name /* sanitizedName */ ,
190 isReader /* nameIsPointer */,
191 parcelObj,
192 parcelObjIsPointer,
193 isReader,
194 mode,
195 parentName,
196 "0 /* parentOffset */");
197 }
198
emitReaderWriterForVectorOfBinders(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const199 void VectorType::emitReaderWriterForVectorOfBinders(
200 Formatter &out,
201 const std::string &name,
202 const std::string &parcelObj,
203 bool parcelObjIsPointer,
204 bool isReader,
205 ErrorMode mode) const {
206 const std::string parcelObjDeref =
207 parcelObj + (parcelObjIsPointer ? "->" : ".");
208
209 if (isReader) {
210 out << "{\n";
211 out.indent();
212
213 const std::string sizeName = "_hidl_" + name + "_size";
214
215 out << "uint64_t "
216 << sizeName
217 << ";\n";
218
219 out << "_hidl_err = "
220 << parcelObjDeref
221 << "readUint64(&"
222 << sizeName
223 << ");\n";
224
225 handleError(out, mode);
226
227 out << name
228 << ".resize("
229 << sizeName
230 << ");\n\n"
231 << "for (size_t _hidl_index = 0; _hidl_index < "
232 << sizeName
233 << "; ++_hidl_index) {\n";
234
235 out.indent();
236
237 out << mElementType->getCppStackType(true /* specifyNamespaces */)
238 << " _hidl_base;\n";
239
240 mElementType->emitReaderWriter(
241 out,
242 "_hidl_base",
243 parcelObj,
244 parcelObjIsPointer,
245 isReader,
246 mode);
247
248 out << name
249 << "[_hidl_index] = _hidl_base;\n";
250
251 out.unindent();
252 out << "}\n";
253
254 out.unindent();
255 out << "}\n";
256 } else {
257 out << "_hidl_err = "
258 << parcelObjDeref
259 << "writeUint64("
260 << name
261 << ".size());\n";
262
263 handleError(out, mode);
264
265 out << "for (size_t _hidl_index = 0; _hidl_index < "
266 << name
267 << ".size(); ++_hidl_index) {\n";
268
269 out.indent();
270
271 mElementType->emitReaderWriter(
272 out,
273 name + "[_hidl_index]",
274 parcelObj,
275 parcelObjIsPointer,
276 isReader,
277 mode);
278
279 out.unindent();
280 out << "}\n";
281 }
282 }
283
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) const284 void VectorType::emitReaderWriterEmbedded(
285 Formatter &out,
286 size_t depth,
287 const std::string &name,
288 const std::string &sanitizedName,
289 bool nameIsPointer,
290 const std::string &parcelObj,
291 bool parcelObjIsPointer,
292 bool isReader,
293 ErrorMode mode,
294 const std::string &parentName,
295 const std::string &offsetText) const {
296 std::string baseType = getCppStackType();
297
298 const std::string childName = "_hidl_" + sanitizedName + "_child";
299 out << "size_t " << childName << ";\n\n";
300
301 emitReaderWriterEmbeddedForTypeName(
302 out,
303 name,
304 nameIsPointer,
305 parcelObj,
306 parcelObjIsPointer,
307 isReader,
308 mode,
309 parentName,
310 offsetText,
311 baseType,
312 childName,
313 "::android::hardware");
314
315 if (!mElementType->needsEmbeddedReadWrite()) {
316 return;
317 }
318
319 const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
320
321 baseType = mElementType->getCppStackType();
322
323 std::string iteratorName = "_hidl_index_" + std::to_string(depth);
324
325 out << "for (size_t "
326 << iteratorName
327 << " = 0; "
328 << iteratorName
329 << " < "
330 << nameDeref
331 << "size(); ++"
332 << iteratorName
333 << ") {\n";
334
335 out.indent();
336
337 mElementType->emitReaderWriterEmbedded(
338 out,
339 depth + 1,
340 (nameIsPointer ? "(*" + name + ")" : name)
341 + "[" + iteratorName + "]",
342 sanitizedName + (nameIsPointer ? "_deref" : "") + "_indexed",
343 false /* nameIsPointer */,
344 parcelObj,
345 parcelObjIsPointer,
346 isReader,
347 mode,
348 childName,
349 iteratorName + " * sizeof(" + baseType + ")");
350
351 out.unindent();
352
353 out << "}\n\n";
354 }
355
emitResolveReferences(Formatter & out,const std::string & name,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const356 void VectorType::emitResolveReferences(
357 Formatter &out,
358 const std::string &name,
359 bool nameIsPointer,
360 const std::string &parcelObj,
361 bool parcelObjIsPointer,
362 bool isReader,
363 ErrorMode mode) const {
364 emitResolveReferencesEmbeddedHelper(
365 out,
366 0, /* depth */
367 name,
368 name /* sanitizedName */,
369 nameIsPointer,
370 parcelObj,
371 parcelObjIsPointer,
372 isReader,
373 mode,
374 "_hidl_" + name + "_child",
375 "0 /* parentOffset */");
376 }
377
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 &,const std::string &) const378 void VectorType::emitResolveReferencesEmbedded(
379 Formatter &out,
380 size_t depth,
381 const std::string &name,
382 const std::string &sanitizedName,
383 bool nameIsPointer,
384 const std::string &parcelObj,
385 bool parcelObjIsPointer,
386 bool isReader,
387 ErrorMode mode,
388 const std::string & /* parentName */,
389 const std::string & /* offsetText */) const {
390 emitResolveReferencesEmbeddedHelper(
391 out, depth, name, sanitizedName, nameIsPointer, parcelObj,
392 parcelObjIsPointer, isReader, mode, "", "");
393 }
394
useParentInEmitResolveReferencesEmbedded() const395 bool VectorType::useParentInEmitResolveReferencesEmbedded() const {
396 // parentName and offsetText is not used in emitResolveReferencesEmbedded
397 return false;
398 }
399
emitResolveReferencesEmbeddedHelper(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 & childName,const std::string & childOffsetText) const400 void VectorType::emitResolveReferencesEmbeddedHelper(
401 Formatter &out,
402 size_t depth,
403 const std::string &name,
404 const std::string &sanitizedName,
405 bool nameIsPointer,
406 const std::string &parcelObj,
407 bool parcelObjIsPointer,
408 bool isReader,
409 ErrorMode mode,
410 const std::string &childName,
411 const std::string &childOffsetText) const {
412 CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
413
414 const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
415 const std::string nameDerefed = (nameIsPointer ? "*" : "") + name;
416 std::string elementType = mElementType->getCppStackType();
417
418 std::string myChildName = childName, myChildOffset = childOffsetText;
419
420 if(myChildName.empty() && myChildOffset.empty()) {
421 myChildName = "_hidl_" + sanitizedName + "_child";
422 myChildOffset = "0";
423
424 out << "size_t " << myChildName << ";\n";
425 out << "_hidl_err = ::android::hardware::findInParcel("
426 << nameDerefed << ", "
427 << (parcelObjIsPointer ? "*" : "") << parcelObj << ", "
428 << "&" << myChildName
429 << ");\n";
430
431 handleError(out, mode);
432 }
433
434 std::string iteratorName = "_hidl_index_" + std::to_string(depth);
435
436 out << "for (size_t "
437 << iteratorName
438 << " = 0; "
439 << iteratorName
440 << " < "
441 << nameDeref
442 << "size(); ++"
443 << iteratorName
444 << ") {\n";
445
446 out.indent();
447
448 mElementType->emitResolveReferencesEmbedded(
449 out,
450 depth + 1,
451 (nameIsPointer ? "(*" + name + ")" : name) + "[" + iteratorName + "]",
452 sanitizedName + (nameIsPointer ? "_deref" : "") + "_indexed",
453 false /* nameIsPointer */,
454 parcelObj,
455 parcelObjIsPointer,
456 isReader,
457 mode,
458 myChildName,
459 myChildOffset + " + " +
460 iteratorName + " * sizeof(" + elementType + ")");
461
462 out.unindent();
463
464 out << "}\n\n";
465 }
466
emitJavaReaderWriter(Formatter & out,const std::string & parcelObj,const std::string & argName,bool isReader) const467 void VectorType::emitJavaReaderWriter(
468 Formatter &out,
469 const std::string &parcelObj,
470 const std::string &argName,
471 bool isReader) const {
472 if (mElementType->isCompoundType()) {
473
474 if (isReader) {
475 out << mElementType->getJavaType()
476 << ".readVectorFromParcel("
477 << parcelObj
478 << ");\n";
479 } else {
480 out << mElementType->getJavaType()
481 << ".writeVectorToParcel("
482 << parcelObj
483 << ", "
484 << argName
485 << ");\n";
486 }
487
488 return;
489 }
490
491 if (mElementType->isArray()) {
492 size_t align, size;
493 getAlignmentAndSize(&align, &size);
494 if (isReader) {
495 out << " new "
496 << getJavaType(false /* forInitializer */)
497 << "();\n";
498 }
499
500 out << "{\n";
501 out.indent();
502
503 out << "android.os.HwBlob _hidl_blob = ";
504
505 if (isReader) {
506 out << parcelObj
507 << ".readBuffer("
508 << size
509 << " /* size */);\n";
510 } else {
511
512 out << "new android.os.HwBlob("
513 << size
514 << " /* size */);\n";
515 }
516
517 emitJavaFieldReaderWriter(
518 out,
519 0 /* depth */,
520 parcelObj,
521 "_hidl_blob",
522 argName,
523 "0 /* offset */",
524 isReader);
525
526 if (!isReader) {
527 out << parcelObj << ".writeBuffer(_hidl_blob);\n";
528 };
529
530 out.unindent();
531 out << "}\n";
532
533 return;
534 }
535
536 emitJavaReaderWriterWithSuffix(
537 out,
538 parcelObj,
539 argName,
540 isReader,
541 mElementType->getJavaSuffix() + "Vector",
542 "" /* extra */);
543 }
544
emitJavaFieldInitializer(Formatter & out,const std::string & fieldName) const545 void VectorType::emitJavaFieldInitializer(
546 Formatter &out, const std::string &fieldName) const {
547 std::string javaType = getJavaType(false /* forInitializer */);
548
549 out << "final "
550 << javaType
551 << " "
552 << fieldName
553 << " = new "
554 << javaType
555 << "();\n";
556 }
557
emitJavaFieldReaderWriter(Formatter & out,size_t depth,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader) const558 void VectorType::emitJavaFieldReaderWriter(
559 Formatter &out,
560 size_t depth,
561 const std::string &parcelName,
562 const std::string &blobName,
563 const std::string &fieldName,
564 const std::string &offset,
565 bool isReader) const {
566 VectorType::EmitJavaFieldReaderWriterForElementType(
567 out,
568 depth,
569 mElementType.get(),
570 parcelName,
571 blobName,
572 fieldName,
573 offset,
574 isReader);
575 }
576
EmitJavaFieldReaderWriterForElementType(Formatter & out,size_t depth,const Type * elementType,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader)577 void VectorType::EmitJavaFieldReaderWriterForElementType(
578 Formatter &out,
579 size_t depth,
580 const Type *elementType,
581 const std::string &parcelName,
582 const std::string &blobName,
583 const std::string &fieldName,
584 const std::string &offset,
585 bool isReader) {
586 size_t elementAlign, elementSize;
587 elementType->getAlignmentAndSize(&elementAlign, &elementSize);
588
589 if (isReader) {
590 out << "{\n";
591 out.indent();
592
593 out << "int _hidl_vec_size = "
594 << blobName
595 << ".getInt32("
596 << offset
597 << " + 8 /* offsetof(hidl_vec<T>, mSize) */);\n";
598
599 out << "android.os.HwBlob childBlob = "
600 << parcelName
601 << ".readEmbeddedBuffer(\n";
602
603 out.indent();
604 out.indent();
605
606 out << "_hidl_vec_size * "
607 << elementSize << ","
608 << blobName
609 << ".handle(),\n"
610 << offset
611 << " + 0 /* offsetof(hidl_vec<T>, mBuffer) */,"
612 << "true /* nullable */);\n\n";
613
614 out.unindent();
615 out.unindent();
616
617 out << fieldName << ".clear();\n";
618 std::string iteratorName = "_hidl_index_" + std::to_string(depth);
619
620 out << "for (int "
621 << iteratorName
622 << " = 0; "
623 << iteratorName
624 << " < _hidl_vec_size; "
625 << "++"
626 << iteratorName
627 << ") {\n";
628
629 out.indent();
630
631 elementType->emitJavaFieldInitializer(out, "_hidl_vec_element");
632
633 elementType->emitJavaFieldReaderWriter(
634 out,
635 depth + 1,
636 parcelName,
637 "childBlob",
638 "_hidl_vec_element",
639 iteratorName + " * " + std::to_string(elementSize),
640 true /* isReader */);
641
642 out << fieldName
643 << ".add(_hidl_vec_element);\n";
644
645 out.unindent();
646
647 out << "}\n";
648
649 out.unindent();
650 out << "}\n";
651
652 return;
653 }
654
655 out << "{\n";
656 out.indent();
657
658 out << "int _hidl_vec_size = "
659 << fieldName
660 << ".size();\n";
661
662 out << blobName
663 << ".putInt32("
664 << offset
665 << " + 8 /* offsetof(hidl_vec<T>, mSize) */, _hidl_vec_size);\n";
666
667 out << blobName
668 << ".putBool("
669 << offset
670 << " + 12 /* offsetof(hidl_vec<T>, mOwnsBuffer) */, false);\n";
671
672 // XXX make HwBlob constructor take a long instead of an int?
673 out << "android.os.HwBlob childBlob = new android.os.HwBlob((int)(_hidl_vec_size * "
674 << elementSize
675 << "));\n";
676
677 std::string iteratorName = "_hidl_index_" + std::to_string(depth);
678
679 out << "for (int "
680 << iteratorName
681 << " = 0; "
682 << iteratorName
683 << " < _hidl_vec_size; "
684 << "++"
685 << iteratorName
686 << ") {\n";
687
688 out.indent();
689
690 elementType->emitJavaFieldReaderWriter(
691 out,
692 depth + 1,
693 parcelName,
694 "childBlob",
695 fieldName + ".get(" + iteratorName + ")",
696 iteratorName + " * " + std::to_string(elementSize),
697 false /* isReader */);
698
699 out.unindent();
700
701 out << "}\n";
702
703 out << blobName
704 << ".putBlob("
705 << offset
706 << " + 0 /* offsetof(hidl_vec<T>, mBuffer) */, childBlob);\n";
707
708 out.unindent();
709 out << "}\n";
710 }
711
needsEmbeddedReadWrite() const712 bool VectorType::needsEmbeddedReadWrite() const {
713 return true;
714 }
715
deepNeedsResolveReferences(std::unordered_set<const Type * > * visited) const716 bool VectorType::deepNeedsResolveReferences(std::unordered_set<const Type*>* visited) const {
717 if (mElementType->needsResolveReferences(visited)) {
718 return true;
719 }
720 return TemplatedType::deepNeedsResolveReferences(visited);
721 }
722
resultNeedsDeref() const723 bool VectorType::resultNeedsDeref() const {
724 return !isVectorOfBinders();
725 }
726
deepIsJavaCompatible(std::unordered_set<const Type * > * visited) const727 bool VectorType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
728 if (!mElementType->isJavaCompatible(visited)) {
729 return false;
730 }
731
732 if (mElementType->isArray()) {
733 return static_cast<const ArrayType*>(mElementType.get())->countDimensions() == 1;
734 }
735
736 if (mElementType->isVector()) {
737 return false;
738 }
739
740 if (isVectorOfBinders()) {
741 return false;
742 }
743
744 return TemplatedType::deepIsJavaCompatible(visited);
745 }
746
deepContainsPointer(std::unordered_set<const Type * > * visited) const747 bool VectorType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
748 if (mElementType->containsPointer(visited)) {
749 return true;
750 }
751 return TemplatedType::deepContainsPointer(visited);
752 }
753
754 // All hidl_vec<T> have the same size.
755 static HidlTypeAssertion assertion("hidl_vec<char>", 16 /* size */);
756
getAlignmentAndSizeStatic(size_t * align,size_t * size)757 void VectorType::getAlignmentAndSizeStatic(size_t *align, size_t *size) {
758 *align = 8; // hidl_vec<T>
759 *size = assertion.size();
760 }
761
getAlignmentAndSize(size_t * align,size_t * size) const762 void VectorType::getAlignmentAndSize(size_t *align, size_t *size) const {
763 VectorType::getAlignmentAndSizeStatic(align, size);
764 }
765
766 } // namespace android
767
768