217 lines
8.3 KiB
C++
217 lines
8.3 KiB
C++
/*
|
|
* 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
|