blob: 794b2bbe4c39fc9d2e04b0664ab912308d6cd7f9 [file] [log] [blame]
Steven Morelandb0057e72018-08-27 01:44:11 -07001/*
2 * Copyright (C) 2018, 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 */
Jooyung Han7a9aceb2019-12-17 14:18:15 +000016#include "aidl_to_cpp_common.h"
Steven Morelandb0057e72018-08-27 01:44:11 -070017
Devin Moore53fc99c2020-08-12 08:07:52 -070018#include <android-base/stringprintf.h>
Jooyung Han7a9aceb2019-12-17 14:18:15 +000019#include <android-base/strings.h>
Jeongik Cha37e2ad52019-04-18 13:44:26 +090020#include <unordered_map>
Steven Morelandb0057e72018-08-27 01:44:11 -070021
Jooyung Han7a9aceb2019-12-17 14:18:15 +000022#include "ast_cpp.h"
Jeongik Cha37e2ad52019-04-18 13:44:26 +090023#include "logging.h"
Steven Morelandb0057e72018-08-27 01:44:11 -070024#include "os.h"
25
Jooyung Han7a9aceb2019-12-17 14:18:15 +000026using ::android::base::Join;
27
Steven Morelandb0057e72018-08-27 01:44:11 -070028namespace android {
29namespace aidl {
30namespace cpp {
31
32string ClassName(const AidlDefinedType& defined_type, ClassNames type) {
Jiyong Park5b7e5322019-04-03 20:05:01 +090033 string base_name = defined_type.GetName();
34 if (base_name.length() >= 2 && base_name[0] == 'I' && isupper(base_name[1])) {
35 base_name = base_name.substr(1);
36 }
Steven Morelandb0057e72018-08-27 01:44:11 -070037
38 switch (type) {
39 case ClassNames::CLIENT:
Jiyong Park5b7e5322019-04-03 20:05:01 +090040 return "Bp" + base_name;
Steven Morelandb0057e72018-08-27 01:44:11 -070041 case ClassNames::SERVER:
Jiyong Park5b7e5322019-04-03 20:05:01 +090042 return "Bn" + base_name;
Steven Morelandb0057e72018-08-27 01:44:11 -070043 case ClassNames::INTERFACE:
Jiyong Park5b7e5322019-04-03 20:05:01 +090044 return "I" + base_name;
Steven Morelandb0057e72018-08-27 01:44:11 -070045 case ClassNames::DEFAULT_IMPL:
Jiyong Park5b7e5322019-04-03 20:05:01 +090046 return "I" + base_name + "Default";
Steven Morelandb0057e72018-08-27 01:44:11 -070047 case ClassNames::BASE:
Jiyong Park5b7e5322019-04-03 20:05:01 +090048 return base_name;
49 case ClassNames::RAW:
50 [[fallthrough]];
51 default:
52 return defined_type.GetName();
Steven Morelandb0057e72018-08-27 01:44:11 -070053 }
Steven Morelandb0057e72018-08-27 01:44:11 -070054}
55
56std::string HeaderFile(const AidlDefinedType& defined_type, ClassNames class_type,
57 bool use_os_sep) {
58 std::string file_path = defined_type.GetPackage();
59 for (char& c : file_path) {
60 if (c == '.') {
61 c = (use_os_sep) ? OS_PATH_SEPARATOR : '/';
62 }
63 }
64 if (!file_path.empty()) {
65 file_path += (use_os_sep) ? OS_PATH_SEPARATOR : '/';
66 }
67 file_path += ClassName(defined_type, class_type);
68 file_path += ".h";
69
70 return file_path;
71}
72
73void EnterNamespace(CodeWriter& out, const AidlDefinedType& defined_type) {
74 const std::vector<std::string> packages = defined_type.GetSplitPackage();
75 for (const std::string& package : packages) {
76 out << "namespace " << package << " {\n";
77 }
78}
79void LeaveNamespace(CodeWriter& out, const AidlDefinedType& defined_type) {
80 const std::vector<std::string> packages = defined_type.GetSplitPackage();
81 for (auto it = packages.rbegin(); it != packages.rend(); ++it) {
82 out << "} // namespace " << *it << "\n";
83 }
84}
85
Steven Moreland3b1325f2018-09-20 14:45:40 -070086string BuildVarName(const AidlArgument& a) {
87 string prefix = "out_";
88 if (a.GetDirection() & AidlArgument::IN_DIR) {
89 prefix = "in_";
90 }
91 return prefix + a.GetName();
92}
93
Jeongik Cha37e2ad52019-04-18 13:44:26 +090094struct TypeInfo {
95 // name of the type in C++ output
96 std::string cpp_name;
97
98 // function that writes an expression to convert a variable to a Json::Value
99 // object
100 std::function<void(CodeWriter& w, const string& var_name, bool isNdk)> toJsonValueExpr;
101};
102
103const static std::unordered_map<std::string, TypeInfo> kTypeInfoMap = {
104 {"void", {"void", nullptr}},
105 {"boolean",
106 {
107 "bool",
108 [](CodeWriter& c, const string& var_name, bool) {
109 c << "Json::Value(" << var_name << "? \"true\" : \"false\")";
110 },
111 }},
112 {"byte",
113 {
114 "int8_t",
115 [](CodeWriter& c, const string& var_name, bool) {
116 c << "Json::Value(" << var_name << ")";
117 },
118 }},
119 {"char",
120 {
121 "char16_t",
122 [](CodeWriter& c, const string& var_name, bool isNdk) {
123 if (isNdk) {
124 c << "Json::Value(" << var_name << ")";
125 } else {
126 c << "Json::Value(std::string(android::String8(&" << var_name << ", 1)))";
127 }
128 },
129 }},
130 {"int",
131 {
132 "int32_t",
133 [](CodeWriter& c, const string& var_name, bool) {
134 c << "Json::Value(" << var_name << ")";
135 },
136 }},
137 {"long",
138 {
139 "int64_t",
140 [](CodeWriter& c, const string& var_name, bool) {
141 c << "Json::Value(static_cast<Json::Int64>(" << var_name << "))";
142 },
143 }},
144 {"float",
145 {
146 "float",
147 [](CodeWriter& c, const string& var_name, bool) {
148 c << "Json::Value(" << var_name << ")";
149 },
150 }},
151 {"double",
152 {
153 "double",
154 [](CodeWriter& c, const string& var_name, bool) {
155 c << "Json::Value(" << var_name << ")";
156 },
157 }},
158 {"String",
159 {
160 "std::string",
161 [](CodeWriter& c, const string& var_name, bool) {
162 c << "Json::Value(" << var_name << ")";
163 },
164 }}
165 // missing List, Map, ParcelFileDescriptor, IBinder
166};
167
168TypeInfo GetTypeInfo(const AidlTypeSpecifier& aidl) {
169 CHECK(aidl.IsResolved()) << aidl.ToString();
170 const string& aidl_name = aidl.GetName();
171
172 TypeInfo info;
173 if (AidlTypenames::IsBuiltinTypename(aidl_name)) {
174 auto it = kTypeInfoMap.find(aidl_name);
175 if (it != kTypeInfoMap.end()) {
176 info = it->second;
177 }
178 }
179 // Missing interface and parcelable type
180 return info;
181}
182
183inline bool CanWriteLog(const TypeInfo& t) {
184 return t.cpp_name != "";
185}
186
187bool CanWriteLog(const AidlTypeSpecifier& aidl) {
188 return CanWriteLog(GetTypeInfo(aidl));
189}
190
191void WriteLogFor(CodeWriter& writer, const AidlTypeSpecifier& type, const std::string& name,
192 bool isPointer, const std::string& log, bool isNdk) {
193 const TypeInfo info = GetTypeInfo(type);
194 if (!CanWriteLog(info)) {
195 return;
196 }
197
198 const string var_object_expr = ((isPointer ? "*" : "")) + name;
199 if (type.IsArray()) {
200 writer << log << " = Json::Value(Json::arrayValue);\n";
201 writer << "for (const auto& v: " << var_object_expr << ") " << log << ".append(";
202 info.toJsonValueExpr(writer, "v", isNdk);
203 writer << ");";
204 } else {
205 writer << log << " = ";
206 info.toJsonValueExpr(writer, var_object_expr, isNdk);
207 writer << ";";
208 }
209 writer << "\n";
210}
211
212void WriteLogForArguments(CodeWriterPtr& writer, const AidlArgument& a, bool isServer,
213 string logVarName, bool isNdk) {
214 if (!CanWriteLog(a.GetType())) {
215 return;
216 }
217 string logElementVarName = "_log_arg_element";
218 (*writer) << "{\n";
219 (*writer).Indent();
220 (*writer) << "Json::Value " << logElementVarName << "(Json::objectValue);\n";
221 string varName = isServer || isNdk ? BuildVarName(a) : a.GetName();
222 (*writer) << logElementVarName << "[\"name\"] = \"" << varName << "\";\n";
223
224 bool isPointer = a.IsOut() && !isServer;
225 WriteLogFor(*(writer.get()), a.GetType(), varName, isPointer, logElementVarName + "[\"value\"]",
226 isNdk);
227 (*writer) << logVarName << ".append(" << logElementVarName << ");\n";
228 (*writer) << "}\n";
229 (*writer).Dedent();
230}
231
232const string GenLogBeforeExecute(const string className, const AidlMethod& method, bool isServer,
233 bool isNdk) {
234 string code;
235 CodeWriterPtr writer = CodeWriter::ForString(&code);
236 (*writer) << "Json::Value _log_input_args(Json::arrayValue);\n";
237
238 (*writer) << "if (" << className << "::logFunc != nullptr) {\n";
239 (*writer).Indent();
240
241 for (const auto& a : method.GetArguments()) {
242 if (a->IsIn()) {
243 WriteLogForArguments(writer, *a, isServer, "_log_input_args", isNdk);
244 }
245 }
246
247 (*writer).Dedent();
248 (*writer) << "}\n";
249
250 (*writer) << "auto _log_start = std::chrono::steady_clock::now();\n";
251 writer->Close();
252 return code;
253}
254
255const string GenLogAfterExecute(const string className, const AidlInterface& interface,
256 const AidlMethod& method, const string& statusVarName,
257 const string& returnVarName, bool isServer, bool isNdk) {
258 string code;
259 CodeWriterPtr writer = CodeWriter::ForString(&code);
260
261 (*writer) << "if (" << className << "::logFunc != nullptr) {\n";
262 (*writer).Indent();
263
264 // Write the log as a Json object. For example,
265 //
266 // Json log object for following interface description
267 //
268 // package foo.bar;
269 // interface IFoo {
270 // String TestMethod(int arg1, inout String[] arg2, out double arg3);
271 // }
272 //
273 // would be:
274 //
275 // {
276 // duration_ms: 100.42,
277 // interface_name: "foo.bar.IFoo",
278 // method_name: "TestMethod",
279 // (proxy|stub)_address: "0x12345678",
280 // input_args: [
281 // {name: "arg1", value: 30,},
282 // {name: "arg2", value: ["apple", "grape"],},
283 // ],
284 // output_args: [
285 // {name: "arg2", value: ["mango", "banana"],},
286 // {name: "arg3", value: "10.5",},
287 // ],
288 // _aidl_return: "ok",
289 // binder_status: {
290 // exception_code: -8,
291 // exception_message: "Something wrong",
292 // transaction_error: 0,
293 // service_specific_error_code: -42,
294 // },
295 // }
296 (*writer) << "auto _log_end = std::chrono::steady_clock::now();\n";
297 (*writer) << "Json::Value _log_transaction(Json::objectValue);\n";
298 (*writer) << "_log_transaction[\"duration_ms\"] = "
299 << "std::chrono::duration<double, std::milli>(_log_end - "
300 "_log_start).count();\n";
301 (*writer) << "_log_transaction[\"interface_name\"] = "
302 << "Json::Value(\"" << interface.GetCanonicalName() << "\");\n";
303 (*writer) << "_log_transaction[\"method_name\"] = "
304 << "Json::Value(\"" << method.GetName() << "\");\n";
305
306 (*writer) << "_log_transaction[\"" << (isServer ? "stub_address" : "proxy_address") << "\"] = ";
307 (*writer) << "Json::Value("
308 << "(std::ostringstream() << "
309 << (isNdk && isServer ? "_aidl_impl" : "static_cast<const void*>(this)") << ").str()"
310 << ");\n";
311 (*writer) << "_log_transaction[\"input_args\"] = _log_input_args;\n";
312 (*writer) << "Json::Value _log_output_args(Json::arrayValue);\n";
313
314 (*writer) << "Json::Value _log_status(Json::objectValue);\n";
315 if (isNdk) {
316 (*writer) << "_log_status[\"exception_code\"] = Json::Value(AStatus_getExceptionCode("
317 << statusVarName << ".get()));\n";
318 (*writer) << "_log_status[\"exception_message\"] = Json::Value(AStatus_getMessage("
319 << statusVarName << ".get()));\n";
320 (*writer) << "_log_status[\"transaction_error\"] = Json::Value(AStatus_getStatus("
321 << statusVarName << ".get()));\n";
Jeongik Chaeaf978e2019-05-04 00:32:35 +0900322 (*writer) << "_log_status[\"service_specific_error_code\"] = "
323 "Json::Value(AStatus_getServiceSpecificError("
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900324 << statusVarName << ".get()));\n";
325 } else {
326 (*writer) << "_log_status[\"exception_code\"] = Json::Value(" << statusVarName
327 << ".exceptionCode());\n";
328 (*writer) << "_log_status[\"exception_message\"] = Json::Value(" << statusVarName
329 << ".exceptionMessage());\n";
330 (*writer) << "_log_status[\"transaction_error\"] = Json::Value(" << statusVarName
331 << ".transactionError());\n";
332 (*writer) << "_log_status[\"service_specific_error_code\"] = Json::Value(" << statusVarName
333 << ".serviceSpecificErrorCode());\n";
334 }
335
336 (*writer) << "_log_transaction[\"binder_status\"] = _log_status;\n";
337
338 for (const auto& a : method.GetOutArguments()) {
339 WriteLogForArguments(writer, *a, isServer, "_log_output_args", isNdk);
340 }
341
342 (*writer) << "_log_transaction[\"output_args\"] = _log_output_args;\n";
343
344 if (method.GetType().GetName() != "void") {
345 WriteLogFor(*(writer.get()), method.GetType(), returnVarName, !isServer,
346 "_log_transaction[\"" + returnVarName + "\"]", isNdk);
347 }
348
349 // call the user-provided function with the Json object for the entire
350 // transaction
351 (*writer) << className << "::logFunc(_log_transaction);\n";
352
353 (*writer).Dedent();
354 (*writer) << "}\n";
355
356 writer->Close();
357 return code;
358}
359
Jooyung Han7a9aceb2019-12-17 14:18:15 +0000360std::string GenerateEnumValues(const AidlEnumDeclaration& enum_decl,
361 const std::vector<std::string>& enclosing_namespaces_of_enum_decl) {
362 const auto fq_name =
363 Join(Append(enclosing_namespaces_of_enum_decl, enum_decl.GetSplitPackage()), "::") +
364 "::" + enum_decl.GetName();
365 const auto size = enum_decl.GetEnumerators().size();
366 std::ostringstream code;
Jooyung Han0e2a03c2019-12-17 23:25:39 +0900367 code << "#pragma clang diagnostic push\n";
368 code << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
Jooyung Han7a9aceb2019-12-17 14:18:15 +0000369 code << "template <>\n";
370 code << "constexpr inline std::array<" << fq_name << ", " << size << "> enum_values<" << fq_name
371 << "> = {\n";
372 for (const auto& enumerator : enum_decl.GetEnumerators()) {
373 code << " " << fq_name << "::" << enumerator->GetName() << ",\n";
374 }
375 code << "};\n";
Jooyung Han0e2a03c2019-12-17 23:25:39 +0900376 code << "#pragma clang diagnostic pop\n";
Jooyung Han7a9aceb2019-12-17 14:18:15 +0000377 return code.str();
378}
379
Devin Moore53fc99c2020-08-12 08:07:52 -0700380std::string TemplateDecl(const AidlStructuredParcelable& defined_type) {
381 std::string decl = "";
382 if (defined_type.IsGeneric()) {
383 std::vector<std::string> template_params;
384 for (const auto& parameter : defined_type.GetTypeParameters()) {
385 template_params.push_back(parameter);
386 }
387 decl = base::StringPrintf("template <typename %s>\n",
388 base::Join(template_params, ", typename ").c_str());
389 }
390 return decl;
391}
392
Steven Morelandb0057e72018-08-27 01:44:11 -0700393} // namespace cpp
394} // namespace aidl
395} // namespace android