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