Generate code for AIDL defined string constants

Also validate that constant names are not duplicated between
integer and string constants.

Bug: 28233277
Test: Unittests expanded to reflect this change.
      Integration tests expanded to reflect this change.

Change-Id: If46619151cf6ff0146a2dfa90b863b096435a30a
diff --git a/aidl.cpp b/aidl.cpp
index d74c376..3602d1e 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -424,6 +424,32 @@
     return 0;
 }
 
+bool validate_constants(const AidlInterface& interface) {
+  bool success = true;
+  set<string> names;
+  for (const std::unique_ptr<AidlIntConstant>& int_constant :
+       interface.GetIntConstants()) {
+    if (names.count(int_constant->GetName()) > 0) {
+      LOG(ERROR) << "Found duplicate constant name '" << int_constant->GetName()
+                 << "'";
+      success = false;
+    }
+    names.insert(int_constant->GetName());
+  }
+  for (const std::unique_ptr<AidlStringConstant>& string_constant :
+       interface.GetStringConstants()) {
+    if (names.count(string_constant->GetName()) > 0) {
+      LOG(ERROR) << "Found duplicate constant name '" << string_constant->GetName()
+                 << "'";
+      success = false;
+    }
+    names.insert(string_constant->GetName());
+    // We've logged an error message for this on object construction.
+    success = success && string_constant->IsValid();
+  }
+  return success;
+}
+
 // TODO: Remove this in favor of using the YACC parser b/25479378
 bool ParsePreprocessedLine(const string& line, string* decl,
                            vector<string>* package, string* class_name) {
@@ -636,6 +662,9 @@
                                   interface->GetMethods()) != 0) {
     return AidlError::BAD_METHOD_ID;
   }
+  if (!validate_constants(*interface)) {
+    return AidlError::BAD_CONSTANTS;
+  }
 
   if (returned_interface)
     *returned_interface = std::move(interface);
diff --git a/aidl.h b/aidl.h
index 29f0569..dffdf14 100644
--- a/aidl.h
+++ b/aidl.h
@@ -40,6 +40,7 @@
   BAD_TYPE,
   BAD_METHOD_ID,
   GENERATION_ERROR,
+  BAD_CONSTANTS,
 
   OK = 0,
 };
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 3375ed9..4677092 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -66,11 +66,12 @@
 
   unique_ptr<AidlInterface> Parse(const string& path,
                                   const string& contents,
-                                  TypeNamespace* types) {
+                                  TypeNamespace* types,
+                                  AidlError* error = nullptr) {
     io_delegate_.SetFileContents(path, contents);
     unique_ptr<AidlInterface> ret;
     std::vector<std::unique_ptr<AidlImport>> imports;
-    ::android::aidl::internals::load_and_validate_aidl(
+    AidlError actual_error = ::android::aidl::internals::load_and_validate_aidl(
         preprocessed_files_,
         import_paths_,
         path,
@@ -78,6 +79,9 @@
         types,
         &ret,
         &imports);
+    if (error != nullptr) {
+      *error = actual_error;
+    }
     return ret;
   }
 
@@ -263,6 +267,21 @@
   EXPECT_NE(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
 }
 
+TEST_F(AidlTest, FailOnDuplicateConstantNames) {
+  AidlError reported_error;
+  EXPECT_EQ(nullptr,
+            Parse("p/IFoo.aidl",
+                   R"(package p;
+                      interface IFoo {
+                        const String DUPLICATED = "d";
+                        const int DUPLICATED = 1;
+                      }
+                   )",
+                   &cpp_types_,
+                   &reported_error));
+  EXPECT_EQ(AidlError::BAD_CONSTANTS, reported_error);
+}
+
 TEST_F(AidlTest, UnderstandsNativeParcelables) {
   io_delegate_.SetFileContents(
       "p/Bar.aidl",
diff --git a/ast_cpp.cpp b/ast_cpp.cpp
index 093ff14..783b0f3 100644
--- a/ast_cpp.cpp
+++ b/ast_cpp.cpp
@@ -182,12 +182,16 @@
       is_const_(modifiers & IS_CONST),
       is_virtual_(modifiers & IS_VIRTUAL),
       is_override_(modifiers & IS_OVERRIDE),
-      is_pure_virtual_(modifiers & IS_PURE_VIRTUAL) {}
+      is_pure_virtual_(modifiers & IS_PURE_VIRTUAL),
+      is_static_(modifiers & IS_STATIC) {}
 
 void MethodDecl::Write(CodeWriter* to) const {
   if (is_virtual_)
     to->Write("virtual ");
 
+  if (is_static_)
+    to->Write("static ");
+
   to->Write("%s %s", return_type_.c_str(), name_.c_str());
 
   arguments_.Write(to);
diff --git a/ast_cpp.h b/ast_cpp.h
index 50a9a08..7849857 100644
--- a/ast_cpp.h
+++ b/ast_cpp.h
@@ -162,6 +162,7 @@
     IS_VIRTUAL = 1 << 1,
     IS_OVERRIDE = 1 << 2,
     IS_PURE_VIRTUAL = 1 << 3,
+    IS_STATIC = 1 << 4,
   };
 
   MethodDecl(const std::string& return_type,
@@ -183,6 +184,7 @@
   bool is_virtual_ = false;
   bool is_override_ = false;
   bool is_pure_virtual_ = false;
+  bool is_static_ = true;
 
   DISALLOW_COPY_AND_ASSIGN(MethodDecl);
 };  // class MethodDecl
diff --git a/ast_java.cpp b/ast_java.cpp
index 44e298d..1ba723c 100644
--- a/ast_java.cpp
+++ b/ast_java.cpp
@@ -417,11 +417,16 @@
   }
 }
 
-void Constant::Write(CodeWriter* to) const {
+void IntConstant::Write(CodeWriter* to) const {
   WriteModifiers(to, STATIC | FINAL | PUBLIC, ALL_MODIFIERS);
   to->Write("int %s = %d;\n", name.c_str(), value);
 }
 
+void StringConstant::Write(CodeWriter* to) const {
+  WriteModifiers(to, STATIC | FINAL | PUBLIC, ALL_MODIFIERS);
+  to->Write("String %s = %s;\n", name.c_str(), value.c_str());
+}
+
 void Class::Write(CodeWriter* to) const {
   size_t N, i;
 
diff --git a/ast_java.h b/ast_java.h
index cd318d7..3ec48b7 100644
--- a/ast_java.h
+++ b/ast_java.h
@@ -326,12 +326,24 @@
   void Write(CodeWriter* to) const override;
 };
 
-struct Constant : public ClassElement {
-  std::string name;
-  int value;
+struct IntConstant : public ClassElement {
+  const std::string name;
+  const int value;
 
-  Constant() = default;
-  virtual ~Constant() = default;
+  IntConstant(std::string name, int value)
+      : name(name), value(value) {}
+  virtual ~IntConstant() = default;
+
+  void Write(CodeWriter* to) const override;
+};
+
+struct StringConstant : public ClassElement {
+  const std::string name;
+  const std::string value;
+
+  StringConstant(std::string name, std::string value)
+      : name(name), value(value) {}
+  ~StringConstant() override = default;
 
   void Write(CodeWriter* to) const override;
 };
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index 0ab136e..77badc4 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -60,6 +60,7 @@
 const char kIInterfaceHeader[] = "binder/IInterface.h";
 const char kParcelHeader[] = "binder/Parcel.h";
 const char kStatusHeader[] = "binder/Status.h";
+const char kString16Header[] = "utils/String16.h";
 const char kStrongPointerHeader[] = "utils/StrongPointer.h";
 
 unique_ptr<AstNode> BreakOnStatusNotOk() {
@@ -572,14 +573,30 @@
     fq_name = interface.GetPackage() + "." + fq_name;
   }
 
+  vector<unique_ptr<Declaration>> decls;
+
   unique_ptr<MacroDecl> meta_if{new MacroDecl{
       "IMPLEMENT_META_INTERFACE",
       ArgList{vector<string>{ClassName(interface, ClassNames::BASE),
                              '"' + fq_name + '"'}}}};
+  decls.push_back(std::move(meta_if));
+
+  for (const auto& constant: interface.GetStringConstants()) {
+    unique_ptr<MethodImpl> getter(new MethodImpl(
+        "const ::android::String16&",
+        ClassName(interface, ClassNames::INTERFACE),
+        constant->GetName(),
+        {}));
+    getter->GetStatementBlock()->AddLiteral(
+        StringPrintf("static const ::android::String16 value(%s)",
+                     constant->GetValue().c_str()));
+    getter->GetStatementBlock()->AddLiteral("return value");
+    decls.push_back(std::move(getter));
+  }
 
   return unique_ptr<Document>{new CppSource{
       include_list,
-      NestInNamespaces(std::move(meta_if), interface.GetSplitPackage())}};
+      NestInNamespaces(std::move(decls), interface.GetSplitPackage())}};
 }
 
 unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
@@ -685,6 +702,16 @@
     if_class->AddPublic(std::move(constant_enum));
   }
 
+  if (!interface.GetStringConstants().empty()) {
+    includes.insert(kString16Header);
+  }
+  for (const auto& constant : interface.GetStringConstants()) {
+    unique_ptr<MethodDecl> getter(new MethodDecl(
+          "const ::android::String16&", constant->GetName(),
+          {}, MethodDecl::IS_STATIC));
+    if_class->AddPublic(std::move(getter));
+  }
+
   if (!interface.GetMethods().empty()) {
     unique_ptr<Enum> call_enum{new Enum{"Call"}};
     for (const auto& method : interface.GetMethods()) {
diff --git a/generate_java_binder.cpp b/generate_java_binder.cpp
index 9ec2a23..02a6922 100644
--- a/generate_java_binder.cpp
+++ b/generate_java_binder.cpp
@@ -245,12 +245,16 @@
   t->CreateFromParcel(addTo, v, parcel, cl);
 }
 
-static void generate_constant(const AidlIntConstant& constant,
-                              Class* interface) {
-  Constant* decl = new Constant;
-  decl->name = constant.GetName();
-  decl->value = constant.GetValue();
+static void generate_int_constant(const AidlIntConstant& constant,
+                                  Class* interface) {
+  IntConstant* decl = new IntConstant(constant.GetName(), constant.GetValue());
+  interface->elements.push_back(decl);
+}
 
+static void generate_string_constant(const AidlStringConstant& constant,
+                                     Class* interface) {
+  StringConstant* decl = new StringConstant(constant.GetName(),
+                                            constant.GetValue());
   interface->elements.push_back(decl);
 }
 
@@ -529,7 +533,10 @@
 
   // all the declared constants of the interface
   for (const auto& item : iface->GetIntConstants()) {
-    generate_constant(*item, interface);
+    generate_int_constant(*item, interface);
+  }
+  for (const auto& item : iface->GetStringConstants()) {
+    generate_string_constant(*item, interface);
   }
 
   // all the declared methods of the interface
diff --git a/tests/aidl_test_client_primitives.cpp b/tests/aidl_test_client_primitives.cpp
index 405538e..9142abd 100644
--- a/tests/aidl_test_client_primitives.cpp
+++ b/tests/aidl_test_client_primitives.cpp
@@ -86,6 +86,8 @@
       //   U+10437: The 'small letter yee' character in the deseret alphabet
       //   U+20AC: A euro sign
       String16("\xD8\x01\xDC\x37\x20\xAC"),
+      ITestService::STRING_TEST_CONSTANT(),
+      ITestService::STRING_TEST_CONSTANT2(),
   };
   for (const auto& input : inputs) {
     String16 reply;
diff --git a/tests/android/aidl/tests/ITestService.aidl b/tests/android/aidl/tests/ITestService.aidl
index 30887d4..b8a3ab7 100644
--- a/tests/android/aidl/tests/ITestService.aidl
+++ b/tests/android/aidl/tests/ITestService.aidl
@@ -31,6 +31,9 @@
   const int TEST_CONSTANT7 = +0;
   const int TEST_CONSTANT8 = 0;
 
+  const String STRING_TEST_CONSTANT = "foo";
+  const String STRING_TEST_CONSTANT2 = "bar";
+
   // Test that primitives work as parameters and return types.
   boolean RepeatBoolean(boolean token);
   byte RepeatByte(byte token);
diff --git a/tests/java_app/src/android/aidl/tests/TestServiceClient.java b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
index 04b76f6..4af4aa0 100644
--- a/tests/java_app/src/android/aidl/tests/TestServiceClient.java
+++ b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
@@ -154,7 +154,12 @@
                                      " responded " + response);
                 }
             }
-            for (String query : Arrays.asList("not empty", "", "\0")) {
+
+            List<String> queries = Arrays.asList(
+                "not empty", "", "\0",
+                ITestService.STRING_TEST_CONSTANT,
+                ITestService.STRING_TEST_CONSTANT2);
+            for (String query : queries) {
                 String response = service.RepeatString(query);
                 if (!query.equals(response)) {
                     mLog.logAndThrow("Repeat request with '" + query + "'" +
diff --git a/tests/test_data_string_constants.cpp b/tests/test_data_string_constants.cpp
index 40c6547..4674843 100644
--- a/tests/test_data_string_constants.cpp
+++ b/tests/test_data_string_constants.cpp
@@ -96,6 +96,7 @@
 }
 }
 }
+public static final String EXAMPLE_CONSTANT = "foo";
 }
 )";
 
@@ -109,6 +110,7 @@
 #include <binder/IBinder.h>
 #include <binder/IInterface.h>
 #include <binder/Status.h>
+#include <utils/String16.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
@@ -118,6 +120,7 @@
 class IStringConstants : public ::android::IInterface {
 public:
 DECLARE_META_INTERFACE(StringConstants)
+static const ::android::String16& EXAMPLE_CONSTANT();
 };  // class IStringConstants
 
 }  // namespace os
@@ -137,6 +140,11 @@
 
 IMPLEMENT_META_INTERFACE(StringConstants, "android.os.IStringConstants")
 
+const ::android::String16& IStringConstants::EXAMPLE_CONSTANT() {
+static const ::android::String16 value("foo");
+return value;
+}
+
 }  // namespace os
 
 }  // namespace android