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