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