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 "VectorType.h"
21
22 #include <android-base/logging.h>
23 #include <hidl-util/Formatter.h>
24 #include <iostream>
25 #include <unordered_set>
26
27 namespace android {
28
CompoundType(Style style,const char * localName,const FQName & fullName,const Location & location,Scope * parent)29 CompoundType::CompoundType(Style style, const char* localName, const FQName& fullName,
30 const Location& location, Scope* parent)
31 : Scope(localName, fullName, location, parent), mStyle(style), mFields(NULL) {}
32
style() const33 CompoundType::Style CompoundType::style() const {
34 return mStyle;
35 }
36
setFields(std::vector<NamedReference<Type> * > * fields)37 void CompoundType::setFields(std::vector<NamedReference<Type>*>* fields) {
38 mFields = fields;
39 }
40
getReferences() const41 std::vector<const Reference<Type>*> CompoundType::getReferences() const {
42 std::vector<const Reference<Type>*> ret;
43 ret.insert(ret.begin(), mFields->begin(), mFields->end());
44 return ret;
45 }
46
validate() const47 status_t CompoundType::validate() const {
48 for (const auto* field : *mFields) {
49 const Type& type = field->type();
50
51 if ((type.isVector() && static_cast<const VectorType*>(&type)->isVectorOfBinders())) {
52 std::cerr << "ERROR: Struct/Union must not contain references to interfaces at "
53 << field->location() << "\n";
54 return UNKNOWN_ERROR;
55 }
56
57 if (mStyle == STYLE_UNION) {
58 if (type.needsEmbeddedReadWrite()) {
59 std::cerr << "ERROR: Union must not contain any types that need fixup at "
60 << field->location() << "\n";
61 return UNKNOWN_ERROR;
62 }
63 }
64 }
65
66 status_t err = validateUniqueNames();
67 if (err != OK) return err;
68
69 return Scope::validate();
70 }
71
validateUniqueNames() const72 status_t CompoundType::validateUniqueNames() const {
73 std::unordered_set<std::string> names;
74
75 for (const auto* field : *mFields) {
76 if (names.find(field->name()) != names.end()) {
77 std::cerr << "ERROR: Redefinition of field '" << field->name() << "' at "
78 << field->location() << "\n";
79 return UNKNOWN_ERROR;
80 }
81 names.insert(field->name());
82 }
83
84 return OK;
85 }
86
isCompoundType() const87 bool CompoundType::isCompoundType() const {
88 return true;
89 }
90
deepCanCheckEquality(std::unordered_set<const Type * > * visited) const91 bool CompoundType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const {
92 if (mStyle == STYLE_UNION) {
93 return false;
94 }
95 for (const auto* field : *mFields) {
96 if (!field->get()->canCheckEquality(visited)) {
97 return false;
98 }
99 }
100 return true;
101 }
102
typeName() const103 std::string CompoundType::typeName() const {
104 switch (mStyle) {
105 case STYLE_STRUCT: {
106 return "struct " + localName();
107 }
108 case STYLE_UNION: {
109 return "union " + localName();
110 }
111 }
112 CHECK(!"Should not be here");
113 }
114
getCppType(StorageMode mode,bool) const115 std::string CompoundType::getCppType(
116 StorageMode mode,
117 bool /* specifyNamespaces */) const {
118 const std::string base = fullName();
119
120 switch (mode) {
121 case StorageMode_Stack:
122 return base;
123
124 case StorageMode_Argument:
125 return "const " + base + "&";
126
127 case StorageMode_Result:
128 return base + (containsInterface()?"":"*");
129 }
130 }
131
getJavaType(bool) const132 std::string CompoundType::getJavaType(bool /* forInitializer */) const {
133 return fullJavaName();
134 }
135
getVtsType() const136 std::string CompoundType::getVtsType() const {
137 switch (mStyle) {
138 case STYLE_STRUCT:
139 {
140 return "TYPE_STRUCT";
141 }
142 case STYLE_UNION:
143 {
144 return "TYPE_UNION";
145 }
146 }
147 CHECK(!"Should not be here");
148 }
149
containsInterface() const150 bool CompoundType::containsInterface() const {
151 for (const auto& field : *mFields) {
152 if (field->type().isCompoundType()) {
153 const Type& t = field->type();
154 const CompoundType* ct = static_cast<const CompoundType*>(&t);
155 if (ct->containsInterface()) {
156 return true;
157 }
158 }
159 if (field->type().isInterface()) {
160 return true;
161 }
162 }
163 return false;
164 }
165
emitReaderWriter(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const166 void CompoundType::emitReaderWriter(
167 Formatter &out,
168 const std::string &name,
169 const std::string &parcelObj,
170 bool parcelObjIsPointer,
171 bool isReader,
172 ErrorMode mode) const {
173
174 const std::string parcelObjDeref =
175 parcelObj + (parcelObjIsPointer ? "->" : ".");
176
177 if(containsInterface()){
178 for (const auto& field : *mFields) {
179 field->type().emitReaderWriter(out, name + "." + field->name(),
180 parcelObj, parcelObjIsPointer, isReader, mode);
181 }
182 } else {
183 const std::string parentName = "_hidl_" + name + "_parent";
184
185 out << "size_t " << parentName << ";\n\n";
186
187 if (isReader) {
188 out << "_hidl_err = " << parcelObjDeref << "readBuffer("
189 << "sizeof(*" << name << "), &" << parentName << ", "
190 << " const_cast<const void**>(reinterpret_cast<void **>("
191 << "&" << name << ")));\n";
192 handleError(out, mode);
193 } else {
194 out << "_hidl_err = "
195 << parcelObjDeref
196 << "writeBuffer(&"
197 << name
198 << ", sizeof("
199 << name
200 << "), &"
201 << parentName
202 << ");\n";
203 handleError(out, mode);
204 }
205 if (mStyle != STYLE_STRUCT) {
206 return;
207 }
208 if (needsEmbeddedReadWrite()) {
209 emitReaderWriterEmbedded(out, 0 /* depth */, name, name, /* sanitizedName */
210 isReader /* nameIsPointer */, parcelObj, parcelObjIsPointer,
211 isReader, mode, parentName, "0 /* parentOffset */");
212 }
213 }
214 }
215
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) const216 void CompoundType::emitReaderWriterEmbedded(
217 Formatter &out,
218 size_t /* depth */,
219 const std::string &name,
220 const std::string & /*sanitizedName */,
221 bool nameIsPointer,
222 const std::string &parcelObj,
223 bool parcelObjIsPointer,
224 bool isReader,
225 ErrorMode mode,
226 const std::string &parentName,
227 const std::string &offsetText) const {
228 emitReaderWriterEmbeddedForTypeName(
229 out,
230 name,
231 nameIsPointer,
232 parcelObj,
233 parcelObjIsPointer,
234 isReader,
235 mode,
236 parentName,
237 offsetText,
238 fullName(),
239 "" /* childName */,
240 "" /* namespace */);
241 }
242
emitJavaReaderWriter(Formatter & out,const std::string & parcelObj,const std::string & argName,bool isReader) const243 void CompoundType::emitJavaReaderWriter(
244 Formatter &out,
245 const std::string &parcelObj,
246 const std::string &argName,
247 bool isReader) const {
248 if (isReader) {
249 out << "new " << fullJavaName() << "();\n";
250 }
251
252 out << argName
253 << "."
254 << (isReader ? "readFromParcel" : "writeToParcel")
255 << "("
256 << parcelObj
257 << ");\n";
258 }
259
emitJavaFieldInitializer(Formatter & out,const std::string & fieldName) const260 void CompoundType::emitJavaFieldInitializer(
261 Formatter &out, const std::string &fieldName) const {
262 out << "final "
263 << fullJavaName()
264 << " "
265 << fieldName
266 << " = new "
267 << fullJavaName()
268 << "();\n";
269 }
270
emitJavaFieldReaderWriter(Formatter & out,size_t,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader) const271 void CompoundType::emitJavaFieldReaderWriter(
272 Formatter &out,
273 size_t /* depth */,
274 const std::string &parcelName,
275 const std::string &blobName,
276 const std::string &fieldName,
277 const std::string &offset,
278 bool isReader) const {
279 if (isReader) {
280 out << fieldName
281 << ".readEmbeddedFromParcel("
282 << parcelName
283 << ", "
284 << blobName
285 << ", "
286 << offset
287 << ");\n";
288
289 return;
290 }
291
292 out << fieldName
293 << ".writeEmbeddedToBlob("
294 << blobName
295 << ", "
296 << offset
297 << ");\n";
298 }
emitResolveReferences(Formatter & out,const std::string & name,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const299 void CompoundType::emitResolveReferences(
300 Formatter &out,
301 const std::string &name,
302 bool nameIsPointer,
303 const std::string &parcelObj,
304 bool parcelObjIsPointer,
305 bool isReader,
306 ErrorMode mode) const {
307 emitResolveReferencesEmbedded(
308 out,
309 0 /* depth */,
310 name,
311 name /* sanitizedName */,
312 nameIsPointer,
313 parcelObj,
314 parcelObjIsPointer,
315 isReader,
316 mode,
317 "_hidl_" + name + "_parent",
318 "0 /* parentOffset */");
319 }
320
emitResolveReferencesEmbedded(Formatter & out,size_t,const std::string & name,const std::string &,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode,const std::string & parentName,const std::string & offsetText) const321 void CompoundType::emitResolveReferencesEmbedded(
322 Formatter &out,
323 size_t /* depth */,
324 const std::string &name,
325 const std::string &/* sanitizedName */,
326 bool nameIsPointer,
327 const std::string &parcelObj,
328 bool parcelObjIsPointer,
329 bool isReader,
330 ErrorMode mode,
331 const std::string &parentName,
332 const std::string &offsetText) const {
333 CHECK(needsResolveReferences());
334
335 const std::string parcelObjDeref =
336 parcelObjIsPointer ? ("*" + parcelObj) : parcelObj;
337
338 const std::string parcelObjPointer =
339 parcelObjIsPointer ? parcelObj : ("&" + parcelObj);
340
341 const std::string nameDerefed = nameIsPointer ? ("*" + name) : name;
342 const std::string namePointer = nameIsPointer ? name : ("&" + name);
343
344 out << "_hidl_err = ";
345
346 if (isReader) {
347 out << "readEmbeddedReferenceFromParcel(\n";
348 } else {
349 out << "writeEmbeddedReferenceToParcel(\n";
350 }
351
352 out.indent(2, [&]{
353 if (isReader) {
354 out << "const_cast<"
355 << fullName()
356 << " *"
357 << ">("
358 << namePointer
359 << "),\n"
360 << parcelObjDeref;
361 } else {
362 out << nameDerefed
363 << ",\n"
364 << parcelObjPointer;
365 }
366
367 out << ",\n"
368 << parentName
369 << ",\n"
370 << offsetText
371 << ");\n\n";
372 });
373
374 handleError(out, mode);
375 }
376
emitTypeDeclarations(Formatter & out) const377 void CompoundType::emitTypeDeclarations(Formatter& out) const {
378 out << ((mStyle == STYLE_STRUCT) ? "struct" : "union")
379 << " "
380 << localName()
381 << " final {\n";
382
383 out.indent();
384
385 Scope::emitTypeDeclarations(out);
386
387 if (containsPointer()) {
388 for (const auto &field : *mFields) {
389 field->emitDocComment(out);
390 out << field->type().getCppStackType()
391 << " "
392 << field->name()
393 << ";\n";
394 }
395
396 out.unindent();
397 out << "};\n\n";
398
399 return;
400 }
401
402 for (int pass = 0; pass < 2; ++pass) {
403 size_t offset = 0;
404 for (const auto &field : *mFields) {
405 size_t fieldAlign, fieldSize;
406 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
407
408 size_t pad = offset % fieldAlign;
409 if (pad > 0) {
410 offset += fieldAlign - pad;
411 }
412
413 if (pass == 0) {
414 out << field->type().getCppStackType()
415 << " "
416 << field->name()
417 << " __attribute__ ((aligned("
418 << fieldAlign
419 << ")));\n";
420 } else {
421 out << "static_assert(offsetof("
422 << fullName()
423 << ", "
424 << field->name()
425 << ") == "
426 << offset
427 << ", \"wrong offset\");\n";
428 }
429
430 if (mStyle == STYLE_STRUCT) {
431 offset += fieldSize;
432 }
433 }
434
435 if (pass == 0) {
436 out.unindent();
437 out << "};\n\n";
438 }
439 }
440
441 size_t structAlign, structSize;
442 getAlignmentAndSize(&structAlign, &structSize);
443
444 out << "static_assert(sizeof("
445 << fullName()
446 << ") == "
447 << structSize
448 << ", \"wrong size\");\n";
449
450 out << "static_assert(__alignof("
451 << fullName()
452 << ") == "
453 << structAlign
454 << ", \"wrong alignment\");\n\n";
455 }
456
emitTypeForwardDeclaration(Formatter & out) const457 void CompoundType::emitTypeForwardDeclaration(Formatter& out) const {
458 out << ((mStyle == STYLE_STRUCT) ? "struct" : "union") << " " << localName() << ";\n";
459 }
460
emitPackageTypeDeclarations(Formatter & out) const461 void CompoundType::emitPackageTypeDeclarations(Formatter& out) const {
462 Scope::emitPackageTypeDeclarations(out);
463
464 out << "static inline std::string toString("
465 << getCppArgumentType()
466 << (mFields->empty() ? "" : " o")
467 << ") ";
468
469 out.block([&] {
470 // include toString for scalar types
471 out << "using ::android::hardware::toString;\n"
472 << "std::string os;\n";
473 out << "os += \"{\";\n";
474
475 for (const NamedReference<Type>* field : *mFields) {
476 out << "os += \"";
477 if (field != *(mFields->begin())) {
478 out << ", ";
479 }
480 out << "." << field->name() << " = \";\n";
481 field->type().emitDump(out, "os", "o." + field->name());
482 }
483
484 out << "os += \"}\"; return os;\n";
485 }).endl().endl();
486
487 if (canCheckEquality()) {
488 out << "static inline bool operator==("
489 << getCppArgumentType() << " " << (mFields->empty() ? "/* lhs */" : "lhs") << ", "
490 << getCppArgumentType() << " " << (mFields->empty() ? "/* rhs */" : "rhs") << ") ";
491 out.block([&] {
492 for (const auto &field : *mFields) {
493 out.sIf("lhs." + field->name() + " != rhs." + field->name(), [&] {
494 out << "return false;\n";
495 }).endl();
496 }
497 out << "return true;\n";
498 }).endl().endl();
499
500 out << "static inline bool operator!=("
501 << getCppArgumentType() << " lhs," << getCppArgumentType() << " rhs)";
502 out.block([&] {
503 out << "return !(lhs == rhs);\n";
504 }).endl().endl();
505 } else {
506 out << "// operator== and operator!= are not generated for " << localName() << "\n\n";
507 }
508 }
509
emitPackageHwDeclarations(Formatter & out) const510 void CompoundType::emitPackageHwDeclarations(Formatter& out) const {
511 if (needsEmbeddedReadWrite()) {
512 out << "::android::status_t readEmbeddedFromParcel(\n";
513
514 out.indent(2);
515
516 out << "const " << fullName() << " &obj,\n"
517 << "const ::android::hardware::Parcel &parcel,\n"
518 << "size_t parentHandle,\n"
519 << "size_t parentOffset);\n\n";
520
521 out.unindent(2);
522
523 out << "::android::status_t writeEmbeddedToParcel(\n";
524
525 out.indent(2);
526
527 out << "const " << fullName() << " &obj,\n"
528 << "::android::hardware::Parcel *parcel,\n"
529 << "size_t parentHandle,\n"
530 << "size_t parentOffset);\n\n";
531
532 out.unindent(2);
533 }
534
535 if(needsResolveReferences()) {
536 out << "::android::status_t readEmbeddedReferenceFromParcel(\n";
537 out.indent(2);
538 out << fullName() << " *obj,\n"
539 << "const ::android::hardware::Parcel &parcel,\n"
540 << "size_t parentHandle, size_t parentOffset);\n\n";
541 out.unindent(2);
542 out << "::android::status_t writeEmbeddedReferenceToParcel(\n";
543 out.indent(2);
544 out << "const " << fullName() << " &obj,\n"
545 << "::android::hardware::Parcel *,\n"
546 << "size_t parentHandle, size_t parentOffset);\n\n";
547 out.unindent(2);
548 }
549 }
550
emitTypeDefinitions(Formatter & out,const std::string & prefix) const551 void CompoundType::emitTypeDefinitions(Formatter& out, const std::string& prefix) const {
552 std::string space = prefix.empty() ? "" : (prefix + "::");
553 Scope::emitTypeDefinitions(out, space + localName());
554
555 if (needsEmbeddedReadWrite()) {
556 emitStructReaderWriter(out, prefix, true /* isReader */);
557 emitStructReaderWriter(out, prefix, false /* isReader */);
558 }
559
560 if (needsResolveReferences()) {
561 emitResolveReferenceDef(out, prefix, true /* isReader */);
562 emitResolveReferenceDef(out, prefix, false /* isReader */);
563 }
564 }
565
emitJavaTypeDeclarations(Formatter & out,bool atTopLevel) const566 void CompoundType::emitJavaTypeDeclarations(Formatter& out, bool atTopLevel) const {
567 out << "public final ";
568
569 if (!atTopLevel) {
570 out << "static ";
571 }
572
573 out << "class "
574 << localName()
575 << " {\n";
576
577 out.indent();
578
579 Scope::emitJavaTypeDeclarations(out, false /* atTopLevel */);
580
581 for (const auto& field : *mFields) {
582 field->emitDocComment(out);
583
584 out << "public ";
585
586 field->type().emitJavaFieldInitializer(out, field->name());
587 }
588
589 if (!mFields->empty()) {
590 out << "\n";
591 }
592
593 ////////////////////////////////////////////////////////////////////////////
594
595 if (canCheckEquality()) {
596 out << "@Override\npublic final boolean equals(Object otherObject) ";
597 out.block([&] {
598 out.sIf("this == otherObject", [&] {
599 out << "return true;\n";
600 }).endl();
601 out.sIf("otherObject == null", [&] {
602 out << "return false;\n";
603 }).endl();
604 // Though class is final, we use getClass instead of instanceof to be explicit.
605 out.sIf("otherObject.getClass() != " + fullJavaName() + ".class", [&] {
606 out << "return false;\n";
607 }).endl();
608 out << fullJavaName() << " other = (" << fullJavaName() << ")otherObject;\n";
609 for (const auto &field : *mFields) {
610 std::string condition = (field->type().isScalar() || field->type().isEnum())
611 ? "this." + field->name() + " != other." + field->name()
612 : ("!android.os.HidlSupport.deepEquals(this." + field->name()
613 + ", other." + field->name() + ")");
614 out.sIf(condition, [&] {
615 out << "return false;\n";
616 }).endl();
617 }
618 out << "return true;\n";
619 }).endl().endl();
620
621 out << "@Override\npublic final int hashCode() ";
622 out.block([&] {
623 out << "return java.util.Objects.hash(\n";
624 out.indent(2, [&] {
625 out.join(mFields->begin(), mFields->end(), ", \n", [&] (const auto &field) {
626 out << "android.os.HidlSupport.deepHashCode(this." << field->name() << ")";
627 });
628 });
629 out << ");\n";
630 }).endl().endl();
631 } else {
632 out << "// equals() is not generated for " << localName() << "\n";
633 }
634
635 ////////////////////////////////////////////////////////////////////////////
636
637 out << "@Override\npublic final String toString() ";
638 out.block([&] {
639 out << "java.lang.StringBuilder builder = new java.lang.StringBuilder();\n"
640 << "builder.append(\"{\");\n";
641 for (const auto &field : *mFields) {
642 out << "builder.append(\"";
643 if (field != *(mFields->begin())) {
644 out << ", ";
645 }
646 out << "." << field->name() << " = \");\n";
647 field->type().emitJavaDump(out, "builder", "this." + field->name());
648 }
649 out << "builder.append(\"}\");\nreturn builder.toString();\n";
650 }).endl().endl();
651
652 size_t structAlign, structSize;
653 getAlignmentAndSize(&structAlign, &structSize);
654
655 ////////////////////////////////////////////////////////////////////////////
656
657 out << "public final void readFromParcel(android.os.HwParcel parcel) {\n";
658 out.indent();
659 if (containsInterface()) {
660 for (const auto& field : *mFields) {
661 out << field->name() << " = ";
662 field->type().emitJavaReaderWriter(out, "parcel", field->name(), true);
663 }
664 } else {
665 out << "android.os.HwBlob blob = parcel.readBuffer(";
666 out << structSize << "/* size */);\n";
667 out << "readEmbeddedFromParcel(parcel, blob, 0 /* parentOffset */);\n";
668 }
669 out.unindent();
670 out << "}\n\n";
671
672 ////////////////////////////////////////////////////////////////////////////
673
674 size_t vecAlign, vecSize;
675 VectorType::getAlignmentAndSizeStatic(&vecAlign, &vecSize);
676
677 out << "public static final java.util.ArrayList<" << localName()
678 << "> readVectorFromParcel(android.os.HwParcel parcel) {\n";
679 out.indent();
680
681 out << "java.util.ArrayList<" << localName() << "> _hidl_vec = new java.util.ArrayList();\n";
682
683 if (containsInterface()) {
684 out << "int size = parcel.readInt32();\n";
685 out << "for(int i = 0 ; i < size; i ++) {\n";
686 out.indent();
687 out << fullJavaName() << " tmp = ";
688 emitJavaReaderWriter(out, "parcel", "tmp", true);
689 out << "_hidl_vec.add(tmp);\n";
690 out.unindent();
691 out << "}\n";
692 } else {
693 out << "android.os.HwBlob _hidl_blob = parcel.readBuffer(";
694 out << vecSize << " /* sizeof hidl_vec<T> */);\n\n";
695
696 VectorType::EmitJavaFieldReaderWriterForElementType(out, 0 /* depth */, this, "parcel",
697 "_hidl_blob", "_hidl_vec", "0",
698 true /* isReader */);
699 }
700 out << "\nreturn _hidl_vec;\n";
701 out.unindent();
702 out << "}\n\n";
703 ////////////////////////////////////////////////////////////////////////////
704 if (containsInterface()) {
705 out << "// readEmbeddedFromParcel is not generated()\n";
706 } else {
707 out << "public final void readEmbeddedFromParcel(\n";
708 out.indent(2);
709 out << "android.os.HwParcel parcel, android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
710 out.unindent();
711 size_t offset = 0;
712 for (const auto& field : *mFields) {
713 size_t fieldAlign, fieldSize;
714 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
715
716 size_t pad = offset % fieldAlign;
717 if (pad > 0) {
718 offset += fieldAlign - pad;
719 }
720
721 field->type().emitJavaFieldReaderWriter(
722 out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
723 "_hidl_offset + " + std::to_string(offset), true /* isReader */);
724 offset += fieldSize;
725 }
726 out.unindent();
727 out << "}\n\n";
728 }
729
730 ////////////////////////////////////////////////////////////////////////////
731
732 out << "public final void writeToParcel(android.os.HwParcel parcel) {\n";
733 out.indent();
734
735 if (containsInterface()) {
736 for (const auto& field : *mFields) {
737 field->type().emitJavaReaderWriter(out, "parcel", field->name(), false);
738 }
739 } else {
740 out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob(" << structSize
741 << " /* size */);\n";
742
743 out << "writeEmbeddedToBlob(_hidl_blob, 0 /* parentOffset */);\n"
744 << "parcel.writeBuffer(_hidl_blob);\n";
745 }
746 out.unindent();
747 out << "}\n\n";
748
749 ////////////////////////////////////////////////////////////////////////////
750
751 out << "public static final void writeVectorToParcel(\n";
752 out.indent(2);
753 out << "android.os.HwParcel parcel, java.util.ArrayList<" << localName() << "> _hidl_vec) {\n";
754 out.unindent();
755
756 if (containsInterface()) {
757 out << "parcel.writeInt32(_hidl_vec.size());\n";
758 out << "for(" << fullJavaName() << " tmp: _hidl_vec)\n";
759 out.indent();
760 emitJavaReaderWriter(out, "parcel", "tmp", false);
761 out.unindent();
762 } else {
763 out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob(" << vecSize
764 << " /* sizeof(hidl_vec<T>) */);\n";
765
766 VectorType::EmitJavaFieldReaderWriterForElementType(out, 0 /* depth */, this, "parcel",
767 "_hidl_blob", "_hidl_vec", "0",
768 false /* isReader */);
769
770 out << "\nparcel.writeBuffer(_hidl_blob);\n";
771 }
772 out.unindent();
773 out << "}\n\n";
774 ////////////////////////////////////////////////////////////////////////////
775
776 if (containsInterface()) {
777 out << "// writeEmbeddedFromParcel() is not generated\n";
778 } else {
779 out << "public final void writeEmbeddedToBlob(\n";
780 out.indent(2);
781 out << "android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
782 out.unindent();
783 size_t offset = 0;
784 for (const auto& field : *mFields) {
785 size_t fieldAlign, fieldSize;
786 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
787 size_t pad = offset % fieldAlign;
788 if (pad > 0) {
789 offset += fieldAlign - pad;
790 }
791 field->type().emitJavaFieldReaderWriter(
792 out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
793 "_hidl_offset + " + std::to_string(offset), false /* isReader */);
794 offset += fieldSize;
795 }
796
797 out.unindent();
798 out << "}\n";
799 }
800
801 out.unindent();
802 out << "};\n\n";
803 }
804
emitStructReaderWriter(Formatter & out,const std::string & prefix,bool isReader) const805 void CompoundType::emitStructReaderWriter(
806 Formatter &out, const std::string &prefix, bool isReader) const {
807
808 std::string space = prefix.empty() ? "" : (prefix + "::");
809
810 out << "::android::status_t "
811 << (isReader ? "readEmbeddedFromParcel"
812 : "writeEmbeddedToParcel")
813 << "(\n";
814
815 out.indent(2);
816
817 bool useName = false;
818 for (const auto &field : *mFields) {
819 if (field->type().useNameInEmitReaderWriterEmbedded(isReader)) {
820 useName = true;
821 break;
822 }
823 }
824 std::string name = useName ? "obj" : "/* obj */";
825 // if not useName, then obj should not be used at all,
826 // then the #error should not be emitted.
827 std::string error = useName ? "" : "\n#error\n";
828
829 if (isReader) {
830 out << "const " << space << localName() << " &" << name << ",\n";
831 out << "const ::android::hardware::Parcel &parcel,\n";
832 } else {
833 out << "const " << space << localName() << " &" << name << ",\n";
834 out << "::android::hardware::Parcel *parcel,\n";
835 }
836
837 out << "size_t parentHandle,\n"
838 << "size_t parentOffset)";
839
840 out << " {\n";
841
842 out.unindent(2);
843 out.indent();
844
845 out << "::android::status_t _hidl_err = ::android::OK;\n\n";
846
847 for (const auto &field : *mFields) {
848 if (!field->type().needsEmbeddedReadWrite()) {
849 continue;
850 }
851
852 field->type().emitReaderWriterEmbedded(
853 out,
854 0 /* depth */,
855 name + "." + field->name() + error,
856 field->name() /* sanitizedName */,
857 false /* nameIsPointer */,
858 "parcel",
859 !isReader /* parcelObjIsPointer */,
860 isReader,
861 ErrorMode_Return,
862 "parentHandle",
863 "parentOffset + offsetof("
864 + fullName()
865 + ", "
866 + field->name()
867 + ")");
868 }
869
870 out << "return _hidl_err;\n";
871
872 out.unindent();
873 out << "}\n\n";
874 }
875
emitResolveReferenceDef(Formatter & out,const std::string & prefix,bool isReader) const876 void CompoundType::emitResolveReferenceDef(Formatter& out, const std::string& prefix,
877 bool isReader) const {
878 out << "::android::status_t ";
879 const std::string space(prefix.empty() ? "" : (prefix + "::"));
880
881 bool useParent = false;
882 for (const auto &field : *mFields) {
883 if (field->type().useParentInEmitResolveReferencesEmbedded()) {
884 useParent = true;
885 break;
886 }
887 }
888
889 std::string parentHandleName = useParent ? "parentHandle" : "/* parentHandle */";
890 std::string parentOffsetName = useParent ? "parentOffset" : "/* parentOffset */";
891
892 if (isReader) {
893 out << "readEmbeddedReferenceFromParcel(\n";
894 out.indent(2);
895 out << space + localName() + " *obj,\n"
896 << "const ::android::hardware::Parcel &parcel,\n"
897 << "size_t " << parentHandleName << ", "
898 << "size_t " << parentOffsetName << ")\n";
899 out.unindent(2);
900 } else {
901 out << "writeEmbeddedReferenceToParcel(\n";
902 out.indent(2);
903 out << "const " << space + localName() + " &obj,\n"
904 << "::android::hardware::Parcel *parcel,\n"
905 << "size_t " << parentHandleName << ", "
906 << "size_t " << parentOffsetName << ")\n";
907 out.unindent(2);
908 }
909
910 out << " {\n";
911
912 out.indent();
913
914 out << "::android::status_t _hidl_err = ::android::OK;\n\n";
915
916 const std::string nameDeref(isReader ? "obj->" : "obj.");
917 // if not useParent, then parentName and offsetText
918 // should not be used at all, then the #error should not be emitted.
919 std::string error = useParent ? "" : "\n#error\n";
920
921 for (const auto &field : *mFields) {
922 if (!field->type().needsResolveReferences()) {
923 continue;
924 }
925
926 field->type().emitResolveReferencesEmbedded(
927 out,
928 0 /* depth */,
929 nameDeref + field->name(),
930 field->name() /* sanitizedName */,
931 false, // nameIsPointer
932 "parcel", // const std::string &parcelObj,
933 !isReader, // bool parcelObjIsPointer,
934 isReader, // bool isReader,
935 ErrorMode_Return,
936 parentHandleName + error,
937 parentOffsetName
938 + " + offsetof("
939 + fullName()
940 + ", "
941 + field->name()
942 + ")"
943 + error);
944 }
945
946 out << "return _hidl_err;\n";
947
948 out.unindent();
949 out << "}\n\n";
950 }
951
needsEmbeddedReadWrite() const952 bool CompoundType::needsEmbeddedReadWrite() const {
953 if (mStyle != STYLE_STRUCT) {
954 return false;
955 }
956
957 for (const auto &field : *mFields) {
958 if (field->type().needsEmbeddedReadWrite()) {
959 return true;
960 }
961 }
962
963 return false;
964 }
965
deepNeedsResolveReferences(std::unordered_set<const Type * > * visited) const966 bool CompoundType::deepNeedsResolveReferences(std::unordered_set<const Type*>* visited) const {
967 if (mStyle != STYLE_STRUCT) {
968 return false;
969 }
970
971 for (const auto &field : *mFields) {
972 if (field->type().needsResolveReferences(visited)) {
973 return true;
974 }
975 }
976
977 return Scope::deepNeedsResolveReferences(visited);
978 }
979
resultNeedsDeref() const980 bool CompoundType::resultNeedsDeref() const {
981 return !containsInterface() ;
982 }
983
emitVtsTypeDeclarations(Formatter & out) const984 void CompoundType::emitVtsTypeDeclarations(Formatter& out) const {
985 out << "name: \"" << fullName() << "\"\n";
986 out << "type: " << getVtsType() << "\n";
987
988 // Emit declaration for each subtype.
989 for (const auto &type : getSubTypes()) {
990 switch (mStyle) {
991 case STYLE_STRUCT:
992 {
993 out << "sub_struct: {\n";
994 break;
995 }
996 case STYLE_UNION:
997 {
998 out << "sub_union: {\n";
999 break;
1000 }
1001 }
1002 out.indent();
1003 type->emitVtsTypeDeclarations(out);
1004 out.unindent();
1005 out << "}\n";
1006 }
1007
1008 // Emit declaration for each field.
1009 for (const auto &field : *mFields) {
1010 switch (mStyle) {
1011 case STYLE_STRUCT:
1012 {
1013 out << "struct_value: {\n";
1014 break;
1015 }
1016 case STYLE_UNION:
1017 {
1018 out << "union_value: {\n";
1019 break;
1020 }
1021 }
1022 out.indent();
1023 out << "name: \"" << field->name() << "\"\n";
1024 field->type().emitVtsAttributeType(out);
1025 out.unindent();
1026 out << "}\n";
1027 }
1028 }
1029
emitVtsAttributeType(Formatter & out) const1030 void CompoundType::emitVtsAttributeType(Formatter& out) const {
1031 out << "type: " << getVtsType() << "\n";
1032 out << "predefined_type: \"" << fullName() << "\"\n";
1033 }
1034
deepIsJavaCompatible(std::unordered_set<const Type * > * visited) const1035 bool CompoundType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
1036 if (mStyle != STYLE_STRUCT) {
1037 return false;
1038 }
1039
1040 for (const auto* field : *mFields) {
1041 if (!field->get()->isJavaCompatible(visited)) {
1042 return false;
1043 }
1044 }
1045
1046 return Scope::deepIsJavaCompatible(visited);
1047 }
1048
deepContainsPointer(std::unordered_set<const Type * > * visited) const1049 bool CompoundType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
1050 for (const auto* field : *mFields) {
1051 if (field->get()->containsPointer(visited)) {
1052 return true;
1053 }
1054 }
1055
1056 return Scope::deepContainsPointer(visited);
1057 }
1058
getAlignmentAndSize(size_t * align,size_t * size) const1059 void CompoundType::getAlignmentAndSize(size_t *align, size_t *size) const {
1060 *align = 1;
1061 *size = 0;
1062
1063 size_t offset = 0;
1064 for (const auto &field : *mFields) {
1065 // Each field is aligned according to its alignment requirement.
1066 // The surrounding structure's alignment is the maximum of its
1067 // fields' aligments.
1068
1069 size_t fieldAlign, fieldSize;
1070 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
1071
1072 size_t pad = offset % fieldAlign;
1073 if (pad > 0) {
1074 offset += fieldAlign - pad;
1075 }
1076
1077 if (mStyle == STYLE_STRUCT) {
1078 offset += fieldSize;
1079 } else {
1080 *size = std::max(*size, fieldSize);
1081 }
1082
1083 if (fieldAlign > (*align)) {
1084 *align = fieldAlign;
1085 }
1086 }
1087
1088 if (mStyle == STYLE_STRUCT) {
1089 *size = offset;
1090 }
1091
1092 // Final padding to account for the structure's alignment.
1093 size_t pad = (*size) % (*align);
1094 if (pad > 0) {
1095 (*size) += (*align) - pad;
1096 }
1097
1098 if (*size == 0) {
1099 // An empty struct still occupies a byte of space in C++.
1100 *size = 1;
1101 }
1102 }
1103
1104 } // namespace android
1105
1106