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