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 "VectorType.h"
     18 
     19 #include "ArrayType.h"
     20 #include "CompoundType.h"
     21 #include "HidlTypeAssertion.h"
     22 
     23 #include <hidl-util/Formatter.h>
     24 #include <android-base/logging.h>
     25 
     26 namespace android {
     27 
     28 VectorType::VectorType(Scope* parent) : TemplatedType(parent) {}
     29 
     30 std::string VectorType::templatedTypeName() const {
     31     return "vector";
     32 }
     33 
     34 bool VectorType::isCompatibleElementType(const Type* elementType) const {
     35     if (elementType->isScalar()) {
     36         return true;
     37     }
     38     if (elementType->isString()) {
     39         return true;
     40     }
     41     if (elementType->isEnum()) {
     42         return true;
     43     }
     44     if (elementType->isBitField()) {
     45         return true;
     46     }
     47     if (elementType->isCompoundType()) {
     48         return true;
     49     }
     50     if (elementType->isInterface()) {
     51         return true;
     52     }
     53     if (elementType->isHandle()) {
     54         return true;
     55     }
     56     if (elementType->isMemory()) {
     57         return true;
     58     }
     59     if (elementType->isTemplatedType()) {
     60         const Type* inner = static_cast<const TemplatedType*>(elementType)->getElementType();
     61         return this->isCompatibleElementType(inner) && !inner->isInterface();
     62     }
     63     if (elementType->isArray()) {
     64         const Type* inner = static_cast<const ArrayType*>(elementType)->getElementType();
     65         return this->isCompatibleElementType(inner) && !inner->isInterface();
     66     }
     67     return false;
     68 }
     69 
     70 bool VectorType::isVector() const {
     71     return true;
     72 }
     73 
     74 bool VectorType::isVectorOfBinders() const {
     75     return mElementType->isBinder();
     76 }
     77 
     78 bool VectorType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const {
     79     return mElementType->canCheckEquality(visited);
     80 }
     81 
     82 std::vector<const Reference<Type>*> VectorType::getStrongReferences() const {
     83     return {};
     84 }
     85 
     86 std::string VectorType::getCppType(StorageMode mode,
     87                                    bool specifyNamespaces) const {
     88     const std::string base =
     89           std::string(specifyNamespaces ? "::android::hardware::" : "")
     90         + "hidl_vec<"
     91         + mElementType->getCppStackType( specifyNamespaces)
     92         + ">";
     93 
     94     switch (mode) {
     95         case StorageMode_Stack:
     96             return base;
     97 
     98         case StorageMode_Argument:
     99             return "const " + base + "&";
    100 
    101         case StorageMode_Result:
    102         {
    103             if (isVectorOfBinders()) {
    104                 return base;
    105             }
    106 
    107             return "const " + base + "*";
    108         }
    109     }
    110 }
    111 
    112 std::string VectorType::getJavaType(bool /* forInitializer */) const {
    113 
    114     std::string elementJavaType;
    115     if (mElementType->isArray()) {
    116         elementJavaType = mElementType->getJavaType();
    117     } else {
    118         elementJavaType = mElementType->getJavaWrapperType();
    119     }
    120 
    121     return "java.util.ArrayList<"
    122         + elementJavaType
    123         + ">";
    124 }
    125 
    126 std::string VectorType::getVtsType() const {
    127     return "TYPE_VECTOR";
    128 }
    129 
    130 std::string VectorType::getVtsValueName() const {
    131     return "vector_value";
    132 }
    133 
    134 void VectorType::emitReaderWriter(
    135         Formatter &out,
    136         const std::string &name,
    137         const std::string &parcelObj,
    138         bool parcelObjIsPointer,
    139         bool isReader,
    140         ErrorMode mode) const {
    141     if (isVectorOfBinders()) {
    142         emitReaderWriterForVectorOfBinders(
    143                 out, name, parcelObj, parcelObjIsPointer, isReader, mode);
    144 
    145         return;
    146     }
    147 
    148     std::string baseType = mElementType->getCppStackType();
    149 
    150     const std::string parentName = "_hidl_" + name + "_parent";
    151 
    152     out << "size_t " << parentName << ";\n\n";
    153 
    154     const std::string parcelObjDeref =
    155         parcelObj + (parcelObjIsPointer ? "->" : ".");
    156 
    157     if (isReader) {
    158         out << "_hidl_err = "
    159             << parcelObjDeref
    160             << "readBuffer("
    161             << "sizeof(*"
    162             << name
    163             << "), &"
    164             << parentName
    165             << ", "
    166             << " reinterpret_cast<const void **>("
    167             << "&" << name
    168             << "));\n\n";
    169 
    170         handleError(out, mode);
    171     } else {
    172         out << "_hidl_err = "
    173             << parcelObjDeref
    174             << "writeBuffer(&"
    175             << name
    176             << ", sizeof("
    177             << name
    178             << "), &"
    179             << parentName
    180             << ");\n";
    181 
    182         handleError(out, mode);
    183     }
    184 
    185     emitReaderWriterEmbedded(
    186             out,
    187             0 /* depth */,
    188             name,
    189             name /* sanitizedName */ ,
    190             isReader /* nameIsPointer */,
    191             parcelObj,
    192             parcelObjIsPointer,
    193             isReader,
    194             mode,
    195             parentName,
    196             "0 /* parentOffset */");
    197 }
    198 
    199 void VectorType::emitReaderWriterForVectorOfBinders(
    200         Formatter &out,
    201         const std::string &name,
    202         const std::string &parcelObj,
    203         bool parcelObjIsPointer,
    204         bool isReader,
    205         ErrorMode mode) const {
    206     const std::string parcelObjDeref =
    207         parcelObj + (parcelObjIsPointer ? "->" : ".");
    208 
    209     if (isReader) {
    210         out << "{\n";
    211         out.indent();
    212 
    213         const std::string sizeName = "_hidl_" + name + "_size";
    214 
    215         out << "uint64_t "
    216             << sizeName
    217             << ";\n";
    218 
    219         out << "_hidl_err = "
    220             << parcelObjDeref
    221             << "readUint64(&"
    222             << sizeName
    223             << ");\n";
    224 
    225         handleError(out, mode);
    226 
    227         out << name
    228             << ".resize("
    229             << sizeName
    230             << ");\n\n"
    231             << "for (size_t _hidl_index = 0; _hidl_index < "
    232             << sizeName
    233             << "; ++_hidl_index) {\n";
    234 
    235         out.indent();
    236 
    237         out << mElementType->getCppStackType(true /* specifyNamespaces */)
    238             << " _hidl_base;\n";
    239 
    240         mElementType->emitReaderWriter(
    241                 out,
    242                 "_hidl_base",
    243                 parcelObj,
    244                 parcelObjIsPointer,
    245                 isReader,
    246                 mode);
    247 
    248         out << name
    249             << "[_hidl_index] = _hidl_base;\n";
    250 
    251         out.unindent();
    252         out << "}\n";
    253 
    254         out.unindent();
    255         out << "}\n";
    256     } else {
    257         out << "_hidl_err = "
    258             << parcelObjDeref
    259             << "writeUint64("
    260             << name
    261             << ".size());\n";
    262 
    263         handleError(out, mode);
    264 
    265         out << "for (size_t _hidl_index = 0; _hidl_index < "
    266             << name
    267             << ".size(); ++_hidl_index) {\n";
    268 
    269         out.indent();
    270 
    271         mElementType->emitReaderWriter(
    272                 out,
    273                 name + "[_hidl_index]",
    274                 parcelObj,
    275                 parcelObjIsPointer,
    276                 isReader,
    277                 mode);
    278 
    279         out.unindent();
    280         out << "}\n";
    281     }
    282 }
    283 
    284 void VectorType::emitReaderWriterEmbedded(
    285         Formatter &out,
    286         size_t depth,
    287         const std::string &name,
    288         const std::string &sanitizedName,
    289         bool nameIsPointer,
    290         const std::string &parcelObj,
    291         bool parcelObjIsPointer,
    292         bool isReader,
    293         ErrorMode mode,
    294         const std::string &parentName,
    295         const std::string &offsetText) const {
    296     std::string baseType = getCppStackType();
    297 
    298     const std::string childName = "_hidl_" + sanitizedName + "_child";
    299     out << "size_t " << childName << ";\n\n";
    300 
    301     emitReaderWriterEmbeddedForTypeName(
    302             out,
    303             name,
    304             nameIsPointer,
    305             parcelObj,
    306             parcelObjIsPointer,
    307             isReader,
    308             mode,
    309             parentName,
    310             offsetText,
    311             baseType,
    312             childName,
    313             "::android::hardware");
    314 
    315     if (!mElementType->needsEmbeddedReadWrite()) {
    316         return;
    317     }
    318 
    319     const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
    320 
    321     baseType = mElementType->getCppStackType();
    322 
    323     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
    324 
    325     out << "for (size_t "
    326         << iteratorName
    327         << " = 0; "
    328         << iteratorName
    329         << " < "
    330         << nameDeref
    331         << "size(); ++"
    332         << iteratorName
    333         << ") {\n";
    334 
    335     out.indent();
    336 
    337     mElementType->emitReaderWriterEmbedded(
    338             out,
    339             depth + 1,
    340             (nameIsPointer ? "(*" + name + ")" : name)
    341                 + "[" + iteratorName + "]",
    342             sanitizedName + (nameIsPointer ? "_deref" : "") + "_indexed",
    343             false /* nameIsPointer */,
    344             parcelObj,
    345             parcelObjIsPointer,
    346             isReader,
    347             mode,
    348             childName,
    349             iteratorName + " * sizeof(" + baseType + ")");
    350 
    351     out.unindent();
    352 
    353     out << "}\n\n";
    354 }
    355 
    356 void VectorType::emitResolveReferences(
    357             Formatter &out,
    358             const std::string &name,
    359             bool nameIsPointer,
    360             const std::string &parcelObj,
    361             bool parcelObjIsPointer,
    362             bool isReader,
    363             ErrorMode mode) const {
    364     emitResolveReferencesEmbeddedHelper(
    365         out,
    366         0, /* depth */
    367         name,
    368         name /* sanitizedName */,
    369         nameIsPointer,
    370         parcelObj,
    371         parcelObjIsPointer,
    372         isReader,
    373         mode,
    374         "_hidl_" + name + "_child",
    375         "0 /* parentOffset */");
    376 }
    377 
    378 void VectorType::emitResolveReferencesEmbedded(
    379             Formatter &out,
    380             size_t depth,
    381             const std::string &name,
    382             const std::string &sanitizedName,
    383             bool nameIsPointer,
    384             const std::string &parcelObj,
    385             bool parcelObjIsPointer,
    386             bool isReader,
    387             ErrorMode mode,
    388             const std::string & /* parentName */,
    389             const std::string & /* offsetText */) const {
    390     emitResolveReferencesEmbeddedHelper(
    391         out, depth, name, sanitizedName, nameIsPointer, parcelObj,
    392         parcelObjIsPointer, isReader, mode, "", "");
    393 }
    394 
    395 bool VectorType::useParentInEmitResolveReferencesEmbedded() const {
    396     // parentName and offsetText is not used in emitResolveReferencesEmbedded
    397     return false;
    398 }
    399 
    400 void VectorType::emitResolveReferencesEmbeddedHelper(
    401             Formatter &out,
    402             size_t depth,
    403             const std::string &name,
    404             const std::string &sanitizedName,
    405             bool nameIsPointer,
    406             const std::string &parcelObj,
    407             bool parcelObjIsPointer,
    408             bool isReader,
    409             ErrorMode mode,
    410             const std::string &childName,
    411             const std::string &childOffsetText) const {
    412     CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
    413 
    414     const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
    415     const std::string nameDerefed = (nameIsPointer ? "*" : "") + name;
    416     std::string elementType = mElementType->getCppStackType();
    417 
    418     std::string myChildName = childName, myChildOffset = childOffsetText;
    419 
    420     if(myChildName.empty() && myChildOffset.empty()) {
    421         myChildName = "_hidl_" + sanitizedName + "_child";
    422         myChildOffset = "0";
    423 
    424         out << "size_t " << myChildName << ";\n";
    425         out << "_hidl_err = ::android::hardware::findInParcel("
    426             << nameDerefed << ", "
    427             << (parcelObjIsPointer ? "*" : "") << parcelObj << ", "
    428             << "&" << myChildName
    429             << ");\n";
    430 
    431         handleError(out, mode);
    432     }
    433 
    434     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
    435 
    436     out << "for (size_t "
    437         << iteratorName
    438         << " = 0; "
    439         << iteratorName
    440         << " < "
    441         << nameDeref
    442         << "size(); ++"
    443         << iteratorName
    444         << ") {\n";
    445 
    446     out.indent();
    447 
    448     mElementType->emitResolveReferencesEmbedded(
    449         out,
    450         depth + 1,
    451         (nameIsPointer ? "(*" + name + ")" : name) + "[" + iteratorName + "]",
    452         sanitizedName + (nameIsPointer ? "_deref" : "") + "_indexed",
    453         false /* nameIsPointer */,
    454         parcelObj,
    455         parcelObjIsPointer,
    456         isReader,
    457         mode,
    458         myChildName,
    459         myChildOffset + " + " +
    460                 iteratorName + " * sizeof(" + elementType + ")");
    461 
    462     out.unindent();
    463 
    464     out << "}\n\n";
    465 }
    466 
    467 void VectorType::emitJavaReaderWriter(
    468         Formatter &out,
    469         const std::string &parcelObj,
    470         const std::string &argName,
    471         bool isReader) const {
    472     if (mElementType->isCompoundType()) {
    473 
    474         if (isReader) {
    475             out << mElementType->getJavaType()
    476                 << ".readVectorFromParcel("
    477                 << parcelObj
    478                 << ");\n";
    479         } else {
    480             out << mElementType->getJavaType()
    481                 << ".writeVectorToParcel("
    482                 << parcelObj
    483                 << ", "
    484                 << argName
    485                 << ");\n";
    486         }
    487 
    488         return;
    489     }
    490 
    491     if (mElementType->isArray()) {
    492         size_t align, size;
    493         getAlignmentAndSize(&align, &size);
    494         if (isReader) {
    495             out << " new "
    496                 << getJavaType(false /* forInitializer */)
    497                 << "();\n";
    498         }
    499 
    500         out << "{\n";
    501         out.indent();
    502 
    503         out << "android.os.HwBlob _hidl_blob = ";
    504 
    505         if (isReader) {
    506             out << parcelObj
    507                 << ".readBuffer("
    508                 << size
    509                 << " /* size */);\n";
    510         } else {
    511 
    512             out << "new android.os.HwBlob("
    513                 << size
    514                 << " /* size */);\n";
    515         }
    516 
    517         emitJavaFieldReaderWriter(
    518                 out,
    519                 0 /* depth */,
    520                 parcelObj,
    521                 "_hidl_blob",
    522                 argName,
    523                 "0 /* offset */",
    524                 isReader);
    525 
    526         if (!isReader) {
    527             out << parcelObj << ".writeBuffer(_hidl_blob);\n";
    528         };
    529 
    530         out.unindent();
    531         out << "}\n";
    532 
    533         return;
    534     }
    535 
    536     emitJavaReaderWriterWithSuffix(
    537             out,
    538             parcelObj,
    539             argName,
    540             isReader,
    541             mElementType->getJavaSuffix() + "Vector",
    542             "" /* extra */);
    543 }
    544 
    545 void VectorType::emitJavaFieldInitializer(
    546         Formatter &out, const std::string &fieldName) const {
    547     std::string javaType = getJavaType(false /* forInitializer */);
    548 
    549     out << "final "
    550         << javaType
    551         << " "
    552         << fieldName
    553         << " = new "
    554         << javaType
    555         << "();\n";
    556 }
    557 
    558 void VectorType::emitJavaFieldReaderWriter(
    559         Formatter &out,
    560         size_t depth,
    561         const std::string &parcelName,
    562         const std::string &blobName,
    563         const std::string &fieldName,
    564         const std::string &offset,
    565         bool isReader) const {
    566     VectorType::EmitJavaFieldReaderWriterForElementType(
    567             out,
    568             depth,
    569             mElementType.get(),
    570             parcelName,
    571             blobName,
    572             fieldName,
    573             offset,
    574             isReader);
    575 }
    576 
    577 void VectorType::EmitJavaFieldReaderWriterForElementType(
    578         Formatter &out,
    579         size_t depth,
    580         const Type *elementType,
    581         const std::string &parcelName,
    582         const std::string &blobName,
    583         const std::string &fieldName,
    584         const std::string &offset,
    585         bool isReader) {
    586     size_t elementAlign, elementSize;
    587     elementType->getAlignmentAndSize(&elementAlign, &elementSize);
    588 
    589     if (isReader) {
    590         out << "{\n";
    591         out.indent();
    592 
    593         out << "int _hidl_vec_size = "
    594             << blobName
    595             << ".getInt32("
    596             << offset
    597             << " + 8 /* offsetof(hidl_vec<T>, mSize) */);\n";
    598 
    599         out << "android.os.HwBlob childBlob = "
    600             << parcelName
    601             << ".readEmbeddedBuffer(\n";
    602 
    603         out.indent();
    604         out.indent();
    605 
    606         out << "_hidl_vec_size * "
    607             << elementSize << ","
    608             << blobName
    609             << ".handle(),\n"
    610             << offset
    611             << " + 0 /* offsetof(hidl_vec<T>, mBuffer) */,"
    612             << "true /* nullable */);\n\n";
    613 
    614         out.unindent();
    615         out.unindent();
    616 
    617         out << fieldName << ".clear();\n";
    618         std::string iteratorName = "_hidl_index_" + std::to_string(depth);
    619 
    620         out << "for (int "
    621             << iteratorName
    622             << " = 0; "
    623             << iteratorName
    624             << " < _hidl_vec_size; "
    625             << "++"
    626             << iteratorName
    627             << ") {\n";
    628 
    629         out.indent();
    630 
    631         elementType->emitJavaFieldInitializer(out, "_hidl_vec_element");
    632 
    633         elementType->emitJavaFieldReaderWriter(
    634                 out,
    635                 depth + 1,
    636                 parcelName,
    637                 "childBlob",
    638                 "_hidl_vec_element",
    639                 iteratorName + " * " + std::to_string(elementSize),
    640                 true /* isReader */);
    641 
    642         out << fieldName
    643             << ".add(_hidl_vec_element);\n";
    644 
    645         out.unindent();
    646 
    647         out << "}\n";
    648 
    649         out.unindent();
    650         out << "}\n";
    651 
    652         return;
    653     }
    654 
    655     out << "{\n";
    656     out.indent();
    657 
    658     out << "int _hidl_vec_size = "
    659         << fieldName
    660         << ".size();\n";
    661 
    662     out << blobName
    663         << ".putInt32("
    664         << offset
    665         << " + 8 /* offsetof(hidl_vec<T>, mSize) */, _hidl_vec_size);\n";
    666 
    667     out << blobName
    668         << ".putBool("
    669         << offset
    670         << " + 12 /* offsetof(hidl_vec<T>, mOwnsBuffer) */, false);\n";
    671 
    672     // XXX make HwBlob constructor take a long instead of an int?
    673     out << "android.os.HwBlob childBlob = new android.os.HwBlob((int)(_hidl_vec_size * "
    674         << elementSize
    675         << "));\n";
    676 
    677     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
    678 
    679     out << "for (int "
    680         << iteratorName
    681         << " = 0; "
    682         << iteratorName
    683         << " < _hidl_vec_size; "
    684         << "++"
    685         << iteratorName
    686         << ") {\n";
    687 
    688     out.indent();
    689 
    690     elementType->emitJavaFieldReaderWriter(
    691             out,
    692             depth + 1,
    693             parcelName,
    694             "childBlob",
    695             fieldName + ".get(" + iteratorName + ")",
    696             iteratorName + " * " + std::to_string(elementSize),
    697             false /* isReader */);
    698 
    699     out.unindent();
    700 
    701     out << "}\n";
    702 
    703     out << blobName
    704         << ".putBlob("
    705         << offset
    706         << " + 0 /* offsetof(hidl_vec<T>, mBuffer) */, childBlob);\n";
    707 
    708     out.unindent();
    709     out << "}\n";
    710 }
    711 
    712 bool VectorType::needsEmbeddedReadWrite() const {
    713     return true;
    714 }
    715 
    716 bool VectorType::deepNeedsResolveReferences(std::unordered_set<const Type*>* visited) const {
    717     if (mElementType->needsResolveReferences(visited)) {
    718         return true;
    719     }
    720     return TemplatedType::deepNeedsResolveReferences(visited);
    721 }
    722 
    723 bool VectorType::resultNeedsDeref() const {
    724     return !isVectorOfBinders();
    725 }
    726 
    727 bool VectorType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
    728     if (!mElementType->isJavaCompatible(visited)) {
    729         return false;
    730     }
    731 
    732     if (mElementType->isArray()) {
    733         return static_cast<const ArrayType*>(mElementType.get())->countDimensions() == 1;
    734     }
    735 
    736     if (mElementType->isVector()) {
    737         return false;
    738     }
    739 
    740     if (isVectorOfBinders()) {
    741         return false;
    742     }
    743 
    744     return TemplatedType::deepIsJavaCompatible(visited);
    745 }
    746 
    747 bool VectorType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
    748     if (mElementType->containsPointer(visited)) {
    749         return true;
    750     }
    751     return TemplatedType::deepContainsPointer(visited);
    752 }
    753 
    754 // All hidl_vec<T> have the same size.
    755 static HidlTypeAssertion assertion("hidl_vec<char>", 16 /* size */);
    756 
    757 void VectorType::getAlignmentAndSizeStatic(size_t *align, size_t *size) {
    758     *align = 8;  // hidl_vec<T>
    759     *size = assertion.size();
    760 }
    761 
    762 void VectorType::getAlignmentAndSize(size_t *align, size_t *size) const {
    763     VectorType::getAlignmentAndSizeStatic(align, size);
    764 }
    765 
    766 }  // namespace android
    767 
    768