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