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