/* * Copyright (C) 2022, 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 "generate_cpp_analyzer.h" #include #include "aidl.h" #include "aidl_language.h" #include "aidl_to_common.h" #include "aidl_to_cpp.h" #include "code_writer.h" #include "logging.h" using std::string; using std::unique_ptr; namespace android { namespace aidl { namespace cpp { namespace { const char kAndroidStatusVarName[] = "_aidl_ret_status"; const char kReturnVarName[] = "_aidl_return"; const char kDataVarName[] = "_aidl_data"; const char kReplyVarName[] = "_aidl_reply"; void GenerateAnalyzerTransaction(CodeWriter& out, const AidlInterface& interface, const AidlMethod& method, const AidlTypenames& typenames, const Options& options) { // Reading past the interface descriptor and reply binder status out << "_aidl_ret_status = ::android::OK;\n"; out.Write("if (!(%s.enforceInterface(android::String16(\"%s\")))) {\n", kDataVarName, interface.GetDescriptor().c_str()); out.Write(" %s = ::android::BAD_TYPE;\n", kAndroidStatusVarName); out << " std::cout << \" Failure: Parcel interface does not match.\" << std::endl;\n" << " break;\n" << "}\n"; // Declare parameters for (const unique_ptr& a : method.GetArguments()) { out.Write("%s %s;\n", CppNameOf(a->GetType(), typenames).c_str(), BuildVarName(*a).c_str()); } out << "::android::binder::Status binderStatus;\n"; // Declare and read the return value. // Read past the binder status. out.Write("binderStatus.readFromParcel(%s);\n", kReplyVarName); if (method.GetType().GetName() != "void") { out.Write("%s %s;\n", CppNameOf(method.GetType(), typenames).c_str(), kReturnVarName); out.Write("bool returnError = false;\n"); } // Read Reply if (method.GetType().GetName() != "void") { out.Write("%s = %s.%s(%s);\n", kAndroidStatusVarName, kReplyVarName, ParcelReadMethodOf(method.GetType(), typenames).c_str(), ParcelReadCastOf(method.GetType(), typenames, string("&") + kReturnVarName).c_str()); out.Write("if (((%s) != (android::NO_ERROR))) {\n", kAndroidStatusVarName); out.Indent(); out.Write( "std::cerr << \"Failure: error in reading return value from Parcel.\" << std::endl;\n"); out.Write("returnError = true;\n"); out.Dedent(); out.Write("}\n"); } // Reading arguments out << "do { // Single-pass loop to break if argument reading fails\n"; out.Indent(); for (const auto& a : method.GetArguments()) { out.Write("%s = %s.%s(%s);\n", kAndroidStatusVarName, kDataVarName, ParcelReadMethodOf(a->GetType(), typenames).c_str(), ParcelReadCastOf(a->GetType(), typenames, "&" + BuildVarName(*a)).c_str()); out.Write("if (((%s) != (android::NO_ERROR))) {\n", kAndroidStatusVarName); out.Indent(); out.Write("std::cerr << \"Failure: error in reading argument %s from Parcel.\" << std::endl;\n", a->GetName().c_str()); out.Dedent(); out.Write(" break;\n}\n"); } out.Dedent(); out << "} while(false);\n"; if (!method.GetArguments().empty() && options.GetMinSdkVersion() >= SDK_VERSION_Tiramisu) { out.Write( "if (!%s.enforceNoDataAvail().isOk()) {\n %s = android::BAD_VALUE;\n std::cout << \" " "Failure: Parcel has too much data.\" << std::endl;\n break;\n}\n", kDataVarName, kAndroidStatusVarName); } // Arguments out.Write("std::cout << \" arguments: \" << std::endl;\n"); for (const auto& a : method.GetArguments()) { out.Write( "std::cout << \" %s: \" << ::android::internal::ToString(%s) " "<< std::endl;\n", a->GetName().c_str(), BuildVarName(*a).c_str()); } // Return Value if (method.GetType().GetName() != "void") { out.Write("if (returnError) {\n"); out.Indent(); out.Write("std::cout << \" return: \" << std::endl;\n"); out.Dedent(); out.Write("} else {"); out.Indent(); out.Write("std::cout << \" return: \" << ::android::internal::ToString(%s) << std::endl;\n", kReturnVarName); out.Dedent(); out.Write("}\n"); } else { out.Write("std::cout << \" return: void\" << std::endl;\n"); } } void GenerateAnalyzerSource(CodeWriter& out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options) { auto interface = AidlCast(defined_type); string q_name = GetQualifiedName(*interface, ClassNames::INTERFACE); string canonicalName = defined_type.GetCanonicalName(); string interfaceName = defined_type.GetName(); // Includes vector include_list{ "iostream", "binder/Parcel.h", "android/binder_to_string.h", HeaderFile(*interface, ClassNames::RAW, false), // HeaderFile(*interface, ClassNames::INTERFACE, false), }; for (const auto& include : include_list) { out << "#include <" << include << ">\n"; } out << "namespace {\n"; // Function Start out.Write( "android::status_t analyze%s(uint32_t _aidl_code, const android::Parcel& %s, const " "android::Parcel& %s) {\n", q_name.c_str(), kDataVarName, kReplyVarName); out.Indent(); out.Write("android::status_t %s;\nswitch(_aidl_code) {\n", kAndroidStatusVarName); out.Indent(); // Main Switch Statement for (const auto& method : interface->GetMethods()) { out.Write("case ::android::IBinder::FIRST_CALL_TRANSACTION + %d:\n{\n", (method->GetId())); out.Indent(); out.Write("std::cout << \"%s.%s()\" << std::endl;\n", interfaceName.c_str(), method->GetName().c_str()); GenerateAnalyzerTransaction(out, *interface, *method, typenames, options); out.Dedent(); out << "}\n"; out << "break;\n"; } out << "default:\n{\n std::cout << \" Transaction code \" << _aidl_code << \" not known.\" << " "std::endl;\n"; out.Write("%s = android::UNKNOWN_TRANSACTION;\n}\n", kAndroidStatusVarName); out.Dedent(); out.Write("}\nreturn %s;\n", kAndroidStatusVarName); out << "// To prevent unused variable warnings\n"; out.Write("(void)%s; (void)%s; (void)%s;\n", kAndroidStatusVarName, kDataVarName, kReplyVarName); out.Dedent(); out << "}\n\n} // namespace\n"; out << "\n#include \nusing android::aidl::Analyzer;\n"; out.Write( "__attribute__((constructor)) static void addAnalyzer() {\n" " Analyzer::installAnalyzer(std::make_unique(\"%s\", \"%s\", &analyze%s));\n}\n", canonicalName.c_str(), interfaceName.c_str(), q_name.c_str()); } void GenerateAnalyzerPlaceholder(CodeWriter& out, const AidlDefinedType& /*defined_type*/, const AidlTypenames& /*typenames*/, const Options& /*options*/) { out << "// This file is intentionally left blank as placeholder for building an analyzer.\n"; } } // namespace bool GenerateCppAnalyzer(const string& output_file, const Options& options, const AidlTypenames& typenames, const AidlDefinedType& defined_type, const IoDelegate& io_delegate) { if (!ValidateOutputFilePath(output_file, options, defined_type)) { return false; } using GenFn = void (*)(CodeWriter & out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options); auto gen = [&](auto file, GenFn fn) { unique_ptr writer(io_delegate.GetCodeWriter(file)); GenerateAutoGenHeader(*writer, options); fn(*writer, defined_type, typenames, options); AIDL_FATAL_IF(!writer->Close(), defined_type) << "I/O Error!"; return true; }; if (AidlCast(defined_type)) { return gen(output_file, &GenerateAnalyzerSource); } else { return gen(output_file, &GenerateAnalyzerPlaceholder); } } } // namespace cpp } // namespace aidl } // namespace android