diff options
author | Luke Huang <huangluke@google.com> | 2019-05-09 11:48:12 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-05-09 11:48:12 +0000 |
commit | 1844e2f3dc98ec3dc1fa46d4db594865891163e4 (patch) | |
tree | e8d4be599a6ae43f524387077a2057ed1304b3d6 | |
parent | e308abd33006e46fc978ff7881bf43222afbca95 (diff) | |
parent | ba72499d84f4eec3bdc1ad725dc47179c4bf16f6 (diff) | |
download | aidl-1844e2f3dc98ec3dc1fa46d4db594865891163e4.tar.gz |
Merge changes from topic "b/126501406" into qt-dev
* changes:
AIDL NDK logger bugfix
Log supporting for binder ndk
-rw-r--r-- | Android.bp | 13 | ||||
-rw-r--r-- | aidl_to_cpp.cpp | 113 | ||||
-rw-r--r-- | aidl_to_cpp.h | 4 | ||||
-rw-r--r-- | aidl_to_cpp_common.cpp | 270 | ||||
-rw-r--r-- | aidl_to_cpp_common.h | 6 | ||||
-rw-r--r-- | build/aidl_interface.go | 16 | ||||
-rw-r--r-- | build/properties.go | 1 | ||||
-rw-r--r-- | generate_cpp.cpp | 152 | ||||
-rw-r--r-- | generate_ndk.cpp | 67 | ||||
-rw-r--r-- | options.cpp | 4 | ||||
-rw-r--r-- | tests/android/aidl/loggable/ILoggableInterfaceNdk.aidl | 14 |
11 files changed, 381 insertions, 279 deletions
@@ -251,3 +251,16 @@ aidl_interface { }, }, } + +aidl_interface { + name: "aidl_test_loggable_interface_ndk", + local_include_dir: "tests", + srcs: [ + "tests/android/aidl/loggable/ILoggableInterfaceNdk.aidl", + ], + backend: { + ndk: { + gen_log: true, + }, + }, +}
\ No newline at end of file diff --git a/aidl_to_cpp.cpp b/aidl_to_cpp.cpp index d5a9f025..61917e99 100644 --- a/aidl_to_cpp.cpp +++ b/aidl_to_cpp.cpp @@ -35,119 +35,6 @@ std::string ConstantValueDecorator(const AidlTypeSpecifier& type, const std::str return raw_value; }; -struct TypeInfo { - // name of the type in C++ output - std::string cpp_name; - - // function that writes an expression to convert a variable to a Json::Value - // object - std::function<void(const CodeGeneratorContext& c, const string& var_name)> toJsonValueExpr; -}; - -const static std::unordered_map<std::string, TypeInfo> kTypeInfoMap = { - {"void", {"void", nullptr}}, - {"boolean", - { - "bool", - [](const CodeGeneratorContext& c, const string& var_name) { - c.writer << "Json::Value(" << var_name << "? \"true\" : \"false\")"; - }, - }}, - {"byte", - { - "int8_t", - [](const CodeGeneratorContext& c, const string& var_name) { - c.writer << "Json::Value(" << var_name << ")"; - }, - }}, - {"char", - { - "char16_t", - [](const CodeGeneratorContext& c, const string& var_name) { - c.writer << "Json::Value(std::string(android::String8(&" << var_name << ", 1)))"; - }, - }}, - {"int", - { - "int32_t", - [](const CodeGeneratorContext& c, const string& var_name) { - c.writer << "Json::Value(" << var_name << ")"; - }, - }}, - {"long", - { - "int64_t", - [](const CodeGeneratorContext& c, const string& var_name) { - c.writer << "Json::Value(static_cast<Json::Int64>(" << var_name << "))"; - }, - }}, - {"float", - { - "float", - [](const CodeGeneratorContext& c, const string& var_name) { - c.writer << "Json::Value(" << var_name << ")"; - }, - }}, - {"double", - { - "double", - [](const CodeGeneratorContext& c, const string& var_name) { - c.writer << "Json::Value(" << var_name << ")"; - }, - }}, - {"String", - { - "std::string", - [](const CodeGeneratorContext& c, const string& var_name) { - c.writer << "Json::Value(" << var_name << ")"; - }, - }} - // missing List, Map, ParcelFileDescriptor, IBinder -}; - -TypeInfo GetTypeInfo(const AidlTypeSpecifier& aidl) { - CHECK(aidl.IsResolved()) << aidl.ToString(); - const string& aidl_name = aidl.GetName(); - - TypeInfo info; - if (AidlTypenames::IsBuiltinTypename(aidl_name)) { - auto it = kTypeInfoMap.find(aidl_name); - if (it != kTypeInfoMap.end()) { - info = it->second; - } - } - // Missing interface and parcelable type - return info; -} - -inline bool CanWriteLog(const TypeInfo& t) { - return t.cpp_name != ""; -} - -bool CanWriteLog(const AidlTypeSpecifier& aidl) { - return CanWriteLog(GetTypeInfo(aidl)); -} - -void WriteLogFor(const CodeGeneratorContext& c) { - const TypeInfo info = GetTypeInfo(c.type); - if (!CanWriteLog(info)) { - return; - } - - const string var_object_expr = ((c.isPointer ? "*" : "")) + c.name; - if (c.type.IsArray()) { - c.writer << c.log << " = Json::Value(Json::arrayValue);\n"; - c.writer << "for (const auto& v: " << var_object_expr << ") " << c.log << ".append("; - info.toJsonValueExpr(c, "v"); - c.writer << ");"; - } else { - c.writer << c.log << " = "; - info.toJsonValueExpr(c, var_object_expr); - c.writer << ";"; - } - c.writer << "\n"; -} - std::string GetTransactionIdFor(const AidlMethod& method) { ostringstream output; diff --git a/aidl_to_cpp.h b/aidl_to_cpp.h index ca5a6cd0..5c936c9b 100644 --- a/aidl_to_cpp.h +++ b/aidl_to_cpp.h @@ -35,10 +35,6 @@ struct CodeGeneratorContext { const string log; // name of the variable of type Json::Value to write the log into }; -// Emits code that writes name and value of an argument or the return value to -// the Json object -void WriteLogFor(const CodeGeneratorContext& c); -bool CanWriteLog(const AidlTypeSpecifier& aidl); std::string GetTransactionIdFor(const AidlMethod& method); } // namespace cpp } // namespace aidl diff --git a/aidl_to_cpp_common.cpp b/aidl_to_cpp_common.cpp index 9dbcadd0..89783110 100644 --- a/aidl_to_cpp_common.cpp +++ b/aidl_to_cpp_common.cpp @@ -14,8 +14,10 @@ * limitations under the License. */ -#include "aidl_to_cpp_common.h" +#include <unordered_map> +#include "aidl_to_cpp_common.h" +#include "logging.h" #include "os.h" namespace android { @@ -84,6 +86,272 @@ string BuildVarName(const AidlArgument& a) { return prefix + a.GetName(); } +struct TypeInfo { + // name of the type in C++ output + std::string cpp_name; + + // function that writes an expression to convert a variable to a Json::Value + // object + std::function<void(CodeWriter& w, const string& var_name, bool isNdk)> toJsonValueExpr; +}; + +const static std::unordered_map<std::string, TypeInfo> kTypeInfoMap = { + {"void", {"void", nullptr}}, + {"boolean", + { + "bool", + [](CodeWriter& c, const string& var_name, bool) { + c << "Json::Value(" << var_name << "? \"true\" : \"false\")"; + }, + }}, + {"byte", + { + "int8_t", + [](CodeWriter& c, const string& var_name, bool) { + c << "Json::Value(" << var_name << ")"; + }, + }}, + {"char", + { + "char16_t", + [](CodeWriter& c, const string& var_name, bool isNdk) { + if (isNdk) { + c << "Json::Value(" << var_name << ")"; + } else { + c << "Json::Value(std::string(android::String8(&" << var_name << ", 1)))"; + } + }, + }}, + {"int", + { + "int32_t", + [](CodeWriter& c, const string& var_name, bool) { + c << "Json::Value(" << var_name << ")"; + }, + }}, + {"long", + { + "int64_t", + [](CodeWriter& c, const string& var_name, bool) { + c << "Json::Value(static_cast<Json::Int64>(" << var_name << "))"; + }, + }}, + {"float", + { + "float", + [](CodeWriter& c, const string& var_name, bool) { + c << "Json::Value(" << var_name << ")"; + }, + }}, + {"double", + { + "double", + [](CodeWriter& c, const string& var_name, bool) { + c << "Json::Value(" << var_name << ")"; + }, + }}, + {"String", + { + "std::string", + [](CodeWriter& c, const string& var_name, bool) { + c << "Json::Value(" << var_name << ")"; + }, + }} + // missing List, Map, ParcelFileDescriptor, IBinder +}; + +TypeInfo GetTypeInfo(const AidlTypeSpecifier& aidl) { + CHECK(aidl.IsResolved()) << aidl.ToString(); + const string& aidl_name = aidl.GetName(); + + TypeInfo info; + if (AidlTypenames::IsBuiltinTypename(aidl_name)) { + auto it = kTypeInfoMap.find(aidl_name); + if (it != kTypeInfoMap.end()) { + info = it->second; + } + } + // Missing interface and parcelable type + return info; +} + +inline bool CanWriteLog(const TypeInfo& t) { + return t.cpp_name != ""; +} + +bool CanWriteLog(const AidlTypeSpecifier& aidl) { + return CanWriteLog(GetTypeInfo(aidl)); +} + +void WriteLogFor(CodeWriter& writer, const AidlTypeSpecifier& type, const std::string& name, + bool isPointer, const std::string& log, bool isNdk) { + const TypeInfo info = GetTypeInfo(type); + if (!CanWriteLog(info)) { + return; + } + + const string var_object_expr = ((isPointer ? "*" : "")) + name; + if (type.IsArray()) { + writer << log << " = Json::Value(Json::arrayValue);\n"; + writer << "for (const auto& v: " << var_object_expr << ") " << log << ".append("; + info.toJsonValueExpr(writer, "v", isNdk); + writer << ");"; + } else { + writer << log << " = "; + info.toJsonValueExpr(writer, var_object_expr, isNdk); + writer << ";"; + } + writer << "\n"; +} + +void WriteLogForArguments(CodeWriterPtr& writer, const AidlArgument& a, bool isServer, + string logVarName, bool isNdk) { + if (!CanWriteLog(a.GetType())) { + return; + } + string logElementVarName = "_log_arg_element"; + (*writer) << "{\n"; + (*writer).Indent(); + (*writer) << "Json::Value " << logElementVarName << "(Json::objectValue);\n"; + string varName = isServer || isNdk ? BuildVarName(a) : a.GetName(); + (*writer) << logElementVarName << "[\"name\"] = \"" << varName << "\";\n"; + + bool isPointer = a.IsOut() && !isServer; + WriteLogFor(*(writer.get()), a.GetType(), varName, isPointer, logElementVarName + "[\"value\"]", + isNdk); + (*writer) << logVarName << ".append(" << logElementVarName << ");\n"; + (*writer) << "}\n"; + (*writer).Dedent(); +} + +const string GenLogBeforeExecute(const string className, const AidlMethod& method, bool isServer, + bool isNdk) { + string code; + CodeWriterPtr writer = CodeWriter::ForString(&code); + (*writer) << "Json::Value _log_input_args(Json::arrayValue);\n"; + + (*writer) << "if (" << className << "::logFunc != nullptr) {\n"; + (*writer).Indent(); + + for (const auto& a : method.GetArguments()) { + if (a->IsIn()) { + WriteLogForArguments(writer, *a, isServer, "_log_input_args", isNdk); + } + } + + (*writer).Dedent(); + (*writer) << "}\n"; + + (*writer) << "auto _log_start = std::chrono::steady_clock::now();\n"; + writer->Close(); + return code; +} + +const string GenLogAfterExecute(const string className, const AidlInterface& interface, + const AidlMethod& method, const string& statusVarName, + const string& returnVarName, bool isServer, bool isNdk) { + string code; + CodeWriterPtr writer = CodeWriter::ForString(&code); + + (*writer) << "if (" << className << "::logFunc != nullptr) {\n"; + (*writer).Indent(); + + // Write the log as a Json object. For example, + // + // Json log object for following interface description + // + // package foo.bar; + // interface IFoo { + // String TestMethod(int arg1, inout String[] arg2, out double arg3); + // } + // + // would be: + // + // { + // duration_ms: 100.42, + // interface_name: "foo.bar.IFoo", + // method_name: "TestMethod", + // (proxy|stub)_address: "0x12345678", + // input_args: [ + // {name: "arg1", value: 30,}, + // {name: "arg2", value: ["apple", "grape"],}, + // ], + // output_args: [ + // {name: "arg2", value: ["mango", "banana"],}, + // {name: "arg3", value: "10.5",}, + // ], + // _aidl_return: "ok", + // binder_status: { + // exception_code: -8, + // exception_message: "Something wrong", + // transaction_error: 0, + // service_specific_error_code: -42, + // }, + // } + (*writer) << "auto _log_end = std::chrono::steady_clock::now();\n"; + (*writer) << "Json::Value _log_transaction(Json::objectValue);\n"; + (*writer) << "_log_transaction[\"duration_ms\"] = " + << "std::chrono::duration<double, std::milli>(_log_end - " + "_log_start).count();\n"; + (*writer) << "_log_transaction[\"interface_name\"] = " + << "Json::Value(\"" << interface.GetCanonicalName() << "\");\n"; + (*writer) << "_log_transaction[\"method_name\"] = " + << "Json::Value(\"" << method.GetName() << "\");\n"; + + (*writer) << "_log_transaction[\"" << (isServer ? "stub_address" : "proxy_address") << "\"] = "; + (*writer) << "Json::Value(" + << "(std::ostringstream() << " + << (isNdk && isServer ? "_aidl_impl" : "static_cast<const void*>(this)") << ").str()" + << ");\n"; + (*writer) << "_log_transaction[\"input_args\"] = _log_input_args;\n"; + (*writer) << "Json::Value _log_output_args(Json::arrayValue);\n"; + + (*writer) << "Json::Value _log_status(Json::objectValue);\n"; + if (isNdk) { + (*writer) << "_log_status[\"exception_code\"] = Json::Value(AStatus_getExceptionCode(" + << statusVarName << ".get()));\n"; + (*writer) << "_log_status[\"exception_message\"] = Json::Value(AStatus_getMessage(" + << statusVarName << ".get()));\n"; + (*writer) << "_log_status[\"transaction_error\"] = Json::Value(AStatus_getStatus(" + << statusVarName << ".get()));\n"; + (*writer) << "_log_status[\"service_specific_error_code\"] = " + "Json::Value(AStatus_getServiceSpecificError(" + << statusVarName << ".get()));\n"; + } else { + (*writer) << "_log_status[\"exception_code\"] = Json::Value(" << statusVarName + << ".exceptionCode());\n"; + (*writer) << "_log_status[\"exception_message\"] = Json::Value(" << statusVarName + << ".exceptionMessage());\n"; + (*writer) << "_log_status[\"transaction_error\"] = Json::Value(" << statusVarName + << ".transactionError());\n"; + (*writer) << "_log_status[\"service_specific_error_code\"] = Json::Value(" << statusVarName + << ".serviceSpecificErrorCode());\n"; + } + + (*writer) << "_log_transaction[\"binder_status\"] = _log_status;\n"; + + for (const auto& a : method.GetOutArguments()) { + WriteLogForArguments(writer, *a, isServer, "_log_output_args", isNdk); + } + + (*writer) << "_log_transaction[\"output_args\"] = _log_output_args;\n"; + + if (method.GetType().GetName() != "void") { + WriteLogFor(*(writer.get()), method.GetType(), returnVarName, !isServer, + "_log_transaction[\"" + returnVarName + "\"]", isNdk); + } + + // call the user-provided function with the Json object for the entire + // transaction + (*writer) << className << "::logFunc(_log_transaction);\n"; + + (*writer).Dedent(); + (*writer) << "}\n"; + + writer->Close(); + return code; +} + } // namespace cpp } // namespace aidl } // namespace android diff --git a/aidl_to_cpp_common.h b/aidl_to_cpp_common.h index 3a6e2e60..381a8c96 100644 --- a/aidl_to_cpp_common.h +++ b/aidl_to_cpp_common.h @@ -49,7 +49,11 @@ void EnterNamespace(CodeWriter& out, const AidlDefinedType& defined_type); void LeaveNamespace(CodeWriter& out, const AidlDefinedType& defined_type); string BuildVarName(const AidlArgument& a); - +const string GenLogBeforeExecute(const string className, const AidlMethod& method, bool isServer, + bool isNdk); +const string GenLogAfterExecute(const string className, const AidlInterface& interface, + const AidlMethod& method, const string& statusVarName, + const string& returnVarName, bool isServer, bool isNdk); } // namespace cpp } // namespace aidl } // namespace android diff --git a/build/aidl_interface.go b/build/aidl_interface.go index 89594d23..dcda58f2 100644 --- a/build/aidl_interface.go +++ b/build/aidl_interface.go @@ -559,6 +559,10 @@ type aidlInterfaceProperties struct { // Whether to generate C++ code using NDK binder APIs // Default: true Enabled *bool + // Whether to generate additional code for gathering information + // about the transactions + // Default: false + Gen_log *bool } } } @@ -751,6 +755,8 @@ func addCppLibrary(mctx android.LoadHookContext, i *aidlInterface, version strin genLog := false if lang == langCpp { genLog = proptools.Bool(i.properties.Backend.Cpp.Gen_log) + } else if lang == langNdk || lang == langNdkPlatform { + genLog = proptools.Bool(i.properties.Backend.Ndk.Gen_log) } mctx.CreateModule(android.ModuleFactoryAdaptor(aidlGenFactory), &nameProperties{ @@ -767,25 +773,30 @@ func addCppLibrary(mctx android.LoadHookContext, i *aidlInterface, version strin importExportDependencies := wrap("", i.properties.Imports, "-"+lang) var libJSONCppDependency []string + var staticLibDependency []string var sdkVersion *string var stl *string var cpp_std *string - if lang == langCpp { importExportDependencies = append(importExportDependencies, "libbinder", "libutils") if genLog { libJSONCppDependency = []string{"libjsoncpp"} - importExportDependencies = append(importExportDependencies, "libbase") } sdkVersion = nil stl = nil cpp_std = nil } else if lang == langNdk { importExportDependencies = append(importExportDependencies, "libbinder_ndk") + if genLog { + staticLibDependency = []string{"libjsoncpp_ndk"} + } sdkVersion = proptools.StringPtr("current") stl = proptools.StringPtr("c++_shared") } else if lang == langNdkPlatform { importExportDependencies = append(importExportDependencies, "libbinder_ndk") + if genLog { + libJSONCppDependency = []string{"libjsoncpp"} + } } else { panic("Unrecognized language: " + lang) } @@ -800,6 +811,7 @@ func addCppLibrary(mctx android.LoadHookContext, i *aidlInterface, version strin Export_generated_headers: []string{cppSourceGen}, Static: staticLib{Whole_static_libs: libJSONCppDependency}, Shared: sharedLib{Shared_libs: libJSONCppDependency, Export_shared_lib_headers: libJSONCppDependency}, + Static_libs: staticLibDependency, Shared_libs: importExportDependencies, Export_shared_lib_headers: importExportDependencies, Sdk_version: sdkVersion, diff --git a/build/properties.go b/build/properties.go index 13f1705a..f0256b88 100644 --- a/build/properties.go +++ b/build/properties.go @@ -34,6 +34,7 @@ type ccProperties struct { Generated_headers []string Shared sharedLib Static staticLib + Static_libs []string Shared_libs []string Export_shared_lib_headers []string Export_generated_headers []string diff --git a/generate_cpp.cpp b/generate_cpp.cpp index 61552c1b..6d08eac7 100644 --- a/generate_cpp.cpp +++ b/generate_cpp.cpp @@ -225,140 +225,6 @@ string BuildHeaderGuard(const AidlDefinedType& defined_type, ClassNames header_t return ret; } -void WriteLogForArguments(CodeWriterPtr& writer, const AidlArgument& a, const TypeNamespace& types, - bool isServer, string logVarName) { - if (!CanWriteLog(a.GetType())) { - return; - } - string logElementVarName = "_log_arg_element"; - (*writer) << "{\n"; - (*writer).Indent(); - (*writer) << "Json::Value " << logElementVarName << "(Json::objectValue);\n"; - string varName = isServer ? BuildVarName(a) : a.GetName(); - (*writer) << logElementVarName << "[\"name\"] = \"" << varName << "\";\n"; - - bool isPointer = a.IsOut() && !isServer; - WriteLogFor({*(writer.get()), types.typenames_, a.GetType(), varName, isPointer, - logElementVarName + "[\"value\"]"}); - (*writer) << logVarName << ".append(" << logElementVarName << ");\n"; - (*writer) << "}\n"; - (*writer).Dedent(); -} - -const string GenLogBeforeExecute(const string className, const AidlMethod& method, - const TypeNamespace& types, bool isServer) { - string code; - CodeWriterPtr writer = CodeWriter::ForString(&code); - (*writer) << "Json::Value _log_input_args(Json::arrayValue);\n"; - - (*writer) << "if (" << className << "::logFunc != nullptr) {\n"; - (*writer).Indent(); - - for (const auto& a : method.GetArguments()) { - if (a->IsIn()) { - WriteLogForArguments(writer, *a, types, isServer, "_log_input_args"); - } - } - - (*writer).Dedent(); - (*writer) << "}\n"; - - (*writer) << "auto _log_start = std::chrono::steady_clock::now();\n"; - writer->Close(); - return code; -} - -const string GenLogAfterExecute(const string className, const AidlInterface& interface, - const AidlMethod& method, const TypeNamespace& types, - const string& statusVarName, const string& returnVarName, - bool isServer) { - string code; - CodeWriterPtr writer = CodeWriter::ForString(&code); - - (*writer) << "if (" << className << "::logFunc != nullptr) {\n"; - (*writer).Indent(); - - // Write the log as a Json object. For example, - // - // Json log object for following interface description - // - // package foo.bar; - // interface IFoo { - // String TestMethod(int arg1, inout String[] arg2, out double arg3); - // } - // - // would be: - // - // { - // duration_ms: 100.42, - // interface_name: "foo.bar.IFoo", - // method_name: "TestMethod", - // (proxy|stub)_address: "0x12345678", - // input_args: [ - // {name: "arg1", value: 30,}, - // {name: "arg2", value: ["apple", "grape"],}, - // ], - // output_args: [ - // {name: "arg2", value: ["mango", "banana"],}, - // {name: "arg3", value: "10.5",}, - // ], - // _aidl_return: "ok", - // binder_status: { - // exception_code: -8, - // exception_message: "Something wrong", - // transaction_error: 0, - // service_specific_error_code: -42, - // }, - // } - (*writer) << "auto _log_end = std::chrono::steady_clock::now();\n"; - (*writer) << "Json::Value _log_transaction(Json::objectValue);\n"; - (*writer) << "_log_transaction[\"duration_ms\"] = " - << "std::chrono::duration<double, std::milli>(_log_end - " - "_log_start).count();\n"; - (*writer) << "_log_transaction[\"interface_name\"] = " - << "Json::Value(\"" << interface.GetCanonicalName() << "\");\n"; - (*writer) << "_log_transaction[\"method_name\"] = " - << "Json::Value(\"" << method.GetName() << "\");\n"; - - (*writer) << "_log_transaction[\"" << (isServer ? "stub_address" : "proxy_address") << "\"] = " - << "Json::Value(android::base::StringPrintf(\"0x%%p\", this));\n"; - (*writer) << "_log_transaction[\"input_args\"] = _log_input_args;\n"; - (*writer) << "Json::Value _log_output_args(Json::arrayValue);\n"; - - (*writer) << "Json::Value _log_status(Json::objectValue);\n"; - (*writer) << "_log_status[\"exception_code\"] = Json::Value(" << statusVarName - << ".exceptionCode());\n"; - (*writer) << "_log_status[\"exception_message\"] = Json::Value(" << statusVarName - << ".exceptionMessage());\n"; - (*writer) << "_log_status[\"transaction_error\"] = Json::Value(" << statusVarName - << ".transactionError());\n"; - (*writer) << "_log_status[\"service_specific_error_code\"] = Json::Value(" << statusVarName - << ".serviceSpecificErrorCode());\n"; - - (*writer) << "_log_transaction[\"binder_status\"] = _log_status;\n"; - - for (const auto& a : method.GetOutArguments()) { - WriteLogForArguments(writer, *a, types, isServer, "_log_output_args"); - } - - (*writer) << "_log_transaction[\"output_args\"] = _log_output_args;\n"; - - if (method.GetType().GetName() != "void") { - WriteLogFor({*(writer.get()), types.typenames_, method.GetType(), returnVarName, !isServer, - "_log_transaction[\"" + returnVarName + "\"]"}); - } - - // call the user-provided function with the Json object for the entire - // transaction - (*writer) << className << "::logFunc(_log_transaction);\n"; - - (*writer).Dedent(); - (*writer) << "}\n"; - - writer->Close(); - return code; -} - unique_ptr<Declaration> DefineClientTransaction(const TypeNamespace& types, const AidlInterface& interface, const AidlMethod& method, const Options& options) { @@ -388,7 +254,8 @@ unique_ptr<Declaration> DefineClientTransaction(const TypeNamespace& types, } if (options.GenLog()) { - b->AddLiteral(GenLogBeforeExecute(bp_name, method, types, false), false /* no semicolon */); + b->AddLiteral(GenLogBeforeExecute(bp_name, method, false /* isServer */, false /* isNdk */), + false /* no semicolon */); } // Add the name of the interface we're hoping to call. @@ -517,8 +384,8 @@ unique_ptr<Declaration> DefineClientTransaction(const TypeNamespace& types, kAndroidStatusVarName)); if (options.GenLog()) { - b->AddLiteral(GenLogAfterExecute(bp_name, interface, method, types, kStatusVarName, - kReturnVarName, false), + b->AddLiteral(GenLogAfterExecute(bp_name, interface, method, kStatusVarName, kReturnVarName, + false /* isServer */, false /* isNdk */), false /* no semicolon */); } @@ -571,7 +438,6 @@ unique_ptr<Document> BuildClientSource(const TypeNamespace& types, const AidlInt include_list.emplace_back("chrono"); include_list.emplace_back("functional"); include_list.emplace_back("json/value.h"); - include_list.emplace_back("android-base/stringprintf.h"); } vector<unique_ptr<Declaration>> file_decls; @@ -675,7 +541,8 @@ bool HandleServerTransaction(const TypeNamespace& types, const AidlInterface& in } const string bn_name = ClassName(interface, ClassNames::SERVER); if (options.GenLog()) { - b->AddLiteral(GenLogBeforeExecute(bn_name, method, types, true), false); + b->AddLiteral(GenLogBeforeExecute(bn_name, method, true /* isServer */, false /* isNdk */), + false); } // Call the actual method. This is implemented by the subclass. vector<unique_ptr<AstNode>> status_args; @@ -692,9 +559,9 @@ bool HandleServerTransaction(const TypeNamespace& types, const AidlInterface& in } if (options.GenLog()) { - b->AddLiteral( - GenLogAfterExecute(bn_name, interface, method, types, kStatusVarName, kReturnVarName, true), - false); + b->AddLiteral(GenLogAfterExecute(bn_name, interface, method, kStatusVarName, kReturnVarName, + true /* isServer */, false /* isNdk */), + false); } // Write exceptions during transaction handling to parcel. @@ -766,7 +633,6 @@ unique_ptr<Document> BuildServerSource(const TypeNamespace& types, const AidlInt include_list.emplace_back("chrono"); include_list.emplace_back("functional"); include_list.emplace_back("json/value.h"); - include_list.emplace_back("android-base/stringprintf.h"); } unique_ptr<MethodImpl> on_transact{new MethodImpl{ kAndroidStatusLiteral, bn_name, "onTransact", diff --git a/generate_ndk.cpp b/generate_ndk.cpp index cafd794d..f0445f7a 100644 --- a/generate_ndk.cpp +++ b/generate_ndk.cpp @@ -233,9 +233,11 @@ static std::string MethodId(const AidlMethod& m) { return "(FIRST_CALL_TRANSACTION + " + std::to_string(m.GetId()) + " /*" + m.GetName() + "*/)"; } -static void GenerateClientMethodDefinition( - CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, - const AidlMethod& method, const std::optional<std::string> return_value_cached_to) { +static void GenerateClientMethodDefinition(CodeWriter& out, const AidlTypenames& types, + const AidlInterface& defined_type, + const AidlMethod& method, + const std::optional<std::string> return_value_cached_to, + const Options& options) { const std::string clazz = ClassName(defined_type, ClassNames::CLIENT); out << NdkMethodDecl(types, method, clazz) << " {\n"; @@ -256,6 +258,11 @@ static void GenerateClientMethodDefinition( out << "::ndk::ScopedAParcel _aidl_out;\n"; out << "\n"; + if (options.GenLog()) { + out << cpp::GenLogBeforeExecute(ClassName(defined_type, ClassNames::CLIENT), method, + false /* isServer */, true /* isNdk */); + } + out << "_aidl_ret_status = AIBinder_prepareTransaction(asBinder().get(), _aidl_in.getR());\n"; StatusCheckGoto(out); @@ -320,14 +327,19 @@ static void GenerateClientMethodDefinition( out << "_aidl_error:\n"; out << "_aidl_status.set(AStatus_fromStatus(_aidl_ret_status));\n"; + if (options.GenLog()) { + out << cpp::GenLogAfterExecute(ClassName(defined_type, ClassNames::CLIENT), defined_type, + method, "_aidl_status", "_aidl_return", false /* isServer */, + true /* isNdk */); + } out << "return _aidl_status;\n"; out.Dedent(); out << "}\n"; } static void GenerateServerCaseDefinition(CodeWriter& out, const AidlTypenames& types, - const AidlInterface& /*defined_type*/, - const AidlMethod& method) { + const AidlInterface& defined_type, + const AidlMethod& method, const Options& options) { out << "case " << MethodId(method) << ": {\n"; out.Indent(); for (const auto& arg : method.GetArguments()) { @@ -351,10 +363,18 @@ static void GenerateServerCaseDefinition(CodeWriter& out, const AidlTypenames& t out << "_aidl_ret_status = ::ndk::AParcel_resizeVector(_aidl_in, &" << var_name << ");\n"; } } - + if (options.GenLog()) { + out << cpp::GenLogBeforeExecute(ClassName(defined_type, ClassNames::SERVER), method, + true /* isServer */, true /* isNdk */); + } out << "::ndk::ScopedAStatus _aidl_status = _aidl_impl->" << method.GetName() << "(" << NdkArgList(types, method, FormatArgForCall) << ");\n"; + if (options.GenLog()) { + out << cpp::GenLogAfterExecute(ClassName(defined_type, ClassNames::SERVER), defined_type, + method, "_aidl_status", "_aidl_return", true /* isServer */, + true /* isNdk */); + } if (method.IsOneway()) { // For a oneway transaction, the kernel will have already returned a result. This is for the // in-process case when a oneway transaction is parceled/unparceled in the same process. @@ -378,14 +398,13 @@ static void GenerateServerCaseDefinition(CodeWriter& out, const AidlTypenames& t StatusCheckBreak(out); } } - out << "break;\n"; out.Dedent(); out << "}\n"; } void GenerateClassSource(CodeWriter& out, const AidlTypenames& types, - const AidlInterface& defined_type, const Options& /*options*/) { + const AidlInterface& defined_type, const Options& options) { const std::string clazz = ClassName(defined_type, ClassNames::INTERFACE); const std::string bn_clazz = ClassName(defined_type, ClassNames::SERVER); @@ -405,7 +424,7 @@ void GenerateClassSource(CodeWriter& out, const AidlTypenames& types, out << "switch (_aidl_code) {\n"; out.Indent(); for (const auto& method : defined_type.GetMethods()) { - GenerateServerCaseDefinition(out, types, defined_type, *method); + GenerateServerCaseDefinition(out, types, defined_type, *method, options); } out.Dedent(); out << "}\n"; @@ -426,6 +445,9 @@ void GenerateClientSource(CodeWriter& out, const AidlTypenames& types, out << clazz << "::" << clazz << "(const ::ndk::SpAIBinder& binder) : BpCInterface(binder) {}\n"; out << clazz << "::~" << clazz << "() {}\n"; + if (options.GenLog()) { + out << "std::function<void(const Json::Value&)> " << clazz << "::logFunc;\n"; + } out << "\n"; for (const auto& method : defined_type.GetMethods()) { // Only getInterfaceVersion can use cache. @@ -433,7 +455,8 @@ void GenerateClientSource(CodeWriter& out, const AidlTypenames& types, options.Version() > 0; const auto return_value_cached_to = cacheable ? std::make_optional<std::string>(kCacheVariable) : std::nullopt; - GenerateClientMethodDefinition(out, types, defined_type, *method, return_value_cached_to); + GenerateClientMethodDefinition(out, types, defined_type, *method, return_value_cached_to, + options); } } void GenerateServerSource(CodeWriter& out, const AidlTypenames& types, @@ -444,7 +467,9 @@ void GenerateServerSource(CodeWriter& out, const AidlTypenames& types, out << "// Source for " << clazz << "\n"; out << clazz << "::" << clazz << "() {}\n"; out << clazz << "::~" << clazz << "() {}\n"; - + if (options.GenLog()) { + out << "std::function<void(const Json::Value&)> " << clazz << "::logFunc;\n"; + } out << "::ndk::SpAIBinder " << clazz << "::createBinder() {\n"; out.Indent(); out << "AIBinder* binder = AIBinder_new(" << kClazz << ", static_cast<void*>(this));\n"; @@ -585,6 +610,12 @@ void GenerateClientHeader(CodeWriter& out, const AidlTypenames& types, << "\"\n"; out << "\n"; out << "#include <android/binder_ibinder.h>\n"; + if (options.GenLog()) { + out << "#include <json/value.h>\n"; + out << "#include <functional>\n"; + out << "#include <chrono>\n"; + out << "#include <sstream>\n"; + } out << "\n"; EnterNdkNamespace(out, defined_type); out << "class " << clazz << " : public ::ndk::BpCInterface<" @@ -601,7 +632,9 @@ void GenerateClientHeader(CodeWriter& out, const AidlTypenames& types, if (options.Version() > 0) { out << "int32_t " << kCacheVariable << " = -1;\n"; } - + if (options.GenLog()) { + out << "static std::function<void(const Json::Value&)> logFunc;\n"; + } out.Dedent(); out << "};\n"; LeaveNdkNamespace(out, defined_type); @@ -635,7 +668,9 @@ void GenerateServerHeader(CodeWriter& out, const AidlTypenames& types, AIDL_FATAL(defined_type) << "Meta method '" << method->GetName() << "' is unimplemented."; } } - + if (options.GenLog()) { + out << "static std::function<void(const Json::Value&)> logFunc;\n"; + } out.Dedent(); out << "protected:\n"; out.Indent(); @@ -653,6 +688,12 @@ void GenerateInterfaceHeader(CodeWriter& out, const AidlTypenames& types, out << "#pragma once\n\n"; out << "#include <android/binder_interface_utils.h>\n"; + if (options.GenLog()) { + out << "#include <json/value.h>\n"; + out << "#include <functional>\n"; + out << "#include <chrono>\n"; + out << "#include <sstream>\n"; + } out << "\n"; GenerateHeaderIncludes(out, types, defined_type); diff --git a/options.cpp b/options.cpp index 166e8ac1..351b4f6a 100644 --- a/options.cpp +++ b/options.cpp @@ -408,8 +408,8 @@ Options::Options(int argc, const char* const argv[], Options::Language default_l << "file." << endl; return; } - if (gen_log_ && language_ != Options::Language::CPP) { - error_message_ << "--log is currently supported only for --lang=cpp" << endl; + if (gen_log_ && (language_ != Options::Language::CPP && language_ != Options::Language::NDK)) { + error_message_ << "--log is currently supported for either --lang=cpp or --lang=ndk" << endl; return; } } diff --git a/tests/android/aidl/loggable/ILoggableInterfaceNdk.aidl b/tests/android/aidl/loggable/ILoggableInterfaceNdk.aidl new file mode 100644 index 00000000..b3d2de69 --- /dev/null +++ b/tests/android/aidl/loggable/ILoggableInterfaceNdk.aidl @@ -0,0 +1,14 @@ +package android.aidl.loggable; + +interface ILoggableInterfaceNdk { + String[] LogThis(boolean boolValue, inout boolean[] boolArray, + byte byteValue, inout byte[] byteArray, + char charValue, inout char[] charArray, + int intValue, inout int[] intArray, + long longValue, inout long[] longArray, + float floatValue, inout float[] floatArray, + double doubleValue, inout double[] doubleArray, + String stringValue, inout String[] stringArray, + IBinder binderValue, + inout ParcelFileDescriptor pfdValue); +} |