• 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 
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