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 "ScalarType.h"
21 #include "VectorType.h"
22
23 #include <android-base/logging.h>
24 #include <hidl-util/Formatter.h>
25 #include <iostream>
26 #include <unordered_set>
27
28 namespace android {
29
CompoundType(Style style,const char * localName,const FQName & fullName,const Location & location,Scope * parent)30 CompoundType::CompoundType(Style style, const char* localName, const FQName& fullName,
31 const Location& location, Scope* parent)
32 : Scope(localName, fullName, location, parent), mStyle(style), mFields(nullptr) {}
33
style() const34 CompoundType::Style CompoundType::style() const {
35 return mStyle;
36 }
37
setFields(std::vector<NamedReference<Type> * > * fields)38 void CompoundType::setFields(std::vector<NamedReference<Type>*>* fields) {
39 mFields = fields;
40 }
41
getReferences() const42 std::vector<const Reference<Type>*> CompoundType::getReferences() const {
43 std::vector<const Reference<Type>*> ret;
44 ret.insert(ret.begin(), mFields->begin(), mFields->end());
45 return ret;
46 }
47
validate() const48 status_t CompoundType::validate() const {
49 for (const auto* field : *mFields) {
50 const Type& type = field->type();
51
52 if ((type.isVector() && static_cast<const VectorType*>(&type)->isVectorOfBinders())) {
53 std::cerr << "ERROR: Struct/union cannot contain vectors of interfaces at "
54 << field->location() << "\n";
55 return UNKNOWN_ERROR;
56 }
57
58 if (mStyle == STYLE_UNION) {
59 if (type.isInterface()) {
60 std::cerr << "ERROR: Union cannot contain interfaces at " << field->location()
61 << "\n";
62 return UNKNOWN_ERROR;
63 }
64
65 if (type.needsEmbeddedReadWrite()) {
66 std::cerr << "ERROR: Union must not contain any types that need fixup at "
67 << field->location() << "\n";
68 return UNKNOWN_ERROR;
69 }
70 }
71 }
72
73 if (mStyle == STYLE_SAFE_UNION && mFields->size() < 2) {
74 std::cerr << "ERROR: Safe union must contain at least two types to be useful at "
75 << location() << "\n";
76 return UNKNOWN_ERROR;
77 }
78
79 status_t err = validateUniqueNames();
80 if (err != OK) return err;
81
82 err = validateSubTypeNames();
83 if (err != OK) return err;
84
85 return Scope::validate();
86 }
87
validateUniqueNames() const88 status_t CompoundType::validateUniqueNames() const {
89 std::unordered_set<std::string> names;
90
91 for (const auto* field : *mFields) {
92 if (names.find(field->name()) != names.end()) {
93 std::cerr << "ERROR: Redefinition of field '" << field->name() << "' at "
94 << field->location() << "\n";
95 return UNKNOWN_ERROR;
96 }
97 names.insert(field->name());
98 }
99
100 return OK;
101 }
102
emitInvalidSubTypeNamesError(const std::string & subTypeName,const Location & location) const103 void CompoundType::emitInvalidSubTypeNamesError(const std::string& subTypeName,
104 const Location& location) const {
105 std::cerr << "ERROR: Type name '" << subTypeName << "' defined at "
106 << location << " conflicts with a member function of "
107 << "safe_union " << localName() << ". Consider renaming or "
108 << "moving its definition outside the safe_union scope.\n";
109 }
110
validateSubTypeNames() const111 status_t CompoundType::validateSubTypeNames() const {
112 if (mStyle != STYLE_SAFE_UNION) { return OK; }
113 const auto& subTypes = Scope::getSubTypes();
114
115 for (const auto& subType : subTypes) {
116 if (subType->localName() == "getDiscriminator") {
117 emitInvalidSubTypeNamesError(subType->localName(),
118 subType->location());
119 return UNKNOWN_ERROR;
120 }
121 }
122
123 return OK;
124 }
125
isCompoundType() const126 bool CompoundType::isCompoundType() const {
127 return true;
128 }
129
deepCanCheckEquality(std::unordered_set<const Type * > * visited) const130 bool CompoundType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const {
131 if (mStyle == STYLE_UNION) {
132 return false;
133 }
134 for (const auto* field : *mFields) {
135 if (!field->get()->canCheckEquality(visited)) {
136 return false;
137 }
138 }
139 return true;
140 }
141
typeName() const142 std::string CompoundType::typeName() const {
143 switch (mStyle) {
144 case STYLE_STRUCT: {
145 return "struct " + localName();
146 }
147 case STYLE_UNION: {
148 return "union " + localName();
149 }
150 case STYLE_SAFE_UNION: {
151 return "safe_union " + localName();
152 }
153 }
154 CHECK(!"Should not be here");
155 }
156
getCppType(StorageMode mode,bool) const157 std::string CompoundType::getCppType(
158 StorageMode mode,
159 bool /* specifyNamespaces */) const {
160 const std::string base = fullName();
161
162 switch (mode) {
163 case StorageMode_Stack:
164 return base;
165
166 case StorageMode_Argument:
167 return "const " + base + "&";
168
169 case StorageMode_Result:
170 return base + (containsInterface()?"":"*");
171 }
172 CHECK(!"Should not be here");
173 }
174
getJavaType(bool) const175 std::string CompoundType::getJavaType(bool /* forInitializer */) const {
176 return fullJavaName();
177 }
178
getVtsType() const179 std::string CompoundType::getVtsType() const {
180 switch (mStyle) {
181 case STYLE_STRUCT:
182 {
183 return "TYPE_STRUCT";
184 }
185 case STYLE_UNION:
186 {
187 return "TYPE_UNION";
188 }
189 case STYLE_SAFE_UNION:
190 {
191 return "TYPE_SAFE_UNION";
192 }
193 }
194 CHECK(!"Should not be here");
195 }
196
containsInterface() const197 bool CompoundType::containsInterface() const {
198 for (const auto& field : *mFields) {
199 if (field->type().isCompoundType()) {
200 const Type& t = field->type();
201 const CompoundType* ct = static_cast<const CompoundType*>(&t);
202 if (ct->containsInterface()) {
203 return true;
204 }
205 }
206 if (field->type().isInterface()) {
207 return true;
208 }
209 }
210 return false;
211 }
212
emitSafeUnionUnknownDiscriminatorError(Formatter & out,const std::string & value,bool fatal) const213 void CompoundType::emitSafeUnionUnknownDiscriminatorError(Formatter& out, const std::string& value,
214 bool fatal) const {
215 if (fatal) {
216 out << "::android::hardware::details::logAlwaysFatal(";
217 } else {
218 out << "ALOGE(\"%s\", ";
219 }
220 out << "(\n";
221 out.indent(2, [&] {
222 out << "\"Unknown union discriminator (value: \" +\n"
223 << "std::to_string(" << getUnionDiscriminatorType()->getCppTypeCast(value)
224 << ") + \").\").c_str());\n";
225 });
226 }
227
emitSafeUnionReaderWriterForInterfaces(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const228 void CompoundType::emitSafeUnionReaderWriterForInterfaces(
229 Formatter &out,
230 const std::string &name,
231 const std::string &parcelObj,
232 bool parcelObjIsPointer,
233 bool isReader,
234 ErrorMode mode) const {
235
236 CHECK(mStyle == STYLE_SAFE_UNION);
237
238 out.block([&] {
239 const auto discriminatorType = getUnionDiscriminatorType();
240 if (isReader) {
241 out << discriminatorType->getCppStackType()
242 << " _hidl_d_primitive;\n";
243 } else {
244 out << "const "
245 << discriminatorType->getCppStackType()
246 << " _hidl_d_primitive = "
247 << discriminatorType->getCppTypeCast(name + ".getDiscriminator()")
248 << ";\n";
249 }
250
251 getUnionDiscriminatorType()->emitReaderWriter(out, "_hidl_d_primitive", parcelObj,
252 parcelObjIsPointer, isReader, mode);
253 out << "switch (("
254 << fullName()
255 << "::hidl_discriminator) _hidl_d_primitive) ";
256
257 out.block([&] {
258 for (const auto& field : *mFields) {
259 out << "case "
260 << fullName()
261 << "::hidl_discriminator::"
262 << field->name()
263 << ": ";
264
265 const std::string tempFieldName = "_hidl_temp_" + field->name();
266 out.block([&] {
267 if (isReader) {
268 out << field->type().getCppResultType()
269 << " "
270 << tempFieldName
271 << ";\n";
272
273 field->type().emitReaderWriter(out, tempFieldName, parcelObj,
274 parcelObjIsPointer, isReader, mode);
275
276 const std::string derefOperator = field->type().resultNeedsDeref()
277 ? "*" : "";
278 out << name
279 << "."
280 << field->name()
281 << "(std::move("
282 << derefOperator
283 << tempFieldName
284 << "));\n";
285 } else {
286 const std::string fieldValue = name + "." + field->name() + "()";
287 out << field->type().getCppArgumentType()
288 << " "
289 << tempFieldName
290 << " = "
291 << fieldValue
292 << ";\n";
293
294 field->type().emitReaderWriter(out, tempFieldName, parcelObj,
295 parcelObjIsPointer, isReader, mode);
296 }
297 out << "break;\n";
298 }).endl();
299 }
300
301 out << "default: ";
302 out.block([&] {
303 emitSafeUnionUnknownDiscriminatorError(out, "_hidl_d_primitive",
304 !isReader /*fatal*/);
305 if (isReader) {
306 out << "_hidl_err = BAD_VALUE;\n";
307 handleError(out, mode);
308 }
309 })
310 .endl();
311 }).endl();
312 }).endl();
313 }
314
emitReaderWriter(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const315 void CompoundType::emitReaderWriter(
316 Formatter &out,
317 const std::string &name,
318 const std::string &parcelObj,
319 bool parcelObjIsPointer,
320 bool isReader,
321 ErrorMode mode) const {
322
323 const std::string parcelObjDeref =
324 parcelObj + (parcelObjIsPointer ? "->" : ".");
325
326 if(containsInterface()){
327 if (mStyle == STYLE_SAFE_UNION) {
328 emitSafeUnionReaderWriterForInterfaces(out, name, parcelObj,
329 parcelObjIsPointer,
330 isReader, mode);
331 return;
332 }
333
334 for (const auto& field : *mFields) {
335 const std::string tempFieldName = "_hidl_temp_" + field->name();
336 const std::string fieldValue = name + "." + field->name();
337
338 out.block([&] {
339 if (isReader) {
340 out << field->type().getCppResultType()
341 << " "
342 << tempFieldName
343 << ";\n";
344 } else {
345 out << field->type().getCppArgumentType()
346 << " "
347 << tempFieldName
348 << " = "
349 << fieldValue
350 << ";\n";
351 }
352
353 field->type().emitReaderWriter(out, tempFieldName, parcelObj,
354 parcelObjIsPointer, isReader, mode);
355 if (isReader) {
356 const std::string derefOperator = field->type().resultNeedsDeref()
357 ? "*" : "";
358 out << fieldValue
359 << " = std::move("
360 << derefOperator
361 << tempFieldName
362 << ");\n";
363 }
364 }).endl();
365 }
366 } else {
367 const std::string parentName = "_hidl_" + name + "_parent";
368
369 out << "size_t " << parentName << ";\n\n";
370
371 if (isReader) {
372 out << "_hidl_err = " << parcelObjDeref << "readBuffer("
373 << "sizeof(*" << name << "), &" << parentName << ", "
374 << " const_cast<const void**>(reinterpret_cast<void **>("
375 << "&" << name << ")));\n";
376 handleError(out, mode);
377 } else {
378 out << "_hidl_err = "
379 << parcelObjDeref
380 << "writeBuffer(&"
381 << name
382 << ", sizeof("
383 << name
384 << "), &"
385 << parentName
386 << ");\n";
387 handleError(out, mode);
388 }
389
390 bool needEmbeddedReadWrite = needsEmbeddedReadWrite();
391 CHECK(mStyle != STYLE_UNION || !needEmbeddedReadWrite);
392
393 if (needEmbeddedReadWrite) {
394 emitReaderWriterEmbedded(out, 0 /* depth */, name, name, /* sanitizedName */
395 isReader /* nameIsPointer */, parcelObj, parcelObjIsPointer,
396 isReader, mode, parentName, "0 /* parentOffset */");
397 }
398 }
399 }
400
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) const401 void CompoundType::emitReaderWriterEmbedded(
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 &parentName,
412 const std::string &offsetText) const {
413 emitReaderWriterEmbeddedForTypeName(
414 out,
415 name,
416 nameIsPointer,
417 parcelObj,
418 parcelObjIsPointer,
419 isReader,
420 mode,
421 parentName,
422 offsetText,
423 fullName(),
424 "" /* childName */,
425 "" /* namespace */);
426 }
427
emitJavaReaderWriter(Formatter & out,const std::string & parcelObj,const std::string & argName,bool isReader) const428 void CompoundType::emitJavaReaderWriter(
429 Formatter &out,
430 const std::string &parcelObj,
431 const std::string &argName,
432 bool isReader) const {
433 if (isReader) {
434 out << "new " << fullJavaName() << "();\n";
435 }
436
437 out << "(" << getJavaTypeCast(argName) << ")."
438 << (isReader ? "readFromParcel" : "writeToParcel") << "(" << parcelObj << ");\n";
439 }
440
emitJavaFieldInitializer(Formatter & out,const std::string & fieldName) const441 void CompoundType::emitJavaFieldInitializer(
442 Formatter &out, const std::string &fieldName) const {
443 const std::string fieldDeclaration = fullJavaName() + " " + fieldName;
444 emitJavaFieldDefaultInitialValue(out, fieldDeclaration);
445 }
446
emitJavaFieldDefaultInitialValue(Formatter & out,const std::string & declaredFieldName) const447 void CompoundType::emitJavaFieldDefaultInitialValue(
448 Formatter &out, const std::string &declaredFieldName) const {
449 out << declaredFieldName
450 << " = new "
451 << fullJavaName()
452 << "();\n";
453 }
454
emitJavaFieldReaderWriter(Formatter & out,size_t,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader) const455 void CompoundType::emitJavaFieldReaderWriter(
456 Formatter &out,
457 size_t /* depth */,
458 const std::string &parcelName,
459 const std::string &blobName,
460 const std::string &fieldName,
461 const std::string &offset,
462 bool isReader) const {
463 if (isReader) {
464 out << "("
465 << getJavaTypeCast(fieldName)
466 << ").readEmbeddedFromParcel("
467 << parcelName
468 << ", "
469 << blobName
470 << ", "
471 << offset
472 << ");\n";
473
474 return;
475 }
476
477 out << fieldName
478 << ".writeEmbeddedToBlob("
479 << blobName
480 << ", "
481 << offset
482 << ");\n";
483 }
emitResolveReferences(Formatter & out,const std::string & name,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const484 void CompoundType::emitResolveReferences(
485 Formatter &out,
486 const std::string &name,
487 bool nameIsPointer,
488 const std::string &parcelObj,
489 bool parcelObjIsPointer,
490 bool isReader,
491 ErrorMode mode) const {
492 emitResolveReferencesEmbedded(
493 out,
494 0 /* depth */,
495 name,
496 name /* sanitizedName */,
497 nameIsPointer,
498 parcelObj,
499 parcelObjIsPointer,
500 isReader,
501 mode,
502 "_hidl_" + name + "_parent",
503 "0 /* parentOffset */");
504 }
505
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) const506 void CompoundType::emitResolveReferencesEmbedded(
507 Formatter &out,
508 size_t /* depth */,
509 const std::string &name,
510 const std::string &/* sanitizedName */,
511 bool nameIsPointer,
512 const std::string &parcelObj,
513 bool parcelObjIsPointer,
514 bool isReader,
515 ErrorMode mode,
516 const std::string &parentName,
517 const std::string &offsetText) const {
518 CHECK(needsResolveReferences());
519
520 const std::string parcelObjDeref =
521 parcelObjIsPointer ? ("*" + parcelObj) : parcelObj;
522
523 const std::string parcelObjPointer =
524 parcelObjIsPointer ? parcelObj : ("&" + parcelObj);
525
526 const std::string nameDerefed = nameIsPointer ? ("*" + name) : name;
527 const std::string namePointer = nameIsPointer ? name : ("&" + name);
528
529 out << "_hidl_err = ";
530
531 if (isReader) {
532 out << "readEmbeddedReferenceFromParcel(\n";
533 } else {
534 out << "writeEmbeddedReferenceToParcel(\n";
535 }
536
537 out.indent(2, [&]{
538 if (isReader) {
539 out << "const_cast<"
540 << fullName()
541 << " *"
542 << ">("
543 << namePointer
544 << "),\n"
545 << parcelObjDeref;
546 } else {
547 out << nameDerefed
548 << ",\n"
549 << parcelObjPointer;
550 }
551
552 out << ",\n"
553 << parentName
554 << ",\n"
555 << offsetText
556 << ");\n\n";
557 });
558
559 handleError(out, mode);
560 }
561
emitLayoutAsserts(Formatter & out,const Layout & layout,const std::string & layoutName) const562 void CompoundType::emitLayoutAsserts(Formatter& out, const Layout& layout,
563 const std::string& layoutName) const {
564 out << "static_assert(sizeof("
565 << fullName()
566 << layoutName
567 << ") == "
568 << layout.size
569 << ", \"wrong size\");\n";
570
571 out << "static_assert(__alignof("
572 << fullName()
573 << layoutName
574 << ") == "
575 << layout.align
576 << ", \"wrong alignment\");\n";
577 }
578
emitSafeUnionTypeDeclarations(Formatter & out) const579 void CompoundType::emitSafeUnionTypeDeclarations(Formatter& out) const {
580 out << "struct "
581 << localName()
582 << " final {\n";
583
584 out.indent();
585
586 Scope::emitTypeDeclarations(out);
587
588 bool hasPointer = containsPointer();
589 CompoundLayout layout = hasPointer
590 ? CompoundLayout()
591 : getCompoundAlignmentAndSize();
592
593 out << "enum class hidl_discriminator : "
594 << getUnionDiscriminatorType()->getCppType(StorageMode_Stack, false)
595 << " ";
596
597 out.block([&] {
598 const auto elements = getSafeUnionEnumElements(true /* useCppTypeName */);
599 for (size_t i = 0; i < elements.size(); i++) {
600 out << elements[i].fieldName
601 << " = "
602 << i
603 << ",";
604
605 if (!elements[i].fieldTypeName.empty()) {
606 out << " // "
607 << elements[i].fieldTypeName;
608 }
609 out << "\n";
610 }
611 });
612 out << ";\n\n";
613
614 out << localName() << "();\n" // Constructor
615 << "~" << localName() << "();\n" // Destructor
616 << localName() << "(" << localName() << "&&);\n" // Move constructor
617 << localName() << "(const " << localName() << "&);\n" // Copy constructor
618 << localName() << "& operator=(" << localName() << "&&);\n" // Move assignment
619 << localName() << "& operator=(const " << localName() << "&);\n\n"; // Copy assignment
620
621 for (const auto& field : *mFields) {
622 // Setter (copy)
623 out << "void "
624 << field->name()
625 << "("
626 << field->type().getCppArgumentType()
627 << ");\n";
628
629 if (field->type().resolveToScalarType() == nullptr) {
630 // Setter (move)
631 out << "void "
632 << field->name()
633 << "("
634 << field->type().getCppStackType()
635 << "&&);\n";
636 }
637
638 // Getter (mutable)
639 out << field->type().getCppStackType()
640 << "& "
641 << field->name()
642 << "();\n";
643
644 // Getter (immutable)
645 out << field->type().getCppArgumentType()
646 << " "
647 << field->name()
648 << "() const;\n\n";
649 }
650
651 out << "// Utility methods\n";
652 out << "hidl_discriminator getDiscriminator() const;\n\n";
653
654 out << "constexpr size_t hidl_getUnionOffset() const ";
655 out.block([&] {
656 out << "return offsetof(" << fullName() << ", hidl_u);\n";
657 }).endl().endl();
658
659 out.unindent();
660 out << "private:\n";
661 out.indent();
662
663 out << "void hidl_destructUnion();\n\n";
664
665 out << "hidl_discriminator hidl_d";
666 if (!hasPointer) {
667 out << " __attribute__ ((aligned("
668 << layout.discriminator.align << "))) ";
669 }
670 out << ";\n";
671 out << "union hidl_union final {\n";
672 out.indent();
673
674 for (const auto& field : *mFields) {
675
676 size_t fieldAlign, fieldSize;
677 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
678
679 out << field->type().getCppStackType()
680 << " "
681 << field->name();
682
683 if (!hasPointer) {
684 out << " __attribute__ ((aligned("
685 << fieldAlign
686 << ")))";
687 }
688 out << ";\n";
689 }
690
691 out << "\n"
692 << "hidl_union();\n"
693 << "~hidl_union();\n";
694
695 out.unindent();
696 out << "} hidl_u;\n";
697
698 if (!hasPointer) {
699 out << "\n";
700
701 emitLayoutAsserts(out, layout.innerStruct, "::hidl_union");
702 emitLayoutAsserts(out, layout.discriminator, "::hidl_discriminator");
703 }
704
705 out.unindent();
706 out << "};\n\n";
707
708 if (!hasPointer) {
709 emitLayoutAsserts(out, layout.overall, "");
710 out << "\n";
711 }
712 }
713
emitTypeDeclarations(Formatter & out) const714 void CompoundType::emitTypeDeclarations(Formatter& out) const {
715 if (mStyle == STYLE_SAFE_UNION) {
716 emitSafeUnionTypeDeclarations(out);
717 return;
718 }
719
720 out << ((mStyle == STYLE_STRUCT) ? "struct" : "union")
721 << " "
722 << localName()
723 << " final {\n";
724
725 out.indent();
726
727 Scope::emitTypeDeclarations(out);
728
729 if (containsPointer()) {
730 for (const auto &field : *mFields) {
731 field->emitDocComment(out);
732 out << field->type().getCppStackType()
733 << " "
734 << field->name()
735 << ";\n";
736 }
737
738 out.unindent();
739 out << "};\n\n";
740
741 return;
742 }
743
744 for (int pass = 0; pass < 2; ++pass) {
745 size_t offset = 0;
746 for (const auto &field : *mFields) {
747 size_t fieldAlign, fieldSize;
748 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
749
750 offset += Layout::getPad(offset, fieldAlign);
751
752 if (pass == 0) {
753 out << field->type().getCppStackType()
754 << " "
755 << field->name()
756 << " __attribute__ ((aligned("
757 << fieldAlign
758 << ")));\n";
759 } else {
760 out << "static_assert(offsetof("
761 << fullName()
762 << ", "
763 << field->name()
764 << ") == "
765 << offset
766 << ", \"wrong offset\");\n";
767 }
768
769 if (mStyle == STYLE_STRUCT) {
770 offset += fieldSize;
771 }
772 }
773
774 if (pass == 0) {
775 out.unindent();
776 out << "};\n\n";
777 }
778 }
779
780 CompoundLayout layout = getCompoundAlignmentAndSize();
781 emitLayoutAsserts(out, layout.overall, "");
782 out << "\n";
783 }
784
emitTypeForwardDeclaration(Formatter & out) const785 void CompoundType::emitTypeForwardDeclaration(Formatter& out) const {
786 switch (mStyle) {
787 case STYLE_UNION: {
788 out << "union";
789 break;
790 }
791 case STYLE_STRUCT:
792 case STYLE_SAFE_UNION: {
793 out << "struct";
794 break;
795 }
796 default: {
797 CHECK(!"Should not be here");
798 }
799 }
800 out << " " << localName() << ";\n";
801 }
802
emitPackageTypeDeclarations(Formatter & out) const803 void CompoundType::emitPackageTypeDeclarations(Formatter& out) const {
804 Scope::emitPackageTypeDeclarations(out);
805
806 out << "static inline std::string toString("
807 << getCppArgumentType()
808 << (mFields->empty() ? "" : " o")
809 << ");\n";
810
811 if (canCheckEquality()) {
812 out << "static inline bool operator==("
813 << getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs);\n";
814
815 out << "static inline bool operator!=("
816 << getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs);\n";
817 } else {
818 out << "// operator== and operator!= are not generated for " << localName() << "\n";
819 }
820
821 out.endl();
822 }
823
emitPackageTypeHeaderDefinitions(Formatter & out) const824 void CompoundType::emitPackageTypeHeaderDefinitions(Formatter& out) const {
825 Scope::emitPackageTypeHeaderDefinitions(out);
826
827 out << "static inline std::string toString("
828 << getCppArgumentType()
829 << (mFields->empty() ? "" : " o")
830 << ") ";
831
832 out.block([&] {
833 // include toString for scalar types
834 out << "using ::android::hardware::toString;\n"
835 << "std::string os;\n";
836 out << "os += \"{\";\n";
837
838 if (mStyle == STYLE_SAFE_UNION) {
839 out << "\nswitch (o.getDiscriminator()) {\n";
840 out.indent();
841 }
842
843 for (const NamedReference<Type>* field : *mFields) {
844 if (mStyle == STYLE_SAFE_UNION) {
845 out << "case "
846 << fullName()
847 << "::hidl_discriminator::"
848 << field->name()
849 << ": ";
850
851 out.block([&] {
852 out << "os += \"."
853 << field->name()
854 << " = \";\n"
855 << "os += toString(o."
856 << field->name()
857 << "());\n"
858 << "break;\n";
859 }).endl();
860 } else {
861 out << "os += \"";
862 if (field != *(mFields->begin())) {
863 out << ", ";
864 }
865 out << "." << field->name() << " = \";\n";
866 field->type().emitDump(out, "os", "o." + field->name());
867 }
868 }
869
870 if (mStyle == STYLE_SAFE_UNION) {
871 out << "default: ";
872 out.block([&] {
873 emitSafeUnionUnknownDiscriminatorError(out, "o.getDiscriminator()",
874 true /*fatal*/);
875 })
876 .endl();
877
878 out.unindent();
879 out << "}\n";
880 }
881 out << "os += \"}\"; return os;\n";
882 }).endl().endl();
883
884 if (canCheckEquality()) {
885 out << "static inline bool operator==("
886 << getCppArgumentType() << " " << (mFields->empty() ? "/* lhs */" : "lhs") << ", "
887 << getCppArgumentType() << " " << (mFields->empty() ? "/* rhs */" : "rhs") << ") ";
888 out.block([&] {
889 if (mStyle == STYLE_SAFE_UNION) {
890 out.sIf("lhs.getDiscriminator() != rhs.getDiscriminator()", [&] {
891 out << "return false;\n";
892 }).endl();
893
894 out << "switch (lhs.getDiscriminator()) {\n";
895 out.indent();
896 }
897
898 for (const auto& field : *mFields) {
899 if (mStyle == STYLE_SAFE_UNION) {
900 out << "case "
901 << fullName()
902 << "::hidl_discriminator::"
903 << field->name()
904 << ": ";
905
906 out.block([&] {
907 out << "return (lhs."
908 << field->name()
909 << "() == rhs."
910 << field->name()
911 << "());\n";
912 }).endl();
913 } else {
914 out.sIf("lhs." + field->name() + " != rhs." + field->name(), [&] {
915 out << "return false;\n";
916 }).endl();
917 }
918 }
919
920 if (mStyle == STYLE_SAFE_UNION) {
921 out << "default: ";
922 out.block([&] {
923 emitSafeUnionUnknownDiscriminatorError(out, "lhs.getDiscriminator()",
924 true /*fatal*/);
925 })
926 .endl();
927
928 out.unindent();
929 out << "}\n";
930 }
931 out << "return true;\n";
932 }).endl().endl();
933
934 out << "static inline bool operator!=("
935 << getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs)";
936 out.block([&] {
937 out << "return !(lhs == rhs);\n";
938 }).endl().endl();
939 } else {
940 out << "// operator== and operator!= are not generated for " << localName() << "\n\n";
941 }
942 }
943
emitPackageHwDeclarations(Formatter & out) const944 void CompoundType::emitPackageHwDeclarations(Formatter& out) const {
945 if (needsEmbeddedReadWrite()) {
946 out << "::android::status_t readEmbeddedFromParcel(\n";
947
948 out.indent(2);
949
950 out << "const " << fullName() << " &obj,\n"
951 << "const ::android::hardware::Parcel &parcel,\n"
952 << "size_t parentHandle,\n"
953 << "size_t parentOffset);\n\n";
954
955 out.unindent(2);
956
957 out << "::android::status_t writeEmbeddedToParcel(\n";
958
959 out.indent(2);
960
961 out << "const " << fullName() << " &obj,\n"
962 << "::android::hardware::Parcel *parcel,\n"
963 << "size_t parentHandle,\n"
964 << "size_t parentOffset);\n\n";
965
966 out.unindent(2);
967 }
968
969 if(needsResolveReferences()) {
970 out << "::android::status_t readEmbeddedReferenceFromParcel(\n";
971 out.indent(2);
972 out << fullName() << " *obj,\n"
973 << "const ::android::hardware::Parcel &parcel,\n"
974 << "size_t parentHandle, size_t parentOffset);\n\n";
975 out.unindent(2);
976 out << "::android::status_t writeEmbeddedReferenceToParcel(\n";
977 out.indent(2);
978 out << "const " << fullName() << " &obj,\n"
979 << "::android::hardware::Parcel *,\n"
980 << "size_t parentHandle, size_t parentOffset);\n\n";
981 out.unindent(2);
982 }
983 }
984
emitSafeUnionFieldConstructor(Formatter & out,const NamedReference<Type> * field,const std::string & initializerObjectName)985 static void emitSafeUnionFieldConstructor(Formatter& out,
986 const NamedReference<Type>* field,
987 const std::string& initializerObjectName) {
988 out << "new (&hidl_u."
989 << field->name()
990 << ") "
991 << field->type().getCppStackType()
992 << "("
993 << initializerObjectName
994 << ");\n";
995 }
996
emitSafeUnionSetterDefinition(Formatter & out,const NamedReference<Type> * field,const std::string & parameterName,bool usesMoveSemantics)997 static void emitSafeUnionSetterDefinition(Formatter& out,
998 const NamedReference<Type>* field,
999 const std::string& parameterName,
1000 bool usesMoveSemantics) {
1001 out.block([&] {
1002 out << "if (hidl_d != hidl_discriminator::"
1003 << field->name()
1004 << ") ";
1005
1006 const std::string argumentName = usesMoveSemantics
1007 ? ("std::move(" + parameterName + ")")
1008 : parameterName;
1009 out.block([&] {
1010 out << "hidl_destructUnion();\n"
1011 << "::std::memset(&hidl_u, 0, sizeof(hidl_u));\n\n";
1012
1013 emitSafeUnionFieldConstructor(out, field, argumentName);
1014 out << "hidl_d = hidl_discriminator::"
1015 << field->name()
1016 << ";\n";
1017 }).endl();
1018
1019 out << "else if (&(hidl_u."
1020 << field->name()
1021 << ") != &"
1022 << parameterName
1023 << ") ";
1024
1025 out.block([&] {
1026 out << "hidl_u."
1027 << field->name()
1028 << " = "
1029 << argumentName
1030 << ";\n";
1031 }).endl();
1032 }).endl().endl();
1033 }
1034
emitSafeUnionGetterDefinition(Formatter & out,const std::string & fieldName)1035 static void emitSafeUnionGetterDefinition(Formatter& out, const std::string& fieldName) {
1036 out.block([&] {
1037 out << "if (CC_UNLIKELY(hidl_d != hidl_discriminator::"
1038 << fieldName
1039 << ")) ";
1040
1041 out.block([&] {
1042 out << "LOG_ALWAYS_FATAL(\"Bad safe_union access: safe_union has discriminator %\" "
1043 << "PRIu64 \" but discriminator %\" PRIu64 \" was accessed.\",\n";
1044 out.indent(2, [&] {
1045 out << "static_cast<uint64_t>(hidl_d), "
1046 << "static_cast<uint64_t>(hidl_discriminator::" << fieldName << "));";
1047 }).endl();
1048 }).endl().endl();
1049
1050 out << "return hidl_u."
1051 << fieldName
1052 << ";\n";
1053 }).endl().endl();
1054 }
1055
getSafeUnionEnumElements(bool useCppTypeName) const1056 std::vector<CompoundType::SafeUnionEnumElement> CompoundType::getSafeUnionEnumElements(
1057 bool useCppTypeName) const {
1058 std::vector<SafeUnionEnumElement> elements;
1059
1060 for (const auto& field : *mFields) {
1061 const std::string fieldTypeName = useCppTypeName
1062 ? field->type().getCppStackType(true /* specifyNamespaces */)
1063 : field->type().getJavaType(true /* forInitializer */);
1064
1065 elements.push_back({field->name(), fieldTypeName});
1066 }
1067
1068 return elements;
1069 }
1070
emitSafeUnionCopyAndAssignDefinition(Formatter & out,const std::string & parameterName,bool isCopyConstructor,bool usesMoveSemantics) const1071 void CompoundType::emitSafeUnionCopyAndAssignDefinition(Formatter& out,
1072 const std::string& parameterName,
1073 bool isCopyConstructor,
1074 bool usesMoveSemantics) const {
1075 out.block([&] {
1076 if (!isCopyConstructor) {
1077 out << "if (this == &"
1078 << parameterName
1079 << ") { return *this; }\n\n";
1080 }
1081
1082 out << "switch ("
1083 << parameterName
1084 << ".hidl_d) ";
1085
1086 out.block([&] {
1087 for (const auto& field : *mFields) {
1088 const std::string parameterFieldName = (parameterName + ".hidl_u." +
1089 field->name());
1090
1091 const std::string argumentName = usesMoveSemantics
1092 ? ("std::move(" + parameterFieldName + ")")
1093 : parameterFieldName;
1094
1095 out << "case hidl_discriminator::"
1096 << field->name()
1097 << ": ";
1098
1099 if (isCopyConstructor) {
1100 out.block([&] {
1101 emitSafeUnionFieldConstructor(out, field, argumentName);
1102 out << "break;\n";
1103 }).endl();
1104 } else {
1105 out.block([&] {
1106 out << field->name()
1107 << "("
1108 << argumentName
1109 << ");\n"
1110 << "break;\n";
1111 }).endl();
1112 }
1113 }
1114
1115 out << "default: ";
1116 out.block([&] {
1117 emitSafeUnionUnknownDiscriminatorError(out, parameterName + ".hidl_d",
1118 true /*fatal*/);
1119 })
1120 .endl();
1121 }).endl();
1122
1123 if (isCopyConstructor) {
1124 out << "\nhidl_d = "
1125 << parameterName
1126 << ".hidl_d;\n";
1127 } else {
1128 out << "return *this;\n";
1129 }
1130 }).endl().endl();
1131 }
1132
emitSafeUnionTypeConstructors(Formatter & out) const1133 void CompoundType::emitSafeUnionTypeConstructors(Formatter& out) const {
1134
1135 // Default constructor
1136 out << fullName()
1137 << "::"
1138 << localName()
1139 << "() ";
1140
1141 out.block([&] {
1142 out << "static_assert(offsetof("
1143 << fullName()
1144 << ", hidl_d) == 0, \"wrong offset\");\n";
1145
1146 const CompoundLayout layout = getCompoundAlignmentAndSize();
1147
1148 if (!containsPointer()) {
1149 out << "static_assert(offsetof(" << fullName()
1150 << ", hidl_u) == " << layout.innerStruct.offset << ", \"wrong offset\");\n";
1151 }
1152
1153 out.endl();
1154
1155 out << "::std::memset(&hidl_u, 0, sizeof(hidl_u));\n";
1156
1157 // union itself is zero'd when set
1158 // padding after descriminator
1159 size_t dpad = layout.innerStruct.offset - layout.discriminator.size;
1160 emitPaddingZero(out, layout.discriminator.size /*offset*/, dpad /*size*/);
1161
1162 size_t innerStructEnd = layout.innerStruct.offset + layout.innerStruct.size;
1163 // final padding of the struct
1164 size_t fpad = layout.overall.size - innerStructEnd;
1165 emitPaddingZero(out, innerStructEnd /*offset*/, fpad /*size*/);
1166
1167 out.endl();
1168
1169 CHECK(!mFields->empty());
1170 out << "hidl_d = hidl_discriminator::" << mFields->at(0)->name() << ";\n";
1171 emitSafeUnionFieldConstructor(out, mFields->at(0), "");
1172 }).endl().endl();
1173
1174 // Destructor
1175 out << fullName()
1176 << "::~"
1177 << localName()
1178 << "() ";
1179
1180 out.block([&] {
1181 out << "hidl_destructUnion();\n";
1182 }).endl().endl();
1183
1184 // Move constructor
1185 out << fullName() << "::" << localName() << "(" << localName() << "&& other) : " << fullName()
1186 << "() ";
1187
1188 emitSafeUnionCopyAndAssignDefinition(
1189 out, "other", true /* isCopyConstructor */, true /* usesMoveSemantics */);
1190
1191 // Copy constructor
1192 out << fullName() << "::" << localName() << "(const " << localName()
1193 << "& other) : " << fullName() << "() ";
1194
1195 emitSafeUnionCopyAndAssignDefinition(
1196 out, "other", true /* isCopyConstructor */, false /* usesMoveSemantics */);
1197
1198 // Move assignment operator
1199 out << fullName()
1200 << "& ("
1201 << fullName()
1202 << "::operator=)("
1203 << localName()
1204 << "&& other) ";
1205
1206 emitSafeUnionCopyAndAssignDefinition(
1207 out, "other", false /* isCopyConstructor */, true /* usesMoveSemantics */);
1208
1209 // Copy assignment operator
1210 out << fullName()
1211 << "& ("
1212 << fullName()
1213 << "::operator=)(const "
1214 << localName()
1215 << "& other) ";
1216
1217 emitSafeUnionCopyAndAssignDefinition(
1218 out, "other", false /* isCopyConstructor */, false /* usesMoveSemantics */);
1219 }
1220
emitSafeUnionTypeDefinitions(Formatter & out) const1221 void CompoundType::emitSafeUnionTypeDefinitions(Formatter& out) const {
1222 emitSafeUnionTypeConstructors(out);
1223
1224 out << "void "
1225 << fullName()
1226 << "::hidl_destructUnion() ";
1227
1228 out.block([&] {
1229 out << "switch (hidl_d) ";
1230 out.block([&] {
1231
1232 for (const auto& field : *mFields) {
1233 out << "case hidl_discriminator::"
1234 << field->name()
1235 << ": ";
1236
1237 out.block([&] {
1238 out << "::android::hardware::details::destructElement(&(hidl_u."
1239 << field->name()
1240 << "));\n"
1241 << "break;\n";
1242 }).endl();
1243 }
1244
1245 out << "default: ";
1246 out.block(
1247 [&] { emitSafeUnionUnknownDiscriminatorError(out, "hidl_d", true /*fatal*/); })
1248 .endl();
1249 }).endl().endl();
1250 }).endl().endl();
1251
1252 for (const NamedReference<Type>* field : *mFields) {
1253 // Setter (copy)
1254 out << "void "
1255 << fullName()
1256 << "::"
1257 << field->name()
1258 << "("
1259 << field->type().getCppArgumentType()
1260 << " o) ";
1261
1262 emitSafeUnionSetterDefinition(out, field, "o", false /* usesMoveSemantics */);
1263
1264 if (field->type().resolveToScalarType() == nullptr) {
1265 // Setter (move)
1266 out << "void "
1267 << fullName()
1268 << "::"
1269 << field->name()
1270 << "("
1271 << field->type().getCppStackType()
1272 << "&& o) ";
1273
1274 emitSafeUnionSetterDefinition(out, field, "o", true /* usesMoveSemantics */);
1275 }
1276
1277 // Getter (mutable)
1278 out << field->type().getCppStackType()
1279 << "& ("
1280 << fullName()
1281 << "::"
1282 << field->name()
1283 << ")() ";
1284
1285 emitSafeUnionGetterDefinition(out, field->name());
1286
1287 // Getter (immutable)
1288 out << field->type().getCppArgumentType()
1289 << " ("
1290 << fullName()
1291 << "::"
1292 << field->name()
1293 << ")() const ";
1294
1295 emitSafeUnionGetterDefinition(out, field->name());
1296 }
1297
1298 // Trivial constructor/destructor for internal union
1299 out << fullName() << "::hidl_union::hidl_union() {}\n\n"
1300 << fullName() << "::hidl_union::~hidl_union() {}\n\n";
1301
1302 // Utility method
1303 out << fullName() << "::hidl_discriminator ("
1304 << fullName() << "::getDiscriminator)() const ";
1305
1306 out.block([&] {
1307 out << "return hidl_d;\n";
1308 }).endl().endl();
1309 }
1310
emitTypeDefinitions(Formatter & out,const std::string & prefix) const1311 void CompoundType::emitTypeDefinitions(Formatter& out, const std::string& prefix) const {
1312 std::string space = prefix.empty() ? "" : (prefix + "::");
1313 Scope::emitTypeDefinitions(out, space + localName());
1314
1315 if (needsEmbeddedReadWrite()) {
1316 emitStructReaderWriter(out, prefix, true /* isReader */);
1317 emitStructReaderWriter(out, prefix, false /* isReader */);
1318 }
1319
1320 if (needsResolveReferences()) {
1321 emitResolveReferenceDef(out, prefix, true /* isReader */);
1322 emitResolveReferenceDef(out, prefix, false /* isReader */);
1323 }
1324
1325 if (mStyle == STYLE_SAFE_UNION) {
1326 emitSafeUnionTypeDefinitions(out);
1327 }
1328 }
1329
emitJavaSafeUnionUnknownDiscriminatorError(Formatter & out,bool fatal)1330 static void emitJavaSafeUnionUnknownDiscriminatorError(Formatter& out, bool fatal) {
1331 out << "throw new ";
1332
1333 if (fatal) {
1334 out << "Error";
1335 } else {
1336 out << "IllegalStateException";
1337 }
1338
1339 out << "(\"Unknown union discriminator (value: \" + hidl_d + \").\");\n";
1340 }
1341
emitJavaTypeDeclarations(Formatter & out,bool atTopLevel) const1342 void CompoundType::emitJavaTypeDeclarations(Formatter& out, bool atTopLevel) const {
1343 out << "public final ";
1344
1345 if (!atTopLevel) {
1346 out << "static ";
1347 }
1348
1349 out << "class "
1350 << localName()
1351 << " {\n";
1352
1353 out.indent();
1354
1355 Scope::emitJavaTypeDeclarations(out, false /* atTopLevel */);
1356
1357 if (mStyle == STYLE_SAFE_UNION) {
1358 out << "public " << localName() << "() ";
1359 out.block([&] {
1360 CHECK(!mFields->empty());
1361 mFields->at(0)->type().emitJavaFieldDefaultInitialValue(out, "hidl_o");
1362 }).endl().endl();
1363
1364 const std::string discriminatorStorageType = (
1365 getUnionDiscriminatorType()->getJavaType(false));
1366
1367 out << "public static final class hidl_discriminator ";
1368 out.block([&] {
1369 const auto elements = getSafeUnionEnumElements(false /* useCppTypeName */);
1370 for (size_t idx = 0; idx < elements.size(); idx++) {
1371 out << "public static final "
1372 << discriminatorStorageType
1373 << " "
1374 << elements[idx].fieldName
1375 << " = "
1376 << idx
1377 << ";";
1378
1379 if (!elements[idx].fieldTypeName.empty()) {
1380 out << " // "
1381 << elements[idx].fieldTypeName;
1382 }
1383 out << "\n";
1384 }
1385
1386 out << "\n"
1387 << "public static final String getName("
1388 << discriminatorStorageType
1389 << " value) ";
1390
1391 out.block([&] {
1392 out << "switch (value) ";
1393 out.block([&] {
1394 for (size_t idx = 0; idx < elements.size(); idx++) {
1395 out << "case "
1396 << idx
1397 << ": { return \""
1398 << elements[idx].fieldName
1399 << "\"; }\n";
1400 }
1401 out << "default: { return \"Unknown\"; }\n";
1402 }).endl();
1403 }).endl().endl();
1404
1405 out << "private hidl_discriminator() {}\n";
1406 }).endl().endl();
1407
1408 out << "private " << discriminatorStorageType << " hidl_d = 0;\n";
1409 out << "private Object hidl_o = null;\n";
1410
1411 for (const auto& field : *mFields) {
1412 // Setter
1413 out << "public void "
1414 << field->name()
1415 << "("
1416 << field->type().getJavaType(false)
1417 << " "
1418 << field->name()
1419 << ") ";
1420
1421 out.block([&] {
1422 out << "hidl_d = hidl_discriminator."
1423 << field->name()
1424 << ";\n";
1425
1426 out << "hidl_o = "
1427 << field->name()
1428 << ";\n";
1429 }).endl().endl();
1430
1431 // Getter
1432 out << "public "
1433 << field->type().getJavaType(false)
1434 << " "
1435 << field->name()
1436 << "() ";
1437
1438 out.block([&] {
1439 out << "if (hidl_d != hidl_discriminator."
1440 << field->name()
1441 << ") ";
1442
1443 out.block([&] {
1444 out << "String className = (hidl_o != null) ? "
1445 << "hidl_o.getClass().getName() : \"null\";\n";
1446
1447 out << "throw new IllegalStateException(\n";
1448 out.indent(2, [&] {
1449 out << "\"Read access to inactive union components is disallowed. \" +\n"
1450 << "\"Discriminator value is \" + hidl_d + \" (corresponding \" +\n"
1451 << "\"to \" + hidl_discriminator.getName(hidl_d) + \"), and \" +\n"
1452 << "\"hidl_o is of type \" + className + \".\");\n";
1453 });
1454 }).endl();
1455
1456 out << "if (hidl_o != null && !"
1457 << field->type().getJavaTypeClass()
1458 << ".class.isInstance(hidl_o)) ";
1459
1460 out.block([&] {
1461 out << "throw new Error(\"Union is in a corrupted state.\");\n";
1462 }).endl();
1463
1464 out << "return ("
1465 << field->type().getJavaTypeCast("hidl_o")
1466 << ");\n";
1467 }).endl().endl();
1468 }
1469
1470 out << "// Utility method\n"
1471 << "public "
1472 << discriminatorStorageType
1473 << " getDiscriminator() { return hidl_d; }\n\n";
1474
1475 } else {
1476 for (const auto& field : *mFields) {
1477 field->emitDocComment(out);
1478
1479 out << "public ";
1480 field->type().emitJavaFieldInitializer(out, field->name());
1481 }
1482
1483 out << "\n";
1484 }
1485
1486 ////////////////////////////////////////////////////////////////////////////
1487
1488 if (canCheckEquality()) {
1489 out << "@Override\npublic final boolean equals(Object otherObject) ";
1490 out.block([&] {
1491 out.sIf("this == otherObject", [&] {
1492 out << "return true;\n";
1493 }).endl();
1494 out.sIf("otherObject == null", [&] {
1495 out << "return false;\n";
1496 }).endl();
1497 // Though class is final, we use getClass instead of instanceof to be explicit.
1498 out.sIf("otherObject.getClass() != " + fullJavaName() + ".class", [&] {
1499 out << "return false;\n";
1500 }).endl();
1501 out << fullJavaName() << " other = (" << fullJavaName() << ")otherObject;\n";
1502
1503 if (mStyle == STYLE_SAFE_UNION) {
1504 out.sIf("this.hidl_d != other.hidl_d", [&] {
1505 out << "return false;\n";
1506 }).endl();
1507 out.sIf("!android.os.HidlSupport.deepEquals(this.hidl_o, other.hidl_o)", [&] {
1508 out << "return false;\n";
1509 }).endl();
1510 } else {
1511 for (const auto &field : *mFields) {
1512 std::string condition = (field->type().isScalar() || field->type().isEnum())
1513 ? "this." + field->name() + " != other." + field->name()
1514 : ("!android.os.HidlSupport.deepEquals(this." + field->name()
1515 + ", other." + field->name() + ")");
1516 out.sIf(condition, [&] {
1517 out << "return false;\n";
1518 }).endl();
1519 }
1520 }
1521 out << "return true;\n";
1522 }).endl().endl();
1523
1524 out << "@Override\npublic final int hashCode() ";
1525 out.block([&] {
1526 out << "return java.util.Objects.hash(\n";
1527 out.indent(2, [&] {
1528 if (mStyle == STYLE_SAFE_UNION) {
1529 out << "android.os.HidlSupport.deepHashCode(this.hidl_o),\n"
1530 << "java.util.Objects.hashCode(this.hidl_d)";
1531 } else {
1532 out.join(mFields->begin(), mFields->end(), ", \n", [&] (const auto &field) {
1533 out << "android.os.HidlSupport.deepHashCode(this." << field->name() << ")";
1534 });
1535 }
1536 });
1537 out << ");\n";
1538 }).endl().endl();
1539 } else {
1540 out << "// equals() is not generated for " << localName() << "\n";
1541 }
1542
1543 ////////////////////////////////////////////////////////////////////////////
1544
1545 out << "@Override\npublic final String toString() ";
1546 out.block([&] {
1547 out << "java.lang.StringBuilder builder = new java.lang.StringBuilder();\n"
1548 << "builder.append(\"{\");\n";
1549
1550 if (mStyle == STYLE_SAFE_UNION) {
1551 out << "switch (this.hidl_d) {\n";
1552 out.indent();
1553 }
1554
1555 for (const auto &field : *mFields) {
1556 if (mStyle == STYLE_SAFE_UNION) {
1557 out << "case hidl_discriminator."
1558 << field->name()
1559 << ": ";
1560
1561 out.block([&] {
1562 out << "builder.append(\""
1563 << "."
1564 << field->name()
1565 << " = \");\n";
1566
1567 field->type().emitJavaDump(out, "builder", "this." + field->name() + "()");
1568 out << "break;\n";
1569 }).endl();
1570 }
1571 else {
1572 out << "builder.append(\"";
1573 if (field != *(mFields->begin())) {
1574 out << ", ";
1575 }
1576 out << "." << field->name() << " = \");\n";
1577 field->type().emitJavaDump(out, "builder", "this." + field->name());
1578 }
1579 }
1580
1581 if (mStyle == STYLE_SAFE_UNION) {
1582 out << "default: ";
1583 out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
1584 .endl();
1585
1586 out.unindent();
1587 out << "}\n";
1588 }
1589
1590 out << "builder.append(\"}\");\nreturn builder.toString();\n";
1591 }).endl().endl();
1592
1593 CompoundLayout layout = getCompoundAlignmentAndSize();
1594
1595 ////////////////////////////////////////////////////////////////////////////
1596
1597 out << "public final void readFromParcel(android.os.HwParcel parcel) {\n";
1598 out.indent();
1599 if (containsInterface()) {
1600
1601 if (mStyle == STYLE_SAFE_UNION) {
1602 out << "hidl_d = ";
1603 getUnionDiscriminatorType()->emitJavaReaderWriter(
1604 out, "parcel", "hidl_d", true);
1605
1606 out << "switch (hidl_d) {\n";
1607 out.indent();
1608 }
1609
1610 for (const auto& field : *mFields) {
1611 if (mStyle == STYLE_SAFE_UNION) {
1612 out << "case hidl_discriminator."
1613 << field->name()
1614 << ": ";
1615
1616 out.block([&] {
1617 out << "hidl_o = ";
1618 field->type().emitJavaReaderWriter(out, "parcel", "hidl_o", true);
1619
1620 out << "break;\n";
1621 }).endl();
1622 } else {
1623 out << field->name() << " = ";
1624 field->type().emitJavaReaderWriter(out, "parcel", field->name(), true);
1625 }
1626 }
1627
1628 if (mStyle == STYLE_SAFE_UNION) {
1629 out << "default: ";
1630 out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, false /*fatal*/); })
1631 .endl();
1632
1633 out.unindent();
1634 out << "}\n";
1635 }
1636 } else {
1637 out << "android.os.HwBlob blob = parcel.readBuffer(";
1638 out << layout.overall.size << " /* size */);\n";
1639 out << "readEmbeddedFromParcel(parcel, blob, 0 /* parentOffset */);\n";
1640 }
1641 out.unindent();
1642 out << "}\n\n";
1643
1644 ////////////////////////////////////////////////////////////////////////////
1645
1646 size_t vecAlign, vecSize;
1647 VectorType::getAlignmentAndSizeStatic(&vecAlign, &vecSize);
1648
1649 out << "public static final java.util.ArrayList<" << localName()
1650 << "> readVectorFromParcel(android.os.HwParcel parcel) {\n";
1651 out.indent();
1652
1653 out << "java.util.ArrayList<" << localName() << "> _hidl_vec = new java.util.ArrayList();\n";
1654
1655 if (containsInterface()) {
1656 out << "int size = parcel.readInt32();\n";
1657 out << "for(int i = 0 ; i < size; i ++) {\n";
1658 out.indent();
1659 out << fullJavaName() << " tmp = ";
1660 emitJavaReaderWriter(out, "parcel", "tmp", true);
1661 out << "_hidl_vec.add(tmp);\n";
1662 out.unindent();
1663 out << "}\n";
1664 } else {
1665 out << "android.os.HwBlob _hidl_blob = parcel.readBuffer(";
1666 out << vecSize << " /* sizeof hidl_vec<T> */);\n\n";
1667
1668 VectorType::EmitJavaFieldReaderWriterForElementType(out, 0 /* depth */, this, "parcel",
1669 "_hidl_blob", "_hidl_vec", "0",
1670 true /* isReader */);
1671 }
1672 out << "\nreturn _hidl_vec;\n";
1673 out.unindent();
1674 out << "}\n\n";
1675 ////////////////////////////////////////////////////////////////////////////
1676 if (containsInterface()) {
1677 out << "// readEmbeddedFromParcel is not generated()\n";
1678 } else {
1679 out << "public final void readEmbeddedFromParcel(\n";
1680 out.indent(2);
1681 out << "android.os.HwParcel parcel, android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
1682 out.unindent();
1683
1684 if (mStyle == STYLE_SAFE_UNION) {
1685 getUnionDiscriminatorType()->emitJavaFieldReaderWriter(
1686 out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_d",
1687 "_hidl_offset + " + std::to_string(layout.discriminator.offset),
1688 true /* isReader */);
1689
1690 out << "switch (this.hidl_d) {\n";
1691 out.indent();
1692 }
1693
1694 size_t offset = layout.innerStruct.offset;
1695 for (const auto& field : *mFields) {
1696
1697 if (mStyle == STYLE_SAFE_UNION) {
1698 out << "case hidl_discriminator."
1699 << field->name()
1700 << ": ";
1701
1702 out.block([&] {
1703 field->type().emitJavaFieldDefaultInitialValue(out, "hidl_o");
1704 field->type().emitJavaFieldReaderWriter(
1705 out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_o",
1706 "_hidl_offset + " + std::to_string(offset), true /* isReader */);
1707
1708 out << "break;\n";
1709 }).endl();
1710 } else {
1711 size_t fieldAlign, fieldSize;
1712 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
1713
1714 offset += Layout::getPad(offset, fieldAlign);
1715 field->type().emitJavaFieldReaderWriter(
1716 out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
1717 "_hidl_offset + " + std::to_string(offset), true /* isReader */);
1718 offset += fieldSize;
1719 }
1720 }
1721
1722 if (mStyle == STYLE_SAFE_UNION) {
1723 out << "default: ";
1724 out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, false /*fatal*/); })
1725 .endl();
1726
1727 out.unindent();
1728 out << "}\n";
1729 }
1730 out.unindent();
1731 out << "}\n\n";
1732 }
1733
1734 ////////////////////////////////////////////////////////////////////////////
1735
1736 out << "public final void writeToParcel(android.os.HwParcel parcel) {\n";
1737 out.indent();
1738
1739 if (containsInterface()) {
1740 if (mStyle == STYLE_SAFE_UNION) {
1741 getUnionDiscriminatorType()->emitJavaReaderWriter(
1742 out, "parcel", "hidl_d", false);
1743
1744 out << "switch (this.hidl_d) {\n";
1745 out.indent();
1746 }
1747
1748 for (const auto& field : *mFields) {
1749 if (mStyle == STYLE_SAFE_UNION) {
1750 out << "case hidl_discriminator."
1751 << field->name()
1752 << ": ";
1753
1754 out.block([&] {
1755 field->type().emitJavaReaderWriter(out, "parcel", field->name() + "()", false);
1756 out << "break;\n";
1757 }).endl();
1758 } else {
1759 field->type().emitJavaReaderWriter(out, "parcel", field->name(), false);
1760 }
1761 }
1762
1763 if (mStyle == STYLE_SAFE_UNION) {
1764 out << "default: ";
1765 out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
1766 .endl();
1767
1768 out.unindent();
1769 out << "}\n";
1770 }
1771 } else {
1772 out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob("
1773 << layout.overall.size
1774 << " /* size */);\n";
1775
1776 out << "writeEmbeddedToBlob(_hidl_blob, 0 /* parentOffset */);\n"
1777 << "parcel.writeBuffer(_hidl_blob);\n";
1778 }
1779 out.unindent();
1780 out << "}\n\n";
1781
1782 ////////////////////////////////////////////////////////////////////////////
1783
1784 out << "public static final void writeVectorToParcel(\n";
1785 out.indent(2);
1786 out << "android.os.HwParcel parcel, java.util.ArrayList<" << localName() << "> _hidl_vec) {\n";
1787 out.unindent();
1788
1789 if (containsInterface()) {
1790 out << "parcel.writeInt32(_hidl_vec.size());\n";
1791 out << "for(" << fullJavaName() << " tmp: _hidl_vec) ";
1792 out.block([&] {
1793 emitJavaReaderWriter(out, "parcel", "tmp", false);
1794 }).endl();
1795 } else {
1796 out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob(" << vecSize
1797 << " /* sizeof(hidl_vec<T>) */);\n";
1798
1799 VectorType::EmitJavaFieldReaderWriterForElementType(out, 0 /* depth */, this, "parcel",
1800 "_hidl_blob", "_hidl_vec", "0",
1801 false /* isReader */);
1802
1803 out << "\nparcel.writeBuffer(_hidl_blob);\n";
1804 }
1805 out.unindent();
1806 out << "}\n\n";
1807 ////////////////////////////////////////////////////////////////////////////
1808
1809 if (containsInterface()) {
1810 out << "// writeEmbeddedToBlob() is not generated\n";
1811 } else {
1812 out << "public final void writeEmbeddedToBlob(\n";
1813 out.indent(2);
1814 out << "android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
1815 out.unindent();
1816
1817 if (mStyle == STYLE_SAFE_UNION) {
1818 getUnionDiscriminatorType()->emitJavaFieldReaderWriter(
1819 out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_d",
1820 "_hidl_offset + " + std::to_string(layout.discriminator.offset),
1821 false /* isReader */);
1822
1823 out << "switch (this.hidl_d) {\n";
1824 out.indent();
1825 }
1826
1827 size_t offset = layout.innerStruct.offset;
1828 for (const auto& field : *mFields) {
1829 if (mStyle == STYLE_SAFE_UNION) {
1830 out << "case hidl_discriminator."
1831 << field->name()
1832 << ": ";
1833
1834 out.block([&] {
1835 field->type().emitJavaFieldReaderWriter(
1836 out, 0 /* depth */, "parcel", "_hidl_blob", field->name() + "()",
1837 "_hidl_offset + " + std::to_string(offset), false /* isReader */);
1838
1839 out << "break;\n";
1840 }).endl();
1841 } else {
1842 size_t fieldAlign, fieldSize;
1843 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
1844
1845 offset += Layout::getPad(offset, fieldAlign);
1846 field->type().emitJavaFieldReaderWriter(
1847 out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
1848 "_hidl_offset + " + std::to_string(offset), false /* isReader */);
1849 offset += fieldSize;
1850 }
1851 }
1852
1853 if (mStyle == STYLE_SAFE_UNION) {
1854 out << "default: ";
1855 out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
1856 .endl();
1857
1858 out.unindent();
1859 out << "}\n";
1860 }
1861 out.unindent();
1862 out << "}\n";
1863 }
1864
1865 out.unindent();
1866 out << "};\n\n";
1867 }
1868
emitStructReaderWriter(Formatter & out,const std::string & prefix,bool isReader) const1869 void CompoundType::emitStructReaderWriter(
1870 Formatter &out, const std::string &prefix, bool isReader) const {
1871
1872 std::string space = prefix.empty() ? "" : (prefix + "::");
1873
1874 out << "::android::status_t "
1875 << (isReader ? "readEmbeddedFromParcel"
1876 : "writeEmbeddedToParcel")
1877 << "(\n";
1878
1879 out.indent(2);
1880
1881 const std::string name = "obj";
1882 if (isReader) {
1883 out << "const " << space << localName() << " &" << name << ",\n";
1884 out << "const ::android::hardware::Parcel &parcel,\n";
1885 } else {
1886 out << "const " << space << localName() << " &" << name << ",\n";
1887 out << "::android::hardware::Parcel *parcel,\n";
1888 }
1889
1890 out << "size_t parentHandle,\n"
1891 << "size_t parentOffset)";
1892
1893 out << " {\n";
1894
1895 out.unindent(2);
1896 out.indent();
1897
1898 out << "::android::status_t _hidl_err = ::android::OK;\n\n";
1899
1900 if (mStyle == STYLE_SAFE_UNION) {
1901 out << "switch (" << name << ".getDiscriminator()) {\n";
1902 out.indent();
1903 }
1904
1905 for (const auto &field : *mFields) {
1906 if (!field->type().needsEmbeddedReadWrite()) {
1907 continue;
1908 }
1909
1910 if (mStyle == STYLE_SAFE_UNION) {
1911 out << "case " << fullName() << "::hidl_discriminator::"
1912 << field->name() << ": {\n";
1913 out.indent();
1914 }
1915
1916 const std::string fieldName = (mStyle == STYLE_SAFE_UNION)
1917 ? (name + "." + field->name() + "()")
1918 : (name + "." + field->name());
1919
1920 const std::string fieldOffset = (mStyle == STYLE_SAFE_UNION)
1921 ? (name + ".hidl_getUnionOffset() " +
1922 "/* safe_union: union offset into struct */")
1923 : ("offsetof(" + fullName() + ", " + field->name() + ")");
1924
1925 field->type().emitReaderWriterEmbedded(
1926 out,
1927 0 /* depth */,
1928 fieldName,
1929 field->name() /* sanitizedName */,
1930 false /* nameIsPointer */,
1931 "parcel",
1932 !isReader /* parcelObjIsPointer */,
1933 isReader,
1934 ErrorMode_Return,
1935 "parentHandle",
1936 "parentOffset + " + fieldOffset);
1937
1938 if (mStyle == STYLE_SAFE_UNION) {
1939 out << "break;\n";
1940 out.unindent();
1941 out << "}\n";
1942 }
1943 }
1944
1945 if (mStyle == STYLE_SAFE_UNION) {
1946 out << "default: { break; }\n";
1947 out.unindent();
1948 out << "}\n";
1949 }
1950
1951 out << "return _hidl_err;\n";
1952
1953 out.unindent();
1954 out << "}\n\n";
1955 }
1956
emitResolveReferenceDef(Formatter & out,const std::string & prefix,bool isReader) const1957 void CompoundType::emitResolveReferenceDef(Formatter& out, const std::string& prefix,
1958 bool isReader) const {
1959 out << "::android::status_t ";
1960 const std::string space(prefix.empty() ? "" : (prefix + "::"));
1961
1962 bool useParent = false;
1963 for (const auto &field : *mFields) {
1964 if (field->type().useParentInEmitResolveReferencesEmbedded()) {
1965 useParent = true;
1966 break;
1967 }
1968 }
1969
1970 std::string parentHandleName = useParent ? "parentHandle" : "/* parentHandle */";
1971 std::string parentOffsetName = useParent ? "parentOffset" : "/* parentOffset */";
1972
1973 if (isReader) {
1974 out << "readEmbeddedReferenceFromParcel(\n";
1975 out.indent(2);
1976 out << space + localName() + " *obj,\n"
1977 << "const ::android::hardware::Parcel &parcel,\n"
1978 << "size_t " << parentHandleName << ", "
1979 << "size_t " << parentOffsetName << ")\n";
1980 out.unindent(2);
1981 } else {
1982 out << "writeEmbeddedReferenceToParcel(\n";
1983 out.indent(2);
1984 out << "const " << space + localName() + " &obj,\n"
1985 << "::android::hardware::Parcel *parcel,\n"
1986 << "size_t " << parentHandleName << ", "
1987 << "size_t " << parentOffsetName << ")\n";
1988 out.unindent(2);
1989 }
1990
1991 out << " {\n";
1992
1993 out.indent();
1994
1995 out << "::android::status_t _hidl_err = ::android::OK;\n\n";
1996
1997 const std::string nameDeref(isReader ? "obj->" : "obj.");
1998 // if not useParent, then parentName and offsetText
1999 // should not be used at all, then the #error should not be emitted.
2000 std::string error = useParent ? "" : "\n#error\n";
2001
2002 if (mStyle == STYLE_SAFE_UNION) {
2003 out << "switch (" << nameDeref << "getDiscriminator()) {\n";
2004 out.indent();
2005 }
2006
2007 for (const auto &field : *mFields) {
2008 if (!field->type().needsResolveReferences()) {
2009 continue;
2010 }
2011
2012 if (mStyle == STYLE_SAFE_UNION) {
2013 out << "case " << fullName() << "::hidl_discriminator::"
2014 << field->name() << ": {\n";
2015 out.indent();
2016 }
2017
2018 const std::string fieldName = (mStyle == STYLE_SAFE_UNION)
2019 ? (nameDeref + field->name() + "()")
2020 : (nameDeref + field->name());
2021
2022 const std::string fieldOffset = (mStyle == STYLE_SAFE_UNION)
2023 ? (nameDeref + "hidl_getUnionOffset() " +
2024 "/* safe_union: union offset into struct */")
2025 : ("offsetof(" + fullName() + ", " + field->name() + ")");
2026
2027 field->type().emitResolveReferencesEmbedded(
2028 out,
2029 0 /* depth */,
2030 fieldName,
2031 field->name() /* sanitizedName */,
2032 false, // nameIsPointer
2033 "parcel", // const std::string &parcelObj,
2034 !isReader, // bool parcelObjIsPointer,
2035 isReader, // bool isReader,
2036 ErrorMode_Return,
2037 parentHandleName + error,
2038 parentOffsetName
2039 + " + "
2040 + fieldOffset
2041 + error);
2042
2043 if (mStyle == STYLE_SAFE_UNION) {
2044 out << "break;\n";
2045 out.unindent();
2046 out << "}\n";
2047 }
2048 }
2049
2050 if (mStyle == STYLE_SAFE_UNION) {
2051 out << "default: { _hidl_err = ::android::BAD_VALUE; break; }\n";
2052 out.unindent();
2053 out << "}\n";
2054 }
2055
2056 out << "return _hidl_err;\n";
2057
2058 out.unindent();
2059 out << "}\n\n";
2060 }
2061
needsEmbeddedReadWrite() const2062 bool CompoundType::needsEmbeddedReadWrite() const {
2063 if (mStyle == STYLE_UNION) {
2064 return false;
2065 }
2066
2067 for (const auto &field : *mFields) {
2068 if (field->type().needsEmbeddedReadWrite()) {
2069 return true;
2070 }
2071 }
2072
2073 return false;
2074 }
2075
deepNeedsResolveReferences(std::unordered_set<const Type * > * visited) const2076 bool CompoundType::deepNeedsResolveReferences(std::unordered_set<const Type*>* visited) const {
2077 if (mStyle == STYLE_UNION) {
2078 return false;
2079 }
2080
2081 for (const auto &field : *mFields) {
2082 if (field->type().needsResolveReferences(visited)) {
2083 return true;
2084 }
2085 }
2086
2087 return Scope::deepNeedsResolveReferences(visited);
2088 }
2089
resultNeedsDeref() const2090 bool CompoundType::resultNeedsDeref() const {
2091 return !containsInterface() ;
2092 }
2093
emitVtsTypeDeclarations(Formatter & out) const2094 void CompoundType::emitVtsTypeDeclarations(Formatter& out) const {
2095 out << "name: \"" << fullName() << "\"\n";
2096 out << "type: " << getVtsType() << "\n";
2097
2098 // Emit declaration for each subtype.
2099 for (const auto &type : getSubTypes()) {
2100 switch (mStyle) {
2101 case STYLE_STRUCT:
2102 {
2103 out << "sub_struct: {\n";
2104 break;
2105 }
2106 case STYLE_UNION:
2107 {
2108 out << "sub_union: {\n";
2109 break;
2110 }
2111 case STYLE_SAFE_UNION:
2112 {
2113 out << "sub_safe_union: {\n";
2114 break;
2115 }
2116 default:
2117 {
2118 CHECK(!"Should not be here");
2119 }
2120 }
2121 out.indent();
2122 type->emitVtsTypeDeclarations(out);
2123 out.unindent();
2124 out << "}\n";
2125 }
2126
2127 // Emit declaration for each field.
2128 for (const auto &field : *mFields) {
2129 switch (mStyle) {
2130 case STYLE_STRUCT:
2131 {
2132 out << "struct_value: {\n";
2133 break;
2134 }
2135 case STYLE_UNION:
2136 {
2137 out << "union_value: {\n";
2138 break;
2139 }
2140 case STYLE_SAFE_UNION:
2141 {
2142 out << "safe_union_value: {\n";
2143 break;
2144 }
2145 default:
2146 {
2147 CHECK(!"Should not be here");
2148 }
2149 }
2150 out.indent();
2151 out << "name: \"" << field->name() << "\"\n";
2152 field->type().emitVtsAttributeType(out);
2153 out.unindent();
2154 out << "}\n";
2155 }
2156 }
2157
emitVtsAttributeType(Formatter & out) const2158 void CompoundType::emitVtsAttributeType(Formatter& out) const {
2159 out << "type: " << getVtsType() << "\n";
2160 out << "predefined_type: \"" << fullName() << "\"\n";
2161 }
2162
deepIsJavaCompatible(std::unordered_set<const Type * > * visited) const2163 bool CompoundType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
2164 if (mStyle == STYLE_UNION) {
2165 return false;
2166 }
2167
2168 for (const auto* field : *mFields) {
2169 if (!field->get()->isJavaCompatible(visited)) {
2170 return false;
2171 }
2172 }
2173
2174 return Scope::deepIsJavaCompatible(visited);
2175 }
2176
deepContainsPointer(std::unordered_set<const Type * > * visited) const2177 bool CompoundType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
2178 for (const auto* field : *mFields) {
2179 if (field->get()->containsPointer(visited)) {
2180 return true;
2181 }
2182 }
2183
2184 return Scope::deepContainsPointer(visited);
2185 }
2186
getAlignmentAndSize(size_t * align,size_t * size) const2187 void CompoundType::getAlignmentAndSize(size_t *align, size_t *size) const {
2188 CompoundLayout layout = getCompoundAlignmentAndSize();
2189 *align = layout.overall.align;
2190 *size = layout.overall.size;
2191 }
2192
getCompoundAlignmentAndSize() const2193 CompoundType::CompoundLayout CompoundType::getCompoundAlignmentAndSize() const {
2194 CompoundLayout compoundLayout;
2195
2196 // Local aliases for convenience
2197 Layout& overall = compoundLayout.overall;
2198 Layout& innerStruct = compoundLayout.innerStruct;
2199 Layout& discriminator = compoundLayout.discriminator;
2200
2201 if (mStyle == STYLE_SAFE_UNION) {
2202 getUnionDiscriminatorType()->getAlignmentAndSize(
2203 &(discriminator.align), &(discriminator.size));
2204
2205 innerStruct.offset = discriminator.size;
2206 }
2207
2208 for (const auto &field : *mFields) {
2209
2210 // Each field is aligned according to its alignment requirement.
2211 // The surrounding structure's alignment is the maximum of its
2212 // fields' aligments.
2213 size_t fieldAlign, fieldSize;
2214 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
2215 size_t lPad = Layout::getPad(innerStruct.size, fieldAlign);
2216
2217 innerStruct.size = (mStyle == STYLE_STRUCT)
2218 ? (innerStruct.size + lPad + fieldSize)
2219 : std::max(innerStruct.size, fieldSize);
2220
2221 innerStruct.align = std::max(innerStruct.align, fieldAlign);
2222 }
2223
2224 // Pad the inner structure's size
2225 innerStruct.size += Layout::getPad(innerStruct.size,
2226 innerStruct.align);
2227
2228 // Compute its final offset
2229 innerStruct.offset += Layout::getPad(innerStruct.offset,
2230 innerStruct.align);
2231
2232 // An empty struct/union still occupies a byte of space in C++.
2233 if (innerStruct.size == 0) {
2234 innerStruct.size = 1;
2235 }
2236
2237 overall.size = innerStruct.offset + innerStruct.size;
2238
2239 // Pad the overall structure's size
2240 overall.align = std::max(innerStruct.align, discriminator.align);
2241 overall.size += Layout::getPad(overall.size, overall.align);
2242
2243 if (mStyle != STYLE_SAFE_UNION) {
2244 CHECK(overall.offset == innerStruct.offset) << overall.offset << " " << innerStruct.offset;
2245 CHECK(overall.align == innerStruct.align) << overall.align << " " << innerStruct.align;
2246 CHECK(overall.size == innerStruct.size) << overall.size << " " << innerStruct.size;
2247 }
2248
2249 return compoundLayout;
2250 }
2251
emitPaddingZero(Formatter & out,size_t offset,size_t size) const2252 void CompoundType::emitPaddingZero(Formatter& out, size_t offset, size_t size) const {
2253 if (size > 0) {
2254 out << "::std::memset(reinterpret_cast<uint8_t*>(this) + " << offset << ", 0, " << size
2255 << ");\n";
2256 } else {
2257 out << "// no padding to zero starting at offset " << offset << "\n";
2258 }
2259 }
2260
getUnionDiscriminatorType() const2261 std::unique_ptr<ScalarType> CompoundType::getUnionDiscriminatorType() const {
2262 static const std::vector<std::pair<int, ScalarType::Kind> > scalars {
2263 {8, ScalarType::Kind::KIND_UINT8},
2264 {16, ScalarType::Kind::KIND_UINT16},
2265 {32, ScalarType::Kind::KIND_UINT32},
2266 };
2267
2268 size_t numFields = mFields->size();
2269 auto kind = ScalarType::Kind::KIND_UINT64;
2270
2271 for (const auto& scalar : scalars) {
2272 if (numFields <= (1ULL << scalar.first)) {
2273 kind = scalar.second; break;
2274 }
2275 }
2276
2277 return std::unique_ptr<ScalarType>(new ScalarType(kind, nullptr));
2278 }
2279
getPad(size_t offset,size_t align)2280 size_t CompoundType::Layout::getPad(size_t offset, size_t align) {
2281 size_t remainder = offset % align;
2282 return (remainder > 0) ? (align - remainder) : 0;
2283 }
2284
2285 } // namespace android
2286
2287