/* * 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 "code_gen/driver/HalHidlCodeGen.h" #include #include #include "VtsCompilerUtils.h" #include "code_gen/common/HalHidlCodeGenUtils.h" #include "test/vts/proto/ComponentSpecificationMessage.pb.h" #include "utils/InterfaceSpecUtil.h" #include "utils/StringUtil.h" using namespace std; using namespace android; namespace android { namespace vts { const char* const HalHidlCodeGen::kInstanceVariableName = "hw_binder_proxy_"; void HalHidlCodeGen::GenerateCppBodyInterfaceImpl( Formatter& out, const ComponentSpecificationMessage& message, const string& /*fuzzer_extended_class_name*/) { out << "\n"; FQName component_fq_name = GetFQName(message); for (const auto& api : message.interface().api()) { // Generate return statement. if (CanElideCallback(api)) { out << "::android::hardware::Return<" << GetCppVariableType(api.return_type_hidl(0)) << "> "; } else { out << "::android::hardware::Return "; } // Generate function call. string full_method_name = "Vts_" + component_fq_name.tokenName() + "::" + api.name(); out << full_method_name << "(\n"; out.indent(); for (int index = 0; index < api.arg_size(); index++) { const auto& arg = api.arg(index); out << GetCppVariableType(arg, IsConstType(arg.type())) << " arg" << index << " __attribute__((__unused__))"; if (index != (api.arg_size() - 1)) out << ",\n"; } if (api.return_type_hidl_size() == 0 || CanElideCallback(api)) { out << ") {\n"; } else { // handle the case of callbacks. out << (api.arg_size() != 0 ? ", " : ""); out << "std::function cb) {\n"; } out << "LOG(INFO) << \"" << api.name() << " called\";\n"; out << "AndroidSystemCallbackRequestMessage callback_message;\n"; out << "callback_message.set_id(GetCallbackID(\"" << api.name() << "\"));\n"; out << "callback_message.set_name(\"" << full_method_name << "\");\n"; for (int index = 0; index < api.arg_size(); index++) { out << "VariableSpecificationMessage* var_msg" << index << " = " << "callback_message.add_arg();\n"; GenerateSetResultCodeForTypedVariable(out, api.arg(index), "var_msg" + std::to_string(index), "arg" + std::to_string(index)); } out << "RpcCallToAgent(callback_message, callback_socket_name_);\n"; // TODO(zhuoyao): return the received results from host. if (CanElideCallback(api)) { out << "return "; GenerateDefaultReturnValForTypedVariable(out, api.return_type_hidl(0)); out << ";\n"; } else { if (api.return_type_hidl_size() > 0) { out << "cb("; for (int index = 0; index < api.return_type_hidl_size(); index++) { GenerateDefaultReturnValForTypedVariable(out, api.return_type_hidl(index)); if (index != (api.return_type_hidl_size() - 1)) { out << ", "; } } out << ");\n"; } out << "return ::android::hardware::Void();\n"; } out.unindent(); out << "}" << "\n"; out << "\n"; } string component_name_token = "Vts_" + component_fq_name.tokenName(); out << "sp<" << component_fq_name.cppName() << "> VtsFuzzerCreate" << component_name_token << "(const string& callback_socket_name) {\n"; out.indent(); out << "static sp<" << component_fq_name.cppName() << "> result;\n"; out << "result = new " << component_name_token << "(callback_socket_name);\n"; out << "return result;\n"; out.unindent(); out << "}\n\n"; } void HalHidlCodeGen::GenerateScalarTypeInC(Formatter& out, const string& type) { if (type == "bool_t") { out << "bool"; } else if (type == "int8_t" || type == "uint8_t" || type == "int16_t" || type == "uint16_t" || type == "int32_t" || type == "uint32_t" || type == "int64_t" || type == "uint64_t" || type == "size_t") { out << type; } else if (type == "float_t") { out << "float"; } else if (type == "double_t") { out << "double"; } else if (type == "char_pointer") { out << "char*"; } else if (type == "void_pointer") { out << "void*"; } else { cerr << __func__ << ":" << __LINE__ << " unsupported scalar type " << type << "\n"; exit(-1); } } void HalHidlCodeGen::GenerateCppBodyFuzzFunction( Formatter& out, const ComponentSpecificationMessage& /*message*/, const string& fuzzer_extended_class_name) { out << "bool " << fuzzer_extended_class_name << "::Fuzz(" << "\n"; out.indent(); out << "FunctionSpecificationMessage* /*func_msg*/," << "\n"; out << "void** /*result*/, const string& /*callback_socket_name*/) {\n"; out << "return true;\n"; out.unindent(); out << "}\n"; } void HalHidlCodeGen::GenerateDriverFunctionImpl(Formatter& out, const ComponentSpecificationMessage& message, const string& fuzzer_extended_class_name) { if (message.component_name() != "types") { out << "bool " << fuzzer_extended_class_name << "::CallFunction(" << "\n"; out.indent(); out << "const FunctionSpecificationMessage& func_msg," << "\n"; out << "const string& callback_socket_name __attribute__((__unused__))," << "\n"; out << "FunctionSpecificationMessage* result_msg) {\n"; out << "const char* func_name = func_msg.name().c_str();" << "\n"; out << "if (hw_binder_proxy_ == nullptr) {\n"; out.indent(); out << "LOG(ERROR) << \"" << kInstanceVariableName << " is null. \";\n"; out << "return false;\n"; out.unindent(); out << "}\n"; for (auto const& api : message.interface().api()) { GenerateDriverImplForMethod(out, api); } GenerateDriverImplForReservedMethods(out); out << "return false;\n"; out.unindent(); out << "}\n"; } } void HalHidlCodeGen::GenerateDriverImplForReservedMethods(Formatter& out) { // Generate call for reserved method: notifySyspropsChanged. out << "if (!strcmp(func_name, \"notifySyspropsChanged\")) {\n"; out.indent(); out << "LOG(INFO) << \"Call notifySyspropsChanged\";" << "\n"; out << kInstanceVariableName << "->notifySyspropsChanged();\n"; out << "result_msg->set_name(\"notifySyspropsChanged\");\n"; out << "return true;\n"; out.unindent(); out << "}\n"; // TODO(zhuoyao): Add generation code for other reserved method, // e.g interfaceChain } void HalHidlCodeGen::GenerateDriverImplForMethod(Formatter& out, const FunctionSpecificationMessage& func_msg) { out << "if (!strcmp(func_name, \"" << func_msg.name() << "\")) {\n"; out.indent(); // Process the arguments. for (int i = 0; i < func_msg.arg_size(); i++) { const auto& arg = func_msg.arg(i); string cur_arg_name = "arg" + std::to_string(i); string var_type = GetCppVariableType(arg); if (arg.type() == TYPE_POINTER || (arg.type() == TYPE_SCALAR && (arg.scalar_type() == "pointer" || arg.scalar_type() == "void_pointer" || arg.scalar_type() == "function_pointer"))) { out << var_type << " " << cur_arg_name << " = nullptr;\n"; } else if (arg.type() == TYPE_SCALAR) { out << var_type << " " << cur_arg_name << " = 0;\n"; } else if (arg.type() == TYPE_FMQ_SYNC || arg.type() == TYPE_FMQ_UNSYNC) { // FMQ type, use pointer to store arguments because copy assignment // is not allowed for fmq descriptor. // Use const because getDesc() function in FMQ implementation // returns const type. out << "const " << var_type << "* " << cur_arg_name << ";\n"; } else { out << var_type << " " << cur_arg_name << ";\n"; } GenerateDriverImplForTypedVariable( out, arg, cur_arg_name, "func_msg.arg(" + std::to_string(i) + ")"); } // may need to check whether the function is actually defined. out << "LOG(DEBUG) << \"local_device = \" << " << kInstanceVariableName << ".get();\n"; // Call the HAL function. if (CanElideCallback(func_msg)) { out << GetCppVariableType(func_msg.return_type_hidl(0)) << " result0 = "; GenerateHalFunctionCall(out, func_msg); // Set the return results value to the proto message. for (int index = 0; index < func_msg.return_type_hidl_size(); index++) { out << "VariableSpecificationMessage* result_val_" << index << " = " << "result_msg->add_return_type_hidl();\n"; GenerateSetResultCodeForTypedVariable( out, func_msg.return_type_hidl(index), "result_val_" + std::to_string(index), "result" + std::to_string(index)); } } else { GenerateHalFunctionCall(out, func_msg); } out << "return true;\n"; out.unindent(); out << "}\n"; } void HalHidlCodeGen::GenerateHalFunctionCall(Formatter& out, const FunctionSpecificationMessage& func_msg) { out << kInstanceVariableName << "->" << func_msg.name() << "("; for (int index = 0; index < func_msg.arg_size(); index++) { if (func_msg.arg(index).type() == TYPE_FMQ_SYNC || func_msg.arg(index).type() == TYPE_FMQ_UNSYNC) { // only FMQ types store arguments as pointers, dereference it now. out << "*arg" << index; } else { out << "arg" << index; } if (index != (func_msg.arg_size() - 1)) out << ", "; } if (func_msg.return_type_hidl_size()== 0 || CanElideCallback(func_msg)) { out << ");\n"; out << "result_msg->set_name(\"" << func_msg.name() << "\");\n"; } else { out << (func_msg.arg_size() != 0 ? ", " : ""); GenerateSyncCallbackFunctionImpl(out, func_msg); out << ");\n"; } } void HalHidlCodeGen::GenerateSyncCallbackFunctionImpl(Formatter& out, const FunctionSpecificationMessage& func_msg) { out << "[&]("; for (int index = 0; index < func_msg.return_type_hidl_size(); index++) { const auto& return_val = func_msg.return_type_hidl(index); out << GetCppVariableType(return_val, IsConstType(return_val.type())) << " arg" << index << " __attribute__((__unused__))"; if (index != (func_msg.return_type_hidl_size() - 1)) out << ","; } out << "){\n"; out.indent(); out << "LOG(INFO) << \"callback " << func_msg.name() << " called\"" << ";\n"; // Set the return results value to the proto message. out << "result_msg->set_name(\"" << func_msg.name() << "\");\n"; for (int index = 0; index < func_msg.return_type_hidl_size(); index++) { out << "VariableSpecificationMessage* result_val_" << index << " = " << "result_msg->add_return_type_hidl();\n"; GenerateSetResultCodeForTypedVariable(out, func_msg.return_type_hidl(index), "result_val_" + std::to_string(index), "arg" + std::to_string(index)); } out.unindent(); out << "}"; } void HalHidlCodeGen::GenerateCppBodyGetAttributeFunction( Formatter& out, const ComponentSpecificationMessage& message, const string& fuzzer_extended_class_name) { if (message.component_name() != "types") { out << "bool " << fuzzer_extended_class_name << "::GetAttribute(" << "\n"; out.indent(); out << "FunctionSpecificationMessage* /*func_msg*/," << "\n"; out << "void** /*result*/) {" << "\n"; // TOOD: impl out << "LOG(ERROR) << \"attribute not found.\";\n" << "return false;\n"; out.unindent(); out << "}" << "\n"; } } void HalHidlCodeGen::GenerateClassConstructionFunction(Formatter& out, const ComponentSpecificationMessage& message, const string& fuzzer_extended_class_name) { out << fuzzer_extended_class_name << "() : DriverBase("; if (message.component_name() != "types") { out << "HAL_HIDL), " << kInstanceVariableName << "()"; } else { out << "HAL_HIDL)"; } out << " {}" << "\n"; out << "\n"; FQName fqname = GetFQName(message); out << "explicit " << fuzzer_extended_class_name << "(" << fqname.cppName() << "* hw_binder_proxy) : DriverBase(" << "HAL_HIDL)"; if (message.component_name() != "types") { out << ", " << kInstanceVariableName << "(hw_binder_proxy)"; } out << " {}\n"; } void HalHidlCodeGen::GenerateHeaderGlobalFunctionDeclarations(Formatter& out, const ComponentSpecificationMessage& message, const bool print_extern_block) { if (message.component_name() != "types") { if (print_extern_block) { out << "extern \"C\" {" << "\n"; } DriverCodeGenBase::GenerateHeaderGlobalFunctionDeclarations( out, message, false); string function_name_prefix = GetFunctionNamePrefix(message); FQName fqname = GetFQName(message); out << "extern " << "android::vts::DriverBase* " << function_name_prefix << "with_arg(uint64_t hw_binder_proxy);\n"; if (print_extern_block) { out << "}" << "\n"; } } } void HalHidlCodeGen::GenerateCppBodyGlobalFunctions(Formatter& out, const ComponentSpecificationMessage& message, const string& fuzzer_extended_class_name, const bool print_extern_block) { if (message.component_name() != "types") { if (print_extern_block) { out << "extern \"C\" {" << "\n"; } DriverCodeGenBase::GenerateCppBodyGlobalFunctions( out, message, fuzzer_extended_class_name, false); string function_name_prefix = GetFunctionNamePrefix(message); FQName fqname = GetFQName(message); out << "android::vts::DriverBase* " << function_name_prefix << "with_arg(" << "uint64_t hw_binder_proxy) {\n"; out.indent(); out << fqname.cppName() << "* arg = nullptr;\n"; out << "if (hw_binder_proxy) {\n"; out.indent(); out << "arg = reinterpret_cast<" << fqname.cppName() << "*>(hw_binder_proxy);\n"; out.unindent(); out << "} else {\n"; out.indent(); out << "LOG(INFO) << \" Creating DriverBase with null proxy.\";\n"; out.unindent(); out << "}\n"; out << "android::vts::DriverBase* result =" << "\n" << " new android::vts::" << fuzzer_extended_class_name << "(\n" << " arg);\n"; out << "if (arg != nullptr) {\n"; out.indent(); out << "arg->decStrong(arg);" << "\n"; out.unindent(); out << "}\n"; out << "return result;" << "\n"; out.unindent(); out << "}\n\n"; if (print_extern_block) { out << "}" << "\n"; } } } void HalHidlCodeGen::GenerateClassHeader(Formatter& out, const ComponentSpecificationMessage& message, const string& fuzzer_extended_class_name) { if (message.component_name() != "types") { for (const auto& attribute : message.interface().attribute()) { GenerateAllFunctionDeclForAttribute(out, attribute); } DriverCodeGenBase::GenerateClassHeader(out, message, fuzzer_extended_class_name); } else { for (const auto& attribute : message.attribute()) { GenerateAllFunctionDeclForAttribute(out, attribute); }; } } void HalHidlCodeGen::GenerateHeaderInterfaceImpl( Formatter& out, const ComponentSpecificationMessage& message) { out << "\n"; FQName component_fq_name = GetFQName(message); string component_name_token = "Vts_" + component_fq_name.tokenName(); out << "class " << component_name_token << " : public " << component_fq_name.cppName() << ", public DriverCallbackBase {\n"; out << " public:\n"; out.indent(); out << component_name_token << "(const string& callback_socket_name)\n" << " : callback_socket_name_(callback_socket_name) {};\n\n"; out << "virtual ~" << component_name_token << "()" << " = default;\n\n"; for (const auto& api : message.interface().api()) { // Generate return statement. if (CanElideCallback(api)) { out << "::android::hardware::Return<" << GetCppVariableType(api.return_type_hidl(0)) << "> "; } else { out << "::android::hardware::Return "; } // Generate function call. out << api.name() << "(\n"; out.indent(); for (int index = 0; index < api.arg_size(); index++) { const auto& arg = api.arg(index); out << GetCppVariableType(arg, IsConstType(arg.type())) << " arg" << index; if (index != (api.arg_size() - 1)) out << ",\n"; } if (api.return_type_hidl_size() == 0 || CanElideCallback(api)) { out << ") override;\n\n"; } else { // handle the case of callbacks. out << (api.arg_size() != 0 ? ", " : ""); out << "std::function cb) override;\n\n"; } out.unindent(); } out << "\n"; out.unindent(); out << " private:\n"; out.indent(); out << "string callback_socket_name_;\n"; out.unindent(); out << "};\n\n"; out << "sp<" << component_fq_name.cppName() << "> VtsFuzzerCreate" << component_name_token << "(const string& callback_socket_name);\n\n"; } void HalHidlCodeGen::GenerateClassImpl(Formatter& out, const ComponentSpecificationMessage& message, const string& fuzzer_extended_class_name) { if (message.component_name() != "types") { for (const auto& attribute : message.interface().attribute()) { GenerateAllFunctionImplForAttribute(out, attribute); } GenerateGetServiceImpl(out, message, fuzzer_extended_class_name); DriverCodeGenBase::GenerateClassImpl(out, message, fuzzer_extended_class_name); } else { for (const auto& attribute : message.attribute()) { GenerateAllFunctionImplForAttribute(out, attribute); } } } void HalHidlCodeGen::GenerateHeaderIncludeFiles(Formatter& out, const ComponentSpecificationMessage& message, const string& fuzzer_extended_class_name) { DriverCodeGenBase::GenerateHeaderIncludeFiles(out, message, fuzzer_extended_class_name); out << "#include <" << GetPackagePath(message) << "/" << GetVersion(message) << "/" << GetComponentName(message) << ".h>" << "\n"; out << "#include " << "\n"; for (const auto& import : message.import()) { FQName import_name; if (!FQName::parse(import, &import_name)) { abort(); } string import_package_name = import_name.package(); string import_package_version = import_name.version(); string import_component_name = import_name.name(); string import_package_path = import_package_name; ReplaceSubString(import_package_path, ".", "/"); out << "#include <" << import_package_path << "/" << import_package_version << "/" << import_component_name << ".h>\n"; // Exclude the base hal in include list. if (import_package_name.find("android.hidl.base") == std::string::npos) { if (import_component_name[0] == 'I') { import_component_name = import_component_name.substr(1); } out << "#include <" << import_package_path << "/" << import_package_version << "/" << import_component_name << ".vts.h>\n"; } } out << "\n\n"; } void HalHidlCodeGen::GenerateSourceIncludeFiles(Formatter& out, const ComponentSpecificationMessage& message, const string& fuzzer_extended_class_name) { DriverCodeGenBase::GenerateSourceIncludeFiles(out, message, fuzzer_extended_class_name); out << "#include \n"; out << "#include \n"; out << "#include \n"; out << "#include \n"; } void HalHidlCodeGen::GenerateAdditionalFuctionDeclarations(Formatter& out, const ComponentSpecificationMessage& message, const string& /*fuzzer_extended_class_name*/) { if (message.component_name() != "types") { out << "bool GetService(bool get_stub, const char* service_name);" << "\n\n"; } } void HalHidlCodeGen::GeneratePublicFunctionDeclarations( Formatter& out, const ComponentSpecificationMessage& /*message*/) { out << "uint64_t GetHidlInterfaceProxy() const {\n"; out.indent(); out << "return reinterpret_cast(" << kInstanceVariableName << ".get());\n"; out.unindent(); out << "}\n"; } void HalHidlCodeGen::GeneratePrivateMemberDeclarations(Formatter& out, const ComponentSpecificationMessage& message) { FQName fqname = GetFQName(message); out << "sp<" << fqname.cppName() << "> " << kInstanceVariableName << ";\n"; } void HalHidlCodeGen::GenerateRandomFunctionDeclForAttribute(Formatter& out, const VariableSpecificationMessage& attribute) { if (attribute.type() == TYPE_ENUM) { if (attribute.enum_value().enumerator_size() == 0) { // empty enum without any actual enumerator. return; } string attribute_name = ClearStringWithNameSpaceAccess(attribute.name()); out << attribute.enum_value().scalar_type() << " " << "Random" << attribute_name << "();\n"; } } void HalHidlCodeGen::GenerateRandomFunctionImplForAttribute(Formatter& out, const VariableSpecificationMessage& attribute) { // Random value generator if (attribute.type() == TYPE_ENUM) { if (attribute.enum_value().enumerator_size() == 0) { // empty enum without any actual enumerator. return; } string attribute_name = ClearStringWithNameSpaceAccess(attribute.name()); out << attribute.enum_value().scalar_type() << " Random" << attribute_name << "() {\n"; out.indent(); out << attribute.enum_value().scalar_type() << " choice = " << "(" << attribute.enum_value().scalar_type() << ") " << "rand() / " << attribute.enum_value().enumerator().size() << ";" << "\n"; if (attribute.enum_value().scalar_type().find("u") != 0) { out << "if (choice < 0) choice *= -1;" << "\n"; } for (int index = 0; index < attribute.enum_value().enumerator().size(); index++) { out << "if (choice == "; out << "(" << attribute.enum_value().scalar_type() << ") "; if (attribute.enum_value().scalar_type() == "int8_t") { out << attribute.enum_value().scalar_value(index).int8_t(); } else if (attribute.enum_value().scalar_type() == "uint8_t") { out << attribute.enum_value().scalar_value(index).uint8_t() << "U"; } else if (attribute.enum_value().scalar_type() == "int16_t") { out << attribute.enum_value().scalar_value(index).int16_t(); } else if (attribute.enum_value().scalar_type() == "uint16_t") { out << attribute.enum_value().scalar_value(index).uint16_t() << "U"; } else if (attribute.enum_value().scalar_type() == "int32_t") { out << attribute.enum_value().scalar_value(index).int32_t() << "L"; } else if (attribute.enum_value().scalar_type() == "uint32_t") { out << attribute.enum_value().scalar_value(index).uint32_t() << "UL"; } else if (attribute.enum_value().scalar_type() == "int64_t") { if (attribute.enum_value().scalar_value(index).int64_t() == LLONG_MIN) { out << "LLONG_MIN"; } else { out << attribute.enum_value().scalar_value(index).int64_t() << "LL"; } } else if (attribute.enum_value().scalar_type() == "uint64_t") { out << attribute.enum_value().scalar_value(index).uint64_t() << "ULL"; } else { cerr << __func__ << ":" << __LINE__ << " ERROR unsupported enum type " << attribute.enum_value().scalar_type() << "\n"; exit(-1); } out << ") return static_cast<" << attribute.enum_value().scalar_type() << ">(" << attribute.name() << "::" << attribute.enum_value().enumerator(index) << ");\n"; } out << "return static_cast<" << attribute.enum_value().scalar_type() << ">(" << attribute.name() << "::" << attribute.enum_value().enumerator(0) << ");\n"; out.unindent(); out << "}" << "\n"; } } void HalHidlCodeGen::GenerateDriverDeclForAttribute(Formatter& out, const VariableSpecificationMessage& attribute) { if (!IsUserDefinedType(attribute.type())) { cerr << attribute.type() << " is not a user defined type\n"; exit(-1); } for (const auto& sub_struct : attribute.sub_struct()) { GenerateDriverDeclForAttribute(out, sub_struct); } for (const auto& sub_union : attribute.sub_union()) { GenerateDriverDeclForAttribute(out, sub_union); } for (const auto& sub_safe_union : attribute.sub_safe_union()) { GenerateDriverDeclForAttribute(out, sub_safe_union); } string func_name = "MessageTo" + ClearStringWithNameSpaceAccess(attribute.name()); // Add extern C to allow resource_manager to dynamically load this function. out << "extern \"C\" "; out << "void " << func_name << "(const VariableSpecificationMessage& var_msg, " << attribute.name() << "* arg, const string& callback_socket_name);\n"; } void HalHidlCodeGen::GenerateDriverImplForAttribute(Formatter& out, const VariableSpecificationMessage& attribute) { if (!IsUserDefinedType(attribute.type())) { cerr << attribute.type() << " is not a user defined type\n"; exit(-1); } // Recursively generate driver implementation method for all sub_types. for (const auto& sub_struct : attribute.sub_struct()) { GenerateDriverImplForAttribute(out, sub_struct); } for (const auto& sub_union : attribute.sub_union()) { GenerateDriverImplForAttribute(out, sub_union); } for (const auto& sub_safe_union : attribute.sub_safe_union()) { GenerateDriverImplForAttribute(out, sub_safe_union); } string func_name = "MessageTo" + ClearStringWithNameSpaceAccess(attribute.name()); // Add extern C to allow resource_manager to dynamically load this // function. out << "extern \"C\" "; out << "void " << func_name << "(const VariableSpecificationMessage& " "var_msg __attribute__((__unused__)), " << attribute.name() << "* arg __attribute__((__unused__)), " << "const string& callback_socket_name __attribute__((__unused__))) {" << "\n"; out.indent(); switch (attribute.type()) { case TYPE_ENUM: { out << "*arg = (" << attribute.name() << ")var_msg.scalar_value()." << attribute.enum_value().scalar_type() << "();\n"; break; } case TYPE_STRUCT: { int struct_index = 0; for (const auto& struct_value : attribute.struct_value()) { GenerateDriverImplForTypedVariable( out, struct_value, "arg->" + struct_value.name(), "var_msg.struct_value(" + std::to_string(struct_index) + ")"); struct_index++; } break; } case TYPE_UNION: { int union_index = 0; for (const auto& union_value : attribute.union_value()) { out << "if (var_msg.union_value(" << union_index << ").name() == \"" << union_value.name() << "\") {" << "\n"; out.indent(); GenerateDriverImplForTypedVariable( out, union_value, "arg->" + union_value.name(), "var_msg.union_value(" + std::to_string(union_index) + ")"); union_index++; out.unindent(); out << "}\n"; } break; } case TYPE_SAFE_UNION: { out << "LOG(ERROR) << \"TYPE_SAFE_UNION is not supported yet. \";\n"; break; } default: { cerr << __func__ << " unsupported attribute type " << attribute.type() << "\n"; exit(-1); } } out.unindent(); out << "}\n"; } void HalHidlCodeGen::GenerateGetServiceImpl(Formatter& out, const ComponentSpecificationMessage& message, const string& fuzzer_extended_class_name) { out << "bool " << fuzzer_extended_class_name << "::GetService(bool get_stub, const char* service_name) {" << "\n"; out.indent(); out << "static bool initialized = false;" << "\n"; out << "if (!initialized) {" << "\n"; out.indent(); out << "LOG(INFO) << \"HIDL getService\";" << "\n"; out << "if (service_name) {\n" << " LOG(INFO) << \" - service name: \" << service_name;" << "\n" << "}\n"; FQName fqname = GetFQName(message); out << kInstanceVariableName << " = " << fqname.cppName() << "::getService(" << "service_name, get_stub);" << "\n"; out << "if (" << kInstanceVariableName << " == nullptr) {\n"; out.indent(); out << "LOG(ERROR) << \"getService() returned a null pointer.\";\n"; out << "return false;\n"; out.unindent(); out << "}\n"; out << "LOG(DEBUG) << \"" << kInstanceVariableName << " = \" << " << kInstanceVariableName << ".get();" << "\n"; out << "initialized = true;" << "\n"; out.unindent(); out << "}" << "\n"; out << "return true;" << "\n"; out.unindent(); out << "}" << "\n" << "\n"; } void HalHidlCodeGen::GenerateDriverImplForTypedVariable(Formatter& out, const VariableSpecificationMessage& val, const string& arg_name, const string& arg_value_name) { switch (val.type()) { case TYPE_SCALAR: { out << arg_name << " = " << arg_value_name << ".scalar_value()." << val.scalar_type() << "();\n"; break; } case TYPE_STRING: { out << arg_name << " = ::android::hardware::hidl_string(" << arg_value_name << ".string_value().message());\n"; break; } case TYPE_ENUM: { if (val.has_predefined_type()) { string func_name = "MessageTo" + ClearStringWithNameSpaceAccess(val.predefined_type()); out << func_name << "(" << arg_value_name << ", &(" << arg_name << "), callback_socket_name);\n"; } else { out << arg_name << " = (" << val.name() << ")" << arg_value_name << "." << "enum_value().scalar_value(0)." << val.enum_value().scalar_type() << "();\n"; } break; } case TYPE_MASK: { out << arg_name << " = " << arg_value_name << ".scalar_value()." << val.scalar_type() << "();\n"; break; } case TYPE_VECTOR: { out << arg_name << ".resize(" << arg_value_name << ".vector_value_size());\n"; std::string index_name = GetVarString(arg_name) + "_index"; out << "for (int " << index_name << " = 0; " << index_name << " < " << arg_value_name << ".vector_value_size(); " << index_name << "++) {\n"; out.indent(); GenerateDriverImplForTypedVariable( out, val.vector_value(0), arg_name + "[" + index_name + "]", arg_value_name + ".vector_value(" + index_name + ")"); out.unindent(); out << "}\n"; break; } case TYPE_ARRAY: { std::string index_name = GetVarString(arg_name) + "_index"; out << "for (int " << index_name << " = 0; " << index_name << " < " << arg_value_name << ".vector_value_size(); " << index_name << "++) {\n"; out.indent(); GenerateDriverImplForTypedVariable( out, val.vector_value(0), arg_name + "[" + index_name + "]", arg_value_name + ".vector_value(" + index_name + ")"); out.unindent(); out << "}\n"; break; } case TYPE_STRUCT: { if (val.has_predefined_type()) { string func_name = "MessageTo" + ClearStringWithNameSpaceAccess(val.predefined_type()); out << func_name << "(" << arg_value_name << ", &(" << arg_name << "), callback_socket_name);\n"; } else { int struct_index = 0; for (const auto& struct_field : val.struct_value()) { string struct_field_name = arg_name + "." + struct_field.name(); string struct_field_value_name = arg_value_name + ".struct_value(" + std::to_string(struct_index) + ")"; GenerateDriverImplForTypedVariable(out, struct_field, struct_field_name, struct_field_value_name); struct_index++; } } break; } case TYPE_UNION: { if (val.has_predefined_type()) { string func_name = "MessageTo" + ClearStringWithNameSpaceAccess(val.predefined_type()); out << func_name << "(" << arg_value_name << ", &(" << arg_name << "), callback_socket_name);\n"; } else { int union_index = 0; for (const auto& union_field : val.union_value()) { string union_field_name = arg_name + "." + union_field.name(); string union_field_value_name = arg_value_name + ".union_value(" + std::to_string(union_index) + ")"; GenerateDriverImplForTypedVariable(out, union_field, union_field_name, union_field_value_name); union_index++; } } break; } case TYPE_HIDL_CALLBACK: { string type_name = val.predefined_type(); ReplaceSubString(type_name, "::", "_"); out << arg_name << " = VtsFuzzerCreateVts" << type_name << "(callback_socket_name);\n"; out << "static_cast<" << "Vts" + type_name << "*>(" << arg_name << ".get())->Register(" << arg_value_name << ");\n"; break; } case TYPE_HANDLE: { out << "if (" << arg_value_name << ".has_handle_value()) {\n"; out.indent(); out << "if (" << arg_value_name << ".handle_value().has_hidl_handle_address()) {\n"; out.indent(); // if case starts: existing hidl_handle is specified. out << arg_name << " = *(reinterpret_cast(" << arg_value_name << ".handle_value().hidl_handle_address()));\n"; out.unindent(); // if case ends. out << "} else {\n"; out.indent(); // else case starts: create a new handle object. out << "native_handle_t* handle = native_handle_create(" << arg_value_name << ".handle_value().num_fds(), " << arg_value_name << ".handle_value().num_ints());\n"; out << "if (!handle) {\n"; out.indent(); out << "LOG(ERROR) << \"Failed to create handle. \";\n"; out << "exit(-1);\n"; out.unindent(); out << "}\n"; out << "for (int fd_index = 0; fd_index < " << arg_value_name << ".handle_value().num_fds() + " << arg_value_name << ".handle_value().num_ints(); fd_index++) {\n"; out.indent(); out << "if (fd_index < " << arg_value_name << ".handle_value().num_fds()) {\n"; out.indent(); out << "FdMessage fd_val = " << arg_value_name << ".handle_value().fd_val(fd_index);\n"; out << "string file_name = fd_val.file_name();\n"; out << "switch (fd_val.type()) {\n"; out.indent(); out << "case FdType::FILE_TYPE:\n"; out << "{\n"; out.indent(); // Create the parent path recursively if not exist. out << "size_t pre = 0; size_t pos = 0;\n"; out << "string dir;\n"; out << "struct stat st;\n"; out << "while((pos=file_name.find_first_of('/', pre)) " << "!= string::npos){\n"; out.indent(); out << "dir = file_name.substr(0, pos++);\n"; out << "pre = pos;\n"; out << "if(dir.size() == 0) continue; // ignore leading /\n"; out << "if (stat(dir.c_str(), &st) == -1) {\n"; out << "LOG(INFO) << \" Creating dir: \" << dir;\n"; out.indent(); out << "mkdir(dir.c_str(), 0700);\n"; out.unindent(); out << "}\n"; out.unindent(); out << "}\n"; out << "int fd = open(file_name.c_str(), " << "fd_val.flags() | O_CREAT, fd_val.mode());\n"; out << "if (fd == -1) {\n"; out.indent(); out << "LOG(ERROR) << \"Failed to open file: \" << file_name << \" " "error: \" << errno;\n"; out << "exit (-1);\n"; out.unindent(); out << "}\n"; out << "handle->data[fd_index] = fd;\n"; out << "break;\n"; out.unindent(); out << "}\n"; out << "case FdType::DIR_TYPE:\n"; out << "{\n"; out.indent(); out << "struct stat st;\n"; out << "if (!stat(file_name.c_str(), &st)) {\n"; out.indent(); out << "mkdir(file_name.c_str(), fd_val.mode());\n"; out.unindent(); out << "}\n"; out << "handle->data[fd_index] = open(file_name.c_str(), O_DIRECTORY, " << "fd_val.mode());\n"; out << "break;\n"; out.unindent(); out << "}\n"; out << "case FdType::DEV_TYPE:\n"; out << "{\n"; out.indent(); out << "if(file_name == \"/dev/ashmem\") {\n"; out.indent(); out << "handle->data[fd_index] = ashmem_create_region(\"SharedMemory\", " << "fd_val.memory().size());\n"; out.unindent(); out << "}\n"; out << "break;\n"; out.unindent(); out << "}\n"; out << "case FdType::PIPE_TYPE:\n"; out << "case FdType::SOCKET_TYPE:\n"; out << "case FdType::LINK_TYPE:\n"; out << "{\n"; out.indent(); out << "LOG(ERROR) << \"Not supported yet. \";\n"; out << "break;\n"; out.unindent(); out << "}\n"; out.unindent(); out << "}\n"; out.unindent(); out << "} else {\n"; out.indent(); out << "handle->data[fd_index] = " << arg_value_name << ".handle_value().int_val(fd_index -" << arg_value_name << ".handle_value().num_fds());\n"; out.unindent(); out << "}\n"; out.unindent(); out << "}\n"; out << arg_name << " = handle;\n"; out.unindent(); // else case (create a new handle object) ends. out << "}\n"; out.unindent(); out << "} else {\n"; out.indent(); out << arg_name << " = nullptr;\n"; out.unindent(); out << "}\n"; break; } case TYPE_HIDL_INTERFACE: { string type_name = val.predefined_type(); out << "if (" << arg_value_name << ".has_hidl_interface_pointer()) {\n"; out.indent(); out << arg_name << " = reinterpret_cast<" << type_name << "*>(" << arg_value_name << ".hidl_interface_pointer());\n"; out.unindent(); out << "} else {\n"; out.indent(); if (type_name.find("::android::hidl") == 0) { out << "LOG(ERROR) << \"general interface is not supported yet. \";\n"; } else { ReplaceSubString(type_name, "::", "_"); out << arg_name << " = VtsFuzzerCreateVts" << type_name << "(callback_socket_name);\n"; } out.unindent(); out << "}\n"; break; } case TYPE_HIDL_MEMORY: { out << "if (" << arg_value_name << ".hidl_memory_value().has_hidl_mem_address()) {\n"; out.indent(); // if case starts: existing hidl_memory is used. out << arg_name << " = *(reinterpret_cast(" << arg_value_name << ".hidl_memory_value().hidl_mem_address()));\n"; out.unindent(); // if case ends. out << "} else {\n"; out.indent(); // else case starts: allocates new memory region. out << "sp<::android::hidl::allocator::V1_0::IAllocator> ashmemAllocator" << " = ::android::hidl::allocator::V1_0::IAllocator::getService(\"" << "ashmem\");\n"; out << "if (ashmemAllocator == nullptr) {\n"; out.indent(); out << "LOG(ERROR) << \"Failed to get ashmemAllocator! \";\n"; out << "exit(-1);\n"; out.unindent(); out << "}\n"; // TODO(zhuoyao): initialize memory with recorded contents. out << "auto res = ashmemAllocator->allocate(" << arg_value_name << ".hidl_memory_value().size(), [&](bool success, " << "const hardware::hidl_memory& memory) {\n"; out.indent(); out << "if (!success) {\n"; out.indent(); out << "LOG(ERROR) << \"Failed to allocate memory! \";\n"; out << arg_name << " = ::android::hardware::hidl_memory();\n"; out << "return;\n"; out.unindent(); out << "}\n"; out << arg_name << " = memory;\n"; out.unindent(); out << "});\n"; out.unindent(); // else case ends. out << "}\n"; break; } case TYPE_POINTER: { out << "LOG(ERROR) << \"TYPE_POINTER is not supported yet. \";\n"; break; } case TYPE_FMQ_SYNC: case TYPE_FMQ_UNSYNC: { if (arg_name.find("->") != std::string::npos) { out << "LOG(ERROR) << \"Nested structure with fmq is not supported " "yet. \";\n"; } else { // TODO(zhuoyao): consider record and use the queue capacity. std::string element_type = GetCppVariableType(val.fmq_value(0)); std::string queue_name = arg_name + (val.type() == TYPE_FMQ_SYNC ? "_sync_q" : "_unsync_q"); std::string queue_descriptor_type = GetCppVariableType(val); // When caller wants to reuse an existing queue. out << "if (" << arg_value_name << ".fmq_value_size() > 0 && " << arg_value_name << ".fmq_value(0).has_fmq_desc_address()) {\n"; out.indent(); // if case starts out << arg_name << " = " << "reinterpret_cast<" << queue_descriptor_type << "*>(" << arg_value_name << ".fmq_value(0).fmq_desc_address());\n"; out.unindent(); // if case ends // When caller wants to create a brand new queue and write to it. out << "} else {\n"; out.indent(); // else case starts out << "::android::hardware::MessageQueue<" << element_type << ", ::android::hardware::" << (val.type() == TYPE_FMQ_SYNC ? "kSynchronizedReadWrite" : "kUnsynchronizedWrite") << "> " << queue_name << "(1024);\n"; out << "for (int i = 0; i < (int)" << arg_value_name << ".fmq_value_size(); i++) {\n"; out.indent(); // for loop starts std::string fmq_item_name = queue_name + "_item"; out << element_type << " " << fmq_item_name << ";\n"; GenerateDriverImplForTypedVariable(out, val.fmq_value(0), fmq_item_name, arg_value_name + ".fmq_value(i)"); out << queue_name << ".write(&" << fmq_item_name << ");\n"; out.unindent(); // for loop ends out << "}\n"; out << arg_name << " = " << queue_name << ".getDesc();\n"; out.unindent(); // else case ends out << "}\n"; } break; } case TYPE_REF: { out << "LOG(ERROR) << \"TYPE_REF is not supported yet. \";\n"; break; } case TYPE_SAFE_UNION: { out << "LOG(ERROR) << \"TYPE_SAFE_UNION is not supported yet. \";\n"; break; } default: { cerr << __func__ << " ERROR: unsupported type " << val.type() << ".\n"; exit(-1); } } } // TODO(zhuoyao): Verify results based on verification rules instead of perform // an exact match. void HalHidlCodeGen::GenerateVerificationFunctionImpl(Formatter& out, const ComponentSpecificationMessage& message, const string& fuzzer_extended_class_name) { if (message.component_name() != "types") { // Generate the main profiler function. out << "\nbool " << fuzzer_extended_class_name; out.indent(); out << "::VerifyResults(const FunctionSpecificationMessage& " "expected_result __attribute__((__unused__))," << "\n"; out << "const FunctionSpecificationMessage& actual_result " "__attribute__((__unused__))) {\n"; for (const FunctionSpecificationMessage& api : message.interface().api()) { out << "if (!strcmp(actual_result.name().c_str(), \"" << api.name() << "\")) {\n"; out.indent(); out << "if (actual_result.return_type_hidl_size() != " << "expected_result.return_type_hidl_size() " << ") { return false; }\n"; for (int i = 0; i < api.return_type_hidl_size(); i++) { std::string expected_result = "expected_result.return_type_hidl(" + std::to_string(i) + ")"; std::string actual_result = "actual_result.return_type_hidl(" + std::to_string(i) + ")"; GenerateVerificationCodeForTypedVariable(out, api.return_type_hidl(i), expected_result, actual_result); } out << "return true;\n"; out.unindent(); out << "}\n"; } out << "return false;\n"; out.unindent(); out << "}\n\n"; } } void HalHidlCodeGen::GenerateVerificationCodeForTypedVariable(Formatter& out, const VariableSpecificationMessage& val, const string& expected_result, const string& actual_result) { switch (val.type()) { case TYPE_SCALAR: { out << "if (" << actual_result << ".scalar_value()." << val.scalar_type() << "() != " << expected_result << ".scalar_value()." << val.scalar_type() << "()) { return false; }\n"; break; } case TYPE_STRING: { out << "if (strcmp(" << actual_result << ".string_value().message().c_str(), " << expected_result << ".string_value().message().c_str())!= 0)" << "{ return false; }\n"; break; } case TYPE_ENUM: { if (val.has_predefined_type()) { string func_name = "Verify" + ClearStringWithNameSpaceAccess(val.predefined_type()); out << "if(!" << func_name << "(" << expected_result << ", " << actual_result << ")) { return false; }\n"; } else { out << "if (" << actual_result << ".scalar_value()." << val.enum_value().scalar_type() << "() != " << expected_result << ".scalar_value()." << val.enum_value().scalar_type() << "()) { return false; }\n"; } break; } case TYPE_MASK: { out << "if (" << actual_result << ".scalar_value()." << val.scalar_type() << "() != " << expected_result << ".scalar_value()." << val.scalar_type() << "()) { return false; }\n"; break; } case TYPE_VECTOR: { out << "if (" << actual_result << ".vector_value_size() != " << expected_result << ".vector_value_size()) {\n"; out.indent(); out << "LOG(ERROR) << \"Verification failed for vector size. expected: " "\" << " << expected_result << ".vector_value_size() << \" actual: \" << " << actual_result << ".vector_value_size();\n"; out << "return false;\n"; out.unindent(); out << "}\n"; out << "for (int i = 0; i <" << expected_result << ".vector_value_size(); i++) {\n"; out.indent(); GenerateVerificationCodeForTypedVariable( out, val.vector_value(0), expected_result + ".vector_value(i)", actual_result + ".vector_value(i)"); out.unindent(); out << "}\n"; break; } case TYPE_ARRAY: { out << "if (" << actual_result << ".vector_value_size() != " << expected_result << ".vector_value_size()) {\n"; out.indent(); out << "LOG(ERROR) << \"Verification failed for vector size. expected: " "\" << " << expected_result << ".vector_value_size() << \" actual: \" << " << actual_result << ".vector_value_size();\n"; out << "return false;\n"; out.unindent(); out << "}\n"; out << "for (int i = 0; i < " << expected_result << ".vector_value_size(); i++) {\n"; out.indent(); GenerateVerificationCodeForTypedVariable( out, val.vector_value(0), expected_result + ".vector_value(i)", actual_result + ".vector_value(i)"); out.unindent(); out << "}\n"; break; } case TYPE_STRUCT: { if (val.has_predefined_type()) { string func_name = "Verify" + ClearStringWithNameSpaceAccess(val.predefined_type()); out << "if (!" << func_name << "(" << expected_result << ", " << actual_result << ")) { return false; }\n"; } else { for (int i = 0; i < val.struct_value_size(); i++) { string struct_field_actual_result = actual_result + ".struct_value(" + std::to_string(i) + ")"; string struct_field_expected_result = expected_result + ".struct_value(" + std::to_string(i) + ")"; GenerateVerificationCodeForTypedVariable(out, val.struct_value(i), struct_field_expected_result, struct_field_actual_result); } } break; } case TYPE_UNION: { if (val.has_predefined_type()) { string func_name = "Verify" + ClearStringWithNameSpaceAccess(val.predefined_type()); out << "if (!" << func_name << "(" << expected_result << ", " << actual_result << ")) {return false; }\n"; } else { for (int i = 0; i < val.union_value_size(); i++) { string union_field_actual_result = actual_result + ".union_value(" + std::to_string(i) + ")"; string union_field_expected_result = expected_result + ".union_value(" + std::to_string(i) + ")"; GenerateVerificationCodeForTypedVariable(out, val.union_value(i), union_field_expected_result, union_field_actual_result); } } break; } case TYPE_HIDL_CALLBACK: { out << "LOG(ERROR) << \"TYPE_HILD_CALLBACK is not supported yet. \";\n"; break; } case TYPE_HANDLE: { out << "LOG(ERROR) << \"TYPE_HANDLE is not supported yet. \";\n"; break; } case TYPE_HIDL_INTERFACE: { out << "LOG(ERROR) << \"TYPE_HIDL_INTERFACE is not supported yet. \";\n"; break; } case TYPE_HIDL_MEMORY: { out << "LOG(ERROR) << \"TYPE_HIDL_MEMORY is not supported yet. \";\n"; break; } case TYPE_POINTER: { out << "LOG(ERROR) << \"TYPE_POINTER is not supported yet. \";\n"; break; } case TYPE_FMQ_SYNC: { out << "LOG(ERROR) << \"TYPE_FMQ_SYNC is not supported yet. \";\n"; break; } case TYPE_FMQ_UNSYNC: { out << "LOG(ERROR) << \"TYPE_FMQ_UNSYNC is not supported yet. \";\n"; break; } case TYPE_REF: { out << "LOG(ERROR) << \"TYPE_REF is not supported yet. \";\n"; break; } case TYPE_SAFE_UNION: { out << "LOG(ERROR) << \"TYPE_SAFE_UNION is Not supported yet. \";\n"; break; } default: { cerr << __func__ << " ERROR: unsupported type " << val.type() << ".\n"; exit(-1); } } } void HalHidlCodeGen::GenerateVerificationDeclForAttribute(Formatter& out, const VariableSpecificationMessage& attribute) { if (attribute.type() == TYPE_STRUCT || attribute.type() == TYPE_UNION) { // Recursively generate verification method implementation for all sub_types. for (const auto& sub_struct : attribute.sub_struct()) { GenerateVerificationDeclForAttribute(out, sub_struct); } for (const auto& sub_union : attribute.sub_union()) { GenerateVerificationDeclForAttribute(out, sub_union); } } std::string func_name = "bool Verify" + ClearStringWithNameSpaceAccess(attribute.name()); out << func_name << "(const VariableSpecificationMessage& expected_result, " << "const VariableSpecificationMessage& actual_result);\n"; } void HalHidlCodeGen::GenerateVerificationImplForAttribute(Formatter& out, const VariableSpecificationMessage& attribute) { if (attribute.type() == TYPE_STRUCT || attribute.type() == TYPE_UNION) { // Recursively generate verification method implementation for all sub_types. for (const auto& sub_struct : attribute.sub_struct()) { GenerateVerificationImplForAttribute(out, sub_struct); } for (const auto& sub_union : attribute.sub_union()) { GenerateVerificationImplForAttribute(out, sub_union); } } std::string func_name = "bool Verify" + ClearStringWithNameSpaceAccess(attribute.name()); out << func_name << "(const VariableSpecificationMessage& expected_result " "__attribute__((__unused__)), " << "const VariableSpecificationMessage& actual_result " "__attribute__((__unused__))){\n"; out.indent(); GenerateVerificationCodeForTypedVariable(out, attribute, "expected_result", "actual_result"); out << "return true;\n"; out.unindent(); out << "}\n\n"; } // TODO(zhuoyao): consider to generalize the pattern for // Verification/SetResult/DriverImpl. void HalHidlCodeGen::GenerateSetResultCodeForTypedVariable(Formatter& out, const VariableSpecificationMessage& val, const string& result_msg, const string& result_value) { switch (val.type()) { case TYPE_SCALAR: { out << result_msg << "->set_type(TYPE_SCALAR);\n"; out << result_msg << "->set_scalar_type(\"" << val.scalar_type() << "\");\n"; out << result_msg << "->mutable_scalar_value()->set_" << val.scalar_type() << "(" << result_value << ");\n"; break; } case TYPE_STRING: { out << result_msg << "->set_type(TYPE_STRING);\n"; out << result_msg << "->mutable_string_value()->set_message" << "(" << result_value << ".c_str());\n"; out << result_msg << "->mutable_string_value()->set_length" << "(" << result_value << ".size());\n"; break; } case TYPE_ENUM: { out << result_msg << "->set_type(TYPE_ENUM);\n"; if (val.has_predefined_type()) { string func_name = "SetResult" + ClearStringWithNameSpaceAccess(val.predefined_type()); out << func_name << "(" << result_msg << ", " << result_value << ");\n"; } else { const string scalar_type = val.enum_value().scalar_type(); out << result_msg << "->set_scalar_type(\"" << scalar_type << "\");\n"; out << result_msg << "->mutable_scalar_value()->set_" << scalar_type << "(static_cast<" << scalar_type << ">(" << result_value << "));\n"; } break; } case TYPE_MASK: { out << result_msg << "->set_type(TYPE_MASK);\n"; out << result_msg << "->set_scalar_type(\"" << val.scalar_type() << "\");\n"; out << result_msg << "->mutable_scalar_value()->set_" << val.scalar_type() << "(" << result_value << ");\n"; break; } case TYPE_VECTOR: { out << result_msg << "->set_type(TYPE_VECTOR);\n"; out << result_msg << "->set_vector_size(" << result_value << ".size());\n"; out << "for (int i = 0; i < (int)" << result_value << ".size(); i++) {\n"; out.indent(); string vector_element_name = result_msg + "_vector_i"; out << "auto *" << vector_element_name << " = " << result_msg << "->add_vector_value();\n"; GenerateSetResultCodeForTypedVariable(out, val.vector_value(0), vector_element_name, result_value + "[i]"); out.unindent(); out << "}\n"; break; } case TYPE_ARRAY: { out << result_msg << "->set_type(TYPE_ARRAY);\n"; out << result_msg << "->set_vector_size(" << val.vector_value_size() << ");\n"; out << "for (int i = 0; i < " << val.vector_value_size() << "; i++) {\n"; out.indent(); string array_element_name = result_msg + "_array_i"; out << "auto *" << array_element_name << " = " << result_msg << "->add_vector_value();\n"; GenerateSetResultCodeForTypedVariable(out, val.vector_value(0), array_element_name, result_value + "[i]"); out.unindent(); out << "}\n"; break; } case TYPE_STRUCT: { out << result_msg << "->set_type(TYPE_STRUCT);\n"; if (val.has_predefined_type()) { string func_name = "SetResult" + ClearStringWithNameSpaceAccess(val.predefined_type()); out << func_name << "(" << result_msg << ", " << result_value << ");\n"; } else { for (const auto& struct_field : val.struct_value()) { string struct_field_name = result_msg + "_" + struct_field.name(); out << "auto *" << struct_field_name << " = " << result_msg << "->add_struct_value();\n"; GenerateSetResultCodeForTypedVariable( out, struct_field, struct_field_name, result_value + "." + struct_field.name()); if (struct_field.has_name()) { out << struct_field_name << "->set_name(\"" << struct_field.name() << "\");\n"; } } } break; } case TYPE_UNION: { out << result_msg << "->set_type(TYPE_UNION);\n"; if (val.has_predefined_type()) { string func_name = "SetResult" + ClearStringWithNameSpaceAccess(val.predefined_type()); out << func_name << "(" << result_msg << ", " << result_value << ");\n"; } else { for (const auto& union_field : val.union_value()) { string union_field_name = result_msg + "_" + union_field.name(); out << "auto *" << union_field_name << " = " << result_msg << "->add_union_value();\n"; GenerateSetResultCodeForTypedVariable( out, union_field, union_field_name, result_value + "." + union_field.name()); if (union_field.has_name()) { out << union_field_name << "->set_name(\"" << union_field.name() << "\");\n"; } } } break; } case TYPE_HIDL_CALLBACK: { out << result_msg << "->set_type(TYPE_HIDL_CALLBACK);\n"; out << "LOG(ERROR) << \"TYPE HIDL_CALLBACK is not supported yet. \";\n"; break; } case TYPE_HANDLE: { out << result_msg << "->set_type(TYPE_HANDLE);\n"; out << result_msg << "->mutable_handle_value()->set_hidl_handle_address" << "(reinterpret_cast(new android::hardware::hidl_handle(" << result_value << ")));\n"; break; } case TYPE_HIDL_INTERFACE: { out << result_msg << "->set_type(TYPE_HIDL_INTERFACE);\n"; if (!val.has_predefined_type()) { cerr << __func__ << ":" << __LINE__ << " HIDL interface is a return type" << "but predefined_type is unset." << endl; exit(-1); } out << result_msg << "->set_predefined_type(\"" << val.predefined_type() << "\");\n"; out << "if (" << result_value << " != nullptr) {\n"; out.indent(); out << result_value << "->incStrong(" << result_value << ".get());\n"; out << result_msg << "->set_hidl_interface_pointer(" << "reinterpret_cast(" << result_value << ".get()));\n"; out.unindent(); out << "} else {\n"; out.indent(); out << result_msg << "->set_hidl_interface_pointer(0);\n"; out.unindent(); out << "}\n"; break; } case TYPE_HIDL_MEMORY: { out << result_msg << "->set_type(TYPE_HIDL_MEMORY);\n"; out << result_msg << "->mutable_hidl_memory_value()->set_hidl_mem_address" << "(reinterpret_cast(new android::hardware::hidl_memory(" << result_value << ")));\n"; break; } case TYPE_POINTER: { out << result_msg << "->set_type(TYPE_POINTER);\n"; out << "LOG(ERROR) << \"TYPE_POINTER is not supported yet. \";\n"; break; } case TYPE_FMQ_SYNC: case TYPE_FMQ_UNSYNC: { out << result_msg << "->set_type(" << (val.type() == TYPE_FMQ_SYNC ? "TYPE_FMQ_SYNC" : "TYPE_FMQ_UNSYNC") << ");\n"; string item_name = result_msg + "_item"; out << "VariableSpecificationMessage* " << item_name << " = " << result_msg << "->add_fmq_value();\n"; if (val.fmq_value(0).type() == TYPE_SCALAR) { // This FMQ uses scalar type, stores type name in // scalar_type field. out << item_name << "->set_type(TYPE_SCALAR);\n"; out << item_name << "->set_scalar_type(\"" << val.fmq_value(0).scalar_type() << "\");\n"; } else if (val.fmq_value(0).type() == TYPE_ENUM) { // This FMQ uses enum type, stores type name in // predefined_type field. out << item_name << "->set_type(TYPE_ENUM);\n"; out << item_name << "->set_predefined_type(\"" << val.fmq_value(0).predefined_type() << "\");\n"; } else if (val.fmq_value(0).type() == TYPE_STRUCT) { // This FMQ uses struct type, stores type name in // predefined_type field. out << item_name << "->set_type(TYPE_STRUCT);\n"; out << item_name << "->set_predefined_type(\"" << val.fmq_value(0).predefined_type() << "\");\n"; } else if (val.fmq_value(0).type() == TYPE_UNION) { // This FMQ uses union type, stores type name in // predefined_type field. out << item_name << "->set_type(TYPE_UNION);\n"; out << item_name << "->set_predefined_type(\"" << val.fmq_value(0).predefined_type() << "\");\n"; } else { // FMQ doesn't support string, vector, or array type. out << "LOG(ERROR) << \"Unsupport type of data in FMQ\";\n"; } // Cast result into address, and save it in proto. out << item_name << "->set_fmq_desc_address(" << "reinterpret_cast(new (std::nothrow) " << GetCppVariableType(val) << "(" << result_value << ")));\n"; break; } case TYPE_REF: { out << result_msg << "->set_type(TYPE_REF);\n"; out << "LOG(ERROR) << \"TYPE_REF is not supported yet. \";\n"; break; } case TYPE_SAFE_UNION: { out << result_msg << "->set_type(TYPE_SAFE_UNION);\n"; out << "LOG(ERROR) << \"TYPE_SAFE_UNION is not supported yet. \";\n"; break; } default: { cerr << __func__ << " ERROR: unsupported type " << val.type() << ".\n"; exit(-1); } } } void HalHidlCodeGen::GenerateSetResultDeclForAttribute(Formatter& out, const VariableSpecificationMessage& attribute) { if (attribute.type() == TYPE_STRUCT || attribute.type() == TYPE_UNION || attribute.type() == TYPE_SAFE_UNION) { // Recursively generate SetResult method implementation for all sub_types. for (const auto& sub_struct : attribute.sub_struct()) { GenerateSetResultDeclForAttribute(out, sub_struct); } for (const auto& sub_union : attribute.sub_union()) { GenerateSetResultDeclForAttribute(out, sub_union); } for (const auto& sub_safe_union : attribute.sub_safe_union()) { GenerateSetResultDeclForAttribute(out, sub_safe_union); } } // Add extern C to allow resource_manager to dynamically load this function. out << "extern \"C\" "; string func_name = "void SetResult" + ClearStringWithNameSpaceAccess(attribute.name()); out << func_name << "(VariableSpecificationMessage* result_msg, " << attribute.name() << " result_value);\n"; } void HalHidlCodeGen::GenerateSetResultImplForAttribute(Formatter& out, const VariableSpecificationMessage& attribute) { if (attribute.type() == TYPE_STRUCT || attribute.type() == TYPE_UNION || attribute.type() == TYPE_SAFE_UNION) { // Recursively generate SetResult method implementation for all sub_types. for (const auto& sub_struct : attribute.sub_struct()) { GenerateSetResultImplForAttribute(out, sub_struct); } for (const auto& sub_union : attribute.sub_union()) { GenerateSetResultImplForAttribute(out, sub_union); } for (const auto& sub_safe_union : attribute.sub_safe_union()) { GenerateSetResultImplForAttribute(out, sub_safe_union); } } // Add extern C to allow resource_manager to dynamically load this function. out << "extern \"C\" "; string func_name = "void SetResult" + ClearStringWithNameSpaceAccess(attribute.name()); out << func_name << "(VariableSpecificationMessage* result_msg, " << attribute.name() << " result_value __attribute__((__unused__))){\n"; out.indent(); GenerateSetResultCodeForTypedVariable(out, attribute, "result_msg", "result_value"); out.unindent(); out << "}\n\n"; } void HalHidlCodeGen::GenerateDefaultReturnValForTypedVariable( Formatter& out, const VariableSpecificationMessage& val) { switch (val.type()) { case TYPE_SCALAR: { out << "static_cast<" << GetCppVariableType(val.scalar_type()) << ">(0)"; break; } case TYPE_MASK: { out << "static_cast<" << GetCppVariableType(val.scalar_type()) << ">(" << val.predefined_type() << "())"; break; } case TYPE_HIDL_CALLBACK: case TYPE_HIDL_INTERFACE: case TYPE_POINTER: case TYPE_REF: { out << "nullptr"; break; } case TYPE_STRING: case TYPE_ENUM: case TYPE_VECTOR: case TYPE_ARRAY: case TYPE_STRUCT: case TYPE_UNION: case TYPE_SAFE_UNION: case TYPE_HANDLE: case TYPE_HIDL_MEMORY: case TYPE_FMQ_SYNC: case TYPE_FMQ_UNSYNC: { out << GetCppVariableType(val) << "()"; break; } default: { cerr << __func__ << " ERROR: unsupported type " << val.type() << ".\n"; exit(-1); } } } void HalHidlCodeGen::GenerateAllFunctionDeclForAttribute(Formatter& out, const VariableSpecificationMessage& attribute) { GenerateDriverDeclForAttribute(out, attribute); GenerateRandomFunctionDeclForAttribute(out, attribute); GenerateVerificationDeclForAttribute(out, attribute); GenerateSetResultDeclForAttribute(out, attribute); } void HalHidlCodeGen::GenerateAllFunctionImplForAttribute(Formatter& out, const VariableSpecificationMessage& attribute) { GenerateDriverImplForAttribute(out, attribute); GenerateRandomFunctionImplForAttribute(out, attribute); GenerateVerificationImplForAttribute(out, attribute); GenerateSetResultImplForAttribute(out, attribute); } bool HalHidlCodeGen::CanElideCallback( const FunctionSpecificationMessage& func_msg) { // Can't elide callback for void or tuple-returning methods if (func_msg.return_type_hidl_size() != 1) { return false; } const VariableType& type = func_msg.return_type_hidl(0).type(); if (type == TYPE_ARRAY || type == TYPE_VECTOR || type == TYPE_REF) { return false; } return IsElidableType(type); } } // namespace vts } // namespace android