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 "CompoundType.h"
18
19 #include "ArrayType.h"
20 #include "VectorType.h"
21 #include <hidl-util/Formatter.h>
22 #include <android-base/logging.h>
23
24 namespace android {
25
CompoundType(Style style,const char * localName,const Location & location)26 CompoundType::CompoundType(Style style, const char *localName, const Location &location)
27 : Scope(localName, location),
28 mStyle(style),
29 mFields(NULL) {
30 }
31
style() const32 CompoundType::Style CompoundType::style() const {
33 return mStyle;
34 }
35
setFields(std::vector<CompoundField * > * fields,std::string * errorMsg)36 bool CompoundType::setFields(
37 std::vector<CompoundField *> *fields, std::string *errorMsg) {
38 mFields = fields;
39
40 for (const auto &field : *fields) {
41 const Type &type = field->type();
42
43 if (type.isBinder()
44 || (type.isVector()
45 && static_cast<const VectorType *>(
46 &type)->isVectorOfBinders())) {
47 *errorMsg =
48 "Structs/Unions must not contain references to interfaces.";
49
50 return false;
51 }
52
53 if (mStyle == STYLE_UNION) {
54 if (type.needsEmbeddedReadWrite()) {
55 // Can't have those in a union.
56
57 *errorMsg =
58 "Unions must not contain any types that need fixup.";
59
60 return false;
61 }
62 }
63 }
64
65 return true;
66 }
67
isCompoundType() const68 bool CompoundType::isCompoundType() const {
69 return true;
70 }
71
canCheckEquality() const72 bool CompoundType::canCheckEquality() const {
73 if (mStyle == STYLE_UNION) {
74 return false;
75 }
76 for (const auto &field : *mFields) {
77 if (!field->type().canCheckEquality()) {
78 return false;
79 }
80 }
81 return true;
82 }
83
getCppType(StorageMode mode,bool specifyNamespaces) const84 std::string CompoundType::getCppType(
85 StorageMode mode,
86 bool specifyNamespaces) const {
87 const std::string base =
88 specifyNamespaces ? fullName() : partialCppName();
89
90 switch (mode) {
91 case StorageMode_Stack:
92 return base;
93
94 case StorageMode_Argument:
95 return "const " + base + "&";
96
97 case StorageMode_Result:
98 return "const " + base + "*";
99 }
100 }
101
getJavaType(bool) const102 std::string CompoundType::getJavaType(bool /* forInitializer */) const {
103 return fullJavaName();
104 }
105
getVtsType() const106 std::string CompoundType::getVtsType() const {
107 switch (mStyle) {
108 case STYLE_STRUCT:
109 {
110 return "TYPE_STRUCT";
111 }
112 case STYLE_UNION:
113 {
114 return "TYPE_UNION";
115 }
116 }
117 }
118
emitReaderWriter(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const119 void CompoundType::emitReaderWriter(
120 Formatter &out,
121 const std::string &name,
122 const std::string &parcelObj,
123 bool parcelObjIsPointer,
124 bool isReader,
125 ErrorMode mode) const {
126 const std::string parentName = "_hidl_" + name + "_parent";
127
128 out << "size_t " << parentName << ";\n\n";
129
130 const std::string parcelObjDeref =
131 parcelObj + (parcelObjIsPointer ? "->" : ".");
132
133 if (isReader) {
134 out << "_hidl_err = "
135 << parcelObjDeref
136 << "readBuffer("
137 << "sizeof(*"
138 << name
139 << "), &"
140 << parentName
141 << ", "
142 << " reinterpret_cast<const void **>("
143 << "&" << name
144 << "));\n";
145
146 handleError(out, mode);
147 } else {
148 out << "_hidl_err = "
149 << parcelObjDeref
150 << "writeBuffer(&"
151 << name
152 << ", sizeof("
153 << name
154 << "), &"
155 << parentName
156 << ");\n";
157
158 handleError(out, mode);
159 }
160
161 if (mStyle != STYLE_STRUCT || !needsEmbeddedReadWrite()) {
162 return;
163 }
164
165 emitReaderWriterEmbedded(
166 out,
167 0 /* depth */,
168 name,
169 name, /* sanitizedName */
170 isReader /* nameIsPointer */,
171 parcelObj,
172 parcelObjIsPointer,
173 isReader,
174 mode,
175 parentName,
176 "0 /* parentOffset */");
177 }
178
emitReaderWriterEmbedded(Formatter & out,size_t,const std::string & name,const std::string &,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode,const std::string & parentName,const std::string & offsetText) const179 void CompoundType::emitReaderWriterEmbedded(
180 Formatter &out,
181 size_t /* depth */,
182 const std::string &name,
183 const std::string & /*sanitizedName */,
184 bool nameIsPointer,
185 const std::string &parcelObj,
186 bool parcelObjIsPointer,
187 bool isReader,
188 ErrorMode mode,
189 const std::string &parentName,
190 const std::string &offsetText) const {
191 emitReaderWriterEmbeddedForTypeName(
192 out,
193 name,
194 nameIsPointer,
195 parcelObj,
196 parcelObjIsPointer,
197 isReader,
198 mode,
199 parentName,
200 offsetText,
201 fullName(),
202 "" /* childName */,
203 "" /* namespace */);
204 }
205
emitJavaReaderWriter(Formatter & out,const std::string & parcelObj,const std::string & argName,bool isReader) const206 void CompoundType::emitJavaReaderWriter(
207 Formatter &out,
208 const std::string &parcelObj,
209 const std::string &argName,
210 bool isReader) const {
211 if (isReader) {
212 out << "new " << fullJavaName() << "();\n";
213 }
214
215 out << argName
216 << "."
217 << (isReader ? "readFromParcel" : "writeToParcel")
218 << "("
219 << parcelObj
220 << ");\n";
221 }
222
emitJavaFieldInitializer(Formatter & out,const std::string & fieldName) const223 void CompoundType::emitJavaFieldInitializer(
224 Formatter &out, const std::string &fieldName) const {
225 out << "final "
226 << fullJavaName()
227 << " "
228 << fieldName
229 << " = new "
230 << fullJavaName()
231 << "();\n";
232 }
233
emitJavaFieldReaderWriter(Formatter & out,size_t,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader) const234 void CompoundType::emitJavaFieldReaderWriter(
235 Formatter &out,
236 size_t /* depth */,
237 const std::string &parcelName,
238 const std::string &blobName,
239 const std::string &fieldName,
240 const std::string &offset,
241 bool isReader) const {
242 if (isReader) {
243 out << fieldName
244 << ".readEmbeddedFromParcel("
245 << parcelName
246 << ", "
247 << blobName
248 << ", "
249 << offset
250 << ");\n";
251
252 return;
253 }
254
255 out << fieldName
256 << ".writeEmbeddedToBlob("
257 << blobName
258 << ", "
259 << offset
260 << ");\n";
261 }
emitResolveReferences(Formatter & out,const std::string & name,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const262 void CompoundType::emitResolveReferences(
263 Formatter &out,
264 const std::string &name,
265 bool nameIsPointer,
266 const std::string &parcelObj,
267 bool parcelObjIsPointer,
268 bool isReader,
269 ErrorMode mode) const {
270 emitResolveReferencesEmbedded(
271 out,
272 0 /* depth */,
273 name,
274 name /* sanitizedName */,
275 nameIsPointer,
276 parcelObj,
277 parcelObjIsPointer,
278 isReader,
279 mode,
280 "_hidl_" + name + "_parent",
281 "0 /* parentOffset */");
282 }
283
emitResolveReferencesEmbedded(Formatter & out,size_t,const std::string & name,const std::string &,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode,const std::string & parentName,const std::string & offsetText) const284 void CompoundType::emitResolveReferencesEmbedded(
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 CHECK(needsResolveReferences());
297
298 const std::string parcelObjDeref =
299 parcelObjIsPointer ? ("*" + parcelObj) : parcelObj;
300
301 const std::string parcelObjPointer =
302 parcelObjIsPointer ? parcelObj : ("&" + parcelObj);
303
304 const std::string nameDerefed = nameIsPointer ? ("*" + name) : name;
305 const std::string namePointer = nameIsPointer ? name : ("&" + name);
306
307 out << "_hidl_err = ";
308
309 if (isReader) {
310 out << "readEmbeddedReferenceFromParcel(\n";
311 } else {
312 out << "writeEmbeddedReferenceToParcel(\n";
313 }
314
315 out.indent(2, [&]{
316 if (isReader) {
317 out << "const_cast<"
318 << fullName()
319 << " *"
320 << ">("
321 << namePointer
322 << "),\n"
323 << parcelObjDeref;
324 } else {
325 out << nameDerefed
326 << ",\n"
327 << parcelObjPointer;
328 }
329
330 out << ",\n"
331 << parentName
332 << ",\n"
333 << offsetText
334 << ");\n\n";
335 });
336
337 handleError(out, mode);
338 }
339
emitTypeDeclarations(Formatter & out) const340 status_t CompoundType::emitTypeDeclarations(Formatter &out) const {
341 out << ((mStyle == STYLE_STRUCT) ? "struct" : "union")
342 << " "
343 << localName()
344 << " final {\n";
345
346 out.indent();
347
348 Scope::emitTypeDeclarations(out);
349
350 if (containsPointer()) {
351 for (const auto &field : *mFields) {
352 out << field->type().getCppStackType()
353 << " "
354 << field->name()
355 << ";\n";
356 }
357
358 out.unindent();
359 out << "};\n\n";
360
361 return OK;
362 }
363
364 for (int pass = 0; pass < 2; ++pass) {
365 size_t offset = 0;
366 for (const auto &field : *mFields) {
367 size_t fieldAlign, fieldSize;
368 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
369
370 size_t pad = offset % fieldAlign;
371 if (pad > 0) {
372 offset += fieldAlign - pad;
373 }
374
375 if (pass == 0) {
376 out << field->type().getCppStackType()
377 << " "
378 << field->name()
379 << " __attribute__ ((aligned("
380 << fieldAlign
381 << ")));\n";
382 } else {
383 out << "static_assert(offsetof("
384 << fullName()
385 << ", "
386 << field->name()
387 << ") == "
388 << offset
389 << ", \"wrong offset\");\n";
390 }
391
392 if (mStyle == STYLE_STRUCT) {
393 offset += fieldSize;
394 }
395 }
396
397 if (pass == 0) {
398 out.unindent();
399 out << "};\n\n";
400 }
401 }
402
403 size_t structAlign, structSize;
404 getAlignmentAndSize(&structAlign, &structSize);
405
406 out << "static_assert(sizeof("
407 << fullName()
408 << ") == "
409 << structSize
410 << ", \"wrong size\");\n";
411
412 out << "static_assert(__alignof("
413 << fullName()
414 << ") == "
415 << structAlign
416 << ", \"wrong alignment\");\n\n";
417
418 return OK;
419 }
420
421
emitGlobalTypeDeclarations(Formatter & out) const422 status_t CompoundType::emitGlobalTypeDeclarations(Formatter &out) const {
423 Scope::emitGlobalTypeDeclarations(out);
424
425 out << "std::string toString("
426 << getCppArgumentType()
427 << ");\n\n";
428
429 if (canCheckEquality()) {
430 out << "bool operator==("
431 << getCppArgumentType() << ", " << getCppArgumentType() << ");\n\n";
432
433 out << "bool operator!=("
434 << getCppArgumentType() << ", " << getCppArgumentType() << ");\n\n";
435 } else {
436 out << "// operator== and operator!= are not generated for " << localName() << "\n\n";
437 }
438
439 return OK;
440 }
441
emitGlobalHwDeclarations(Formatter & out) const442 status_t CompoundType::emitGlobalHwDeclarations(Formatter &out) const {
443 if (needsEmbeddedReadWrite()) {
444 out << "::android::status_t readEmbeddedFromParcel(\n";
445
446 out.indent(2);
447
448 out << "const " << fullName() << " &obj,\n"
449 << "const ::android::hardware::Parcel &parcel,\n"
450 << "size_t parentHandle,\n"
451 << "size_t parentOffset);\n\n";
452
453 out.unindent(2);
454
455 out << "::android::status_t writeEmbeddedToParcel(\n";
456
457 out.indent(2);
458
459 out << "const " << fullName() << " &obj,\n"
460 << "::android::hardware::Parcel *parcel,\n"
461 << "size_t parentHandle,\n"
462 << "size_t parentOffset);\n\n";
463
464 out.unindent(2);
465 }
466
467 if(needsResolveReferences()) {
468 out << "::android::status_t readEmbeddedReferenceFromParcel(\n";
469 out.indent(2);
470 out << fullName() << " *obj,\n"
471 << "const ::android::hardware::Parcel &parcel,\n"
472 << "size_t parentHandle, size_t parentOffset);\n\n";
473 out.unindent(2);
474 out << "::android::status_t writeEmbeddedReferenceToParcel(\n";
475 out.indent(2);
476 out << "const " << fullName() << " &obj,\n"
477 << "::android::hardware::Parcel *,\n"
478 << "size_t parentHandle, size_t parentOffset);\n\n";
479 out.unindent(2);
480 }
481
482 return OK;
483 }
484
emitTypeDefinitions(Formatter & out,const std::string prefix) const485 status_t CompoundType::emitTypeDefinitions(
486 Formatter &out, const std::string prefix) const {
487 std::string space = prefix.empty() ? "" : (prefix + "::");
488 status_t err = Scope::emitTypeDefinitions(out, space + localName());
489
490 if (err != OK) {
491 return err;
492 }
493
494 if (needsEmbeddedReadWrite()) {
495 emitStructReaderWriter(out, prefix, true /* isReader */);
496 emitStructReaderWriter(out, prefix, false /* isReader */);
497 }
498
499 if (needsResolveReferences()) {
500 emitResolveReferenceDef(out, prefix, true /* isReader */);
501 emitResolveReferenceDef(out, prefix, false /* isReader */);
502 }
503
504 out << "std::string toString("
505 << getCppArgumentType()
506 << (mFields->empty() ? "" : " o")
507 << ") ";
508
509 out.block([&] {
510 // include toString for scalar types
511 out << "using ::android::hardware::toString;\n"
512 << "std::string os;\n";
513 out << "os += \"{\";\n";
514
515 for (const CompoundField *field : *mFields) {
516 out << "os += \"";
517 if (field != *(mFields->begin())) {
518 out << ", ";
519 }
520 out << "." << field->name() << " = \";\n";
521 field->type().emitDump(out, "os", "o." + field->name());
522 }
523
524 out << "os += \"}\"; return os;\n";
525 }).endl().endl();
526
527 if (canCheckEquality()) {
528 out << "bool operator==("
529 << getCppArgumentType() << " " << (mFields->empty() ? "/* lhs */" : "lhs") << ", "
530 << getCppArgumentType() << " " << (mFields->empty() ? "/* rhs */" : "rhs") << ") ";
531 out.block([&] {
532 for (const auto &field : *mFields) {
533 out.sIf("lhs." + field->name() + " != rhs." + field->name(), [&] {
534 out << "return false;\n";
535 }).endl();
536 }
537 out << "return true;\n";
538 }).endl().endl();
539
540 out << "bool operator!=("
541 << getCppArgumentType() << " lhs," << getCppArgumentType() << " rhs)";
542 out.block([&] {
543 out << "return !(lhs == rhs);\n";
544 }).endl().endl();
545 } else {
546 out << "// operator== and operator!= are not generated for " << localName() << "\n";
547 }
548
549 return OK;
550 }
551
emitJavaTypeDeclarations(Formatter & out,bool atTopLevel) const552 status_t CompoundType::emitJavaTypeDeclarations(
553 Formatter &out, bool atTopLevel) const {
554 out << "public final ";
555
556 if (!atTopLevel) {
557 out << "static ";
558 }
559
560 out << "class "
561 << localName()
562 << " {\n";
563
564 out.indent();
565
566 Scope::emitJavaTypeDeclarations(out, false /* atTopLevel */);
567
568 for (const auto &field : *mFields) {
569 out << "public ";
570
571 field->type().emitJavaFieldInitializer(out, field->name());
572 }
573
574 if (!mFields->empty()) {
575 out << "\n";
576 }
577
578 ////////////////////////////////////////////////////////////////////////////
579
580 if (canCheckEquality()) {
581 out << "@Override\npublic final boolean equals(Object otherObject) ";
582 out.block([&] {
583 out.sIf("this == otherObject", [&] {
584 out << "return true;\n";
585 }).endl();
586 out.sIf("otherObject == null", [&] {
587 out << "return false;\n";
588 }).endl();
589 // Though class is final, we use getClass instead of instanceof to be explicit.
590 out.sIf("otherObject.getClass() != " + fullJavaName() + ".class", [&] {
591 out << "return false;\n";
592 }).endl();
593 out << fullJavaName() << " other = (" << fullJavaName() << ")otherObject;\n";
594 for (const auto &field : *mFields) {
595 std::string condition = (field->type().isScalar() || field->type().isEnum())
596 ? "this." + field->name() + " != other." + field->name()
597 : ("!android.os.HidlSupport.deepEquals(this." + field->name()
598 + ", other." + field->name() + ")");
599 out.sIf(condition, [&] {
600 out << "return false;\n";
601 }).endl();
602 }
603 out << "return true;\n";
604 }).endl().endl();
605
606 out << "@Override\npublic final int hashCode() ";
607 out.block([&] {
608 out << "return java.util.Objects.hash(\n";
609 out.indent(2, [&] {
610 out.join(mFields->begin(), mFields->end(), ", \n", [&] (const auto &field) {
611 out << "android.os.HidlSupport.deepHashCode(this." << field->name() << ")";
612 });
613 });
614 out << ");\n";
615 }).endl().endl();
616 } else {
617 out << "// equals() is not generated for " << localName() << "\n";
618 }
619
620 ////////////////////////////////////////////////////////////////////////////
621
622 out << "@Override\npublic final String toString() ";
623 out.block([&] {
624 out << "java.lang.StringBuilder builder = new java.lang.StringBuilder();\n"
625 << "builder.append(\"{\");\n";
626 for (const auto &field : *mFields) {
627 out << "builder.append(\"";
628 if (field != *(mFields->begin())) {
629 out << ", ";
630 }
631 out << "." << field->name() << " = \");\n";
632 field->type().emitJavaDump(out, "builder", "this." + field->name());
633 }
634 out << "builder.append(\"}\");\nreturn builder.toString();\n";
635 }).endl().endl();
636
637 size_t structAlign, structSize;
638 getAlignmentAndSize(&structAlign, &structSize);
639
640 ////////////////////////////////////////////////////////////////////////////
641
642 out << "public final void readFromParcel(android.os.HwParcel parcel) {\n";
643 out.indent();
644 out << "android.os.HwBlob blob = parcel.readBuffer(";
645 out << structSize << "/* size */);\n";
646 out << "readEmbeddedFromParcel(parcel, blob, 0 /* parentOffset */);\n";
647 out.unindent();
648 out << "}\n\n";
649
650 ////////////////////////////////////////////////////////////////////////////
651
652 size_t vecAlign, vecSize;
653 VectorType::getAlignmentAndSizeStatic(&vecAlign, &vecSize);
654
655 out << "public static final java.util.ArrayList<"
656 << localName()
657 << "> readVectorFromParcel(android.os.HwParcel parcel) {\n";
658 out.indent();
659
660 out << "java.util.ArrayList<"
661 << localName()
662 << "> _hidl_vec = new java.util.ArrayList();\n";
663
664 out << "android.os.HwBlob _hidl_blob = parcel.readBuffer(";
665 out << vecSize << " /* sizeof hidl_vec<T> */);\n\n";
666
667 VectorType::EmitJavaFieldReaderWriterForElementType(
668 out,
669 0 /* depth */,
670 this,
671 "parcel",
672 "_hidl_blob",
673 "_hidl_vec",
674 "0",
675 true /* isReader */);
676
677 out << "\nreturn _hidl_vec;\n";
678
679 out.unindent();
680 out << "}\n\n";
681
682 ////////////////////////////////////////////////////////////////////////////
683
684 out << "public final void readEmbeddedFromParcel(\n";
685 out.indent(2);
686 out << "android.os.HwParcel parcel, android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
687 out.unindent();
688
689 size_t offset = 0;
690 for (const auto &field : *mFields) {
691 size_t fieldAlign, fieldSize;
692 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
693
694 size_t pad = offset % fieldAlign;
695 if (pad > 0) {
696 offset += fieldAlign - pad;
697 }
698
699 field->type().emitJavaFieldReaderWriter(
700 out,
701 0 /* depth */,
702 "parcel",
703 "_hidl_blob",
704 field->name(),
705 "_hidl_offset + " + std::to_string(offset),
706 true /* isReader */);
707
708 offset += fieldSize;
709 }
710
711 out.unindent();
712 out << "}\n\n";
713
714 ////////////////////////////////////////////////////////////////////////////
715
716 out << "public final void writeToParcel(android.os.HwParcel parcel) {\n";
717 out.indent();
718
719 out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob("
720 << structSize
721 << " /* size */);\n";
722
723 out << "writeEmbeddedToBlob(_hidl_blob, 0 /* parentOffset */);\n"
724 << "parcel.writeBuffer(_hidl_blob);\n";
725
726 out.unindent();
727 out << "}\n\n";
728
729 ////////////////////////////////////////////////////////////////////////////
730
731 out << "public static final void writeVectorToParcel(\n";
732 out.indent(2);
733 out << "android.os.HwParcel parcel, java.util.ArrayList<"
734 << localName()
735 << "> _hidl_vec) {\n";
736 out.unindent();
737
738 out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob("
739 << vecSize << " /* sizeof(hidl_vec<T>) */);\n";
740
741 VectorType::EmitJavaFieldReaderWriterForElementType(
742 out,
743 0 /* depth */,
744 this,
745 "parcel",
746 "_hidl_blob",
747 "_hidl_vec",
748 "0",
749 false /* isReader */);
750
751 out << "\nparcel.writeBuffer(_hidl_blob);\n";
752
753 out.unindent();
754 out << "}\n\n";
755
756 ////////////////////////////////////////////////////////////////////////////
757
758 out << "public final void writeEmbeddedToBlob(\n";
759 out.indent(2);
760 out << "android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
761 out.unindent();
762
763 offset = 0;
764 for (const auto &field : *mFields) {
765 size_t fieldAlign, fieldSize;
766 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
767
768 size_t pad = offset % fieldAlign;
769 if (pad > 0) {
770 offset += fieldAlign - pad;
771 }
772
773 field->type().emitJavaFieldReaderWriter(
774 out,
775 0 /* depth */,
776 "parcel",
777 "_hidl_blob",
778 field->name(),
779 "_hidl_offset + " + std::to_string(offset),
780 false /* isReader */);
781
782 offset += fieldSize;
783 }
784
785 out.unindent();
786 out << "}\n";
787
788 out.unindent();
789 out << "};\n\n";
790
791 return OK;
792 }
793
emitStructReaderWriter(Formatter & out,const std::string & prefix,bool isReader) const794 void CompoundType::emitStructReaderWriter(
795 Formatter &out, const std::string &prefix, bool isReader) const {
796
797 std::string space = prefix.empty() ? "" : (prefix + "::");
798
799 out << "::android::status_t "
800 << (isReader ? "readEmbeddedFromParcel"
801 : "writeEmbeddedToParcel")
802 << "(\n";
803
804 out.indent(2);
805
806 bool useName = false;
807 for (const auto &field : *mFields) {
808 if (field->type().useNameInEmitReaderWriterEmbedded(isReader)) {
809 useName = true;
810 break;
811 }
812 }
813 std::string name = useName ? "obj" : "/* obj */";
814 // if not useName, then obj should not be used at all,
815 // then the #error should not be emitted.
816 std::string error = useName ? "" : "\n#error\n";
817
818 if (isReader) {
819 out << "const " << space << localName() << " &" << name << ",\n";
820 out << "const ::android::hardware::Parcel &parcel,\n";
821 } else {
822 out << "const " << space << localName() << " &" << name << ",\n";
823 out << "::android::hardware::Parcel *parcel,\n";
824 }
825
826 out << "size_t parentHandle,\n"
827 << "size_t parentOffset)";
828
829 out << " {\n";
830
831 out.unindent(2);
832 out.indent();
833
834 out << "::android::status_t _hidl_err = ::android::OK;\n\n";
835
836 for (const auto &field : *mFields) {
837 if (!field->type().needsEmbeddedReadWrite()) {
838 continue;
839 }
840
841 field->type().emitReaderWriterEmbedded(
842 out,
843 0 /* depth */,
844 name + "." + field->name() + error,
845 field->name() /* sanitizedName */,
846 false /* nameIsPointer */,
847 "parcel",
848 !isReader /* parcelObjIsPointer */,
849 isReader,
850 ErrorMode_Return,
851 "parentHandle",
852 "parentOffset + offsetof("
853 + fullName()
854 + ", "
855 + field->name()
856 + ")");
857 }
858
859 out << "return _hidl_err;\n";
860
861 out.unindent();
862 out << "}\n\n";
863 }
864
emitResolveReferenceDef(Formatter & out,const std::string prefix,bool isReader) const865 void CompoundType::emitResolveReferenceDef(
866 Formatter &out, const std::string prefix, bool isReader) const {
867 out << "::android::status_t ";
868 const std::string space(prefix.empty() ? "" : (prefix + "::"));
869
870 bool useParent = false;
871 for (const auto &field : *mFields) {
872 if (field->type().useParentInEmitResolveReferencesEmbedded()) {
873 useParent = true;
874 break;
875 }
876 }
877
878 std::string parentHandleName = useParent ? "parentHandle" : "/* parentHandle */";
879 std::string parentOffsetName = useParent ? "parentOffset" : "/* parentOffset */";
880
881 if (isReader) {
882 out << "readEmbeddedReferenceFromParcel(\n";
883 out.indent(2);
884 out << space + localName() + " *obj,\n"
885 << "const ::android::hardware::Parcel &parcel,\n"
886 << "size_t " << parentHandleName << ", "
887 << "size_t " << parentOffsetName << ")\n";
888 out.unindent(2);
889 } else {
890 out << "writeEmbeddedReferenceToParcel(\n";
891 out.indent(2);
892 out << "const " << space + localName() + " &obj,\n"
893 << "::android::hardware::Parcel *parcel,\n"
894 << "size_t " << parentHandleName << ", "
895 << "size_t " << parentOffsetName << ")\n";
896 out.unindent(2);
897 }
898
899 out << " {\n";
900
901 out.indent();
902
903 out << "::android::status_t _hidl_err = ::android::OK;\n\n";
904
905 const std::string nameDeref(isReader ? "obj->" : "obj.");
906 // if not useParent, then parentName and offsetText
907 // should not be used at all, then the #error should not be emitted.
908 std::string error = useParent ? "" : "\n#error\n";
909
910 for (const auto &field : *mFields) {
911 if (!field->type().needsResolveReferences()) {
912 continue;
913 }
914
915 field->type().emitResolveReferencesEmbedded(
916 out,
917 0 /* depth */,
918 nameDeref + field->name(),
919 field->name() /* sanitizedName */,
920 false, // nameIsPointer
921 "parcel", // const std::string &parcelObj,
922 !isReader, // bool parcelObjIsPointer,
923 isReader, // bool isReader,
924 ErrorMode_Return,
925 parentHandleName + error,
926 parentOffsetName
927 + " + offsetof("
928 + fullName()
929 + ", "
930 + field->name()
931 + ")"
932 + error);
933 }
934
935 out << "return _hidl_err;\n";
936
937 out.unindent();
938 out << "}\n\n";
939 }
940
needsEmbeddedReadWrite() const941 bool CompoundType::needsEmbeddedReadWrite() const {
942 if (mStyle != STYLE_STRUCT) {
943 return false;
944 }
945
946 for (const auto &field : *mFields) {
947 if (field->type().needsEmbeddedReadWrite()) {
948 return true;
949 }
950 }
951
952 return false;
953 }
954
needsResolveReferences() const955 bool CompoundType::needsResolveReferences() const {
956 if (mStyle != STYLE_STRUCT) {
957 return false;
958 }
959
960 for (const auto &field : *mFields) {
961 if (field->type().needsResolveReferences()) {
962 return true;
963 }
964 }
965
966 return false;
967 }
968
resultNeedsDeref() const969 bool CompoundType::resultNeedsDeref() const {
970 return true;
971 }
972
emitVtsTypeDeclarations(Formatter & out) const973 status_t CompoundType::emitVtsTypeDeclarations(Formatter &out) const {
974 out << "name: \"" << fullName() << "\"\n";
975 out << "type: " << getVtsType() << "\n";
976
977 // Emit declaration for each subtype.
978 for (const auto &type : getSubTypes()) {
979 switch (mStyle) {
980 case STYLE_STRUCT:
981 {
982 out << "sub_struct: {\n";
983 break;
984 }
985 case STYLE_UNION:
986 {
987 out << "sub_union: {\n";
988 break;
989 }
990 }
991 out.indent();
992 status_t status(type->emitVtsTypeDeclarations(out));
993 if (status != OK) {
994 return status;
995 }
996 out.unindent();
997 out << "}\n";
998 }
999
1000 // Emit declaration for each field.
1001 for (const auto &field : *mFields) {
1002 switch (mStyle) {
1003 case STYLE_STRUCT:
1004 {
1005 out << "struct_value: {\n";
1006 break;
1007 }
1008 case STYLE_UNION:
1009 {
1010 out << "union_value: {\n";
1011 break;
1012 }
1013 }
1014 out.indent();
1015 out << "name: \"" << field->name() << "\"\n";
1016 status_t status = field->type().emitVtsAttributeType(out);
1017 if (status != OK) {
1018 return status;
1019 }
1020 out.unindent();
1021 out << "}\n";
1022 }
1023
1024 return OK;
1025 }
1026
emitVtsAttributeType(Formatter & out) const1027 status_t CompoundType::emitVtsAttributeType(Formatter &out) const {
1028 out << "type: " << getVtsType() << "\n";
1029 out << "predefined_type: \"" << fullName() << "\"\n";
1030 return OK;
1031 }
1032
isJavaCompatible() const1033 bool CompoundType::isJavaCompatible() const {
1034 if (mStyle != STYLE_STRUCT || !Scope::isJavaCompatible()) {
1035 return false;
1036 }
1037
1038 for (const auto &field : *mFields) {
1039 if (!field->type().isJavaCompatible()) {
1040 return false;
1041 }
1042 }
1043
1044 return true;
1045 }
1046
containsPointer() const1047 bool CompoundType::containsPointer() const {
1048 if (Scope::containsPointer()) {
1049 return true;
1050 }
1051
1052 for (const auto &field : *mFields) {
1053 if (field->type().containsPointer()) {
1054 return true;
1055 }
1056 }
1057
1058 return false;
1059 }
1060
getAlignmentAndSize(size_t * align,size_t * size) const1061 void CompoundType::getAlignmentAndSize(size_t *align, size_t *size) const {
1062 *align = 1;
1063 *size = 0;
1064
1065 size_t offset = 0;
1066 for (const auto &field : *mFields) {
1067 // Each field is aligned according to its alignment requirement.
1068 // The surrounding structure's alignment is the maximum of its
1069 // fields' aligments.
1070
1071 size_t fieldAlign, fieldSize;
1072 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
1073
1074 size_t pad = offset % fieldAlign;
1075 if (pad > 0) {
1076 offset += fieldAlign - pad;
1077 }
1078
1079 if (mStyle == STYLE_STRUCT) {
1080 offset += fieldSize;
1081 } else {
1082 *size = std::max(*size, fieldSize);
1083 }
1084
1085 if (fieldAlign > (*align)) {
1086 *align = fieldAlign;
1087 }
1088 }
1089
1090 if (mStyle == STYLE_STRUCT) {
1091 *size = offset;
1092 }
1093
1094 // Final padding to account for the structure's alignment.
1095 size_t pad = (*size) % (*align);
1096 if (pad > 0) {
1097 (*size) += (*align) - pad;
1098 }
1099
1100 if (*size == 0) {
1101 // An empty struct still occupies a byte of space in C++.
1102 *size = 1;
1103 }
1104 }
1105
1106 ////////////////////////////////////////////////////////////////////////////////
1107
CompoundField(const char * name,Type * type)1108 CompoundField::CompoundField(const char *name, Type *type)
1109 : mName(name),
1110 mType(type) {
1111 }
1112
name() const1113 std::string CompoundField::name() const {
1114 return mName;
1115 }
1116
type() const1117 const Type &CompoundField::type() const {
1118 return *mType;
1119 }
1120
1121 } // namespace android
1122
1123