Home | History | Annotate | Download | only in hidl
      1 /*
      2  * Copyright (C) 2017 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 "AST.h"
     18 
     19 #include "Coordinator.h"
     20 #include "EnumType.h"
     21 #include "HidlTypeAssertion.h"
     22 #include "Interface.h"
     23 #include "Method.h"
     24 #include "Reference.h"
     25 #include "ScalarType.h"
     26 #include "Scope.h"
     27 
     28 #include <android-base/logging.h>
     29 #include <hidl-util/Formatter.h>
     30 #include <hidl-util/StringHelper.h>
     31 #include <algorithm>
     32 #include <string>
     33 #include <vector>
     34 
     35 namespace android {
     36 
     37 void AST::generateCppAdapterHeader(Formatter& out) const {
     38     const std::string klassName = AST::isInterface() ? getInterface()->getAdapterName() : "Atypes";
     39     const std::string guard = makeHeaderGuard(klassName, true /* indicateGenerated */);
     40 
     41     out << "#ifndef " << guard << "\n";
     42     out << "#define " << guard << "\n\n";
     43 
     44     if (AST::isInterface()) {
     45         generateCppPackageInclude(out, mPackage, getInterface()->localName());
     46 
     47         enterLeaveNamespace(out, true /* enter */);
     48         out.endl();
     49 
     50         const std::string mockName = getInterface()->fqName().cppName();
     51 
     52         out << "class " << klassName << " : public " << mockName << " ";
     53         out.block([&] {
     54             out << "public:\n";
     55             out << "typedef " << mockName << " Pure;\n";
     56 
     57             out << klassName << "(::android::sp<" << mockName << "> impl);\n";
     58 
     59             generateMethods(out, [&](const Method* method, const Interface* /* interface */) {
     60                 if (method->isHidlReserved()) {
     61                     return;
     62                 }
     63 
     64                 out << "virtual ";
     65                 method->generateCppSignature(out);
     66                 out << " override;\n";
     67             });
     68             out << "private:\n";
     69             out << "::android::sp<" << mockName << "> mImpl;\n";
     70 
     71         }) << ";\n\n";
     72 
     73         enterLeaveNamespace(out, false /* enter */);
     74     } else {
     75         out << "// no adapters for types.hal\n";
     76     }
     77 
     78     out << "#endif // " << guard << "\n";
     79 }
     80 
     81 void AST::generateCppAdapterSource(Formatter& out) const {
     82     const std::string klassName = AST::isInterface() ? getInterface()->getAdapterName() : "Atypes";
     83 
     84     generateCppPackageInclude(out, mPackage, klassName);
     85 
     86     if (AST::isInterface()) {
     87         out << "#include <hidladapter/HidlBinderAdapter.h>\n";
     88         generateCppPackageInclude(out, mPackage, getInterface()->localName());
     89 
     90         std::set<FQName> allImportedNames;
     91         getAllImportedNames(&allImportedNames);
     92         for (const auto& item : allImportedNames) {
     93             if (item.name() == "types") {
     94                 continue;
     95             }
     96             generateCppPackageInclude(out, item, item.getInterfaceAdapterName());
     97         }
     98 
     99         out.endl();
    100 
    101         enterLeaveNamespace(out, true /* enter */);
    102         out.endl();
    103 
    104         const std::string mockName = getInterface()->fqName().cppName();
    105 
    106         out << klassName << "::" << klassName << "(::android::sp<" << mockName
    107             << "> impl) : mImpl(impl) {}";
    108 
    109         generateMethods(out, [&](const Method* method, const Interface* /* interface */) {
    110             generateAdapterMethod(out, method);
    111         });
    112 
    113         enterLeaveNamespace(out, false /* enter */);
    114         out.endl();
    115     } else {
    116         out << "// no adapters for types.hal\n";
    117     }
    118 }
    119 
    120 void AST::generateAdapterMethod(Formatter& out, const Method* method) const {
    121     if (method->isHidlReserved()) {
    122         return;
    123     }
    124 
    125     const auto adapt = [](Formatter& out, const std::string& var, const Type* type) {
    126         if (!type->isInterface()) {
    127             out << var;
    128             return;
    129         }
    130 
    131         // TODO(b/66900959): if we are creating the adapter for a 1.1 IFoo
    132         // and we are using a method that takes/returns a 1.0 Callback, but
    133         // there exists a 1.1 Callback (or other subclass that is depended
    134         // on by this module), then wrap with the adapter subclass adapter
    135         // IFF that callback is a subclass. However, if the callback
    136         // is 1.0 ICallback, then wrap with a 1.0 adapter.
    137 
    138         const Interface* interface = static_cast<const Interface*>(type);
    139         out << "static_cast<::android::sp<" << interface->fqName().cppName() << ">>("
    140             << interface->fqName().cppName() << "::castFrom("
    141             << "::android::hardware::details::adaptWithDefault("
    142             << "static_cast<::android::sp<" << interface->fqName().cppName() << ">>(" << var
    143             << "), [&] { return new " << interface->fqName().getInterfaceAdapterFqName().cppName()
    144             << "(" << var << "); })))";
    145     };
    146 
    147     const std::string klassName = getInterface()->getAdapterName();
    148 
    149     method->generateCppSignature(out, klassName);
    150     out.block([&] {
    151          bool hasCallback = !method->canElideCallback() && !method->results().empty();
    152 
    153          if (hasCallback) {
    154              out << method->name() << "_cb _hidl_cb_wrapped = [&](";
    155              method->emitCppResultSignature(out);
    156              out << ") ";
    157              out.block([&] {
    158                  out << "return _hidl_cb(\n";
    159                  out.indent([&]() {
    160                      out.join(method->results().begin(), method->results().end(), ",\n",
    161                               [&](auto arg) { adapt(out, arg->name(), arg->get()); });
    162                  });
    163                  out << ");\n";
    164              });
    165              out << ";\n";
    166          }
    167 
    168          out << "auto _hidl_out = mImpl->" << method->name() << "(\n";
    169          out.indent([&]() {
    170              out.join(method->args().begin(), method->args().end(), ",\n",
    171                       [&](auto arg) { adapt(out, arg->name(), arg->get()); });
    172              if (hasCallback) {
    173                  if (!method->args().empty()) {
    174                      out << ",\n";
    175                  }
    176                  out << "_hidl_cb_wrapped";
    177              }
    178          });
    179          out << ");\n";
    180 
    181          const auto elidedCallback = method->canElideCallback();
    182          if (elidedCallback) {
    183              out.sIf("!_hidl_out.isOkUnchecked()", [&] { out << "return _hidl_out;\n"; });
    184              out << "return ";
    185              adapt(out, "_hidl_out", elidedCallback->get());
    186              out << ";\n";
    187          } else {
    188              out << "return _hidl_out;\n";
    189          }
    190      }).endl();
    191 }
    192 
    193 }  // namespace android
    194