1 /*
2 * Copyright 2016 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 "HalHidlProfilerCodeGen.h"
18 #include "utils/InterfaceSpecUtil.h"
19 #include "utils/StringUtil.h"
20 #include "VtsCompilerUtils.h"
21
22 namespace android {
23 namespace vts {
24
GenerateProfilerForScalarVariable(Formatter & out,const VariableSpecificationMessage & val,const std::string & arg_name,const std::string & arg_value)25 void HalHidlProfilerCodeGen::GenerateProfilerForScalarVariable(Formatter& out,
26 const VariableSpecificationMessage& val, const std::string& arg_name,
27 const std::string& arg_value) {
28 out << arg_name << "->set_type(TYPE_SCALAR);\n";
29 out << arg_name << "->mutable_scalar_value()->set_" << val.scalar_type()
30 << "(" << arg_value << ");\n";
31 }
32
GenerateProfilerForStringVariable(Formatter & out,const VariableSpecificationMessage &,const std::string & arg_name,const std::string & arg_value)33 void HalHidlProfilerCodeGen::GenerateProfilerForStringVariable(Formatter& out,
34 const VariableSpecificationMessage&, const std::string& arg_name,
35 const std::string& arg_value) {
36 out << arg_name << "->set_type(TYPE_STRING);\n";
37 out << arg_name << "->mutable_string_value()->set_message" << "(" << arg_value
38 << ".c_str());\n";
39 out << arg_name << "->mutable_string_value()->set_length" << "(" << arg_value
40 << ".size());\n";
41 }
42
GenerateProfilerForEnumVariable(Formatter & out,const VariableSpecificationMessage & val,const std::string & arg_name,const std::string & arg_value)43 void HalHidlProfilerCodeGen::GenerateProfilerForEnumVariable(Formatter& out,
44 const VariableSpecificationMessage& val, const std::string& arg_name,
45 const std::string& arg_value) {
46 out << arg_name << "->set_type(TYPE_ENUM);\n";
47
48 // For predefined type, call the corresponding profile method.
49 if (val.has_predefined_type()) {
50 std::string predefined_type = val.predefined_type();
51 ReplaceSubString(predefined_type, "::", "__");
52 out << "profile__" << predefined_type << "(" << arg_name << ", "
53 << arg_value << ");\n";
54 } else {
55 const std::string scalar_type = val.enum_value().scalar_type();
56 out << arg_name << "->mutable_scalar_value()->set_" << scalar_type
57 << "(static_cast<" << scalar_type << ">(" << arg_value << "));\n";
58 out << arg_name << "->set_scalar_type(\"" << scalar_type << "\");\n";
59 }
60 }
61
GenerateProfilerForVectorVariable(Formatter & out,const VariableSpecificationMessage & val,const std::string & arg_name,const std::string & arg_value)62 void HalHidlProfilerCodeGen::GenerateProfilerForVectorVariable(Formatter& out,
63 const VariableSpecificationMessage& val, const std::string& arg_name,
64 const std::string& arg_value) {
65 out << arg_name << "->set_type(TYPE_VECTOR);\n";
66 out << arg_name << "->set_vector_size(" << arg_value << ".size());\n";
67 out << "for (int i = 0; i < (int)" << arg_value << ".size(); i++) {\n";
68 out.indent();
69 std::string vector_element_name = arg_name + "_vector_i";
70 out << "auto *" << vector_element_name << " = " << arg_name
71 << "->add_vector_value();\n";
72 GenerateProfilerForTypedVariable(out, val.vector_value(0),
73 vector_element_name, arg_value + "[i]");
74 out.unindent();
75 out << "}\n";
76 }
77
GenerateProfilerForArrayVariable(Formatter & out,const VariableSpecificationMessage & val,const std::string & arg_name,const std::string & arg_value)78 void HalHidlProfilerCodeGen::GenerateProfilerForArrayVariable(Formatter& out,
79 const VariableSpecificationMessage& val, const std::string& arg_name,
80 const std::string& arg_value) {
81 out << arg_name << "->set_type(TYPE_ARRAY);\n";
82 out << arg_name << "->set_vector_size(" << val.vector_size() << ");\n";
83 out << "for (int i = 0; i < " << val.vector_size() << "; i++) {\n";
84 out.indent();
85 std::string array_element_name = arg_name + "_array_i";
86 out << "auto *" << array_element_name << " = " << arg_name
87 << "->add_vector_value();\n";
88 GenerateProfilerForTypedVariable(out, val.vector_value(0), array_element_name,
89 arg_value + "[i]");
90 out.unindent();
91 out << "}\n";
92 }
93
GenerateProfilerForStructVariable(Formatter & out,const VariableSpecificationMessage & val,const std::string & arg_name,const std::string & arg_value)94 void HalHidlProfilerCodeGen::GenerateProfilerForStructVariable(Formatter& out,
95 const VariableSpecificationMessage& val, const std::string& arg_name,
96 const std::string& arg_value) {
97 out << arg_name << "->set_type(TYPE_STRUCT);\n";
98 // For predefined type, call the corresponding profile method.
99 if (val.struct_value().size() == 0 && val.has_predefined_type()) {
100 std::string predefined_type = val.predefined_type();
101 ReplaceSubString(predefined_type, "::", "__");
102 out << "profile__" << predefined_type << "(" << arg_name << ", "
103 << arg_value << ");\n";
104 } else {
105 for (const auto struct_field : val.struct_value()) {
106 std::string struct_field_name = arg_name + "_" + struct_field.name();
107 out << "auto *" << struct_field_name << " = " << arg_name
108 << "->add_struct_value();\n";
109 GenerateProfilerForTypedVariable(out, struct_field, struct_field_name,
110 arg_value + "." + struct_field.name());
111 }
112 }
113 }
114
GenerateProfilerForUnionVariable(Formatter & out,const VariableSpecificationMessage & val,const std::string & arg_name,const std::string & arg_value)115 void HalHidlProfilerCodeGen::GenerateProfilerForUnionVariable(Formatter& out,
116 const VariableSpecificationMessage& val, const std::string& arg_name,
117 const std::string& arg_value) {
118 out << arg_name << "->set_type(TYPE_UNION);\n";
119 // For predefined type, call the corresponding profile method.
120 if (val.union_value().size() == 0 && val.has_predefined_type()) {
121 std::string predefined_type = val.predefined_type();
122 ReplaceSubString(predefined_type, "::", "__");
123 out << "profile__" << predefined_type << "(" << arg_name << ", "
124 << arg_value << ");\n";
125 } else {
126 for (const auto union_field : val.union_value()) {
127 std::string union_field_name = arg_name + "_" + union_field.name();
128 out << "auto *" << union_field_name << " = " << arg_name
129 << "->add_union_value();\n";
130 GenerateProfilerForTypedVariable(out, union_field, union_field_name,
131 arg_value + "." + union_field.name());
132 }
133 }
134 }
135
GenerateProfilerForHidlCallbackVariable(Formatter & out,const VariableSpecificationMessage &,const std::string & arg_name,const std::string &)136 void HalHidlProfilerCodeGen::GenerateProfilerForHidlCallbackVariable(
137 Formatter& out, const VariableSpecificationMessage&,
138 const std::string& arg_name, const std::string&) {
139 out << arg_name << "->set_type(TYPE_HIDL_CALLBACK);\n";
140 // TODO(zhuoyao): figure the right way to profile hidl callback type.
141 }
142
GenerateProfilerForHidlInterfaceVariable(Formatter & out,const VariableSpecificationMessage &,const std::string & arg_name,const std::string &)143 void HalHidlProfilerCodeGen::GenerateProfilerForHidlInterfaceVariable(
144 Formatter& out, const VariableSpecificationMessage&,
145 const std::string& arg_name, const std::string&) {
146 out << arg_name << "->set_type(TYPE_HIDL_INTERFACE);\n";
147 // TODO(zhuoyao): figure the right way to profile hidl interface type.
148 }
149
GenerateProfilerForMaskVariable(Formatter & out,const VariableSpecificationMessage &,const std::string & arg_name,const std::string &)150 void HalHidlProfilerCodeGen::GenerateProfilerForMaskVariable(Formatter& out,
151 const VariableSpecificationMessage&, const std::string& arg_name,
152 const std::string&) {
153 out << arg_name << "->set_type(TYPE_MASK);\n";
154 // TODO(zhuoyao): figure the right way to profile mask type.
155 }
156
GenerateProfilerForHidlMemoryVariable(Formatter & out,const VariableSpecificationMessage &,const std::string & arg_name,const std::string &)157 void HalHidlProfilerCodeGen::GenerateProfilerForHidlMemoryVariable(
158 Formatter& out, const VariableSpecificationMessage&,
159 const std::string& arg_name, const std::string&) {
160 out << arg_name << "->set_type(TYPE_HIDL_MEMORY);\n";
161 // TODO(zhuoyao): figure the right way to profile hidl memory type.
162 }
163
GenerateProfilerForPointerVariable(Formatter & out,const VariableSpecificationMessage &,const std::string & arg_name,const std::string &)164 void HalHidlProfilerCodeGen::GenerateProfilerForPointerVariable(Formatter& out,
165 const VariableSpecificationMessage&, const std::string& arg_name,
166 const std::string&) {
167 out << arg_name << "->set_type(TYPE_POINTER);\n";
168 // TODO(zhuoyao): figure the right way to profile pointer type.
169 }
170
GenerateProfilerForFMQSyncVariable(Formatter & out,const VariableSpecificationMessage &,const std::string & arg_name,const std::string &)171 void HalHidlProfilerCodeGen::GenerateProfilerForFMQSyncVariable(Formatter& out,
172 const VariableSpecificationMessage&, const std::string& arg_name,
173 const std::string&) {
174 out << arg_name << "->set_type(TYPE_FMQ_SYNC);\n";
175 // TODO(zhuoyao): figure the right way to profile fmq sync type.
176 }
177
GenerateProfilerForFMQUnsyncVariable(Formatter & out,const VariableSpecificationMessage &,const std::string & arg_name,const std::string &)178 void HalHidlProfilerCodeGen::GenerateProfilerForFMQUnsyncVariable(
179 Formatter& out, const VariableSpecificationMessage&,
180 const std::string& arg_name, const std::string&) {
181 out << arg_name << "->set_type(TYPE_FMQ_UNSYNC);\n";
182 // TODO(zhuoyao): figure the right way to profile fmq unsync type.
183 }
184
GenerateProfilerForMethod(Formatter & out,const FunctionSpecificationMessage & method)185 void HalHidlProfilerCodeGen::GenerateProfilerForMethod(Formatter& out,
186 const FunctionSpecificationMessage& method) {
187 out << "FunctionSpecificationMessage msg;\n";
188 out << "msg.set_name(\"" << method.name() << "\");\n";
189 out << "if (!args) {\n";
190 out.indent();
191 out << "LOG(WARNING) << \"no argument passed\";\n";
192 out.unindent();
193 out << "} else {\n";
194 out.indent();
195 out << "switch (event) {\n";
196 out.indent();
197 // TODO(b/32141398): Support profiling in passthrough mode.
198 out << "case details::HidlInstrumentor::CLIENT_API_ENTRY:\n";
199 out << "case details::HidlInstrumentor::SERVER_API_ENTRY:\n";
200 out << "case details::HidlInstrumentor::PASSTHROUGH_ENTRY:\n";
201 out << "{\n";
202 out.indent();
203 ComponentSpecificationMessage message;
204 out << "if ((*args).size() != " << method.arg().size() << ") {\n";
205 out.indent();
206 out << "LOG(ERROR) << \"Number of arguments does not match. expect: "
207 << method.arg().size()
208 << ", actual: \" << (*args).size() << \", method name: "
209 << method.name()
210 << ", event type: \" << event;\n";
211 out << "break;\n";
212 out.unindent();
213 out << "}\n";
214 for (int i = 0; i < method.arg().size(); i++) {
215 const VariableSpecificationMessage arg = method.arg(i);
216 std::string arg_name = "arg_" + std::to_string(i);
217 std::string arg_value = "arg_val_" + std::to_string(i);
218 out << "auto *" << arg_name << " = msg.add_arg();\n";
219 // TODO(zhuoyao): GetCppVariableType does not support array type for now.
220 out << GetCppVariableType(arg, &message) << " *" << arg_value
221 << " = reinterpret_cast<" << GetCppVariableType(arg, &message)
222 << "*> ((*args)[" << i << "]);\n";
223 GenerateProfilerForTypedVariable(out, arg, arg_name,
224 "(*" + arg_value + ")");
225 }
226 out << "break;\n";
227 out.unindent();
228 out << "}\n";
229
230 // TODO(b/32141398): Support profiling in passthrough mode.
231 out << "case details::HidlInstrumentor::CLIENT_API_EXIT:\n";
232 out << "case details::HidlInstrumentor::SERVER_API_EXIT:\n";
233 out << "case details::HidlInstrumentor::PASSTHROUGH_EXIT:\n";
234 out << "{\n";
235 out.indent();
236 out << "if ((*args).size() != " << method.return_type_hidl().size() << ") {\n";
237 out.indent();
238 out << "LOG(ERROR) << \"Number of return values does not match. expect: "
239 << method.return_type_hidl().size()
240 << ", actual: \" << (*args).size() << \", method name: "
241 << method.name()
242 << ", event type: \" << event;\n";
243 out << "break;\n";
244 out.unindent();
245 out << "}\n";
246 for (int i = 0; i < method.return_type_hidl().size(); i++) {
247 const VariableSpecificationMessage arg = method.return_type_hidl(i);
248 std::string result_name = "result_" + std::to_string(i);
249 std::string result_value = "result_val_" + std::to_string(i);
250 out << "auto *" << result_name << " = msg.add_return_type_hidl();\n";
251 out << GetCppVariableType(arg, &message) << " *" << result_value
252 << " = reinterpret_cast<" << GetCppVariableType(arg, &message)
253 << "*> ((*args)[" << i << "]);\n";
254 GenerateProfilerForTypedVariable(out, arg, result_name,
255 "(*" + result_value + ")");
256 }
257 out << "break;\n";
258 out.unindent();
259 out << "}\n";
260 out << "default:\n";
261 out << "{\n";
262 out.indent();
263 out << "LOG(WARNING) << \"not supported. \";\n";
264 out << "break;\n";
265 out.unindent();
266 out << "}\n";
267 out.unindent();
268 out << "}\n";
269 out.unindent();
270 out << "}\n";
271 out << "profiler.AddTraceEvent(event, package, version, interface, msg);\n";
272 }
273
GenerateHeaderIncludeFiles(Formatter & out,const ComponentSpecificationMessage & message)274 void HalHidlProfilerCodeGen::GenerateHeaderIncludeFiles(Formatter& out,
275 const ComponentSpecificationMessage& message) {
276 // Basic includes.
277 out << "#include <android-base/logging.h>\n";
278 out << "#include <hidl/HidlSupport.h>\n";
279 out << "#include <linux/limits.h>\n";
280 out << "#include <test/vts/proto/ComponentSpecificationMessage.pb.h>\n";
281 out << "#include \"VtsProfilingInterface.h\"\n";
282 out << "\n";
283
284 std::string package_path = GetPackage(message);
285 ReplaceSubString(package_path, ".", "/");
286
287 // Include generated hal classes.
288 out << "#include <" << package_path << "/" << GetPackageVersion(message)
289 << "/" << GetComponentName(message) << ".h>\n";
290
291 // Include imported classes.
292 for (const auto& import : message.import()) {
293 FQName import_name = FQName(import);
294 string imported_package_name = import_name.package();
295 string imported_package_version = import_name.version();
296 string imported_component_name = import_name.name();
297 string imported_package_path = imported_package_name;
298 ReplaceSubString(imported_package_path, ".", "/");
299 out << "#include <" << imported_package_path << "/"
300 << imported_package_version << "/" << imported_component_name
301 << ".h>\n";
302 if (imported_package_name.find("android.hardware") != std::string::npos) {
303 if (imported_component_name[0] == 'I') {
304 imported_component_name = imported_component_name.substr(1);
305 }
306 out << "#include <" << imported_package_path << "/"
307 << imported_package_version << "/" << imported_component_name
308 << ".vts.h>\n";
309 }
310 }
311 out << "\n\n";
312 }
313
GenerateSourceIncludeFiles(Formatter & out,const ComponentSpecificationMessage &)314 void HalHidlProfilerCodeGen::GenerateSourceIncludeFiles(Formatter& out,
315 const ComponentSpecificationMessage& /*message*/) {
316 // Include the corresponding profiler header file.
317 out << "#include \"" << input_vts_file_path_ << ".h\"\n";
318 out << "\n";
319 }
320
GenerateUsingDeclaration(Formatter & out,const ComponentSpecificationMessage & message)321 void HalHidlProfilerCodeGen::GenerateUsingDeclaration(Formatter& out,
322 const ComponentSpecificationMessage& message) {
323 std::string package_path = GetPackage(message);
324 ReplaceSubString(package_path, ".", "::");
325
326 out << "using namespace ";
327 out << package_path << "::"
328 << GetVersionString(message.component_type_version(), true) << ";\n";
329 out << "using namespace android::hardware;\n";
330 out << "\n";
331 }
332
GenerateMacros(Formatter & out,const ComponentSpecificationMessage &)333 void HalHidlProfilerCodeGen::GenerateMacros(Formatter& out,
334 const ComponentSpecificationMessage&) {
335 out << "#define TRACEFILEPREFIX \"/data/local/tmp\"\n";
336 out << "\n";
337 }
338
GenerateProfierSanityCheck(Formatter & out,const ComponentSpecificationMessage & message)339 void HalHidlProfilerCodeGen::GenerateProfierSanityCheck(Formatter& out,
340 const ComponentSpecificationMessage& message) {
341 out << "if (strcmp(package, \"" << GetPackage(message) << "\") != 0) {\n";
342 out.indent();
343 out << "LOG(WARNING) << \"incorrect package.\";\n";
344 out << "return;\n";
345 out.unindent();
346 out << "}\n";
347
348 out << "if (strcmp(version, \"" << GetPackageVersion(message)
349 << "\") != 0) {\n";
350 out.indent();
351 out << "LOG(WARNING) << \"incorrect version.\";\n";
352 out << "return;\n";
353 out.unindent();
354 out << "}\n";
355
356 out << "if (strcmp(interface, \"" << GetComponentName(message)
357 << "\") != 0) {\n";
358 out.indent();
359 out << "LOG(WARNING) << \"incorrect interface.\";\n";
360 out << "return;\n";
361 out.unindent();
362 out << "}\n";
363 out << "\n";
364 }
365
GenerateLocalVariableDefinition(Formatter & out,const ComponentSpecificationMessage &)366 void HalHidlProfilerCodeGen::GenerateLocalVariableDefinition(Formatter& out,
367 const ComponentSpecificationMessage&) {
368 // generate the name of file to store the trace.
369 out << "char trace_file[PATH_MAX];\n";
370 out << "sprintf(trace_file, \"%s/%s_%s\", TRACEFILEPREFIX, package, version);"
371 << "\n";
372
373 // create and initialize the VTS profiler interface.
374 out << "VtsProfilingInterface& profiler = "
375 << "VtsProfilingInterface::getInstance(trace_file);\n";
376 out << "profiler.Init();\n";
377 out << "\n";
378 }
379
380 } // namespace vts
381 } // namespace android
382