aboutsummaryrefslogtreecommitdiff
path: root/generate_cpp_analyzer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'generate_cpp_analyzer.cpp')
-rw-r--r--generate_cpp_analyzer.cpp216
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