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 "VtsCompilerUtils.h" 19 #include "utils/InterfaceSpecUtil.h" 20 #include "utils/StringUtil.h" 21 22 namespace android { 23 namespace vts { 24 25 void HalHidlProfilerCodeGen::GenerateProfilerForScalarVariable( 26 Formatter& out, const VariableSpecificationMessage& val, 27 const std::string& arg_name, 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 33 void HalHidlProfilerCodeGen::GenerateProfilerForStringVariable( 34 Formatter& out, const VariableSpecificationMessage&, 35 const std::string& arg_name, const std::string& arg_value) { 36 out << arg_name << "->set_type(TYPE_STRING);\n"; 37 out << arg_name << "->mutable_string_value()->set_message" 38 << "(" << arg_value << ".c_str());\n"; 39 out << arg_name << "->mutable_string_value()->set_length" 40 << "(" << arg_value << ".size());\n"; 41 } 42 43 void HalHidlProfilerCodeGen::GenerateProfilerForEnumVariable( 44 Formatter& out, const VariableSpecificationMessage& val, 45 const std::string& arg_name, 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 62 void HalHidlProfilerCodeGen::GenerateProfilerForVectorVariable( 63 Formatter& out, const VariableSpecificationMessage& val, 64 const std::string& arg_name, 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 71 << " __attribute__((__unused__)) = " << arg_name 72 << "->add_vector_value();\n"; 73 GenerateProfilerForTypedVariable(out, val.vector_value(0), 74 vector_element_name, arg_value + "[i]"); 75 out.unindent(); 76 out << "}\n"; 77 } 78 79 void HalHidlProfilerCodeGen::GenerateProfilerForArrayVariable( 80 Formatter& out, const VariableSpecificationMessage& val, 81 const std::string& arg_name, const std::string& arg_value) { 82 out << arg_name << "->set_type(TYPE_ARRAY);\n"; 83 out << arg_name << "->set_vector_size(" << val.vector_size() << ");\n"; 84 out << "for (int i = 0; i < " << val.vector_size() << "; i++) {\n"; 85 out.indent(); 86 std::string array_element_name = arg_name + "_array_i"; 87 out << "auto *" << array_element_name 88 << " __attribute__((__unused__)) = " << arg_name 89 << "->add_vector_value();\n"; 90 GenerateProfilerForTypedVariable(out, val.vector_value(0), array_element_name, 91 arg_value + "[i]"); 92 out.unindent(); 93 out << "}\n"; 94 } 95 96 void HalHidlProfilerCodeGen::GenerateProfilerForStructVariable( 97 Formatter& out, const VariableSpecificationMessage& val, 98 const std::string& arg_name, const std::string& arg_value) { 99 out << arg_name << "->set_type(TYPE_STRUCT);\n"; 100 // For predefined type, call the corresponding profile method. 101 if (val.struct_value().size() == 0 && val.has_predefined_type()) { 102 std::string predefined_type = val.predefined_type(); 103 ReplaceSubString(predefined_type, "::", "__"); 104 out << "profile__" << predefined_type << "(" << arg_name << ", " 105 << arg_value << ");\n"; 106 } else { 107 for (const auto struct_field : val.struct_value()) { 108 std::string struct_field_name = arg_name + "_" + struct_field.name(); 109 out << "auto *" << struct_field_name 110 << " __attribute__((__unused__)) = " << arg_name 111 << "->add_struct_value();\n"; 112 GenerateProfilerForTypedVariable(out, struct_field, struct_field_name, 113 arg_value + "." + struct_field.name()); 114 } 115 } 116 } 117 118 void HalHidlProfilerCodeGen::GenerateProfilerForUnionVariable( 119 Formatter& out, const VariableSpecificationMessage& val, 120 const std::string& arg_name, const std::string& arg_value) { 121 out << arg_name << "->set_type(TYPE_UNION);\n"; 122 // For predefined type, call the corresponding profile method. 123 if (val.union_value().size() == 0 && val.has_predefined_type()) { 124 std::string predefined_type = val.predefined_type(); 125 ReplaceSubString(predefined_type, "::", "__"); 126 out << "profile__" << predefined_type << "(" << arg_name << ", " 127 << arg_value << ");\n"; 128 } else { 129 for (const auto union_field : val.union_value()) { 130 std::string union_field_name = arg_name + "_" + union_field.name(); 131 out << "auto *" << union_field_name << " = " << arg_name 132 << "->add_union_value();\n"; 133 GenerateProfilerForTypedVariable(out, union_field, union_field_name, 134 arg_value + "." + union_field.name()); 135 } 136 } 137 } 138 139 void HalHidlProfilerCodeGen::GenerateProfilerForHidlCallbackVariable( 140 Formatter& out, const VariableSpecificationMessage& val, 141 const std::string& arg_name, const std::string&) { 142 out << arg_name << "->set_type(TYPE_HIDL_CALLBACK);\n"; 143 out << arg_name << "->set_predefined_type(\"" << val.predefined_type() 144 << "\");\n"; 145 } 146 147 void HalHidlProfilerCodeGen::GenerateProfilerForHidlInterfaceVariable( 148 Formatter& out, const VariableSpecificationMessage& val, 149 const std::string& arg_name, const std::string&) { 150 out << arg_name << "->set_type(TYPE_HIDL_INTERFACE);\n"; 151 out << arg_name << "->set_predefined_type(\"" << val.predefined_type() 152 << "\");\n"; 153 } 154 155 void HalHidlProfilerCodeGen::GenerateProfilerForMaskVariable( 156 Formatter& out, const VariableSpecificationMessage& val, 157 const std::string& arg_name, const std::string& arg_value) { 158 out << arg_name << "->set_type(TYPE_MASK);\n"; 159 out << arg_name << "->set_scalar_type(\"" << val.scalar_type() << "\");\n"; 160 out << arg_name << "->mutable_scalar_value()->set_" << val.scalar_type() 161 << "(" << arg_value << ");\n"; 162 } 163 164 void HalHidlProfilerCodeGen::GenerateProfilerForHandleVariable( 165 Formatter& out, const VariableSpecificationMessage&, 166 const std::string& arg_name, const std::string& arg_value) { 167 out << arg_name << "->set_type(TYPE_HANDLE);\n"; 168 std::string handle_name = arg_name + "_h"; 169 out << "auto " << handle_name << " = " << arg_value 170 << ".getNativeHandle();\n"; 171 out << "if (!" << handle_name << ") {\n"; 172 out.indent(); 173 out << "LOG(WARNING) << \"null handle\";\n"; 174 out << "return;\n"; 175 out.unindent(); 176 out << "}\n"; 177 out << arg_name << "->mutable_handle_value()->set_version(" << handle_name 178 << "->version);\n"; 179 out << arg_name << "->mutable_handle_value()->set_num_ints(" << handle_name 180 << "->numInts);\n"; 181 out << arg_name << "->mutable_handle_value()->set_num_fds(" << handle_name 182 << "->numFds);\n"; 183 out << "for (int i = 0; i < " << handle_name << "->numInts + " << handle_name 184 << "->numFds; i++) {\n"; 185 out.indent(); 186 out << "if(i < " << handle_name << "->numFds) {\n"; 187 out.indent(); 188 out << "auto* fd_val_i = " << arg_name 189 << "->mutable_handle_value()->add_fd_val();\n"; 190 out << "char filePath[PATH_MAX];\n"; 191 out << "string procPath = \"/proc/self/fd/\" + to_string(" << handle_name 192 << "->data[i]);\n"; 193 out << "ssize_t r = readlink(procPath.c_str(), filePath, " 194 "sizeof(filePath));\n"; 195 out << "if (r == -1) {\n"; 196 out.indent(); 197 out << "LOG(ERROR) << \"Unable to get file path\";\n"; 198 out << "continue;\n"; 199 out.unindent(); 200 out << "}\n"; 201 out << "filePath[r] = '\\0';\n"; 202 out << "fd_val_i->set_file_name(filePath);\n"; 203 out << "struct stat statbuf;\n"; 204 out << "fstat(" << handle_name << "->data[i], &statbuf);\n"; 205 out << "fd_val_i->set_mode(statbuf.st_mode);\n"; 206 out << "if(S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode)){\n"; 207 out.indent(); 208 out << "fd_val_i->set_type(S_ISREG(statbuf.st_mode)? FILE_TYPE: DIR_TYPE);\n"; 209 out << "int flags = fcntl(" << handle_name << "->data[i], F_GETFL);\n"; 210 out << "fd_val_i->set_flags(flags);\n"; 211 out.unindent(); 212 out << "}\n"; 213 out << "else if(S_ISCHR(statbuf.st_mode) || S_ISBLK(statbuf.st_mode)){\n"; 214 out.indent(); 215 out << "fd_val_i->set_type(DEV_TYPE);\n"; 216 out << "if(strcmp(filePath, \"/dev/ashmem\") == 0) {\n"; 217 out.indent(); 218 out << "int size = ashmem_get_size_region(" << handle_name << "->data[i]);\n"; 219 out << "fd_val_i->mutable_memory()->set_size(size);\n"; 220 out.unindent(); 221 out << "}\n"; 222 out.unindent(); 223 out << "}\n"; 224 out << "else if(S_ISFIFO(statbuf.st_mode)){\n"; 225 out.indent(); 226 out << "fd_val_i->set_type(PIPE_TYPE);\n"; 227 out.unindent(); 228 out << "}\n"; 229 out << "else if(S_ISSOCK(statbuf.st_mode)){\n"; 230 out.indent(); 231 out << "fd_val_i->set_type(SOCKET_TYPE);\n"; 232 out.unindent(); 233 out << "}\n"; 234 out << "else {\n"; 235 out.indent(); 236 out << "fd_val_i->set_type(LINK_TYPE);\n"; 237 out.unindent(); 238 out << "}\n"; 239 out.unindent(); 240 out << "} else {\n"; 241 out.indent(); 242 out << arg_name << "->mutable_handle_value()->add_int_val(" << handle_name 243 << "->data[i]);\n"; 244 out.unindent(); 245 out << "}\n"; 246 out.unindent(); 247 out << "}\n"; 248 } 249 250 void HalHidlProfilerCodeGen::GenerateProfilerForHidlMemoryVariable( 251 Formatter& out, const VariableSpecificationMessage&, 252 const std::string& arg_name, const std::string& arg_value) { 253 out << arg_name << "->set_type(TYPE_HIDL_MEMORY);\n"; 254 out << arg_name << "->mutable_hidl_memory_value()->set_size" 255 << "(" << arg_value << ".size());\n"; 256 // TODO(zhuoyao): dump the memory contents as well. 257 } 258 259 void HalHidlProfilerCodeGen::GenerateProfilerForPointerVariable( 260 Formatter& out, const VariableSpecificationMessage&, 261 const std::string& arg_name, const std::string&) { 262 out << arg_name << "->set_type(TYPE_POINTER);\n"; 263 // TODO(zhuoyao): figure the right way to profile pointer type. 264 } 265 266 void HalHidlProfilerCodeGen::GenerateProfilerForFMQSyncVariable( 267 Formatter& out, const VariableSpecificationMessage& val, 268 const std::string& arg_name, const std::string& arg_value) { 269 out << arg_name << "->set_type(TYPE_FMQ_SYNC);\n"; 270 string element_type = GetCppVariableType(val.fmq_value(0), nullptr); 271 std::string queue_name = arg_name + "_q"; 272 std::string temp_result_name = arg_name + "_result"; 273 out << "MessageQueue<" << element_type << ", kSynchronizedReadWrite> " 274 << queue_name << "(" << arg_value << ", false);\n"; 275 out << "for (int i = 0; i < (int)" << queue_name 276 << ".availableToRead(); i++) {\n"; 277 out.indent(); 278 std::string fmq_item_name = arg_name + "_item_i"; 279 out << "auto *" << fmq_item_name << " = " << arg_name 280 << "->add_fmq_value();\n"; 281 out << element_type << " " << temp_result_name << ";\n"; 282 out << queue_name << ".read(&" << temp_result_name << ");\n"; 283 out << queue_name << ".write(&" << temp_result_name << ");\n"; 284 GenerateProfilerForTypedVariable(out, val.fmq_value(0), fmq_item_name, 285 temp_result_name); 286 out.unindent(); 287 out << "}\n"; 288 } 289 290 void HalHidlProfilerCodeGen::GenerateProfilerForFMQUnsyncVariable( 291 Formatter& out, const VariableSpecificationMessage& val, 292 const std::string& arg_name, const std::string& arg_value) { 293 out << arg_name << "->set_type(TYPE_FMQ_UNSYNC);\n"; 294 string element_type = GetCppVariableType(val.fmq_value(0), nullptr); 295 std::string queue_name = arg_name + "_q"; 296 std::string temp_result_name = arg_name + "_result"; 297 out << "MessageQueue<" << element_type << ", kUnsynchronizedWrite> " 298 << queue_name << "(" << arg_value << ");\n"; 299 out << "for (int i = 0; i < (int)" << queue_name 300 << ".availableToRead(); i++) {\n"; 301 out.indent(); 302 std::string fmq_item_name = arg_name + "_item_i"; 303 out << "auto *" << fmq_item_name << " = " << arg_name 304 << "->add_fmq_value();\n"; 305 out << element_type << " " << temp_result_name << ";\n"; 306 out << queue_name << ".read(&" << temp_result_name << ");\n"; 307 GenerateProfilerForTypedVariable(out, val.fmq_value(0), fmq_item_name, 308 temp_result_name); 309 out.unindent(); 310 out << "}\n"; 311 } 312 313 void HalHidlProfilerCodeGen::GenerateProfilerForMethod( 314 Formatter& out, const FunctionSpecificationMessage& method) { 315 out << "FunctionSpecificationMessage msg;\n"; 316 out << "msg.set_name(\"" << method.name() << "\");\n"; 317 out << "if (!args) {\n"; 318 out.indent(); 319 out << "LOG(WARNING) << \"no argument passed\";\n"; 320 out.unindent(); 321 out << "} else {\n"; 322 out.indent(); 323 out << "switch (event) {\n"; 324 out.indent(); 325 // TODO(b/32141398): Support profiling in passthrough mode. 326 out << "case details::HidlInstrumentor::CLIENT_API_ENTRY:\n"; 327 out << "case details::HidlInstrumentor::SERVER_API_ENTRY:\n"; 328 out << "case details::HidlInstrumentor::PASSTHROUGH_ENTRY:\n"; 329 out << "{\n"; 330 out.indent(); 331 ComponentSpecificationMessage message; 332 out << "if ((*args).size() != " << method.arg().size() << ") {\n"; 333 out.indent(); 334 out << "LOG(ERROR) << \"Number of arguments does not match. expect: " 335 << method.arg().size() 336 << ", actual: \" << (*args).size() << \", method name: " << method.name() 337 << ", event type: \" << event;\n"; 338 out << "break;\n"; 339 out.unindent(); 340 out << "}\n"; 341 for (int i = 0; i < method.arg().size(); i++) { 342 const VariableSpecificationMessage arg = method.arg(i); 343 std::string arg_name = "arg_" + std::to_string(i); 344 std::string arg_value = "arg_val_" + std::to_string(i); 345 out << "auto *" << arg_name 346 << " __attribute__((__unused__)) = msg.add_arg();\n"; 347 out << GetCppVariableType(arg, &message) << " *" << arg_value 348 << " __attribute__((__unused__)) = reinterpret_cast<" 349 << GetCppVariableType(arg, &message) << "*> ((*args)[" << i << "]);\n"; 350 GenerateProfilerForTypedVariable(out, arg, arg_name, 351 "(*" + arg_value + ")"); 352 } 353 out << "break;\n"; 354 out.unindent(); 355 out << "}\n"; 356 357 out << "case details::HidlInstrumentor::CLIENT_API_EXIT:\n"; 358 out << "case details::HidlInstrumentor::SERVER_API_EXIT:\n"; 359 out << "case details::HidlInstrumentor::PASSTHROUGH_EXIT:\n"; 360 out << "{\n"; 361 out.indent(); 362 out << "if ((*args).size() != " << method.return_type_hidl().size() 363 << ") {\n"; 364 out.indent(); 365 out << "LOG(ERROR) << \"Number of return values does not match. expect: " 366 << method.return_type_hidl().size() 367 << ", actual: \" << (*args).size() << \", method name: " << method.name() 368 << ", event type: \" << event;\n"; 369 out << "break;\n"; 370 out.unindent(); 371 out << "}\n"; 372 for (int i = 0; i < method.return_type_hidl().size(); i++) { 373 const VariableSpecificationMessage arg = method.return_type_hidl(i); 374 std::string result_name = "result_" + std::to_string(i); 375 std::string result_value = "result_val_" + std::to_string(i); 376 out << "auto *" << result_name 377 << " __attribute__((__unused__)) = msg.add_return_type_hidl();\n"; 378 out << GetCppVariableType(arg, &message) << " *" << result_value 379 << " __attribute__((__unused__)) = reinterpret_cast<" 380 << GetCppVariableType(arg, &message) << "*> ((*args)[" << i << "]);\n"; 381 GenerateProfilerForTypedVariable(out, arg, result_name, 382 "(*" + result_value + ")"); 383 } 384 out << "break;\n"; 385 out.unindent(); 386 out << "}\n"; 387 out << "default:\n"; 388 out << "{\n"; 389 out.indent(); 390 out << "LOG(WARNING) << \"not supported. \";\n"; 391 out << "break;\n"; 392 out.unindent(); 393 out << "}\n"; 394 out.unindent(); 395 out << "}\n"; 396 out.unindent(); 397 out << "}\n"; 398 out << "profiler.AddTraceEvent(event, package, version, interface, msg);\n"; 399 } 400 401 void HalHidlProfilerCodeGen::GenerateHeaderIncludeFiles( 402 Formatter& out, const ComponentSpecificationMessage& message) { 403 // Basic includes. 404 out << "#include <android-base/logging.h>\n"; 405 out << "#include <hidl/HidlSupport.h>\n"; 406 out << "#include <linux/limits.h>\n"; 407 out << "#include <test/vts/proto/ComponentSpecificationMessage.pb.h>\n"; 408 out << "#include \"VtsProfilingInterface.h\"\n"; 409 out << "\n"; 410 411 // Include generated hal classes. 412 out << "#include <" << GetPackagePath(message) << "/" << GetVersion(message) 413 << "/" << GetComponentName(message) << ".h>\n"; 414 415 // Include imported classes. 416 for (const auto& import : message.import()) { 417 FQName import_name = FQName(import); 418 string imported_package_name = import_name.package(); 419 string imported_package_version = import_name.version(); 420 string imported_component_name = import_name.name(); 421 string imported_package_path = imported_package_name; 422 ReplaceSubString(imported_package_path, ".", "/"); 423 out << "#include <" << imported_package_path << "/" 424 << imported_package_version << "/" << imported_component_name 425 << ".h>\n"; 426 if (imported_package_name.find("android.hardware") != std::string::npos) { 427 if (imported_component_name[0] == 'I') { 428 imported_component_name = imported_component_name.substr(1); 429 } 430 out << "#include <" << imported_package_path << "/" 431 << imported_package_version << "/" << imported_component_name 432 << ".vts.h>\n"; 433 } 434 } 435 out << "\n\n"; 436 } 437 438 void HalHidlProfilerCodeGen::GenerateSourceIncludeFiles( 439 Formatter& out, const ComponentSpecificationMessage& message) { 440 // Include the corresponding profiler header file. 441 out << "#include \"" << GetPackagePath(message) << "/" << GetVersion(message) 442 << "/" << GetComponentBaseName(message) << ".vts.h\"\n"; 443 out << "#include <cutils/ashmem.h>\n"; 444 out << "#include <fcntl.h>\n"; 445 out << "#include <fmq/MessageQueue.h>\n"; 446 out << "#include <sys/stat.h>\n"; 447 out << "\n"; 448 } 449 450 void HalHidlProfilerCodeGen::GenerateUsingDeclaration( 451 Formatter& out, const ComponentSpecificationMessage& message) { 452 out << "using namespace "; 453 out << GetPackageNamespaceToken(message) << "::" << GetVersion(message, true) 454 << ";\n"; 455 out << "using namespace android::hardware;\n"; 456 out << "\n"; 457 } 458 459 void HalHidlProfilerCodeGen::GenerateMacros( 460 Formatter& out, const ComponentSpecificationMessage&) { 461 out << "#define TRACEFILEPREFIX \"/data/local/tmp\"\n"; 462 out << "\n"; 463 } 464 465 void HalHidlProfilerCodeGen::GenerateProfilerSanityCheck( 466 Formatter& out, const ComponentSpecificationMessage& message) { 467 out << "if (strcmp(package, \"" << GetPackageName(message) << "\") != 0) {\n"; 468 out.indent(); 469 out << "LOG(WARNING) << \"incorrect package.\";\n"; 470 out << "return;\n"; 471 out.unindent(); 472 out << "}\n"; 473 474 out << "if (strcmp(version, \"" << GetVersion(message) << "\") != 0) {\n"; 475 out.indent(); 476 out << "LOG(WARNING) << \"incorrect version.\";\n"; 477 out << "return;\n"; 478 out.unindent(); 479 out << "}\n"; 480 481 out << "if (strcmp(interface, \"" << GetComponentName(message) 482 << "\") != 0) {\n"; 483 out.indent(); 484 out << "LOG(WARNING) << \"incorrect interface.\";\n"; 485 out << "return;\n"; 486 out.unindent(); 487 out << "}\n"; 488 out << "\n"; 489 } 490 491 void HalHidlProfilerCodeGen::GenerateLocalVariableDefinition( 492 Formatter& out, const ComponentSpecificationMessage&) { 493 // generate the name of file to store the trace. 494 out << "char trace_file[PATH_MAX];\n"; 495 out << "sprintf(trace_file, \"%s/%s_%s\", TRACEFILEPREFIX, package, version);" 496 << "\n"; 497 498 // create and initialize the VTS profiler interface. 499 out << "VtsProfilingInterface& profiler = " 500 << "VtsProfilingInterface::getInstance(trace_file);\n"; 501 out << "profiler.Init();\n"; 502 out << "\n"; 503 } 504 505 } // namespace vts 506 } // namespace android 507