• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 #include <unordered_map>
18 
19 #include "aidl_to_cpp_common.h"
20 #include "logging.h"
21 #include "os.h"
22 
23 namespace android {
24 namespace aidl {
25 namespace cpp {
26 
ClassName(const AidlDefinedType & defined_type,ClassNames type)27 string ClassName(const AidlDefinedType& defined_type, ClassNames type) {
28   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   }
32 
33   switch (type) {
34     case ClassNames::CLIENT:
35       return "Bp" + base_name;
36     case ClassNames::SERVER:
37       return "Bn" + base_name;
38     case ClassNames::INTERFACE:
39       return "I" + base_name;
40     case ClassNames::DEFAULT_IMPL:
41       return "I" + base_name + "Default";
42     case ClassNames::BASE:
43       return base_name;
44     case ClassNames::RAW:
45       [[fallthrough]];
46     default:
47       return defined_type.GetName();
48   }
49 }
50 
HeaderFile(const AidlDefinedType & defined_type,ClassNames class_type,bool use_os_sep)51 std::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 
EnterNamespace(CodeWriter & out,const AidlDefinedType & defined_type)68 void 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 }
LeaveNamespace(CodeWriter & out,const AidlDefinedType & defined_type)74 void 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 
BuildVarName(const AidlArgument & a)81 string 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 
89 struct 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 
98 const static std::unordered_map<std::string, TypeInfo> kTypeInfoMap = {
99     {"void", {"void", nullptr}},
100     {"boolean",
101      {
102          "bool",
__anonc907a31c0102() 103          [](CodeWriter& c, const string& var_name, bool) {
104            c << "Json::Value(" << var_name << "? \"true\" : \"false\")";
105          },
106      }},
107     {"byte",
108      {
109          "int8_t",
__anonc907a31c0202() 110          [](CodeWriter& c, const string& var_name, bool) {
111            c << "Json::Value(" << var_name << ")";
112          },
113      }},
114     {"char",
115      {
116          "char16_t",
__anonc907a31c0302() 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",
__anonc907a31c0402() 128          [](CodeWriter& c, const string& var_name, bool) {
129            c << "Json::Value(" << var_name << ")";
130          },
131      }},
132     {"long",
133      {
134          "int64_t",
__anonc907a31c0502() 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",
__anonc907a31c0602() 142          [](CodeWriter& c, const string& var_name, bool) {
143            c << "Json::Value(" << var_name << ")";
144          },
145      }},
146     {"double",
147      {
148          "double",
__anonc907a31c0702() 149          [](CodeWriter& c, const string& var_name, bool) {
150            c << "Json::Value(" << var_name << ")";
151          },
152      }},
153     {"String",
154      {
155          "std::string",
__anonc907a31c0802() 156          [](CodeWriter& c, const string& var_name, bool) {
157            c << "Json::Value(" << var_name << ")";
158          },
159      }}
160     // missing List, Map, ParcelFileDescriptor, IBinder
161 };
162 
GetTypeInfo(const AidlTypeSpecifier & aidl)163 TypeInfo 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 
CanWriteLog(const TypeInfo & t)178 inline bool CanWriteLog(const TypeInfo& t) {
179   return t.cpp_name != "";
180 }
181 
CanWriteLog(const AidlTypeSpecifier & aidl)182 bool CanWriteLog(const AidlTypeSpecifier& aidl) {
183   return CanWriteLog(GetTypeInfo(aidl));
184 }
185 
WriteLogFor(CodeWriter & writer,const AidlTypeSpecifier & type,const std::string & name,bool isPointer,const std::string & log,bool isNdk)186 void 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 
WriteLogForArguments(CodeWriterPtr & writer,const AidlArgument & a,bool isServer,string logVarName,bool isNdk)207 void 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 
GenLogBeforeExecute(const string className,const AidlMethod & method,bool isServer,bool isNdk)227 const 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 
GenLogAfterExecute(const string className,const AidlInterface & interface,const AidlMethod & method,const string & statusVarName,const string & returnVarName,bool isServer,bool isNdk)250 const 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";
317     (*writer) << "_log_status[\"service_specific_error_code\"] = "
318                  "Json::Value(AStatus_getServiceSpecificError("
319               << 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 
355 }  // namespace cpp
356 }  // namespace aidl
357 }  // namespace android
358