Log AIDL transaction for binder native

Add logging code for server when gen_log is true

If you want to add your own logging code in server side, you should
assign log function into Bn...::logFunc

Bug: 111163090
Test: m -j

Change-Id: I7064b513204e742439492221a0b799757f23c191
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index 28bd32d..2e2b963 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -225,6 +225,107 @@
   return ret;
 }
 
+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::objectValue);\n";
+
+  (*writer) << "if (" << className << "::logFunc != nullptr) {\n";
+  (*writer).Indent();
+
+  for (const auto& a : method.GetArguments()) {
+    if (a->IsIn()) {
+      string varName = isServer ? BuildVarName(*a) : a->GetName();
+      bool isPointer = a->IsOut() && !isServer;
+      WriteLogFor(
+          {*(writer.get()), types.typenames_, a->GetType(), varName, isPointer, "_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 kReturnVarName, 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,
+  //   interface_name: "foo.bar.IFoo",
+  //   method_name: "TestMethod",
+  //   (proxy|stub)_address: "0x12345678",
+  //   input_args: {
+  //     arg1: 30,
+  //     arg2: ["apple", "grape"],
+  //   },
+  //   output_args: {
+  //     arg2: ["mango", "banana"],
+  //     arg3: "10.5",
+  //   },
+  //   _aidl_return: "ok",
+  // }
+  (*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_cast<std::chrono::milliseconds>(_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::objectValue);\n";
+
+  for (const auto& a : method.GetOutArguments()) {
+    string varName = isServer ? BuildVarName(*a) : a->GetName();
+    bool isPointer = !isServer;
+    WriteLogFor(
+        {*(writer.get()), types.typenames_, a->GetType(), varName, isPointer, "_log_output_args"});
+  }
+
+  (*writer) << "_log_transaction[\"output_args\"] = _log_output_args;\n";
+
+  if (method.GetType().GetName() != "void") {
+    WriteLogFor({*(writer.get()), types.typenames_, method.GetType(), kReturnVarName, !isServer,
+                 "_log_transaction"});
+  }
+
+  // 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) {
@@ -254,26 +355,7 @@
   }
 
   if (options.GenLog()) {
-    string code;
-    CodeWriterPtr writer = CodeWriter::ForString(&code);
-    (*writer) << "Json::Value _log_input_args(Json::objectValue);\n";
-
-    (*writer) << "if (" << bp_name << "::logFunc != nullptr) {\n";
-    (*writer).Indent();
-
-    for (const auto& a : method.GetArguments()) {
-      if (a->IsIn()) {
-        WriteLogFor({*(writer.get()), types.typenames_, a->GetType(), a->GetName(), a->IsOut(),
-                     "_log_input_args"});
-      }
-    }
-
-    (*writer).Dedent();
-    (*writer) << "}\n";
-
-    (*writer) << "auto _log_start = std::chrono::steady_clock::now();\n";
-    writer->Close();
-    b->AddLiteral(code, false /* no semicolon */);
+    b->AddLiteral(GenLogBeforeExecute(bp_name, method, types, false), false /* no semicolon */);
   }
 
   // Add the name of the interface we're hoping to call.
@@ -402,73 +484,8 @@
                    kAndroidStatusVarName));
 
   if (options.GenLog()) {
-    string code;
-    CodeWriterPtr writer = CodeWriter::ForString(&code);
-
-    (*writer) << "if (" << bp_name << "::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,
-    //   interface_name: "foo.bar.IFoo",
-    //   method_name: "TestMethod",
-    //   proxy_address: "0x12345678",
-    //   input_args: {
-    //     arg1: 30,
-    //     arg2: ["apple", "grape"],
-    //   },
-    //   output_args: {
-    //     arg2: ["mango", "banana"],
-    //     arg3: "10.5",
-    //   },
-    //   _aidl_return: "ok",
-    // }
-    (*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_cast<std::chrono::milliseconds>(_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[\"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::objectValue);\n";
-
-    for (const auto& a : method.GetOutArguments()) {
-      WriteLogFor({*(writer.get()), types.typenames_, a->GetType(), a->GetName(), true,
-                   "_log_output_args"});
-    }
-
-    (*writer) << "_log_transaction[\"output_args\"] = _log_output_args;\n";
-
-    if (method.GetType().GetName() != "void") {
-      WriteLogFor({*(writer.get()), types.typenames_, method.GetType(), kReturnVarName, true,
-                   "_log_transaction"});
-    }
-
-    // call the user-provided function with the Json object for the entire
-    // transaction
-    (*writer) << bp_name << "::logFunc(_log_transaction);\n";
-
-    (*writer).Dedent();
-    (*writer) << "}\n";
-
-    writer->Close();
-    b->AddLiteral(code, false /* no semicolon */);
+    b->AddLiteral(GenLogAfterExecute(bp_name, interface, method, types, kReturnVarName, false),
+                  false /* no semicolon */);
   }
 
   b->AddLiteral(StringPrintf("return %s", kStatusVarName));
@@ -622,7 +639,10 @@
                      interface.GetName().c_str(),
                      method.GetName().c_str())}})));
   }
-
+  const string bn_name = ClassName(interface, ClassNames::SERVER);
+  if (options.GenLog()) {
+    b->AddLiteral(GenLogBeforeExecute(bn_name, method, types, true), false);
+  }
   // Call the actual method.  This is implemented by the subclass.
   vector<unique_ptr<AstNode>> status_args;
   status_args.emplace_back(new MethodCall(
@@ -659,7 +679,10 @@
         ArgList{return_type->WriteCast(kReturnVarName)}}});
     b->AddStatement(BreakOnStatusNotOk());
   }
-
+  if (options.GenLog()) {
+    b->AddLiteral(GenLogAfterExecute(bn_name, interface, method, types, kReturnVarName, true),
+                  false);
+  }
   // Write each out parameter to the reply parcel.
   for (const AidlArgument* a : method.GetOutArguments()) {
     // Serialization looks roughly like:
@@ -703,6 +726,12 @@
       HeaderFile(interface, ClassNames::SERVER, false),
       kParcelHeader
   };
+  if (options.GenLog()) {
+    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",
       ArgList{{StringPrintf("uint32_t %s", kCodeVarName),
@@ -760,10 +789,20 @@
   // Finally, the server's onTransact method just returns a status code.
   on_transact->GetStatementBlock()->AddLiteral(
       StringPrintf("return %s", kAndroidStatusVarName));
+  vector<unique_ptr<Declaration>> decls;
+  decls.push_back(std::move(on_transact));
 
-  return unique_ptr<Document>{new CppSource{
-      include_list,
-      NestInNamespaces(std::move(on_transact), interface.GetSplitPackage())}};
+  if (options.GenLog()) {
+    string code;
+    ClassName(interface, ClassNames::SERVER);
+    CodeWriterPtr writer = CodeWriter::ForString(&code);
+    (*writer) << "std::function<void(const Json::Value&)> "
+              << ClassName(interface, ClassNames::SERVER) << "::logFunc;\n";
+    writer->Close();
+    decls.push_back(unique_ptr<Declaration>(new LiteralDecl(code)));
+  }
+  return unique_ptr<Document>{
+      new CppSource{include_list, NestInNamespaces(std::move(decls), interface.GetSplitPackage())}};
 }
 
 unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& types,
@@ -898,7 +937,7 @@
 }
 
 unique_ptr<Document> BuildServerHeader(const TypeNamespace& /* types */,
-                                       const AidlInterface& interface, const Options&) {
+                                       const AidlInterface& interface, const Options& options) {
   const string i_name = ClassName(interface, ClassNames::INTERFACE);
   const string bn_name = ClassName(interface, ClassNames::SERVER);
 
@@ -911,10 +950,19 @@
                StringPrintf("uint32_t %s", kFlagsVarName)}},
       MethodDecl::IS_OVERRIDE
   }};
+  vector<string> includes = {"binder/IInterface.h",
+                             HeaderFile(interface, ClassNames::INTERFACE, false)};
 
-  std::vector<unique_ptr<Declaration>> publics;
+  vector<unique_ptr<Declaration>> publics;
   publics.push_back(std::move(on_transact));
 
+  if (options.GenLog()) {
+    includes.emplace_back("chrono");      // for std::chrono::steady_clock
+    includes.emplace_back("functional");  // for std::function
+    includes.emplace_back("json/value.h");
+    publics.emplace_back(
+        new LiteralDecl{"static std::function<void(const Json::Value&)> logFunc;\n"});
+  }
   unique_ptr<ClassDecl> bn_class{
       new ClassDecl{bn_name,
                     "::android::BnInterface<" + i_name + ">",
@@ -922,11 +970,9 @@
                     {}
       }};
 
-  return unique_ptr<Document>{new CppHeader{
-      BuildHeaderGuard(interface, ClassNames::SERVER),
-      {"binder/IInterface.h",
-       HeaderFile(interface, ClassNames::INTERFACE, false)},
-      NestInNamespaces(std::move(bn_class), interface.GetSplitPackage())}};
+  return unique_ptr<Document>{
+      new CppHeader{BuildHeaderGuard(interface, ClassNames::SERVER), includes,
+                    NestInNamespaces(std::move(bn_class), interface.GetSplitPackage())}};
 }
 
 unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,