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