diff options
Diffstat (limited to 'generate_cpp_analyzer.cpp')
-rw-r--r-- | generate_cpp_analyzer.cpp | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/generate_cpp_analyzer.cpp b/generate_cpp_analyzer.cpp new file mode 100644 index 00000000..36fc0434 --- /dev/null +++ b/generate_cpp_analyzer.cpp @@ -0,0 +1,216 @@ +/* + * 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 <string> +#include "aidl.h" +#include "aidl_language.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<AidlArgument>& 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: <error>\" << 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<AidlInterface>(defined_type); + string q_name = GetQualifiedName(*interface, ClassNames::INTERFACE); + + string canonicalName = defined_type.GetCanonicalName(); + string interfaceName = defined_type.GetName(); + + // Includes + vector<string> 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 <Analyzer.h>\nusing android::aidl::Analyzer;\n"; + out.Write( + "__attribute__((constructor)) static void addAnalyzer() {\n" + " Analyzer::installAnalyzer(std::make_unique<Analyzer>(\"%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<CodeWriter> writer(io_delegate.GetCodeWriter(file)); + fn(*writer, defined_type, typenames, options); + AIDL_FATAL_IF(!writer->Close(), defined_type) << "I/O Error!"; + return true; + }; + + if (AidlCast<AidlInterface>(defined_type)) { + return gen(output_file, &GenerateAnalyzerSource); + } else { + return gen(output_file, &GenerateAnalyzerPlaceholder); + } +} + +} // namespace cpp +} // namespace aidl +} // namespace android |