blob: a0b93565c75bf52efeeb300d83bbe7e967563717 [file] [log] [blame]
/*
* Copyright 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "HalHidlProfilerCodeGen.h"
#include "utils/InterfaceSpecUtil.h"
#include "utils/StringUtil.h"
#include "VtsCompilerUtils.h"
namespace android {
namespace vts {
void HalHidlProfilerCodeGen::GenerateProfilerForScalarVariable(Formatter& out,
const VariableSpecificationMessage& val, const std::string& arg_name,
const std::string& arg_value) {
out << arg_name << "->set_type(TYPE_SCALAR);\n";
out << arg_name << "->mutable_scalar_value()->set_" << val.scalar_type()
<< "(" << arg_value << ");\n";
}
void HalHidlProfilerCodeGen::GenerateProfilerForStringVariable(Formatter& out,
const VariableSpecificationMessage&, const std::string& arg_name,
const std::string& arg_value) {
out << arg_name << "->set_type(TYPE_STRING);\n";
out << arg_name << "->mutable_string_value()->set_message" << "(" << arg_value
<< ".c_str());\n";
out << arg_name << "->mutable_string_value()->set_length" << "(" << arg_value
<< ".size());\n";
}
void HalHidlProfilerCodeGen::GenerateProfilerForEnumVariable(Formatter& out,
const VariableSpecificationMessage& val, const std::string& arg_name,
const std::string& arg_value) {
out << arg_name << "->set_type(TYPE_ENUM);\n";
// For predefined type, call the corresponding profile method.
if (val.has_predefined_type()) {
std::string predefined_type = val.predefined_type();
ReplaceSubString(predefined_type, "::", "__");
out << "profile__" << predefined_type << "(" << arg_name << ", "
<< arg_value << ");\n";
} else {
const std::string scalar_type = val.enum_value().scalar_type();
out << arg_name << "->mutable_scalar_value()->set_" << scalar_type
<< "(static_cast<" << scalar_type << ">(" << arg_value << "));\n";
out << arg_name << "->set_scalar_type(\"" << scalar_type << "\");\n";
}
}
void HalHidlProfilerCodeGen::GenerateProfilerForVectorVariable(Formatter& out,
const VariableSpecificationMessage& val, const std::string& arg_name,
const std::string& arg_value) {
out << arg_name << "->set_type(TYPE_VECTOR);\n";
out << arg_name << "->set_vector_size(" << arg_value << ".size());\n";
out << "for (int i = 0; i < (int)" << arg_value << ".size(); i++) {\n";
out.indent();
std::string vector_element_name = arg_name + "_vector_i";
out << "auto *" << vector_element_name << " = " << arg_name
<< "->add_vector_value();\n";
GenerateProfilerForTypedVariable(out, val.vector_value(0),
vector_element_name, arg_value + "[i]");
out.unindent();
out << "}\n";
}
void HalHidlProfilerCodeGen::GenerateProfilerForArrayVariable(Formatter& out,
const VariableSpecificationMessage& val, const std::string& arg_name,
const std::string& arg_value) {
out << arg_name << "->set_type(TYPE_ARRAY);\n";
out << arg_name << "->set_vector_size(" << val.vector_size() << ");\n";
out << "for (int i = 0; i < " << val.vector_size() << "; i++) {\n";
out.indent();
std::string array_element_name = arg_name + "_array_i";
out << "auto *" << array_element_name << " = " << arg_name
<< "->add_vector_value();\n";
GenerateProfilerForTypedVariable(out, val.vector_value(0), array_element_name,
arg_value + "[i]");
out.unindent();
out << "}\n";
}
void HalHidlProfilerCodeGen::GenerateProfilerForStructVariable(Formatter& out,
const VariableSpecificationMessage& val, const std::string& arg_name,
const std::string& arg_value) {
out << arg_name << "->set_type(TYPE_STRUCT);\n";
// For predefined type, call the corresponding profile method.
if (val.struct_value().size() == 0 && val.has_predefined_type()) {
std::string predefined_type = val.predefined_type();
ReplaceSubString(predefined_type, "::", "__");
out << "profile__" << predefined_type << "(" << arg_name << ", "
<< arg_value << ");\n";
} else {
for (const auto struct_field : val.struct_value()) {
std::string struct_field_name = arg_name + "_" + struct_field.name();
out << "auto *" << struct_field_name << " = " << arg_name
<< "->add_struct_value();\n";
GenerateProfilerForTypedVariable(out, struct_field, struct_field_name,
arg_value + "." + struct_field.name());
}
}
}
void HalHidlProfilerCodeGen::GenerateProfilerForUnionVariable(Formatter& out,
const VariableSpecificationMessage& val, const std::string& arg_name,
const std::string& arg_value) {
out << arg_name << "->set_type(TYPE_UNION);\n";
// For predefined type, call the corresponding profile method.
if (val.union_value().size() == 0 && val.has_predefined_type()) {
std::string predefined_type = val.predefined_type();
ReplaceSubString(predefined_type, "::", "__");
out << "profile__" << predefined_type << "(" << arg_name << ", "
<< arg_value << ");\n";
} else {
for (const auto union_field : val.union_value()) {
std::string union_field_name = arg_name + "_" + union_field.name();
out << "auto *" << union_field_name << " = " << arg_name
<< "->add_union_value();\n";
GenerateProfilerForTypedVariable(out, union_field, union_field_name,
arg_value + "." + union_field.name());
}
}
}
void HalHidlProfilerCodeGen::GenerateProfilerForHidlCallbackVariable(
Formatter& out, const VariableSpecificationMessage&,
const std::string& arg_name, const std::string&) {
out << arg_name << "->set_type(TYPE_HIDL_CALLBACK);\n";
// TODO(zhuoyao): figure the right way to profile hidl callback type.
}
void HalHidlProfilerCodeGen::GenerateProfilerForHidlInterfaceVariable(
Formatter& out, const VariableSpecificationMessage&,
const std::string& arg_name, const std::string&) {
out << arg_name << "->set_type(TYPE_HIDL_INTERFACE);\n";
// TODO(zhuoyao): figure the right way to profile hidl interface type.
}
void HalHidlProfilerCodeGen::GenerateProfilerForMaskVariable(Formatter& out,
const VariableSpecificationMessage&, const std::string& arg_name,
const std::string&) {
out << arg_name << "->set_type(TYPE_MASK);\n";
// TODO(zhuoyao): figure the right way to profile mask type.
}
void HalHidlProfilerCodeGen::GenerateProfilerForHidlMemoryVariable(
Formatter& out, const VariableSpecificationMessage&,
const std::string& arg_name, const std::string&) {
out << arg_name << "->set_type(TYPE_HIDL_MEMORY);\n";
// TODO(zhuoyao): figure the right way to profile hidl memory type.
}
void HalHidlProfilerCodeGen::GenerateProfilerForPointerVariable(Formatter& out,
const VariableSpecificationMessage&, const std::string& arg_name,
const std::string&) {
out << arg_name << "->set_type(TYPE_POINTER);\n";
// TODO(zhuoyao): figure the right way to profile pointer type.
}
void HalHidlProfilerCodeGen::GenerateProfilerForFMQSyncVariable(Formatter& out,
const VariableSpecificationMessage&, const std::string& arg_name,
const std::string&) {
out << arg_name << "->set_type(TYPE_FMQ_SYNC);\n";
// TODO(zhuoyao): figure the right way to profile fmq sync type.
}
void HalHidlProfilerCodeGen::GenerateProfilerForFMQUnsyncVariable(
Formatter& out, const VariableSpecificationMessage&,
const std::string& arg_name, const std::string&) {
out << arg_name << "->set_type(TYPE_FMQ_UNSYNC);\n";
// TODO(zhuoyao): figure the right way to profile fmq unsync type.
}
void HalHidlProfilerCodeGen::GenerateProfilerForMethod(Formatter& out,
const FunctionSpecificationMessage& method) {
out << "FunctionSpecificationMessage msg;\n";
out << "msg.set_name(\"" << method.name() << "\");\n";
out << "if (!args) {\n";
out.indent();
out << "LOG(WARNING) << \"no argument passed\";\n";
out.unindent();
out << "} else {\n";
out.indent();
out << "switch (event) {\n";
out.indent();
// TODO(b/32141398): Support profiling in passthrough mode.
out << "case details::HidlInstrumentor::CLIENT_API_ENTRY:\n";
out << "case details::HidlInstrumentor::SERVER_API_ENTRY:\n";
out << "case details::HidlInstrumentor::PASSTHROUGH_ENTRY:\n";
out << "{\n";
out.indent();
ComponentSpecificationMessage message;
out << "if ((*args).size() != " << method.arg().size() << ") {\n";
out.indent();
out << "LOG(ERROR) << \"Number of arguments does not match. expect: "
<< method.arg().size()
<< ", actual: \" << (*args).size() << \", method name: "
<< method.name()
<< ", event type: \" << event;\n";
out << "break;\n";
out.unindent();
out << "}\n";
for (int i = 0; i < method.arg().size(); i++) {
const VariableSpecificationMessage arg = method.arg(i);
std::string arg_name = "arg_" + std::to_string(i);
std::string arg_value = "arg_val_" + std::to_string(i);
out << "auto *" << arg_name << " = msg.add_arg();\n";
// TODO(zhuoyao): GetCppVariableType does not support array type for now.
out << GetCppVariableType(arg, &message) << " *" << arg_value
<< " = reinterpret_cast<" << GetCppVariableType(arg, &message)
<< "*> ((*args)[" << i << "]);\n";
GenerateProfilerForTypedVariable(out, arg, arg_name,
"(*" + arg_value + ")");
}
out << "break;\n";
out.unindent();
out << "}\n";
// TODO(b/32141398): Support profiling in passthrough mode.
out << "case details::HidlInstrumentor::CLIENT_API_EXIT:\n";
out << "case details::HidlInstrumentor::SERVER_API_EXIT:\n";
out << "case details::HidlInstrumentor::PASSTHROUGH_EXIT:\n";
out << "{\n";
out.indent();
out << "if ((*args).size() != " << method.return_type_hidl().size() << ") {\n";
out.indent();
out << "LOG(ERROR) << \"Number of return values does not match. expect: "
<< method.return_type_hidl().size()
<< ", actual: \" << (*args).size() << \", method name: "
<< method.name()
<< ", event type: \" << event;\n";
out << "break;\n";
out.unindent();
out << "}\n";
for (int i = 0; i < method.return_type_hidl().size(); i++) {
const VariableSpecificationMessage arg = method.return_type_hidl(i);
std::string result_name = "result_" + std::to_string(i);
std::string result_value = "result_val_" + std::to_string(i);
out << "auto *" << result_name << " = msg.add_return_type_hidl();\n";
out << GetCppVariableType(arg, &message) << " *" << result_value
<< " = reinterpret_cast<" << GetCppVariableType(arg, &message)
<< "*> ((*args)[" << i << "]);\n";
GenerateProfilerForTypedVariable(out, arg, result_name,
"(*" + result_value + ")");
}
out << "break;\n";
out.unindent();
out << "}\n";
out << "default:\n";
out << "{\n";
out.indent();
out << "LOG(WARNING) << \"not supported. \";\n";
out << "break;\n";
out.unindent();
out << "}\n";
out.unindent();
out << "}\n";
out.unindent();
out << "}\n";
out << "profiler.AddTraceEvent(event, package, version, interface, msg);\n";
}
void HalHidlProfilerCodeGen::GenerateHeaderIncludeFiles(Formatter& out,
const ComponentSpecificationMessage& message) {
// Basic includes.
out << "#include <android-base/logging.h>\n";
out << "#include <hidl/HidlSupport.h>\n";
out << "#include <linux/limits.h>\n";
out << "#include <test/vts/proto/ComponentSpecificationMessage.pb.h>\n";
out << "#include \"VtsProfilingInterface.h\"\n";
out << "\n";
std::string package_path = GetPackage(message);
ReplaceSubString(package_path, ".", "/");
// Include generated hal classes.
out << "#include <" << package_path << "/" << GetPackageVersion(message)
<< "/" << GetComponentName(message) << ".h>\n";
// Include imported classes.
for (const auto& import : message.import()) {
FQName import_name = FQName(import);
string imported_package_name = import_name.package();
string imported_package_version = import_name.version();
string imported_component_name = import_name.name();
string imported_package_path = imported_package_name;
ReplaceSubString(imported_package_path, ".", "/");
out << "#include <" << imported_package_path << "/"
<< imported_package_version << "/" << imported_component_name
<< ".h>\n";
if (imported_package_name.find("android.hardware") != std::string::npos) {
if (imported_component_name[0] == 'I') {
imported_component_name = imported_component_name.substr(1);
}
out << "#include <" << imported_package_path << "/"
<< imported_package_version << "/" << imported_component_name
<< ".vts.h>\n";
}
}
out << "\n\n";
}
void HalHidlProfilerCodeGen::GenerateSourceIncludeFiles(Formatter& out,
const ComponentSpecificationMessage& /*message*/) {
// Include the corresponding profiler header file.
out << "#include \"" << input_vts_file_path_ << ".h\"\n";
out << "\n";
}
void HalHidlProfilerCodeGen::GenerateUsingDeclaration(Formatter& out,
const ComponentSpecificationMessage& message) {
std::string package_path = GetPackage(message);
ReplaceSubString(package_path, ".", "::");
out << "using namespace ";
out << package_path << "::"
<< GetVersionString(message.component_type_version(), true) << ";\n";
out << "using namespace android::hardware;\n";
out << "\n";
}
void HalHidlProfilerCodeGen::GenerateMacros(Formatter& out,
const ComponentSpecificationMessage&) {
out << "#define TRACEFILEPREFIX \"/data/local/tmp\"\n";
out << "\n";
}
void HalHidlProfilerCodeGen::GenerateProfierSanityCheck(Formatter& out,
const ComponentSpecificationMessage& message) {
out << "if (strcmp(package, \"" << GetPackage(message) << "\") != 0) {\n";
out.indent();
out << "LOG(WARNING) << \"incorrect package.\";\n";
out << "return;\n";
out.unindent();
out << "}\n";
out << "if (strcmp(version, \"" << GetPackageVersion(message)
<< "\") != 0) {\n";
out.indent();
out << "LOG(WARNING) << \"incorrect version.\";\n";
out << "return;\n";
out.unindent();
out << "}\n";
out << "if (strcmp(interface, \"" << GetComponentName(message)
<< "\") != 0) {\n";
out.indent();
out << "LOG(WARNING) << \"incorrect interface.\";\n";
out << "return;\n";
out.unindent();
out << "}\n";
out << "\n";
}
void HalHidlProfilerCodeGen::GenerateLocalVariableDefinition(Formatter& out,
const ComponentSpecificationMessage&) {
// generate the name of file to store the trace.
out << "char trace_file[PATH_MAX];\n";
out << "sprintf(trace_file, \"%s/%s_%s\", TRACEFILEPREFIX, package, version);"
<< "\n";
// create and initialize the VTS profiler interface.
out << "VtsProfilingInterface& profiler = "
<< "VtsProfilingInterface::getInstance(trace_file);\n";
out << "profiler.Init();\n";
out << "\n";
}
} // namespace vts
} // namespace android