• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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