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