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