Home | History | Annotate | Download | only in hidl
      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 
     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 
     33 CompoundType::Style CompoundType::style() const {
     34     return mStyle;
     35 }
     36 
     37 void CompoundType::setFields(std::vector<NamedReference<Type>*>* fields) {
     38     mFields = fields;
     39 }
     40 
     41 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 
     47 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 
     72 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 
     87 bool CompoundType::isCompoundType() const {
     88     return true;
     89 }
     90 
     91 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 
    103 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 
    115 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 
    132 std::string CompoundType::getJavaType(bool /* forInitializer */) const {
    133     return fullJavaName();
    134 }
    135 
    136 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 
    150 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 
    166 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 
    216 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 
    243 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 
    260 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 
    271 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 }
    299 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 
    321 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 
    377 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 
    457 void CompoundType::emitTypeForwardDeclaration(Formatter& out) const {
    458     out << ((mStyle == STYLE_STRUCT) ? "struct" : "union") << " " << localName() << ";\n";
    459 }
    460 
    461 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 
    510 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 
    551 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 
    566 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 
    805 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 
    876 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 
    952 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 
    966 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 
    980 bool CompoundType::resultNeedsDeref() const {
    981     return !containsInterface() ;
    982 }
    983 
    984 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 
   1030 void CompoundType::emitVtsAttributeType(Formatter& out) const {
   1031     out << "type: " << getVtsType() << "\n";
   1032     out << "predefined_type: \"" << fullName() << "\"\n";
   1033 }
   1034 
   1035 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 
   1049 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 
   1059 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