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 "RefType.h"
     18 
     19 #include "ArrayType.h"
     20 #include "CompoundType.h"
     21 
     22 #include <hidl-util/Formatter.h>
     23 #include <android-base/logging.h>
     24 
     25 namespace android {
     26 
     27 RefType::RefType() {
     28 }
     29 
     30 std::string RefType::typeName() const {
     31     return "ref" + (mElementType == nullptr ? "" : (" of " + mElementType->typeName()));
     32 }
     33 
     34 std::string RefType::getVtsType() const {
     35     return "TYPE_REF";
     36 }
     37 
     38 std::string RefType::getVtsValueName() const {
     39     return "ref_value";
     40 }
     41 
     42 bool RefType::isCompatibleElementType(Type *elementType) const {
     43     if (elementType->isScalar()) {
     44         return true;
     45     }
     46     if (elementType->isString()) {
     47         return true;
     48     }
     49     if (elementType->isEnum()) {
     50         return true;
     51     }
     52     if (elementType->isBitField()) {
     53         return true;
     54     }
     55     if (elementType->isCompoundType()
     56             && static_cast<CompoundType *>(elementType)->style() == CompoundType::STYLE_STRUCT) {
     57         return true;
     58     }
     59     if (elementType->isTemplatedType()) {
     60         return this->isCompatibleElementType(static_cast<TemplatedType *>(elementType)->getElementType());
     61     }
     62     if (elementType->isArray()) {
     63         return this->isCompatibleElementType(static_cast<ArrayType *>(elementType)->getElementType());
     64     }
     65     return false;
     66 }
     67 
     68 /* return something like "T const *".
     69  * The reason we don't return "const T *" is to handle cases like
     70  * ref<ref<ref<T>>> t_3ptr;
     71  * in this case the const's will get stacked on the left (const const const T *** t_3ptr)
     72  * but in this implementation it would be clearer (T const* const* const* t_3ptr) */
     73 std::string RefType::getCppType(StorageMode /*mode*/, bool specifyNamespaces) const {
     74     return mElementType->getCppStackType(specifyNamespaces)
     75             + " const*";
     76 }
     77 
     78 void RefType::addNamedTypesToSet(std::set<const FQName> &set) const {
     79     mElementType->addNamedTypesToSet(set);
     80 }
     81 
     82 void RefType::emitReaderWriter(
     83         Formatter &,
     84         const std::string &,
     85         const std::string &,
     86         bool,
     87         bool,
     88         ErrorMode) const {
     89     // RefType doesn't get read / written at this stage.
     90     return;
     91 }
     92 
     93 void RefType::emitResolveReferences(
     94             Formatter &out,
     95             const std::string &name,
     96             bool nameIsPointer,
     97             const std::string &parcelObj,
     98             bool parcelObjIsPointer,
     99             bool isReader,
    100             ErrorMode mode) const {
    101 
    102     emitResolveReferencesEmbedded(
    103         out,
    104         0 /* depth */,
    105         name,
    106         name /* sanitizedName */,
    107         nameIsPointer,
    108         parcelObj,
    109         parcelObjIsPointer,
    110         isReader,
    111         mode,
    112         "", // parentName
    113         ""); // offsetText
    114 }
    115 
    116 void RefType::emitResolveReferencesEmbedded(
    117             Formatter &out,
    118             size_t /* depth */,
    119             const std::string &name,
    120             const std::string &sanitizedName,
    121             bool /*nameIsPointer*/,
    122             const std::string &parcelObj,
    123             bool parcelObjIsPointer,
    124             bool isReader,
    125             ErrorMode mode,
    126             const std::string &parentName,
    127             const std::string &offsetText) const {
    128 
    129     std::string elementType = mElementType->getCppStackType();
    130 
    131     std::string baseType = getCppStackType();
    132 
    133     const std::string parcelObjDeref =
    134         parcelObjIsPointer ? ("*" + parcelObj) : parcelObj;
    135 
    136     const std::string parcelObjPointer =
    137         parcelObjIsPointer ? parcelObj : ("&" + parcelObj);
    138 
    139     // as if nameIsPointer is false. Pointers are always pass by values,
    140     // so name is always the pointer value itself. Hence nameIsPointer = false.
    141     const std::string namePointer = "&" + name;
    142     const std::string handleName = "_hidl_" + sanitizedName + "__ref_handle";
    143     const std::string resolveBufName = "_hidl_" + sanitizedName + "__ref_resolve_buf";
    144 
    145     bool isEmbedded = (!parentName.empty() && !offsetText.empty());
    146 
    147     out << "size_t " << handleName << ";\n"
    148         << "bool " << resolveBufName << ";\n\n";
    149 
    150     out << "_hidl_err = ";
    151 
    152     if (isReader) {
    153         out << "::android::hardware::read"
    154             << (isEmbedded ? "Embedded" : "")
    155             << "ReferenceFromParcel<"
    156             << elementType
    157             << ">(const_cast<"
    158             << baseType
    159             << " *>("
    160             << namePointer
    161             << "),";
    162     } else {
    163         out << "::android::hardware::write"
    164             << (isEmbedded ? "Embedded" : "")
    165             << "ReferenceToParcel<"
    166             << elementType
    167             << ">("
    168             << name
    169             << ",";
    170     }
    171 
    172     out.indent();
    173     out.indent();
    174 
    175     out << (isReader ? parcelObjDeref : parcelObjPointer);
    176     if(isEmbedded)
    177         out << ",\n"
    178             << parentName
    179             << ",\n"
    180             << offsetText;
    181 
    182     out << ",\n&" + handleName;
    183     out << ",\n&" + resolveBufName;
    184     out << ");\n\n";
    185 
    186     out.unindent();
    187     out.unindent();
    188 
    189     handleError(out, mode);
    190 
    191     if(!mElementType->needsResolveReferences() && !mElementType->needsEmbeddedReadWrite())
    192         return; // no need to deal with element type recursively.
    193 
    194     out << "if(" << resolveBufName << ") {\n";
    195     out.indent();
    196 
    197     if(mElementType->needsEmbeddedReadWrite()) {
    198         mElementType->emitReaderWriterEmbedded(
    199             out,
    200             0 /* depth */,
    201             name,
    202             sanitizedName,
    203             true /* nameIsPointer */, // for element type, name is a pointer.
    204             parcelObj,
    205             parcelObjIsPointer,
    206             isReader,
    207             mode,
    208             handleName,
    209             "0 /* parentOffset */");
    210     }
    211 
    212     if(mElementType->needsResolveReferences()) {
    213         mElementType->emitResolveReferencesEmbedded(
    214             out,
    215             0 /* depth */,
    216             "(*" + name + ")",
    217             sanitizedName + "_deref",
    218             false /* nameIsPointer */,
    219                 // must deref it and say false here, otherwise pointer to pointers don't work
    220             parcelObj,
    221             parcelObjIsPointer,
    222             isReader,
    223             mode,
    224             handleName,
    225             "0 /* parentOffset */");
    226     }
    227 
    228     out.unindent();
    229     out << "}\n\n";
    230 }
    231 
    232 bool RefType::needsResolveReferences() const {
    233     return true;
    234 }
    235 
    236 bool RefType::needsEmbeddedReadWrite() const {
    237     return false;
    238 }
    239 
    240 bool RefType::resultNeedsDeref() const {
    241     return false;
    242 }
    243 
    244 bool RefType::isJavaCompatible() const {
    245     return false;
    246 }
    247 
    248 bool RefType::containsPointer() const {
    249     return true;
    250 }
    251 
    252 }  // namespace android
    253 
    254