Generate server side .cpp file

Bug: 24505488
Test: Unit tests, wrote some more

Change-Id: I89d18f0bb612f3a3ffadac41c6ff32b67d6552b7
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 7f00635..6458d8a 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -92,6 +92,10 @@
       id_(id) {
   has_id_ = true;
   delete args;
+  for (const unique_ptr<AidlArgument>& a : arguments_) {
+    if (a->IsIn()) { in_arguments_.push_back(a.get()); }
+    if (a->IsOut()) { out_arguments_.push_back(a.get()); }
+  }
 }
 
 AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name,
diff --git a/aidl_language.h b/aidl_language.h
index b6c119c..d076e94 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -80,7 +80,10 @@
   virtual ~AidlArgument() = default;
 
   Direction GetDirection() const { return direction_; }
+  bool IsOut() const { return direction_ & OUT_DIR; }
+  bool IsIn() const { return direction_ & IN_DIR; }
   bool DirectionWasSpecified() const { return direction_specified_; }
+
   std::string GetName() const { return name_; }
   int GetLine() const { return line_; }
   const AidlType& GetType() const { return *type_; }
@@ -117,7 +120,16 @@
   void SetId(unsigned id) { id_ = id; }
 
   const std::vector<std::unique_ptr<AidlArgument>>& GetArguments() const {
-      return arguments_;
+    return arguments_;
+  }
+  // An inout parameter will appear in both GetInArguments()
+  // and GetOutArguments().  AidlMethod retains ownership of the argument
+  // pointers returned in this way.
+  const std::vector<const AidlArgument*>& GetInArguments() const {
+    return in_arguments_;
+  }
+  const std::vector<const AidlArgument*>& GetOutArguments() const {
+    return out_arguments_;
   }
 
  private:
@@ -126,7 +138,9 @@
   std::unique_ptr<AidlType> type_;
   std::string name_;
   unsigned line_;
-  std::vector<std::unique_ptr<AidlArgument>> arguments_;
+  const std::vector<std::unique_ptr<AidlArgument>> arguments_;
+  std::vector<const AidlArgument*> in_arguments_;
+  std::vector<const AidlArgument*> out_arguments_;
   bool has_id_;
   int id_;
 
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index 4f58c50..128e8a8 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -18,11 +18,13 @@
 #include "parse_helpers.h"
 
 #include <cctype>
+#include <cstring>
 #include <memory>
 #include <random>
 #include <string>
 
 #include <base/stringprintf.h>
+#include <base/strings.h>
 
 #include "aidl_language.h"
 #include "ast_cpp.h"
@@ -30,6 +32,7 @@
 #include "logging.h"
 
 using android::base::StringPrintf;
+using android::base::Join;
 using std::string;
 using std::unique_ptr;
 using std::vector;
@@ -39,10 +42,12 @@
 namespace cpp {
 namespace internals {
 namespace {
-
+const char kStatusOkOrBreakCheck[] = "if (status != android::OK) { break; }";
+const char kReturnVarName[] = "_aidl_return";
 const char kAndroidStatusLiteral[] = "android::status_t";
 const char kIBinderHeader[] = "binder/IBinder.h";
 const char kIInterfaceHeader[] = "binder/IInterface.h";
+const char kParcelHeader[] = "binder/Parcel.h";
 
 string UpperCase(const std::string& s) {
   string result = s;
@@ -51,33 +56,53 @@
   return result;
 }
 
-string GetCPPVarDec(const TypeNamespace& types, const AidlType& type,
-                    const string& var_name, bool use_pointer) {
-  const Type* cpp_type = types.Find(type.GetName());
-  if (cpp_type == nullptr) {
-    // We should have caught this in type resolution.
-    LOG(FATAL) << "internal error";
+string BuildVarName(const AidlArgument& a) {
+  string prefix = "out_";
+  if (a.GetDirection() & AidlArgument::IN_DIR) {
+    prefix = "in_";
   }
-  return StringPrintf("%s%s %s%s",
-                      cpp_type->CppType().c_str(),
-                      (use_pointer) ? "*" : "",
-                      var_name.c_str(),
-                      type.IsArray() ? "[]" : "");
+  return prefix + a.GetName();
+}
+
+vector<string> BuildArgList(const TypeNamespace& types,
+                            const AidlMethod& method,
+                            bool for_declaration) {
+  // Build up the argument list for the server method call.
+  vector<string> method_arguments;
+  for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
+    string literal;
+    if (for_declaration) {
+      // Method declarations need types, pointers to out params, and variable
+      // names that match the .aidl specification.
+      const Type* type = types.Find(a->GetType().GetName());
+      literal = StringPrintf(
+          "%s%s %s", type->CppType().c_str(),
+          (a->IsOut()) ? "*" : "",
+          a->GetName().c_str());
+    } else {
+      if (a->IsOut()) { literal = "&"; }
+      literal += BuildVarName(*a);
+    }
+    method_arguments.push_back(literal);
+  }
+
+  const Type* return_type = types.Find(method.GetType().GetName());
+  if (return_type != types.VoidType()) {
+    if (for_declaration) {
+      method_arguments.push_back(
+          StringPrintf("%s* %s", return_type->CppType().c_str(),
+                       kReturnVarName));
+    } else {
+      method_arguments.push_back(string{"&"} + kReturnVarName);
+    }
+  }
+
+  return method_arguments;
 }
 
 unique_ptr<Declaration> BuildMethodDecl(const AidlMethod& method,
                                         const TypeNamespace& types,
                                         bool for_interface) {
-  vector<string> args;
-  for (const unique_ptr<AidlArgument>& arg : method.GetArguments()) {
-    args.push_back(GetCPPVarDec(
-          types, arg->GetType(), arg->GetName(),
-          AidlArgument::OUT_DIR & arg->GetDirection()));
-  }
-
-  string return_arg = GetCPPVarDec(types, method.GetType(), "_aidl_return", true);
-  args.push_back(return_arg);
-
   uint32_t modifiers = 0;
   if (for_interface) {
     modifiers |= MethodDecl::IS_VIRTUAL;
@@ -89,7 +114,7 @@
   return unique_ptr<Declaration>{
       new MethodDecl{kAndroidStatusLiteral,
                      method.GetName(),
-                     args,
+                     BuildArgList(types, method, true /* for method decl */),
                      modifiers}};
 }
 
@@ -99,6 +124,15 @@
   return NPtr{new N{"android", NPtr{new N{"generated", std::move(decl)}}}};
 }
 
+bool DeclareLocalVariable(const TypeNamespace& types, const AidlArgument& a,
+                          StatementBlock* b) {
+  const Type* cpp_type = types.Find(a.GetType().GetName());
+  if (!cpp_type) { return false; }
+
+  b->AddLiteral(cpp_type->CppType() + " " + BuildVarName(a));
+  return true;
+}
+
 }  // namespace
 
 enum class ClassNames { BASE, CLIENT, SERVER, INTERFACE };
@@ -131,10 +165,103 @@
   return unique_ptr<Document>{new CppSource{ {}, std::move(ns)}};
 }
 
+namespace {
+
+bool HandleServerTransaction(const TypeNamespace& types,
+                             const AidlMethod& method,
+                             StatementBlock* b) {
+  // Declare all the parameters now.  In the common case, we expect no errors
+  // in serialization.
+  for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
+    if (!DeclareLocalVariable(types, *a, b)) { return false; }
+  }
+
+  // Declare a variable to hold the return value.
+  const Type* return_type = types.Find(method.GetType().GetName());
+  if (return_type != types.VoidType()) {
+    b->AddLiteral(StringPrintf(
+        "%s %s", return_type->CppType().c_str(), kReturnVarName));
+  }
+
+  // Declare the status variable
+  b->AddLiteral(StringPrintf("%s status", kAndroidStatusLiteral));
+
+  // Deserialize each "in" parameter to the transaction.
+  for (const AidlArgument* a : method.GetInArguments()) {
+    // Deserialization looks roughly like:
+    //     status = data.ReadInt32(&in_param_name);
+    //     if (status != android::OK) { break; }
+    const Type* type = types.Find(a->GetType().GetName());
+    b->AddStatement(new Assignment{
+        "status",
+        new MethodCall{"data." + type->ReadFromParcelMethod(),
+                       "&" + BuildVarName(*a)}});
+    b->AddLiteral(kStatusOkOrBreakCheck, false /* no semicolon */);
+  }
+
+  // Call the actual method.  This is implemented by the subclass.
+  b->AddStatement(new Assignment{
+      "status", new MethodCall{
+          method.GetName(),
+          new ArgList{BuildArgList(types, method,
+                                   false /* not for method decl */)}}});
+  b->AddLiteral(kStatusOkOrBreakCheck, false /* no semicolon */);
+
+  // Write each out parameter to the reply parcel.
+  for (const AidlArgument* a : method.GetOutArguments()) {
+    // Serialization looks roughly like:
+    //     status = data.WriteInt32(out_param_name);
+    //     if (status != android::OK) { break; }
+    const Type* type = types.Find(a->GetType().GetName());
+    b->AddStatement(new Assignment{
+        "status",
+        new MethodCall{"reply->" + type->WriteToParcelMethod(),
+                       BuildVarName(*a)}});
+    b->AddLiteral(kStatusOkOrBreakCheck, false /* no semicolon */);
+  }
+
+  return true;
+}
+
+}  // namespace
+
 unique_ptr<Document> BuildServerSource(const TypeNamespace& types,
                                        const AidlInterface& parsed_doc) {
-  unique_ptr<CppNamespace> ns{new CppNamespace{"android"}};
-  return unique_ptr<Document>{new CppSource{ {}, std::move(ns)}};
+  const string bn_name = ClassName(parsed_doc, ClassNames::SERVER);
+  vector<string> include_list{bn_name + ".h", kParcelHeader};
+  unique_ptr<MethodImpl> on_transact{new MethodImpl{
+      kAndroidStatusLiteral, bn_name, "onTransact",
+      {"uint32_t code",
+       "const android::Parcel& data",
+       "android::Parcel* reply",
+       "uint32_t flags"}
+  }};
+
+  // Add the all important switch statement, but retain a pointer to it.
+  SwitchStatement* s = new SwitchStatement{"code"};
+  on_transact->AddStatement(unique_ptr<AstNode>{s});
+
+  // The switch statement has a case statement for each transaction code.
+  for (const auto& method : parsed_doc.GetMethods()) {
+    StatementBlock* b = s->AddCase("Call::" + UpperCase(method->GetName()));
+    if (!b) { return nullptr; }
+
+    if (!HandleServerTransaction(types, *method, b)) { return nullptr; }
+  }
+
+  // The switch statement has a default case which defers to the super class.
+  // The superclass handles a few pre-defined transactions.
+  StatementBlock* b = s->AddCase("");
+  b->AddLiteral(
+      "status = android::BBinder::onTransact(code, data, reply, flags)");
+
+  // Finally, the server's onTransact method just returns a status code.
+  on_transact->AddStatement(unique_ptr<AstNode>{
+      new LiteralStatement{"return status"}});
+
+  return unique_ptr<Document>{new CppSource{
+      include_list,
+      NestInNamespaces(std::move(on_transact))}};
 }
 
 unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& types,
diff --git a/generate_cpp.h b/generate_cpp.h
index 8dc152b..d6a8177 100644
--- a/generate_cpp.h
+++ b/generate_cpp.h
@@ -18,6 +18,7 @@
 #define AIDL_GENERATE_CPP_H_
 
 #include "aidl_language.h"
+#include "ast_cpp.h"
 #include "options.h"
 #include "type_cpp.h"
 
@@ -29,6 +30,18 @@
                  const cpp::TypeNamespace& types,
                  const AidlInterface& parsed_doc);
 
+namespace internals {
+std::unique_ptr<Document> BuildClientSource(const TypeNamespace& types,
+                                            const AidlInterface& parsed_doc);
+std::unique_ptr<Document> BuildServerSource(const TypeNamespace& types,
+                                            const AidlInterface& parsed_doc);
+std::unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& types,
+                                               const AidlInterface& parsed_doc);
+std::unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
+                                            const AidlInterface& parsed_doc);
+std::unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
+                                               const AidlInterface& parsed_doc);
+}
 }  // namespace cpp
 }  // namespace aidl
 }  // namespace android
diff --git a/generate_cpp_unittest.cpp b/generate_cpp_unittest.cpp
index f6bb7c1..9801d00 100644
--- a/generate_cpp_unittest.cpp
+++ b/generate_cpp_unittest.cpp
@@ -22,6 +22,7 @@
 #include "aidl_language.h"
 #include "ast_cpp.h"
 #include "code_writer.h"
+#include "generate_cpp.h"
 #include "tests/fake_io_delegate.h"
 #include "type_cpp.h"
 
@@ -32,15 +33,6 @@
 namespace android {
 namespace aidl {
 namespace cpp {
-namespace internals {
-unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& types,
-                                          const AidlInterface& parsed_doc);
-unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
-                                       const AidlInterface& parsed_doc);
-unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
-                                          const AidlInterface& parsed_doc);
-}
-
 namespace {
 
 const char kTrivialInterfaceAIDL[] =
@@ -48,6 +40,41 @@
   int Ping(int token);
 })";
 
+const char kExpectedTrivialServerSourceOutput[] =
+R"(#include <BnPingResponder.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+namespace generated {
+
+android::status_t BnPingResponder::onTransact(uint32_t code, const android::Parcel& data, android::Parcel* reply, uint32_t flags) {
+switch (code) {
+case Call::PING:
+{
+int32_t in_token;
+int32_t _aidl_return;
+android::status_t status;
+status = data.readInt32(&in_token);
+if (status != android::OK) { break; }
+status = Ping(in_token, &_aidl_return);
+if (status != android::OK) { break; }
+}
+break;
+default:
+{
+status = android::BBinder::onTransact(code, data, reply, flags);
+}
+break;
+}
+return status;
+}
+
+}  // namespace generated
+
+}  // namespace android
+)";
+
 const char kExpectedTrivialClientHeaderOutput[] =
 R"(#ifndef BpPingResponder_H
 #define BpPingResponder_H
@@ -156,6 +183,14 @@
   Compare(doc.get(), kExpectedTrivialClientHeaderOutput);
 }
 
+TEST_F(TrivialInterfaceASTTest, GeneratesServerSource) {
+  AidlInterface* interface = Parse();
+  ASSERT_NE(interface, nullptr);
+  TypeNamespace types;
+  unique_ptr<Document> doc = internals::BuildServerSource(types, *interface);
+  Compare(doc.get(), kExpectedTrivialServerSourceOutput);
+}
+
 TEST_F(TrivialInterfaceASTTest, GeneratesInterfaceHeader) {
   AidlInterface* interface = Parse();
   ASSERT_NE(interface, nullptr);
diff --git a/type_cpp.cpp b/type_cpp.cpp
index 6f80845..8ab26c3 100644
--- a/type_cpp.cpp
+++ b/type_cpp.cpp
@@ -24,6 +24,18 @@
 namespace android {
 namespace aidl {
 namespace cpp {
+namespace {
+
+class VoidType : public Type {
+ public:
+  VoidType() : Type("void", "void", "XXX", "XXX") {}
+  virtual ~VoidType() = default;
+  bool CanBeArray() const override { return false; }
+  bool CanBeOutParameter() const override { return false; }
+  bool CanWriteToParcel() const override { return false; }
+};  // class VoidType
+
+}  // namespace
 
 Type::Type(const string& aidl_type,
            const string& cpp_type,
@@ -59,6 +71,9 @@
       new Type("float", "float", "readFloat", "writeFloat"));
   types_.emplace_back(
       new Type("double", "double", "readDouble", "writeDouble"));
+
+  void_type_ = new class VoidType();
+  types_.emplace_back(void_type_);
 }
 
 bool TypeNamespace::AddParcelableType(const AidlParcelable* p,
diff --git a/type_cpp.h b/type_cpp.h
index 26f288d..779a0a7 100644
--- a/type_cpp.h
+++ b/type_cpp.h
@@ -72,6 +72,8 @@
 
   const Type* Find(const std::string& type_name) const;
 
+  const Type* VoidType() const { return void_type_; }
+
  protected:
   const ValidatableType* GetValidatableType(
       const std::string& type_name) const override;
@@ -79,6 +81,8 @@
  private:
   std::vector<std::unique_ptr<Type>> types_;
 
+  Type* void_type_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(TypeNamespace);
 };  // class TypeNamespace