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