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
emitSafeUnionAssignDefinition(Formatter & out,const std::string & parameterName,bool usesMoveSemantics) const1016 void CompoundType::emitSafeUnionAssignDefinition(Formatter& out, const std::string& parameterName,
1017 bool usesMoveSemantics) const {
1018 out.block([&] {
1019 out << "if (this == &" << parameterName << ") { return *this; }\n\n";
1020
1021 out << "switch (" << parameterName << ".hidl_d) ";
1022
1023 out.block([&] {
1024 for (const auto& field : mFields) {
1025 const std::string parameterFieldName =
1026 (parameterName + ".hidl_u." + field->name());
1027
1028 const std::string argumentName =
1029 usesMoveSemantics ? ("std::move(" + parameterFieldName + ")")
1030 : parameterFieldName;
1031
1032 out << "case hidl_discriminator::" << field->name() << ": ";
1033
1034 out.block([&] {
1035 out << field->name() << "(" << argumentName << ");\n"
1036 << "break;\n";
1037 }).endl();
1038 }
1039
1040 out << "default: ";
1041 out.block([&] {
1042 emitSafeUnionUnknownDiscriminatorError(out, parameterName + ".hidl_d",
1043 true /*fatal*/);
1044 }).endl();
1045 }).endl();
1046
1047 out << "return *this;\n";
1048 })
1049 .endl()
1050 .endl();
1051 }
1052
emitSafeUnionTypeConstructors(Formatter & out) const1053 void CompoundType::emitSafeUnionTypeConstructors(Formatter& out) const {
1054
1055 // Default constructor
1056 out << fullName() << "::" << definedName() << "() ";
1057
1058 out.block([&] {
1059 out << "static_assert(offsetof("
1060 << fullName()
1061 << ", hidl_d) == 0, \"wrong offset\");\n";
1062
1063 const CompoundLayout layout = getCompoundAlignmentAndSize();
1064
1065 if (!containsPointer()) {
1066 out << "static_assert(offsetof(" << fullName()
1067 << ", hidl_u) == " << layout.innerStruct.offset << ", \"wrong offset\");\n";
1068 }
1069
1070 out.endl();
1071
1072 out << "::std::memset(&hidl_u, 0, sizeof(hidl_u));\n";
1073
1074 // union itself is zero'd when set
1075 // padding after descriminator
1076 size_t dpad = layout.innerStruct.offset - layout.discriminator.size;
1077 emitPaddingZero(out, layout.discriminator.size /*offset*/, dpad /*size*/);
1078
1079 size_t innerStructEnd = layout.innerStruct.offset + layout.innerStruct.size;
1080 // final padding of the struct
1081 size_t fpad = layout.overall.size - innerStructEnd;
1082 emitPaddingZero(out, innerStructEnd /*offset*/, fpad /*size*/);
1083
1084 out.endl();
1085
1086 CHECK(!mFields.empty());
1087 out << "hidl_d = hidl_discriminator::" << mFields.at(0)->name() << ";\n";
1088 emitSafeUnionFieldConstructor(out, mFields.at(0), "");
1089 }).endl().endl();
1090
1091 // Destructor
1092 out << fullName() << "::~" << definedName() << "() ";
1093
1094 out.block([&] {
1095 out << "hidl_destructUnion();\n";
1096 }).endl().endl();
1097
1098 // Move constructor
1099 out << fullName() << "::" << definedName() << "(" << definedName()
1100 << "&& other) : " << fullName() << "() ";
1101 out.block([&] { out << "*this = std::move(other);\n"; }).endl().endl();
1102
1103 // Copy constructor
1104 out << fullName() << "::" << definedName() << "(const " << definedName()
1105 << "& other) : " << fullName() << "() ";
1106 out.block([&] { out << "*this = other;\n"; }).endl().endl();
1107
1108 // Move assignment operator
1109 out << fullName() << "& (" << fullName() << "::operator=)(" << definedName() << "&& other) ";
1110
1111 emitSafeUnionAssignDefinition(out, "other", true /* usesMoveSemantics */);
1112
1113 // Copy assignment operator
1114 out << fullName() << "& (" << fullName() << "::operator=)(const " << definedName()
1115 << "& other) ";
1116
1117 emitSafeUnionAssignDefinition(out, "other", false /* usesMoveSemantics */);
1118 }
1119
emitSafeUnionTypeDefinitions(Formatter & out) const1120 void CompoundType::emitSafeUnionTypeDefinitions(Formatter& out) const {
1121 emitSafeUnionTypeConstructors(out);
1122
1123 out << "void "
1124 << fullName()
1125 << "::hidl_destructUnion() ";
1126
1127 out.block([&] {
1128 out << "switch (hidl_d) ";
1129 out.block([&] {
1130 for (const auto& field : mFields) {
1131 out << "case hidl_discriminator::" << field->name() << ": ";
1132
1133 out.block([&] {
1134 out << "::android::hardware::details::destructElement(&(hidl_u."
1135 << field->name() << "));\n"
1136 << "break;\n";
1137 }).endl();
1138 }
1139
1140 out << "default: ";
1141 out.block([&] {
1142 emitSafeUnionUnknownDiscriminatorError(out, "hidl_d", true /*fatal*/);
1143 }).endl();
1144 })
1145 .endl()
1146 .endl();
1147 }).endl().endl();
1148
1149 for (const NamedReference<Type>* field : mFields) {
1150 // Setter (copy)
1151 out << "void "
1152 << fullName()
1153 << "::"
1154 << field->name()
1155 << "("
1156 << field->type().getCppArgumentType()
1157 << " o) ";
1158
1159 emitSafeUnionSetterDefinition(out, field, "o", false /* usesMoveSemantics */);
1160
1161 if (field->type().resolveToScalarType() == nullptr) {
1162 // Setter (move)
1163 out << "void "
1164 << fullName()
1165 << "::"
1166 << field->name()
1167 << "("
1168 << field->type().getCppStackType()
1169 << "&& o) ";
1170
1171 emitSafeUnionSetterDefinition(out, field, "o", true /* usesMoveSemantics */);
1172 }
1173
1174 // Getter (mutable)
1175 out << field->type().getCppStackType()
1176 << "& ("
1177 << fullName()
1178 << "::"
1179 << field->name()
1180 << ")() ";
1181
1182 emitSafeUnionGetterDefinition(out, field->name());
1183
1184 // Getter (immutable)
1185 out << field->type().getCppArgumentType()
1186 << " ("
1187 << fullName()
1188 << "::"
1189 << field->name()
1190 << ")() const ";
1191
1192 emitSafeUnionGetterDefinition(out, field->name());
1193 }
1194
1195 // Trivial constructor/destructor for internal union
1196 out << fullName() << "::hidl_union::hidl_union() {}\n\n"
1197 << fullName() << "::hidl_union::~hidl_union() {}\n\n";
1198
1199 // Utility method
1200 out << fullName() << "::hidl_discriminator ("
1201 << fullName() << "::getDiscriminator)() const ";
1202
1203 out.block([&] {
1204 out << "return hidl_d;\n";
1205 }).endl().endl();
1206 }
1207
emitTypeDefinitions(Formatter & out,const std::string & prefix) const1208 void CompoundType::emitTypeDefinitions(Formatter& out, const std::string& prefix) const {
1209 std::string space = prefix.empty() ? "" : (prefix + "::");
1210 Scope::emitTypeDefinitions(out, space + definedName());
1211
1212 if (needsEmbeddedReadWrite()) {
1213 emitStructReaderWriter(out, prefix, true /* isReader */);
1214 emitStructReaderWriter(out, prefix, false /* isReader */);
1215 }
1216
1217 if (mStyle == STYLE_SAFE_UNION) {
1218 emitSafeUnionTypeDefinitions(out);
1219 }
1220 }
1221
emitJavaSafeUnionUnknownDiscriminatorError(Formatter & out,bool fatal)1222 static void emitJavaSafeUnionUnknownDiscriminatorError(Formatter& out, bool fatal) {
1223 out << "throw new ";
1224
1225 if (fatal) {
1226 out << "Error";
1227 } else {
1228 out << "IllegalStateException";
1229 }
1230
1231 out << "(\"Unknown union discriminator (value: \" + hidl_d + \").\");\n";
1232 }
1233
emitJavaTypeDeclarations(Formatter & out,bool atTopLevel) const1234 void CompoundType::emitJavaTypeDeclarations(Formatter& out, bool atTopLevel) const {
1235 out << "public final ";
1236
1237 if (!atTopLevel) {
1238 out << "static ";
1239 }
1240
1241 out << "class " << definedName() << " {\n";
1242
1243 out.indent();
1244
1245 Scope::emitJavaTypeDeclarations(out, false /* atTopLevel */);
1246
1247 if (mStyle == STYLE_SAFE_UNION) {
1248 out << "public " << definedName() << "() ";
1249 out.block([&] {
1250 CHECK(!mFields.empty());
1251 mFields.at(0)->type().emitJavaFieldDefaultInitialValue(out, "hidl_o");
1252 })
1253 .endl()
1254 .endl();
1255
1256 const std::string discriminatorStorageType = (
1257 getUnionDiscriminatorType()->getJavaType(false));
1258
1259 out << "public static final class hidl_discriminator ";
1260 out.block([&] {
1261 for (size_t idx = 0; idx < mFields.size(); idx++) {
1262 const auto& field = mFields.at(idx);
1263
1264 field->emitDocComment(out);
1265 out << "public static final " << discriminatorStorageType << " " << field->name()
1266 << " = " << idx << "; // "
1267 << field->type().getJavaType(true /* forInitializer */) << "\n";
1268 }
1269
1270 out << "\n"
1271 << "public static final String getName(" << discriminatorStorageType
1272 << " value) ";
1273
1274 out.block([&] {
1275 out << "switch (value) ";
1276 out.block([&] {
1277 for (size_t idx = 0; idx < mFields.size(); idx++) {
1278 const auto& field = mFields.at(idx);
1279
1280 out << "case " << idx << ": { return \"" << field->name()
1281 << "\"; }\n";
1282 }
1283 out << "default: { return \"Unknown\"; }\n";
1284 }).endl();
1285 })
1286 .endl()
1287 .endl();
1288
1289 out << "private hidl_discriminator() {}\n";
1290 })
1291 .endl()
1292 .endl();
1293
1294 out << "private " << discriminatorStorageType << " hidl_d = 0;\n";
1295 out << "private Object hidl_o = null;\n";
1296
1297 for (const auto& field : mFields) {
1298 // Setter
1299 out << "public void "
1300 << field->name()
1301 << "("
1302 << field->type().getJavaType(false)
1303 << " "
1304 << field->name()
1305 << ") ";
1306
1307 out.block([&] {
1308 out << "hidl_d = hidl_discriminator."
1309 << field->name()
1310 << ";\n";
1311
1312 out << "hidl_o = "
1313 << field->name()
1314 << ";\n";
1315 }).endl().endl();
1316
1317 // Getter
1318 out << "public "
1319 << field->type().getJavaType(false)
1320 << " "
1321 << field->name()
1322 << "() ";
1323
1324 out.block([&] {
1325 out << "if (hidl_d != hidl_discriminator."
1326 << field->name()
1327 << ") ";
1328
1329 out.block([&] {
1330 out << "String className = (hidl_o != null) ? "
1331 << "hidl_o.getClass().getName() : \"null\";\n";
1332
1333 out << "throw new IllegalStateException(\n";
1334 out.indent(2, [&] {
1335 out << "\"Read access to inactive union components is disallowed. \" +\n"
1336 << "\"Discriminator value is \" + hidl_d + \" (corresponding \" +\n"
1337 << "\"to \" + hidl_discriminator.getName(hidl_d) + \"), and \" +\n"
1338 << "\"hidl_o is of type \" + className + \".\");\n";
1339 });
1340 }).endl();
1341
1342 out << "if (hidl_o != null && !"
1343 << field->type().getJavaTypeClass()
1344 << ".class.isInstance(hidl_o)) ";
1345
1346 out.block([&] {
1347 out << "throw new Error(\"Union is in a corrupted state.\");\n";
1348 }).endl();
1349
1350 out << "return ("
1351 << field->type().getJavaTypeCast("hidl_o")
1352 << ");\n";
1353 }).endl().endl();
1354 }
1355
1356 out << "// Utility method\n"
1357 << "public "
1358 << discriminatorStorageType
1359 << " getDiscriminator() { return hidl_d; }\n\n";
1360
1361 } else if (mStyle == STYLE_STRUCT) {
1362 for (const auto& field : mFields) {
1363 field->emitDocComment(out);
1364
1365 out << "public ";
1366 field->type().emitJavaFieldInitializer(out, field->name());
1367 }
1368
1369 out << "\n";
1370 } else {
1371 LOG(FATAL) << "Java output doesn't support " << mStyle;
1372 }
1373
1374 ////////////////////////////////////////////////////////////////////////////
1375
1376 if (canCheckEquality()) {
1377 out << "@Override\npublic final boolean equals(Object otherObject) ";
1378 out.block([&] {
1379 out.sIf("this == otherObject", [&] {
1380 out << "return true;\n";
1381 }).endl();
1382 out.sIf("otherObject == null", [&] {
1383 out << "return false;\n";
1384 }).endl();
1385 // Though class is final, we use getClass instead of instanceof to be explicit.
1386 out.sIf("otherObject.getClass() != " + fullJavaName() + ".class", [&] {
1387 out << "return false;\n";
1388 }).endl();
1389 out << fullJavaName() << " other = (" << fullJavaName() << ")otherObject;\n";
1390
1391 if (mStyle == STYLE_SAFE_UNION) {
1392 out.sIf("this.hidl_d != other.hidl_d", [&] {
1393 out << "return false;\n";
1394 }).endl();
1395 out.sIf("!android.os.HidlSupport.deepEquals(this.hidl_o, other.hidl_o)", [&] {
1396 out << "return false;\n";
1397 }).endl();
1398 } else {
1399 for (const auto& field : mFields) {
1400 std::string condition = (field->type().isScalar() || field->type().isEnum())
1401 ? "this." + field->name() + " != other." + field->name()
1402 : ("!android.os.HidlSupport.deepEquals(this." + field->name()
1403 + ", other." + field->name() + ")");
1404 out.sIf(condition, [&] {
1405 out << "return false;\n";
1406 }).endl();
1407 }
1408 }
1409 out << "return true;\n";
1410 }).endl().endl();
1411
1412 out << "@Override\npublic final int hashCode() ";
1413 out.block([&] {
1414 out << "return java.util.Objects.hash(\n";
1415 out.indent(2, [&] {
1416 if (mStyle == STYLE_SAFE_UNION) {
1417 out << "android.os.HidlSupport.deepHashCode(this.hidl_o),\n"
1418 << "java.util.Objects.hashCode(this.hidl_d)";
1419 } else {
1420 out.join(mFields.begin(), mFields.end(), ", \n", [&](const auto& field) {
1421 out << "android.os.HidlSupport.deepHashCode(this." << field->name() << ")";
1422 });
1423 }
1424 });
1425 out << ");\n";
1426 }).endl().endl();
1427 } else {
1428 out << "// equals() is not generated for " << definedName() << "\n";
1429 }
1430
1431 ////////////////////////////////////////////////////////////////////////////
1432
1433 out << "@Override\npublic final String toString() ";
1434 out.block([&] {
1435 out << "java.lang.StringBuilder builder = new java.lang.StringBuilder();\n"
1436 << "builder.append(\"{\");\n";
1437
1438 if (mStyle == STYLE_SAFE_UNION) {
1439 out << "switch (this.hidl_d) {\n";
1440 out.indent();
1441 }
1442
1443 for (const auto& field : mFields) {
1444 if (mStyle == STYLE_SAFE_UNION) {
1445 out << "case hidl_discriminator."
1446 << field->name()
1447 << ": ";
1448
1449 out.block([&] {
1450 out << "builder.append(\""
1451 << "."
1452 << field->name()
1453 << " = \");\n";
1454
1455 field->type().emitJavaDump(out, "builder", "this." + field->name() + "()");
1456 out << "break;\n";
1457 }).endl();
1458 }
1459 else {
1460 out << "builder.append(\"";
1461 if (field != *(mFields.begin())) {
1462 out << ", ";
1463 }
1464 out << "." << field->name() << " = \");\n";
1465 field->type().emitJavaDump(out, "builder", "this." + field->name());
1466 }
1467 }
1468
1469 if (mStyle == STYLE_SAFE_UNION) {
1470 out << "default: ";
1471 out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
1472 .endl();
1473
1474 out.unindent();
1475 out << "}\n";
1476 }
1477
1478 out << "builder.append(\"}\");\nreturn builder.toString();\n";
1479 }).endl().endl();
1480
1481 CompoundLayout layout = getCompoundAlignmentAndSize();
1482
1483 ////////////////////////////////////////////////////////////////////////////
1484
1485 out << "public final void readFromParcel(android.os.HwParcel parcel) {\n";
1486 out.indent();
1487 if (containsInterface()) {
1488
1489 if (mStyle == STYLE_SAFE_UNION) {
1490 out << "hidl_d = ";
1491 getUnionDiscriminatorType()->emitJavaReaderWriter(
1492 out, "parcel", "hidl_d", true);
1493
1494 out << "switch (hidl_d) {\n";
1495 out.indent();
1496 }
1497
1498 for (const auto& field : mFields) {
1499 if (mStyle == STYLE_SAFE_UNION) {
1500 out << "case hidl_discriminator."
1501 << field->name()
1502 << ": ";
1503
1504 out.block([&] {
1505 out << "hidl_o = ";
1506 field->type().emitJavaReaderWriter(out, "parcel", "hidl_o", true);
1507
1508 out << "break;\n";
1509 }).endl();
1510 } else {
1511 out << field->name() << " = ";
1512 field->type().emitJavaReaderWriter(out, "parcel", field->name(), true);
1513 }
1514 }
1515
1516 if (mStyle == STYLE_SAFE_UNION) {
1517 out << "default: ";
1518 out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, false /*fatal*/); })
1519 .endl();
1520
1521 out.unindent();
1522 out << "}\n";
1523 }
1524 } else {
1525 out << "android.os.HwBlob blob = parcel.readBuffer(";
1526 out << layout.overall.size << " /* size */);\n";
1527 out << "readEmbeddedFromParcel(parcel, blob, 0 /* parentOffset */);\n";
1528 }
1529 out.unindent();
1530 out << "}\n\n";
1531
1532 ////////////////////////////////////////////////////////////////////////////
1533
1534 size_t vecAlign, vecSize;
1535 VectorType::getAlignmentAndSizeStatic(&vecAlign, &vecSize);
1536
1537 out << "public static final java.util.ArrayList<" << definedName()
1538 << "> readVectorFromParcel(android.os.HwParcel parcel) {\n";
1539 out.indent();
1540
1541 out << "java.util.ArrayList<" << definedName() << "> _hidl_vec = new java.util.ArrayList();\n";
1542
1543 if (containsInterface()) {
1544 out << "int size = parcel.readInt32();\n";
1545 out << "for(int i = 0 ; i < size; i ++) {\n";
1546 out.indent();
1547 out << fullJavaName() << " tmp = ";
1548 emitJavaReaderWriter(out, "parcel", "tmp", true);
1549 out << "_hidl_vec.add(tmp);\n";
1550 out.unindent();
1551 out << "}\n";
1552 } else {
1553 out << "android.os.HwBlob _hidl_blob = parcel.readBuffer(";
1554 out << vecSize << " /* sizeof hidl_vec<T> */);\n\n";
1555
1556 VectorType::EmitJavaFieldReaderWriterForElementType(out, 0 /* depth */, this, "parcel",
1557 "_hidl_blob", "_hidl_vec", "0",
1558 true /* isReader */);
1559 }
1560 out << "\nreturn _hidl_vec;\n";
1561 out.unindent();
1562 out << "}\n\n";
1563 ////////////////////////////////////////////////////////////////////////////
1564 if (containsInterface()) {
1565 out << "// readEmbeddedFromParcel is not generated()\n";
1566 } else {
1567 out << "public final void readEmbeddedFromParcel(\n";
1568 out.indent(2);
1569 out << "android.os.HwParcel parcel, android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
1570 out.unindent();
1571
1572 if (mStyle == STYLE_SAFE_UNION) {
1573 getUnionDiscriminatorType()->emitJavaFieldReaderWriter(
1574 out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_d",
1575 "_hidl_offset + " + std::to_string(layout.discriminator.offset),
1576 true /* isReader */);
1577
1578 out << "switch (this.hidl_d) {\n";
1579 out.indent();
1580 }
1581
1582 size_t offset = layout.innerStruct.offset;
1583 for (const auto& field : mFields) {
1584 if (mStyle == STYLE_SAFE_UNION) {
1585 out << "case hidl_discriminator."
1586 << field->name()
1587 << ": ";
1588
1589 out.block([&] {
1590 field->type().emitJavaFieldDefaultInitialValue(out, "hidl_o");
1591 field->type().emitJavaFieldReaderWriter(
1592 out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_o",
1593 "_hidl_offset + " + std::to_string(offset), true /* isReader */);
1594
1595 out << "break;\n";
1596 }).endl();
1597 } else {
1598 size_t fieldAlign, fieldSize;
1599 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
1600
1601 offset += Layout::getPad(offset, fieldAlign);
1602 field->type().emitJavaFieldReaderWriter(
1603 out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
1604 "_hidl_offset + " + std::to_string(offset), true /* isReader */);
1605 offset += fieldSize;
1606 }
1607 }
1608
1609 if (mStyle == STYLE_SAFE_UNION) {
1610 out << "default: ";
1611 out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, false /*fatal*/); })
1612 .endl();
1613
1614 out.unindent();
1615 out << "}\n";
1616 }
1617 out.unindent();
1618 out << "}\n\n";
1619 }
1620
1621 ////////////////////////////////////////////////////////////////////////////
1622
1623 out << "public final void writeToParcel(android.os.HwParcel parcel) {\n";
1624 out.indent();
1625
1626 if (containsInterface()) {
1627 if (mStyle == STYLE_SAFE_UNION) {
1628 getUnionDiscriminatorType()->emitJavaReaderWriter(
1629 out, "parcel", "hidl_d", false);
1630
1631 out << "switch (this.hidl_d) {\n";
1632 out.indent();
1633 }
1634
1635 for (const auto& field : mFields) {
1636 if (mStyle == STYLE_SAFE_UNION) {
1637 out << "case hidl_discriminator."
1638 << field->name()
1639 << ": ";
1640
1641 out.block([&] {
1642 field->type().emitJavaReaderWriter(out, "parcel", field->name() + "()", false);
1643 out << "break;\n";
1644 }).endl();
1645 } else {
1646 field->type().emitJavaReaderWriter(out, "parcel", field->name(), false);
1647 }
1648 }
1649
1650 if (mStyle == STYLE_SAFE_UNION) {
1651 out << "default: ";
1652 out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
1653 .endl();
1654
1655 out.unindent();
1656 out << "}\n";
1657 }
1658 } else {
1659 out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob("
1660 << layout.overall.size
1661 << " /* size */);\n";
1662
1663 out << "writeEmbeddedToBlob(_hidl_blob, 0 /* parentOffset */);\n"
1664 << "parcel.writeBuffer(_hidl_blob);\n";
1665 }
1666 out.unindent();
1667 out << "}\n\n";
1668
1669 ////////////////////////////////////////////////////////////////////////////
1670
1671 out << "public static final void writeVectorToParcel(\n";
1672 out.indent(2);
1673 out << "android.os.HwParcel parcel, java.util.ArrayList<" << definedName()
1674 << "> _hidl_vec) {\n";
1675 out.unindent();
1676
1677 if (containsInterface()) {
1678 out << "parcel.writeInt32(_hidl_vec.size());\n";
1679 out << "for(" << fullJavaName() << " tmp: _hidl_vec) ";
1680 out.block([&] {
1681 emitJavaReaderWriter(out, "parcel", "tmp", false);
1682 }).endl();
1683 } else {
1684 out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob(" << vecSize
1685 << " /* sizeof(hidl_vec<T>) */);\n";
1686
1687 VectorType::EmitJavaFieldReaderWriterForElementType(out, 0 /* depth */, this, "parcel",
1688 "_hidl_blob", "_hidl_vec", "0",
1689 false /* isReader */);
1690
1691 out << "\nparcel.writeBuffer(_hidl_blob);\n";
1692 }
1693 out.unindent();
1694 out << "}\n\n";
1695 ////////////////////////////////////////////////////////////////////////////
1696
1697 if (containsInterface()) {
1698 out << "// writeEmbeddedToBlob() is not generated\n";
1699 } else {
1700 out << "public final void writeEmbeddedToBlob(\n";
1701 out.indent(2);
1702 out << "android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
1703 out.unindent();
1704
1705 if (mStyle == STYLE_SAFE_UNION) {
1706 getUnionDiscriminatorType()->emitJavaFieldReaderWriter(
1707 out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_d",
1708 "_hidl_offset + " + std::to_string(layout.discriminator.offset),
1709 false /* isReader */);
1710
1711 out << "switch (this.hidl_d) {\n";
1712 out.indent();
1713 }
1714
1715 size_t offset = layout.innerStruct.offset;
1716 for (const auto& field : mFields) {
1717 if (mStyle == STYLE_SAFE_UNION) {
1718 out << "case hidl_discriminator."
1719 << field->name()
1720 << ": ";
1721
1722 out.block([&] {
1723 field->type().emitJavaFieldReaderWriter(
1724 out, 0 /* depth */, "parcel", "_hidl_blob", field->name() + "()",
1725 "_hidl_offset + " + std::to_string(offset), false /* isReader */);
1726
1727 out << "break;\n";
1728 }).endl();
1729 } else {
1730 size_t fieldAlign, fieldSize;
1731 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
1732
1733 offset += Layout::getPad(offset, fieldAlign);
1734 field->type().emitJavaFieldReaderWriter(
1735 out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
1736 "_hidl_offset + " + std::to_string(offset), false /* isReader */);
1737 offset += fieldSize;
1738 }
1739 }
1740
1741 if (mStyle == STYLE_SAFE_UNION) {
1742 out << "default: ";
1743 out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
1744 .endl();
1745
1746 out.unindent();
1747 out << "}\n";
1748 }
1749 out.unindent();
1750 out << "}\n";
1751 }
1752
1753 out.unindent();
1754 out << "};\n\n";
1755 }
1756
emitStructReaderWriter(Formatter & out,const std::string & prefix,bool isReader) const1757 void CompoundType::emitStructReaderWriter(
1758 Formatter &out, const std::string &prefix, bool isReader) const {
1759
1760 std::string space = prefix.empty() ? "" : (prefix + "::");
1761
1762 out << "::android::status_t "
1763 << (isReader ? "readEmbeddedFromParcel"
1764 : "writeEmbeddedToParcel")
1765 << "(\n";
1766
1767 out.indent(2);
1768
1769 const std::string name = "obj";
1770 if (isReader) {
1771 out << "const " << space << definedName() << " &" << name << ",\n";
1772 out << "const ::android::hardware::Parcel &parcel,\n";
1773 } else {
1774 out << "const " << space << definedName() << " &" << name << ",\n";
1775 out << "::android::hardware::Parcel *parcel,\n";
1776 }
1777
1778 out << "size_t parentHandle,\n"
1779 << "size_t parentOffset)";
1780
1781 out << " {\n";
1782
1783 out.unindent(2);
1784 out.indent();
1785
1786 out << "::android::status_t _hidl_err = ::android::OK;\n\n";
1787
1788 if (mStyle == STYLE_SAFE_UNION) {
1789 out << "switch (" << name << ".getDiscriminator()) {\n";
1790 out.indent();
1791 }
1792
1793 for (const auto& field : mFields) {
1794 if (!field->type().needsEmbeddedReadWrite()) {
1795 continue;
1796 }
1797
1798 if (mStyle == STYLE_SAFE_UNION) {
1799 out << "case " << fullName() << "::hidl_discriminator::"
1800 << field->name() << ": {\n";
1801 out.indent();
1802 }
1803
1804 const std::string fieldName = (mStyle == STYLE_SAFE_UNION)
1805 ? (name + "." + field->name() + "()")
1806 : (name + "." + field->name());
1807
1808 const std::string fieldOffset = (mStyle == STYLE_SAFE_UNION)
1809 ? (name + ".hidl_getUnionOffset() " +
1810 "/* safe_union: union offset into struct */")
1811 : ("offsetof(" + fullName() + ", " + field->name() + ")");
1812
1813 field->type().emitReaderWriterEmbedded(
1814 out,
1815 0 /* depth */,
1816 fieldName,
1817 field->name() /* sanitizedName */,
1818 false /* nameIsPointer */,
1819 "parcel",
1820 !isReader /* parcelObjIsPointer */,
1821 isReader,
1822 ErrorMode_Return,
1823 "parentHandle",
1824 "parentOffset + " + fieldOffset);
1825
1826 if (mStyle == STYLE_SAFE_UNION) {
1827 out << "break;\n";
1828 out.unindent();
1829 out << "}\n";
1830 }
1831 }
1832
1833 if (mStyle == STYLE_SAFE_UNION) {
1834 out << "default: { break; }\n";
1835 out.unindent();
1836 out << "}\n";
1837 }
1838
1839 out << "return _hidl_err;\n";
1840
1841 out.unindent();
1842 out << "}\n\n";
1843 }
1844
needsEmbeddedReadWrite() const1845 bool CompoundType::needsEmbeddedReadWrite() const {
1846 if (mStyle == STYLE_UNION) {
1847 return false;
1848 }
1849
1850 for (const auto& field : mFields) {
1851 if (field->type().needsEmbeddedReadWrite()) {
1852 return true;
1853 }
1854 }
1855
1856 return false;
1857 }
1858
resultNeedsDeref() const1859 bool CompoundType::resultNeedsDeref() const {
1860 return !containsInterface() ;
1861 }
1862
emitVtsTypeDeclarations(Formatter & out) const1863 void CompoundType::emitVtsTypeDeclarations(Formatter& out) const {
1864 out << "name: \"" << fullName() << "\"\n";
1865 out << "type: " << getVtsType() << "\n";
1866
1867 // Emit declaration for each subtype.
1868 for (const auto &type : getSubTypes()) {
1869 switch (mStyle) {
1870 case STYLE_STRUCT:
1871 {
1872 out << "sub_struct: {\n";
1873 break;
1874 }
1875 case STYLE_UNION:
1876 {
1877 out << "sub_union: {\n";
1878 break;
1879 }
1880 case STYLE_SAFE_UNION:
1881 {
1882 out << "sub_safe_union: {\n";
1883 break;
1884 }
1885 default:
1886 {
1887 CHECK(!"Should not be here");
1888 }
1889 }
1890 out.indent();
1891 type->emitVtsTypeDeclarations(out);
1892 out.unindent();
1893 out << "}\n";
1894 }
1895
1896 // Emit declaration for each field.
1897 for (const auto& field : mFields) {
1898 switch (mStyle) {
1899 case STYLE_STRUCT:
1900 {
1901 out << "struct_value: {\n";
1902 break;
1903 }
1904 case STYLE_UNION:
1905 {
1906 out << "union_value: {\n";
1907 break;
1908 }
1909 case STYLE_SAFE_UNION:
1910 {
1911 out << "safe_union_value: {\n";
1912 break;
1913 }
1914 default:
1915 {
1916 CHECK(!"Should not be here");
1917 }
1918 }
1919 out.indent();
1920 out << "name: \"" << field->name() << "\"\n";
1921 field->type().emitVtsAttributeType(out);
1922 out.unindent();
1923 out << "}\n";
1924 }
1925 }
1926
emitVtsAttributeType(Formatter & out) const1927 void CompoundType::emitVtsAttributeType(Formatter& out) const {
1928 out << "type: " << getVtsType() << "\n";
1929 out << "predefined_type: \"" << fullName() << "\"\n";
1930 }
1931
deepIsJavaCompatible(std::unordered_set<const Type * > * visited) const1932 bool CompoundType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
1933 if (mStyle == STYLE_UNION) {
1934 return false;
1935 }
1936
1937 for (const auto* field : mFields) {
1938 if (!field->get()->isJavaCompatible(visited)) {
1939 return false;
1940 }
1941 }
1942
1943 return Scope::deepIsJavaCompatible(visited);
1944 }
1945
deepContainsPointer(std::unordered_set<const Type * > * visited) const1946 bool CompoundType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
1947 for (const auto* field : mFields) {
1948 if (field->get()->containsPointer(visited)) {
1949 return true;
1950 }
1951 }
1952
1953 return Scope::deepContainsPointer(visited);
1954 }
1955
getAlignmentAndSize(size_t * align,size_t * size) const1956 void CompoundType::getAlignmentAndSize(size_t *align, size_t *size) const {
1957 CompoundLayout layout = getCompoundAlignmentAndSize();
1958 *align = layout.overall.align;
1959 *size = layout.overall.size;
1960 }
1961
getCompoundAlignmentAndSize() const1962 CompoundType::CompoundLayout CompoundType::getCompoundAlignmentAndSize() const {
1963 CompoundLayout compoundLayout;
1964
1965 // Local aliases for convenience
1966 Layout& overall = compoundLayout.overall;
1967 Layout& innerStruct = compoundLayout.innerStruct;
1968 Layout& discriminator = compoundLayout.discriminator;
1969
1970 if (mStyle == STYLE_SAFE_UNION) {
1971 getUnionDiscriminatorType()->getAlignmentAndSize(
1972 &(discriminator.align), &(discriminator.size));
1973
1974 innerStruct.offset = discriminator.size;
1975 }
1976
1977 for (const auto& field : mFields) {
1978 // Each field is aligned according to its alignment requirement.
1979 // The surrounding structure's alignment is the maximum of its
1980 // fields' aligments.
1981 size_t fieldAlign, fieldSize;
1982 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
1983 size_t lPad = Layout::getPad(innerStruct.size, fieldAlign);
1984
1985 innerStruct.size = (mStyle == STYLE_STRUCT)
1986 ? (innerStruct.size + lPad + fieldSize)
1987 : std::max(innerStruct.size, fieldSize);
1988
1989 innerStruct.align = std::max(innerStruct.align, fieldAlign);
1990 }
1991
1992 // Pad the inner structure's size
1993 innerStruct.size += Layout::getPad(innerStruct.size,
1994 innerStruct.align);
1995
1996 // Compute its final offset
1997 innerStruct.offset += Layout::getPad(innerStruct.offset,
1998 innerStruct.align);
1999
2000 // An empty struct/union still occupies a byte of space in C++.
2001 if (innerStruct.size == 0) {
2002 innerStruct.size = 1;
2003 }
2004
2005 overall.size = innerStruct.offset + innerStruct.size;
2006
2007 // Pad the overall structure's size
2008 overall.align = std::max(innerStruct.align, discriminator.align);
2009 overall.size += Layout::getPad(overall.size, overall.align);
2010
2011 if (mStyle != STYLE_SAFE_UNION) {
2012 CHECK(overall.offset == innerStruct.offset) << overall.offset << " " << innerStruct.offset;
2013 CHECK(overall.align == innerStruct.align) << overall.align << " " << innerStruct.align;
2014 CHECK(overall.size == innerStruct.size) << overall.size << " " << innerStruct.size;
2015 }
2016
2017 return compoundLayout;
2018 }
2019
emitPaddingZero(Formatter & out,size_t offset,size_t size) const2020 void CompoundType::emitPaddingZero(Formatter& out, size_t offset, size_t size) const {
2021 if (size > 0) {
2022 out << "::std::memset(reinterpret_cast<uint8_t*>(this) + " << offset << ", 0, " << size
2023 << ");\n";
2024 } else {
2025 out << "// no padding to zero starting at offset " << offset << "\n";
2026 }
2027 }
2028
getUnionDiscriminatorType() const2029 std::unique_ptr<ScalarType> CompoundType::getUnionDiscriminatorType() const {
2030 static const std::vector<std::pair<int, ScalarType::Kind> > scalars {
2031 {8, ScalarType::Kind::KIND_UINT8},
2032 {16, ScalarType::Kind::KIND_UINT16},
2033 {32, ScalarType::Kind::KIND_UINT32},
2034 };
2035
2036 size_t numFields = mFields.size();
2037 auto kind = ScalarType::Kind::KIND_UINT64;
2038
2039 for (const auto& scalar : scalars) {
2040 if (numFields <= (1ULL << scalar.first)) {
2041 kind = scalar.second; break;
2042 }
2043 }
2044
2045 return std::unique_ptr<ScalarType>(new ScalarType(kind, nullptr));
2046 }
2047
getPad(size_t offset,size_t align)2048 size_t CompoundType::Layout::getPad(size_t offset, size_t align) {
2049 size_t remainder = offset % align;
2050 return (remainder > 0) ? (align - remainder) : 0;
2051 }
2052
2053 } // namespace android
2054
2055