1 /*
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 #include "aidl_to_cpp_common.h"
17 
18 #include <android-base/strings.h>
19 #include <unordered_map>
20 
21 #include "ast_cpp.h"
22 #include "logging.h"
23 #include "os.h"
24 
25 using ::android::base::Join;
26 
27 namespace android {
28 namespace aidl {
29 namespace cpp {
30 
ClassName(const AidlDefinedType & defined_type,ClassNames type)31 string ClassName(const AidlDefinedType& defined_type, ClassNames type) {
32   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   }
36 
37   switch (type) {
38     case ClassNames::CLIENT:
39       return "Bp" + base_name;
40     case ClassNames::SERVER:
41       return "Bn" + base_name;
42     case ClassNames::INTERFACE:
43       return "I" + base_name;
44     case ClassNames::DEFAULT_IMPL:
45       return "I" + base_name + "Default";
46     case ClassNames::BASE:
47       return base_name;
48     case ClassNames::RAW:
49       [[fallthrough]];
50     default:
51       return defined_type.GetName();
52   }
53 }
54 
HeaderFile(const AidlDefinedType & defined_type,ClassNames class_type,bool use_os_sep)55 std::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 
EnterNamespace(CodeWriter & out,const AidlDefinedType & defined_type)72 void 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 }
LeaveNamespace(CodeWriter & out,const AidlDefinedType & defined_type)78 void 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 
BuildVarName(const AidlArgument & a)85 string 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 
93 struct 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 
102 const static std::unordered_map<std::string, TypeInfo> kTypeInfoMap = {
103     {"void", {"void", nullptr}},
104     {"boolean",
105      {
106          "bool",
__anon158e6ed30102() 107          [](CodeWriter& c, const string& var_name, bool) {
108            c << "Json::Value(" << var_name << "? \"true\" : \"false\")";
109          },
110      }},
111     {"byte",
112      {
113          "int8_t",
__anon158e6ed30202() 114          [](CodeWriter& c, const string& var_name, bool) {
115            c << "Json::Value(" << var_name << ")";
116          },
117      }},
118     {"char",
119      {
120          "char16_t",
__anon158e6ed30302() 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",
__anon158e6ed30402() 132          [](CodeWriter& c, const string& var_name, bool) {
133            c << "Json::Value(" << var_name << ")";
134          },
135      }},
136     {"long",
137      {
138          "int64_t",
__anon158e6ed30502() 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",
__anon158e6ed30602() 146          [](CodeWriter& c, const string& var_name, bool) {
147            c << "Json::Value(" << var_name << ")";
148          },
149      }},
150     {"double",
151      {
152          "double",
__anon158e6ed30702() 153          [](CodeWriter& c, const string& var_name, bool) {
154            c << "Json::Value(" << var_name << ")";
155          },
156      }},
157     {"String",
158      {
159          "std::string",
__anon158e6ed30802() 160          [](CodeWriter& c, const string& var_name, bool) {
161            c << "Json::Value(" << var_name << ")";
162          },
163      }}
164     // missing List, Map, ParcelFileDescriptor, IBinder
165 };
166 
GetTypeInfo(const AidlTypeSpecifier & aidl)167 TypeInfo 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 
CanWriteLog(const TypeInfo & t)182 inline bool CanWriteLog(const TypeInfo& t) {
183   return t.cpp_name != "";
184 }
185 
CanWriteLog(const AidlTypeSpecifier & aidl)186 bool CanWriteLog(const AidlTypeSpecifier& aidl) {
187   return CanWriteLog(GetTypeInfo(aidl));
188 }
189 
WriteLogFor(CodeWriter & writer,const AidlTypeSpecifier & type,const std::string & name,bool isPointer,const std::string & log,bool isNdk)190 void 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 
WriteLogForArguments(CodeWriterPtr & writer,const AidlArgument & a,bool isServer,string logVarName,bool isNdk)211 void 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 
GenLogBeforeExecute(const string className,const AidlMethod & method,bool isServer,bool isNdk)231 const 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 
GenLogAfterExecute(const string className,const AidlInterface & interface,const AidlMethod & method,const string & statusVarName,const string & returnVarName,bool isServer,bool isNdk)254 const 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";
321     (*writer) << "_log_status[\"service_specific_error_code\"] = "
322                  "Json::Value(AStatus_getServiceSpecificError("
323               << 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 
GenerateEnumValues(const AidlEnumDeclaration & enum_decl,const std::vector<std::string> & enclosing_namespaces_of_enum_decl)359 std::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;
366   code << "#pragma clang diagnostic push\n";
367   code << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
368   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";
375   code << "#pragma clang diagnostic pop\n";
376   return code.str();
377 }
378 
379 }  // namespace cpp
380 }  // namespace aidl
381 }  // namespace android
382