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 
generateCppAdapterHeader(Formatter & out) const37 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()->definedName());
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 << "(const ::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 
generateCppAdapterSource(Formatter & out) const81 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()->definedName());
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 << "(const ::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 
generateAdapterMethod(Formatter & out,const Method * method) const120 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         const Interface* interface = static_cast<const Interface*>(type);
132         out << "static_cast<::android::sp<" << interface->fqName().cppName() << ">>("
133             << interface->fqName().cppName() << "::castFrom("
134             << "::android::hardware::details::adaptWithDefault("
135             << "static_cast<::android::sp<" << interface->fqName().cppName() << ">>(" << var
136             << "), [&] { return new " << interface->fqName().getInterfaceAdapterFqName().cppName()
137             << "(" << var << "); })))";
138     };
139 
140     const std::string klassName = getInterface()->getAdapterName();
141 
142     method->generateCppSignature(out, klassName);
143     out.block([&] {
144          bool hasCallback = !method->canElideCallback() && !method->results().empty();
145 
146          if (hasCallback) {
147              out << method->name() << "_cb _hidl_cb_wrapped = [&](";
148              method->emitCppResultSignature(out);
149              out << ") ";
150              out.block([&] {
151                  out << "return _hidl_cb(\n";
152                  out.indent([&]() {
153                      out.join(method->results().begin(), method->results().end(), ",\n",
154                               [&](auto arg) { adapt(out, arg->name(), arg->get()); });
155                  });
156                  out << ");\n";
157              });
158              out << ";\n";
159          }
160 
161          out << "auto _hidl_out = mImpl->" << method->name() << "(\n";
162          out.indent([&]() {
163              out.join(method->args().begin(), method->args().end(), ",\n",
164                       [&](auto arg) { adapt(out, arg->name(), arg->get()); });
165              if (hasCallback) {
166                  if (!method->args().empty()) {
167                      out << ",\n";
168                  }
169                  out << "_hidl_cb_wrapped";
170              }
171          });
172          out << ");\n";
173 
174          const auto elidedCallback = method->canElideCallback();
175          if (elidedCallback) {
176              out.sIf("!_hidl_out.isOkUnchecked()", [&] { out << "return _hidl_out;\n"; });
177              out << "return ";
178              adapt(out, "_hidl_out", elidedCallback->get());
179              out << ";\n";
180          } else {
181              out << "return _hidl_out;\n";
182          }
183      }).endl();
184 }
185 
186 }  // namespace android
187